Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(373)

Side by Side Diff: runtime/vm/flow_graph_compiler_arm.cc

Issue 12773008: Support checked mode for VM tests on ARM. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/assembler_arm.cc ('k') | runtime/vm/flow_graph_compiler_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM.
6 #if defined(TARGET_ARCH_ARM) 6 #if defined(TARGET_ARCH_ARM)
7 7
8 #include "vm/flow_graph_compiler.h" 8 #include "vm/flow_graph_compiler.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
11 #include "vm/ast_printer.h" 11 #include "vm/ast_printer.h"
12 #include "vm/dart_entry.h" 12 #include "vm/dart_entry.h"
13 #include "vm/il_printer.h" 13 #include "vm/il_printer.h"
14 #include "vm/locations.h" 14 #include "vm/locations.h"
15 #include "vm/object_store.h" 15 #include "vm/object_store.h"
16 #include "vm/parser.h" 16 #include "vm/parser.h"
17 #include "vm/stub_code.h" 17 #include "vm/stub_code.h"
18 #include "vm/symbols.h" 18 #include "vm/symbols.h"
19 19
20 namespace dart { 20 namespace dart {
21 21
22 DECLARE_FLAG(int, optimization_counter_threshold); 22 DECLARE_FLAG(int, optimization_counter_threshold);
23 DECLARE_FLAG(bool, print_ast); 23 DECLARE_FLAG(bool, print_ast);
24 DECLARE_FLAG(bool, print_scopes); 24 DECLARE_FLAG(bool, print_scopes);
25 DECLARE_FLAG(bool, enable_type_checks); 25 DECLARE_FLAG(bool, enable_type_checks);
26 DECLARE_FLAG(bool, eliminate_type_checks);
26 27
27 28
28 FlowGraphCompiler::~FlowGraphCompiler() { 29 FlowGraphCompiler::~FlowGraphCompiler() {
29 // BlockInfos are zone-allocated, so their destructors are not called. 30 // BlockInfos are zone-allocated, so their destructors are not called.
30 // Verify the labels explicitly here. 31 // Verify the labels explicitly here.
31 for (int i = 0; i < block_info_.length(); ++i) { 32 for (int i = 0; i < block_info_.length(); ++i) {
32 ASSERT(!block_info_[i]->jump_label()->IsLinked()); 33 ASSERT(!block_info_[i]->jump_label()->IsLinked());
33 } 34 }
34 } 35 }
35 36
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 Label* is_not_instance_lbl) { 76 Label* is_not_instance_lbl) {
76 UNIMPLEMENTED(); 77 UNIMPLEMENTED();
77 return NULL; 78 return NULL;
78 } 79 }
79 80
80 81
81 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, 82 void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
82 const GrowableArray<intptr_t>& class_ids, 83 const GrowableArray<intptr_t>& class_ids,
83 Label* is_equal_lbl, 84 Label* is_equal_lbl,
84 Label* is_not_equal_lbl) { 85 Label* is_not_equal_lbl) {
85 UNIMPLEMENTED(); 86 for (intptr_t i = 0; i < class_ids.length(); i++) {
87 __ CompareImmediate(class_id_reg, class_ids[i]);
88 __ b(is_equal_lbl, EQ);
89 }
90 __ b(is_not_equal_lbl);
86 } 91 }
87 92
88 93
94 // Testing against an instantiated type with no arguments, without
95 // SubtypeTestCache.
96 // R0: instance being type checked (preserved).
97 // Clobbers R2, R3.
98 // Returns true if there is a fallthrough.
89 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( 99 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
90 intptr_t token_pos, 100 intptr_t token_pos,
91 const AbstractType& type, 101 const AbstractType& type,
92 Label* is_instance_lbl, 102 Label* is_instance_lbl,
93 Label* is_not_instance_lbl) { 103 Label* is_not_instance_lbl) {
94 UNIMPLEMENTED(); 104 __ Comment("InstantiatedTypeNoArgumentsTest");
95 return false; 105 ASSERT(type.IsInstantiated());
106 const Class& type_class = Class::Handle(type.type_class());
107 ASSERT(!type_class.HasTypeArguments());
108
109 const Register kInstanceReg = R0;
110 __ tst(kInstanceReg, ShifterOperand(kSmiTagMask));
111 // If instance is Smi, check directly.
112 const Class& smi_class = Class::Handle(Smi::Class());
113 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
114 type_class,
115 TypeArguments::Handle(),
116 NULL)) {
117 __ b(is_instance_lbl, EQ);
118 } else {
119 __ b(is_not_instance_lbl, EQ);
120 }
121 // Compare if the classes are equal.
122 const Register kClassIdReg = R2;
123 __ LoadClassId(kClassIdReg, kInstanceReg);
124 __ CompareImmediate(kClassIdReg, type_class.id());
125 __ b(is_instance_lbl, EQ);
126 // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
127 // interfaces.
128 // Bool interface can be implemented only by core class Bool.
129 if (type.IsBoolType()) {
130 __ CompareImmediate(kClassIdReg, kBoolCid);
131 __ b(is_instance_lbl, EQ);
132 __ b(is_not_instance_lbl);
133 return false;
134 }
135 if (type.IsFunctionType()) {
136 // Check if instance is a closure.
137 __ LoadClassById(R3, kClassIdReg);
138 __ ldr(R3, FieldAddress(R3, Class::signature_function_offset()));
139 __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null()));
140 __ b(is_instance_lbl, NE);
141 }
142 // Custom checking for numbers (Smi, Mint, Bigint and Double).
143 // Note that instance is not Smi (checked above).
144 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) {
145 GenerateNumberTypeCheck(
146 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
147 return false;
148 }
149 if (type.IsStringType()) {
150 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
151 return false;
152 }
153 // Otherwise fallthrough.
154 return true;
96 } 155 }
97 156
98 157
99 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 158 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
100 intptr_t token_pos, 159 intptr_t token_pos,
101 const Class& type_class, 160 const Class& type_class,
102 Label* is_instance_lbl, 161 Label* is_instance_lbl,
103 Label* is_not_instance_lbl) { 162 Label* is_not_instance_lbl) {
104 UNIMPLEMENTED(); 163 UNIMPLEMENTED();
105 return NULL; 164 return NULL;
106 } 165 }
107 166
108 167
109 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 168 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
110 intptr_t token_pos, 169 intptr_t token_pos,
111 const AbstractType& type, 170 const AbstractType& type,
112 Label* is_instance_lbl, 171 Label* is_instance_lbl,
113 Label* is_not_instance_lbl) { 172 Label* is_not_instance_lbl) {
114 UNIMPLEMENTED(); 173 UNIMPLEMENTED();
115 return NULL; 174 return NULL;
116 } 175 }
117 176
118 177
178 // Inputs:
179 // - R0: instance being type checked (preserved).
180 // - R1: optional instantiator type arguments (preserved).
181 // Clobbers R2, R3.
182 // Returns:
183 // - preserved instance in R0 and optional instantiator type arguments in R1.
184 // Note that this inlined code must be followed by the runtime_call code, as it
185 // may fall through to it. Otherwise, this inline code will jump to the label
186 // is_instance or to the label is_not_instance.
119 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 187 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
120 intptr_t token_pos, 188 intptr_t token_pos,
121 const AbstractType& type, 189 const AbstractType& type,
122 Label* is_instance_lbl, 190 Label* is_instance_lbl,
123 Label* is_not_instance_lbl) { 191 Label* is_not_instance_lbl) {
124 UNIMPLEMENTED(); 192 __ Comment("InlineInstanceof");
125 return NULL; 193 if (type.IsVoidType()) {
194 // A non-null value is returned from a void function, which will result in a
195 // type error. A null value is handled prior to executing this inline code.
196 return SubtypeTestCache::null();
197 }
198 if (TypeCheckAsClassEquality(type)) {
199 const intptr_t type_cid = Class::Handle(type.type_class()).id();
200 const Register kInstanceReg = R0;
201 __ tst(kInstanceReg, ShifterOperand(kSmiTagMask));
202 if (type_cid == kSmiCid) {
203 __ b(is_instance_lbl, EQ);
204 } else {
205 __ b(is_not_instance_lbl, EQ);
206 __ CompareClassId(kInstanceReg, type_cid, R3);
207 __ b(is_instance_lbl, EQ);
208 }
209 __ b(is_not_instance_lbl);
210 return SubtypeTestCache::null();
211 }
212 if (type.IsInstantiated()) {
213 const Class& type_class = Class::ZoneHandle(type.type_class());
214 // A Smi object cannot be the instance of a parameterized class.
215 // A class equality check is only applicable with a dst type of a
216 // non-parameterized class or with a raw dst type of a parameterized class.
217 if (type_class.HasTypeArguments()) {
218 return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
219 type,
220 is_instance_lbl,
221 is_not_instance_lbl);
222 // Fall through to runtime call.
223 }
224 const bool has_fall_through =
225 GenerateInstantiatedTypeNoArgumentsTest(token_pos,
226 type,
227 is_instance_lbl,
228 is_not_instance_lbl);
229 if (has_fall_through) {
230 // If test non-conclusive so far, try the inlined type-test cache.
231 // 'type' is known at compile time.
232 return GenerateSubtype1TestCacheLookup(
233 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
234 } else {
235 return SubtypeTestCache::null();
236 }
237 }
238 return GenerateUninstantiatedTypeTest(token_pos,
239 type,
240 is_instance_lbl,
241 is_not_instance_lbl);
126 } 242 }
127 243
128 244
129 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, 245 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
130 intptr_t deopt_id, 246 intptr_t deopt_id,
131 const AbstractType& type, 247 const AbstractType& type,
132 bool negate_result, 248 bool negate_result,
133 LocationSummary* locs) { 249 LocationSummary* locs) {
134 UNIMPLEMENTED(); 250 UNIMPLEMENTED();
135 } 251 }
136 252
137 253
254 // Optimize assignable type check by adding inlined tests for:
255 // - NULL -> return NULL.
256 // - Smi -> compile time subtype check (only if dst class is not parameterized).
257 // - Class equality (only if class is not parameterized).
258 // Inputs:
259 // - R0: instance being type checked.
260 // - R1: instantiator type arguments or raw_null.
261 // - R2: instantiator or raw_null.
262 // Returns:
263 // - object in R0 for successful assignable check (or throws TypeError).
264 // Performance notes: positive checks must be quick, negative checks can be slow
265 // as they throw an exception.
138 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, 266 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
139 intptr_t deopt_id, 267 intptr_t deopt_id,
140 const AbstractType& dst_type, 268 const AbstractType& dst_type,
141 const String& dst_name, 269 const String& dst_name,
142 LocationSummary* locs) { 270 LocationSummary* locs) {
143 UNIMPLEMENTED(); 271 ASSERT(token_pos >= 0);
272 ASSERT(!dst_type.IsNull());
273 ASSERT(dst_type.IsFinalized());
274 // Assignable check is skipped in FlowGraphBuilder, not here.
275 ASSERT(dst_type.IsMalformed() ||
276 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
277 // Preserve instantiator and its type arguments.
278 __ PushList((1 << R1) | (1 << R2));
279 // A null object is always assignable and is returned as result.
280 Label is_assignable, runtime_call;
281 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null()));
282 __ b(&is_assignable, EQ);
283
284 if (!FLAG_eliminate_type_checks) {
285 // If type checks are not eliminated during the graph building then
286 // a transition sentinel can be seen here.
287 __ CompareObject(R0, Object::transition_sentinel());
288 __ b(&is_assignable, EQ);
289 }
290
291 // Generate throw new TypeError() if the type is malformed.
292 if (dst_type.IsMalformed()) {
293 const Error& error = Error::Handle(dst_type.malformed_error());
294 const String& error_message = String::ZoneHandle(
295 Symbols::New(error.ToErrorCString()));
296 __ PushObject(Object::ZoneHandle()); // Make room for the result.
297 __ Push(R0); // Push the source object.
298 __ PushObject(dst_name); // Push the name of the destination.
299 __ PushObject(error_message);
300 GenerateCallRuntime(token_pos,
301 deopt_id,
302 kMalformedTypeErrorRuntimeEntry,
303 locs);
304 // We should never return here.
305 __ bkpt(0);
306
307 __ Bind(&is_assignable); // For a null object.
308 // Restore instantiator and its type arguments.
309 __ PopList((1 << R1) | (1 << R2));
310 return;
311 }
312
313 // Generate inline type check, linking to runtime call if not assignable.
314 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
315 test_cache = GenerateInlineInstanceof(token_pos, dst_type,
316 &is_assignable, &runtime_call);
317
318 __ Bind(&runtime_call);
319 // Load instantiator and its type arguments.
320 __ ldm(IA, SP, (1 << R1) | (1 << R2));
321 __ PushObject(Object::ZoneHandle()); // Make room for the result.
322 __ Push(R0); // Push the source object.
323 __ PushObject(dst_type); // Push the type of the destination.
324 // Push instantiator and its type arguments.
325 __ PushList((1 << R1) | (1 << R2));
326 __ PushObject(dst_name); // Push the name of the destination.
327 __ LoadObject(R0, test_cache);
328 __ Push(R0);
329 GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, locs);
330 // Pop the parameters supplied to the runtime entry. The result of the
331 // type check runtime call is the checked value.
332 __ Drop(6);
333 __ Pop(R0);
334
335 __ Bind(&is_assignable);
336 // Restore instantiator and its type arguments.
337 __ PopList((1 << R1) | (1 << R2));
144 } 338 }
145 339
146 340
147 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { 341 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
148 if (!is_optimizing()) { 342 if (!is_optimizing()) {
149 if (FLAG_enable_type_checks && instr->IsAssertAssignable()) { 343 if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
150 AssertAssignableInstr* assert = instr->AsAssertAssignable(); 344 AssertAssignableInstr* assert = instr->AsAssertAssignable();
151 AddCurrentDescriptor(PcDescriptors::kDeoptBefore, 345 AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
152 assert->deopt_id(), 346 assert->deopt_id(),
153 assert->token_pos()); 347 assert->token_pos());
(...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after
858 1052
859 1053
860 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { 1054 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
861 UNIMPLEMENTED(); 1055 UNIMPLEMENTED();
862 } 1056 }
863 1057
864 1058
865 } // namespace dart 1059 } // namespace dart
866 1060
867 #endif // defined TARGET_ARCH_ARM 1061 #endif // defined TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « runtime/vm/assembler_arm.cc ('k') | runtime/vm/flow_graph_compiler_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698