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

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

Issue 13619008: Implements type checking in MIPS needed for FindCodeObject test. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 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_mips.cc ('k') | runtime/vm/intermediate_language_mips.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_MIPS. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS.
6 #if defined(TARGET_ARCH_MIPS) 6 #if defined(TARGET_ARCH_MIPS)
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 __ LoadImmediate(TMP, class_ids[i]);
88 __ beq(class_id_reg, TMP, is_equal_lbl);
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 // A0: instance being type checked (preserved).
97 // Clobbers: T0, T1, T2
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 = A0;
110 __ andi(T0, A0, Immediate(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 __ beq(T0, ZR, is_instance_lbl);
118 } else {
119 __ beq(T0, ZR, is_not_instance_lbl);
120 }
121 // Compare if the classes are equal.
122 const Register kClassIdReg = T0;
123 __ LoadClassId(kClassIdReg, kInstanceReg);
124 __ LoadImmediate(T1, type_class.id());
125 __ beq(kClassIdReg, T1, is_instance_lbl);
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 __ LoadImmediate(T1, kBoolCid);
131 __ beq(kClassIdReg, T1, is_instance_lbl);
132 __ b(is_not_instance_lbl);
133 return false;
134 }
135 if (type.IsFunctionType()) {
136 // Check if instance is a closure.
137 __ LoadClassById(T1, kClassIdReg);
138 __ lw(T1, FieldAddress(T1, Class::signature_function_offset()));
139 __ LoadImmediate(T2, reinterpret_cast<int32_t>(Object::null()));
140 __ bne(T1, T2, is_instance_lbl);
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 // - A0: instance being type checked (preserved).
180 // - A1: optional instantiator type arguments (preserved).
181 // Returns:
182 // - preserved instance in A0 and optional instantiator type arguments in A1.
183 // Clobbers: T0, T1, T2
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 = A0;
201 __ andi(T0, kInstanceReg, Immediate(kSmiTagMask));
202 if (type_cid == kSmiCid) {
203 __ beq(T0, ZR, is_instance_lbl);
204 } else {
205 __ beq(T0, ZR, is_not_instance_lbl);
206 __ LoadClassId(T0, kInstanceReg);
207 __ LoadImmediate(T1, type_cid);
208 __ beq(T0, T1, is_instance_lbl);
209 }
210 __ b(is_not_instance_lbl);
211 return SubtypeTestCache::null();
212 }
213 if (type.IsInstantiated()) {
214 const Class& type_class = Class::ZoneHandle(type.type_class());
215 // A Smi object cannot be the instance of a parameterized class.
216 // A class equality check is only applicable with a dst type of a
217 // non-parameterized class or with a raw dst type of a parameterized class.
218 if (type_class.HasTypeArguments()) {
219 return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
220 type,
221 is_instance_lbl,
222 is_not_instance_lbl);
223 // Fall through to runtime call.
224 }
225 const bool has_fall_through =
226 GenerateInstantiatedTypeNoArgumentsTest(token_pos,
227 type,
228 is_instance_lbl,
229 is_not_instance_lbl);
230 if (has_fall_through) {
231 // If test non-conclusive so far, try the inlined type-test cache.
232 // 'type' is known at compile time.
233 return GenerateSubtype1TestCacheLookup(
234 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
235 } else {
236 return SubtypeTestCache::null();
237 }
238 }
239 return GenerateUninstantiatedTypeTest(token_pos,
240 type,
241 is_instance_lbl,
242 is_not_instance_lbl);
126 } 243 }
127 244
128 245
129 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, 246 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
130 intptr_t deopt_id, 247 intptr_t deopt_id,
131 const AbstractType& type, 248 const AbstractType& type,
132 bool negate_result, 249 bool negate_result,
133 LocationSummary* locs) { 250 LocationSummary* locs) {
134 UNIMPLEMENTED(); 251 UNIMPLEMENTED();
135 } 252 }
136 253
137 254
255 // Optimize assignable type check by adding inlined tests for:
256 // - NULL -> return NULL.
257 // - Smi -> compile time subtype check (only if dst class is not parameterized).
258 // - Class equality (only if class is not parameterized).
259 // Inputs:
260 // - A0: instance being type checked.
261 // - A1: instantiator type arguments or raw_null.
262 // - A2: instantiator or raw_null.
263 // Returns:
264 // - object in A0 for successful assignable check (or throws TypeError).
265 // Clobbers: T0, T1, T2
266 // Performance notes: positive checks must be quick, negative checks can be slow
267 // as they throw an exception.
138 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, 268 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
139 intptr_t deopt_id, 269 intptr_t deopt_id,
140 const AbstractType& dst_type, 270 const AbstractType& dst_type,
141 const String& dst_name, 271 const String& dst_name,
142 LocationSummary* locs) { 272 LocationSummary* locs) {
143 UNIMPLEMENTED(); 273 ASSERT(token_pos >= 0);
274 ASSERT(!dst_type.IsNull());
275 ASSERT(dst_type.IsFinalized());
276 // Assignable check is skipped in FlowGraphBuilder, not here.
277 ASSERT(dst_type.IsMalformed() ||
278 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
279 // Preserve instantiator and its type arguments.
280 __ addiu(SP, SP, Immediate(-2 * kWordSize));
281 __ sw(A2, Address(SP, 1 * kWordSize));
282 __ sw(A1, Address(SP, 0 * kWordSize));
283 // A null object is always assignable and is returned as result.
284 Label is_assignable, runtime_call;
285 __ LoadImmediate(T0, reinterpret_cast<int32_t>(Object::null()));
286 __ beq(A0, T0, &is_assignable);
287
288 if (!FLAG_eliminate_type_checks) {
289 // If type checks are not eliminated during the graph building then
290 // a transition sentinel can be seen here.
291 __ LoadObject(T0, Object::transition_sentinel());
292 __ beq(A0, T0, &is_assignable);
293 }
294
295 // Generate throw new TypeError() if the type is malformed.
296 if (dst_type.IsMalformed()) {
297 const Error& error = Error::Handle(dst_type.malformed_error());
298 const String& error_message = String::ZoneHandle(
299 Symbols::New(error.ToErrorCString()));
300 __ PushObject(Object::ZoneHandle()); // Make room for the result.
301 __ Push(A0); // Push the source object.
302 __ PushObject(dst_name); // Push the name of the destination.
303 __ PushObject(error_message);
304 GenerateCallRuntime(token_pos,
305 deopt_id,
306 kMalformedTypeErrorRuntimeEntry,
307 locs);
308 // We should never return here.
309 __ break_(0);
310
311 __ Bind(&is_assignable); // For a null object.
312 // Restore instantiator and its type arguments.
313 __ lw(A1, Address(SP, 0 * kWordSize));
314 __ lw(A2, Address(SP, 1 * kWordSize));
315 __ addiu(SP, SP, Immediate(2 * kWordSize));
316 return;
317 }
318
319 // Generate inline type check, linking to runtime call if not assignable.
320 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
321 test_cache = GenerateInlineInstanceof(token_pos, dst_type,
322 &is_assignable, &runtime_call);
323
324 __ Bind(&runtime_call);
325 // Load instantiator and its type arguments.
326 __ lw(A1, Address(SP, 0 * kWordSize));
327 __ lw(A2, Address(SP, 1 * kWordSize));
328 __ addiu(SP, SP, Immediate(2 * kWordSize));
329 __ PushObject(Object::ZoneHandle()); // Make room for the result.
330 __ Push(A0); // Push the source object.
331 __ PushObject(dst_type); // Push the type of the destination.
332 // Push instantiator and its type arguments.
333 __ addiu(SP, SP, Immediate(-2 * kWordSize));
334 __ sw(A2, Address(SP, 1 * kWordSize));
335 __ sw(A1, Address(SP, 0 * kWordSize));
336 __ PushObject(dst_name); // Push the name of the destination.
337 __ LoadObject(A0, test_cache);
338 __ Push(A0);
339 GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, locs);
340 // Pop the parameters supplied to the runtime entry. The result of the
341 // type check runtime call is the checked value.
342 __ Drop(6);
343 __ Pop(A0);
344
345 __ Bind(&is_assignable);
346 // Restore instantiator and its type arguments.
347 __ lw(A1, Address(SP, 0 * kWordSize));
348 __ lw(A2, Address(SP, 1 * kWordSize));
349 __ addiu(SP, SP, Immediate(2 * kWordSize));
144 } 350 }
145 351
146 352
147 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { 353 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
148 if (!is_optimizing()) { 354 if (!is_optimizing()) {
149 if (FLAG_enable_type_checks && instr->IsAssertAssignable()) { 355 if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
150 AssertAssignableInstr* assert = instr->AsAssertAssignable(); 356 AssertAssignableInstr* assert = instr->AsAssertAssignable();
151 AddCurrentDescriptor(PcDescriptors::kDeoptBefore, 357 AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
152 assert->deopt_id(), 358 assert->deopt_id(),
153 assert->token_pos()); 359 assert->token_pos());
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 __ delay_slot()->SmiUntag(T2); 425 __ delay_slot()->SmiUntag(T2);
220 // We do not use the final allocation index of the variable here, i.e. 426 // We do not use the final allocation index of the variable here, i.e.
221 // scope->VariableAt(i)->index(), because captured variables still need 427 // scope->VariableAt(i)->index(), because captured variables still need
222 // to be copied to the context that is not yet allocated. 428 // to be copied to the context that is not yet allocated.
223 __ Bind(&loop); 429 __ Bind(&loop);
224 __ addu(T4, T1, T2); 430 __ addu(T4, T1, T2);
225 __ addu(T5, T0, T2); 431 __ addu(T5, T0, T2);
226 __ lw(TMP, Address(T4)); 432 __ lw(TMP, Address(T4));
227 __ sw(TMP, Address(T5)); 433 __ sw(TMP, Address(T5));
228 __ Bind(&loop_condition); 434 __ Bind(&loop_condition);
229 __ addiu(T2, T2, Immediate(-4)); 435 __ addiu(T2, T2, Immediate(-kWordSize));
230 __ bgez(T2, &loop); 436 __ bgez(T2, &loop);
231 437
232 // Copy or initialize optional named arguments. 438 // Copy or initialize optional named arguments.
233 Label all_arguments_processed; 439 Label all_arguments_processed;
234 if (num_opt_named_params > 0) { 440 if (num_opt_named_params > 0) {
235 // Start by alphabetically sorting the names of the optional parameters. 441 // Start by alphabetically sorting the names of the optional parameters.
236 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; 442 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params];
237 int* opt_param_position = new int[num_opt_named_params]; 443 int* opt_param_position = new int[num_opt_named_params];
238 for (int pos = num_fixed_params; pos < num_params; pos++) { 444 for (int pos = num_fixed_params; pos < num_params; pos++) {
239 LocalVariable* parameter = scope->VariableAt(pos); 445 LocalVariable* parameter = scope->VariableAt(pos);
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 __ SmiUntag(T2); 591 __ SmiUntag(T2);
386 592
387 __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null())); 593 __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
388 Label null_args_loop, null_args_loop_condition; 594 Label null_args_loop, null_args_loop_condition;
389 __ b(&null_args_loop_condition); 595 __ b(&null_args_loop_condition);
390 __ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize)); 596 __ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize));
391 __ Bind(&null_args_loop); 597 __ Bind(&null_args_loop);
392 __ addu(T3, T1, T2); 598 __ addu(T3, T1, T2);
393 __ sw(TMP, Address(T3)); 599 __ sw(TMP, Address(T3));
394 __ Bind(&null_args_loop_condition); 600 __ Bind(&null_args_loop_condition);
395 __ addiu(T2, T2, Immediate(-4)); 601 __ addiu(T2, T2, Immediate(-kWordSize));
396 __ bgez(T2, &null_args_loop); 602 __ bgez(T2, &null_args_loop);
397 } 603 }
398 604
399 605
400 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { 606 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) {
401 UNIMPLEMENTED(); 607 UNIMPLEMENTED();
402 } 608 }
403 609
404 610
405 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { 611 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after
901 1107
902 1108
903 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { 1109 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
904 UNIMPLEMENTED(); 1110 UNIMPLEMENTED();
905 } 1111 }
906 1112
907 1113
908 } // namespace dart 1114 } // namespace dart
909 1115
910 #endif // defined TARGET_ARCH_MIPS 1116 #endif // defined TARGET_ARCH_MIPS
OLDNEW
« no previous file with comments | « runtime/vm/assembler_mips.cc ('k') | runtime/vm/intermediate_language_mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698