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

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

Issue 10832150: Get rid of ast node ids. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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_IA32. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
6 #if defined(TARGET_ARCH_IA32) 6 #if defined(TARGET_ARCH_IA32)
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"
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 } 142 }
143 143
144 144
145 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 145 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
146 // type test is conclusive, otherwise fallthrough if a type test could not 146 // type test is conclusive, otherwise fallthrough if a type test could not
147 // be completed. 147 // be completed.
148 // EAX: instance (must survive). 148 // EAX: instance (must survive).
149 // Clobbers ECX, EDI. 149 // Clobbers ECX, EDI.
150 RawSubtypeTestCache* 150 RawSubtypeTestCache*
151 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( 151 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
152 intptr_t cid,
153 intptr_t token_pos, 152 intptr_t token_pos,
154 const AbstractType& type, 153 const AbstractType& type,
155 Label* is_instance_lbl, 154 Label* is_instance_lbl,
156 Label* is_not_instance_lbl) { 155 Label* is_not_instance_lbl) {
157 ASSERT(type.IsInstantiated()); 156 ASSERT(type.IsInstantiated());
158 const Class& type_class = Class::ZoneHandle(type.type_class()); 157 const Class& type_class = Class::ZoneHandle(type.type_class());
159 ASSERT(type_class.HasTypeArguments()); 158 ASSERT(type_class.HasTypeArguments());
160 const Register kInstanceReg = EAX; 159 const Register kInstanceReg = EAX;
161 // A Smi object cannot be the instance of a parameterized class. 160 // A Smi object cannot be the instance of a parameterized class.
162 __ testl(kInstanceReg, Immediate(kSmiTagMask)); 161 __ testl(kInstanceReg, Immediate(kSmiTagMask));
163 __ j(ZERO, is_not_instance_lbl); 162 __ j(ZERO, is_not_instance_lbl);
164 const AbstractTypeArguments& type_arguments = 163 const AbstractTypeArguments& type_arguments =
165 AbstractTypeArguments::ZoneHandle(type.arguments()); 164 AbstractTypeArguments::ZoneHandle(type.arguments());
166 const bool is_raw_type = type_arguments.IsNull() || 165 const bool is_raw_type = type_arguments.IsNull() ||
167 type_arguments.IsRaw(type_arguments.Length()); 166 type_arguments.IsRaw(type_arguments.Length());
168 if (is_raw_type) { 167 if (is_raw_type) {
169 const Register kClassIdReg = ECX; 168 const Register kClassIdReg = ECX;
170 // Dynamic type argument, check only classes. 169 // Dynamic type argument, check only classes.
171 // List is a very common case. 170 // List is a very common case.
172 __ LoadClassId(kClassIdReg, kInstanceReg); 171 __ LoadClassId(kClassIdReg, kInstanceReg);
173 if (!type_class.is_interface()) { 172 if (!type_class.is_interface()) {
174 __ cmpl(kClassIdReg, Immediate(type_class.id())); 173 __ cmpl(kClassIdReg, Immediate(type_class.id()));
175 __ j(EQUAL, is_instance_lbl); 174 __ j(EQUAL, is_instance_lbl);
176 } 175 }
177 if (type.IsListInterface()) { 176 if (type.IsListInterface()) {
178 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); 177 GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
179 } 178 }
180 return GenerateSubtype1TestCacheLookup( 179 return GenerateSubtype1TestCacheLookup(
181 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 180 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
182 } 181 }
183 // If one type argument only, check if type argument is Object or Dynamic. 182 // If one type argument only, check if type argument is Object or Dynamic.
184 if (type_arguments.Length() == 1) { 183 if (type_arguments.Length() == 1) {
185 const AbstractType& tp_argument = AbstractType::ZoneHandle( 184 const AbstractType& tp_argument = AbstractType::ZoneHandle(
186 type_arguments.TypeAt(0)); 185 type_arguments.TypeAt(0));
187 ASSERT(!tp_argument.IsMalformed()); 186 ASSERT(!tp_argument.IsMalformed());
188 if (tp_argument.IsType()) { 187 if (tp_argument.IsType()) {
189 ASSERT(tp_argument.HasResolvedTypeClass()); 188 ASSERT(tp_argument.HasResolvedTypeClass());
190 // Check if type argument is dynamic or Object. 189 // Check if type argument is dynamic or Object.
191 const Type& object_type = Type::Handle(Type::ObjectType()); 190 const Type& object_type = Type::Handle(Type::ObjectType());
192 if (object_type.IsSubtypeOf(tp_argument, NULL)) { 191 if (object_type.IsSubtypeOf(tp_argument, NULL)) {
193 // Instance class test only necessary. 192 // Instance class test only necessary.
194 return GenerateSubtype1TestCacheLookup( 193 return GenerateSubtype1TestCacheLookup(
195 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 194 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
196 } 195 }
197 } 196 }
198 } 197 }
199 // Regular subtype test cache involving instance's type arguments. 198 // Regular subtype test cache involving instance's type arguments.
200 const Register kTypeArgumentsReg = kNoRegister; 199 const Register kTypeArgumentsReg = kNoRegister;
201 const Register kTempReg = EDI; 200 const Register kTempReg = EDI;
202 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, 201 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs,
203 kInstanceReg, 202 kInstanceReg,
204 kTypeArgumentsReg, 203 kTypeArgumentsReg,
205 kTempReg, 204 kTempReg,
(...skipping 13 matching lines...) Expand all
219 __ jmp(is_not_equal_lbl); 218 __ jmp(is_not_equal_lbl);
220 } 219 }
221 220
222 221
223 // Testing against an instantiated type with no arguments, without 222 // Testing against an instantiated type with no arguments, without
224 // SubtypeTestCache. 223 // SubtypeTestCache.
225 // EAX: instance to test against (preserved). 224 // EAX: instance to test against (preserved).
226 // Clobbers ECX, EDI. 225 // Clobbers ECX, EDI.
227 // Returns true if there is a fallthrough. 226 // Returns true if there is a fallthrough.
228 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( 227 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
229 intptr_t cid,
230 intptr_t token_pos, 228 intptr_t token_pos,
231 const AbstractType& type, 229 const AbstractType& type,
232 Label* is_instance_lbl, 230 Label* is_instance_lbl,
233 Label* is_not_instance_lbl) { 231 Label* is_not_instance_lbl) {
234 ASSERT(type.IsInstantiated()); 232 ASSERT(type.IsInstantiated());
235 const Class& type_class = Class::Handle(type.type_class()); 233 const Class& type_class = Class::Handle(type.type_class());
236 ASSERT(!type_class.HasTypeArguments()); 234 ASSERT(!type_class.HasTypeArguments());
237 235
238 const Register kInstanceReg = EAX; 236 const Register kInstanceReg = EAX;
239 Label compare_classes; 237 Label compare_classes;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 292
295 293
296 // Uses SubtypeTestCache to store instance class and result. 294 // Uses SubtypeTestCache to store instance class and result.
297 // EAX: instance to test. 295 // EAX: instance to test.
298 // Clobbers EDI, ECX. 296 // Clobbers EDI, ECX.
299 // Immediate class test already done. 297 // Immediate class test already done.
300 // TODO(srdjan): Implement a quicker subtype check, as type test 298 // TODO(srdjan): Implement a quicker subtype check, as type test
301 // arrays can grow too high, but they may be useful when optimizing 299 // arrays can grow too high, but they may be useful when optimizing
302 // code (type-feedback). 300 // code (type-feedback).
303 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 301 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
304 intptr_t cid,
305 intptr_t token_pos, 302 intptr_t token_pos,
306 const Class& type_class, 303 const Class& type_class,
307 Label* is_instance_lbl, 304 Label* is_instance_lbl,
308 Label* is_not_instance_lbl) { 305 Label* is_not_instance_lbl) {
309 const Register kInstanceReg = EAX; 306 const Register kInstanceReg = EAX;
310 __ LoadClass(ECX, kInstanceReg, EDI); 307 __ LoadClass(ECX, kInstanceReg, EDI);
311 // ECX: instance class. 308 // ECX: instance class.
312 // Check immediate superclass equality. 309 // Check immediate superclass equality.
313 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); 310 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset()));
314 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); 311 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset()));
315 __ CompareObject(EDI, type_class); 312 __ CompareObject(EDI, type_class);
316 __ j(EQUAL, is_instance_lbl); 313 __ j(EQUAL, is_instance_lbl);
317 314
318 const Register kTypeArgumentsReg = kNoRegister; 315 const Register kTypeArgumentsReg = kNoRegister;
319 const Register kTempReg = EDI; 316 const Register kTempReg = EDI;
320 return GenerateCallSubtypeTestStub(kTestTypeOneArg, 317 return GenerateCallSubtypeTestStub(kTestTypeOneArg,
321 kInstanceReg, 318 kInstanceReg,
322 kTypeArgumentsReg, 319 kTypeArgumentsReg,
323 kTempReg, 320 kTempReg,
324 is_instance_lbl, 321 is_instance_lbl,
325 is_not_instance_lbl); 322 is_not_instance_lbl);
326 } 323 }
327 324
328 325
329 // Generates inlined check if 'type' is a type parameter or type itsef 326 // Generates inlined check if 'type' is a type parameter or type itsef
330 // EAX: instance (preserved). 327 // EAX: instance (preserved).
331 // Clobbers EDX, EDI, ECX. 328 // Clobbers EDX, EDI, ECX.
332 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 329 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
333 intptr_t cid,
334 intptr_t token_pos, 330 intptr_t token_pos,
335 const AbstractType& type, 331 const AbstractType& type,
336 Label* is_instance_lbl, 332 Label* is_instance_lbl,
337 Label* is_not_instance_lbl) { 333 Label* is_not_instance_lbl) {
338 ASSERT(!type.IsInstantiated()); 334 ASSERT(!type.IsInstantiated());
339 // Skip check if destination is a dynamic type. 335 // Skip check if destination is a dynamic type.
340 const Immediate raw_null = 336 const Immediate raw_null =
341 Immediate(reinterpret_cast<intptr_t>(Object::null())); 337 Immediate(reinterpret_cast<intptr_t>(Object::null()));
342 if (type.IsTypeParameter()) { 338 if (type.IsTypeParameter()) {
343 const TypeParameter& type_param = TypeParameter::Cast(type); 339 const TypeParameter& type_param = TypeParameter::Cast(type);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 // Inputs: 411 // Inputs:
416 // - EAX: instance to test against (preserved). 412 // - EAX: instance to test against (preserved).
417 // - EDX: optional instantiator type arguments (preserved). 413 // - EDX: optional instantiator type arguments (preserved).
418 // Clobbers ECX, EDI. 414 // Clobbers ECX, EDI.
419 // Returns: 415 // Returns:
420 // - preserved instance in EAX and optional instantiator type arguments in EDX. 416 // - preserved instance in EAX and optional instantiator type arguments in EDX.
421 // Note that this inlined code must be followed by the runtime_call code, as it 417 // Note that this inlined code must be followed by the runtime_call code, as it
422 // may fall through to it. Otherwise, this inline code will jump to the label 418 // may fall through to it. Otherwise, this inline code will jump to the label
423 // is_instance or to the label is_not_instance. 419 // is_instance or to the label is_not_instance.
424 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 420 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
425 intptr_t cid,
426 intptr_t token_pos, 421 intptr_t token_pos,
427 const AbstractType& type, 422 const AbstractType& type,
428 Label* is_instance_lbl, 423 Label* is_instance_lbl,
429 Label* is_not_instance_lbl) { 424 Label* is_not_instance_lbl) {
430 if (type.IsVoidType()) { 425 if (type.IsVoidType()) {
431 // A non-null value is returned from a void function, which will result in a 426 // A non-null value is returned from a void function, which will result in a
432 // type error. A null value is handled prior to executing this inline code. 427 // type error. A null value is handled prior to executing this inline code.
433 return SubtypeTestCache::null(); 428 return SubtypeTestCache::null();
434 } 429 }
435 if (type.IsInstantiated()) { 430 if (type.IsInstantiated()) {
436 const Class& type_class = Class::ZoneHandle(type.type_class()); 431 const Class& type_class = Class::ZoneHandle(type.type_class());
437 // A Smi object cannot be the instance of a parameterized class. 432 // A Smi object cannot be the instance of a parameterized class.
438 // A class equality check is only applicable with a dst type of a 433 // A class equality check is only applicable with a dst type of a
439 // non-parameterized class or with a raw dst type of a parameterized class. 434 // non-parameterized class or with a raw dst type of a parameterized class.
440 if (type_class.HasTypeArguments()) { 435 if (type_class.HasTypeArguments()) {
441 return GenerateInstantiatedTypeWithArgumentsTest(cid, 436 return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
442 token_pos,
443 type, 437 type,
444 is_instance_lbl, 438 is_instance_lbl,
445 is_not_instance_lbl); 439 is_not_instance_lbl);
446 // Fall through to runtime call. 440 // Fall through to runtime call.
447 } 441 }
448 const bool has_fall_through = 442 const bool has_fall_through =
449 GenerateInstantiatedTypeNoArgumentsTest(cid, 443 GenerateInstantiatedTypeNoArgumentsTest(token_pos,
450 token_pos,
451 type, 444 type,
452 is_instance_lbl, 445 is_instance_lbl,
453 is_not_instance_lbl); 446 is_not_instance_lbl);
454 if (has_fall_through) { 447 if (has_fall_through) {
455 // If test non-conclusive so far, try the inlined type-test cache. 448 // If test non-conclusive so far, try the inlined type-test cache.
456 // 'type' is known at compile time. 449 // 'type' is known at compile time.
457 return GenerateSubtype1TestCacheLookup( 450 return GenerateSubtype1TestCacheLookup(
458 cid, token_pos, type_class, 451 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
459 is_instance_lbl, is_not_instance_lbl);
460 } else { 452 } else {
461 return SubtypeTestCache::null(); 453 return SubtypeTestCache::null();
462 } 454 }
463 } 455 }
464 return GenerateUninstantiatedTypeTest(cid, 456 return GenerateUninstantiatedTypeTest(token_pos,
465 token_pos,
466 type, 457 type,
467 is_instance_lbl, 458 is_instance_lbl,
468 is_not_instance_lbl); 459 is_not_instance_lbl);
469 } 460 }
470 461
471 462
472 // If instanceof type test cannot be performed successfully at compile time and 463 // If instanceof type test cannot be performed successfully at compile time and
473 // therefore eliminated, optimize it by adding inlined tests for: 464 // therefore eliminated, optimize it by adding inlined tests for:
474 // - NULL -> return false. 465 // - NULL -> return false.
475 // - Smi -> compile time subtype check (only if dst class is not parameterized). 466 // - Smi -> compile time subtype check (only if dst class is not parameterized).
476 // - Class equality (only if class is not parameterized). 467 // - Class equality (only if class is not parameterized).
477 // Inputs: 468 // Inputs:
478 // - EAX: object. 469 // - EAX: object.
479 // - EDX: instantiator type arguments or raw_null. 470 // - EDX: instantiator type arguments or raw_null.
480 // - ECX: instantiator or raw_null. 471 // - ECX: instantiator or raw_null.
481 // Clobbers ECX and EDX. 472 // Clobbers ECX and EDX.
482 // Returns: 473 // Returns:
483 // - true or false in EAX. 474 // - true or false in EAX.
484 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, 475 void FlowGraphCompiler::GenerateInstanceOf(intptr_t deopt_id,
485 intptr_t token_pos, 476 intptr_t token_pos,
486 intptr_t try_index, 477 intptr_t try_index,
487 const AbstractType& type, 478 const AbstractType& type,
488 bool negate_result) { 479 bool negate_result) {
489 ASSERT(type.IsFinalized() && !type.IsMalformed()); 480 ASSERT(type.IsFinalized() && !type.IsMalformed());
490 481
491 const Immediate raw_null = 482 const Immediate raw_null =
492 Immediate(reinterpret_cast<intptr_t>(Object::null())); 483 Immediate(reinterpret_cast<intptr_t>(Object::null()));
493 Label is_instance, is_not_instance; 484 Label is_instance, is_not_instance;
494 __ pushl(ECX); // Store instantiator on stack. 485 __ pushl(ECX); // Store instantiator on stack.
495 __ pushl(EDX); // Store instantiator type arguments. 486 __ pushl(EDX); // Store instantiator type arguments.
496 // If type is instantiated and non-parameterized, we can inline code 487 // If type is instantiated and non-parameterized, we can inline code
497 // checking whether the tested instance is a Smi. 488 // checking whether the tested instance is a Smi.
498 if (type.IsInstantiated()) { 489 if (type.IsInstantiated()) {
499 // A null object is only an instance of Object and Dynamic, which has 490 // A null object is only an instance of Object and Dynamic, which has
500 // already been checked above (if the type is instantiated). So we can 491 // already been checked above (if the type is instantiated). So we can
501 // return false here if the instance is null (and if the type is 492 // return false here if the instance is null (and if the type is
502 // instantiated). 493 // instantiated).
503 // We can only inline this null check if the type is instantiated at compile 494 // We can only inline this null check if the type is instantiated at compile
504 // time, since an uninstantiated type at compile time could be Object or 495 // time, since an uninstantiated type at compile time could be Object or
505 // Dynamic at run time. 496 // Dynamic at run time.
506 __ cmpl(EAX, raw_null); 497 __ cmpl(EAX, raw_null);
507 __ j(EQUAL, &is_not_instance); 498 __ j(EQUAL, &is_not_instance);
508 } 499 }
509 500
510 // Generate inline instanceof test. 501 // Generate inline instanceof test.
511 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 502 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
512 test_cache = GenerateInlineInstanceof(cid, token_pos, type, 503 test_cache = GenerateInlineInstanceof(token_pos, type,
513 &is_instance, &is_not_instance); 504 &is_instance, &is_not_instance);
514 505
515 // test_cache is null if there is no fall-through. 506 // test_cache is null if there is no fall-through.
516 Label done; 507 Label done;
517 if (!test_cache.IsNull()) { 508 if (!test_cache.IsNull()) {
518 // Generate runtime call. 509 // Generate runtime call.
519 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. 510 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments.
520 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. 511 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator.
521 __ PushObject(Object::ZoneHandle()); // Make room for the result. 512 __ PushObject(Object::ZoneHandle()); // Make room for the result.
522 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id.
523 __ pushl(EAX); // Push the instance. 513 __ pushl(EAX); // Push the instance.
524 __ PushObject(type); // Push the type. 514 __ PushObject(type); // Push the type.
525 __ pushl(ECX); // Instantiator. 515 __ pushl(ECX); // Instantiator.
526 __ pushl(EDX); // Instantiator type arguments. 516 __ pushl(EDX); // Instantiator type arguments.
527 __ LoadObject(EAX, test_cache); 517 __ LoadObject(EAX, test_cache);
528 __ pushl(EAX); 518 __ pushl(EAX);
529 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry); 519 GenerateCallRuntime(deopt_id, token_pos, try_index,
520 kInstanceofRuntimeEntry);
530 // Pop the parameters supplied to the runtime entry. The result of the 521 // Pop the parameters supplied to the runtime entry. The result of the
531 // instanceof runtime call will be left as the result of the operation. 522 // instanceof runtime call will be left as the result of the operation.
532 __ Drop(6); 523 __ Drop(5);
533 if (negate_result) { 524 if (negate_result) {
534 __ popl(EDX); 525 __ popl(EDX);
535 __ LoadObject(EAX, bool_true()); 526 __ LoadObject(EAX, bool_true());
536 __ cmpl(EDX, EAX); 527 __ cmpl(EDX, EAX);
537 __ j(NOT_EQUAL, &done, Assembler::kNearJump); 528 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
538 __ LoadObject(EAX, bool_false()); 529 __ LoadObject(EAX, bool_false());
539 } else { 530 } else {
540 __ popl(EAX); 531 __ popl(EAX);
541 } 532 }
542 __ jmp(&done, Assembler::kNearJump); 533 __ jmp(&done, Assembler::kNearJump);
(...skipping 15 matching lines...) Expand all
558 // - Smi -> compile time subtype check (only if dst class is not parameterized). 549 // - Smi -> compile time subtype check (only if dst class is not parameterized).
559 // - Class equality (only if class is not parameterized). 550 // - Class equality (only if class is not parameterized).
560 // Inputs: 551 // Inputs:
561 // - EAX: object. 552 // - EAX: object.
562 // - EDX: instantiator type arguments or raw_null. 553 // - EDX: instantiator type arguments or raw_null.
563 // - ECX: instantiator or raw_null. 554 // - ECX: instantiator or raw_null.
564 // Returns: 555 // Returns:
565 // - object in EAX for successful assignable check (or throws TypeError). 556 // - object in EAX for successful assignable check (or throws TypeError).
566 // Performance notes: positive checks must be quick, negative checks can be slow 557 // Performance notes: positive checks must be quick, negative checks can be slow
567 // as they throw an exception. 558 // as they throw an exception.
568 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, 559 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t deopt_id,
569 intptr_t token_pos, 560 intptr_t token_pos,
570 intptr_t try_index, 561 intptr_t try_index,
571 const AbstractType& dst_type, 562 const AbstractType& dst_type,
572 const String& dst_name) { 563 const String& dst_name) {
573 ASSERT(token_pos >= 0); 564 ASSERT(token_pos >= 0);
574 ASSERT(!dst_type.IsNull()); 565 ASSERT(!dst_type.IsNull());
575 ASSERT(dst_type.IsFinalized()); 566 ASSERT(dst_type.IsFinalized());
576 // Assignable check is skipped in FlowGraphBuilder, not here. 567 // Assignable check is skipped in FlowGraphBuilder, not here.
577 ASSERT(dst_type.IsMalformed() || 568 ASSERT(dst_type.IsMalformed() ||
578 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 569 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
579 __ pushl(ECX); // Store instantiator. 570 __ pushl(ECX); // Store instantiator.
580 __ pushl(EDX); // Store instantiator type arguments. 571 __ pushl(EDX); // Store instantiator type arguments.
581 // A null object is always assignable and is returned as result. 572 // A null object is always assignable and is returned as result.
582 const Immediate raw_null = 573 const Immediate raw_null =
583 Immediate(reinterpret_cast<intptr_t>(Object::null())); 574 Immediate(reinterpret_cast<intptr_t>(Object::null()));
584 Label is_assignable, runtime_call; 575 Label is_assignable, runtime_call;
585 __ cmpl(EAX, raw_null); 576 __ cmpl(EAX, raw_null);
586 __ j(EQUAL, &is_assignable); 577 __ j(EQUAL, &is_assignable);
587 578
588 // Generate throw new TypeError() if the type is malformed. 579 // Generate throw new TypeError() if the type is malformed.
589 if (dst_type.IsMalformed()) { 580 if (dst_type.IsMalformed()) {
590 const Error& error = Error::Handle(dst_type.malformed_error()); 581 const Error& error = Error::Handle(dst_type.malformed_error());
591 const String& error_message = String::ZoneHandle( 582 const String& error_message = String::ZoneHandle(
592 Symbols::New(error.ToErrorCString())); 583 Symbols::New(error.ToErrorCString()));
593 __ PushObject(Object::ZoneHandle()); // Make room for the result. 584 __ PushObject(Object::ZoneHandle()); // Make room for the result.
594 __ pushl(EAX); // Push the source object. 585 __ pushl(EAX); // Push the source object.
595 __ PushObject(dst_name); // Push the name of the destination. 586 __ PushObject(dst_name); // Push the name of the destination.
596 __ PushObject(error_message); 587 __ PushObject(error_message);
597 GenerateCallRuntime(cid, 588 GenerateCallRuntime(deopt_id,
598 token_pos, 589 token_pos,
599 try_index, 590 try_index,
600 kMalformedTypeErrorRuntimeEntry); 591 kMalformedTypeErrorRuntimeEntry);
601 // We should never return here. 592 // We should never return here.
602 __ int3(); 593 __ int3();
603 594
604 __ Bind(&is_assignable); // For a null object. 595 __ Bind(&is_assignable); // For a null object.
605 return; 596 return;
606 } 597 }
607 598
608 // Generate inline type check, linking to runtime call if not assignable. 599 // Generate inline type check, linking to runtime call if not assignable.
609 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 600 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
610 test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type, 601 test_cache = GenerateInlineInstanceof(token_pos, dst_type,
611 &is_assignable, &runtime_call); 602 &is_assignable, &runtime_call);
612 603
613 __ Bind(&runtime_call); 604 __ Bind(&runtime_call);
614 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. 605 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments.
615 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. 606 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator.
616 __ PushObject(Object::ZoneHandle()); // Make room for the result. 607 __ PushObject(Object::ZoneHandle()); // Make room for the result.
617 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id.
618 __ pushl(EAX); // Push the source object. 608 __ pushl(EAX); // Push the source object.
619 __ PushObject(dst_type); // Push the type of the destination. 609 __ PushObject(dst_type); // Push the type of the destination.
620 __ pushl(ECX); // Instantiator. 610 __ pushl(ECX); // Instantiator.
621 __ pushl(EDX); // Instantiator type arguments. 611 __ pushl(EDX); // Instantiator type arguments.
622 __ PushObject(dst_name); // Push the name of the destination. 612 __ PushObject(dst_name); // Push the name of the destination.
623 __ LoadObject(EAX, test_cache); 613 __ LoadObject(EAX, test_cache);
624 __ pushl(EAX); 614 __ pushl(EAX);
625 GenerateCallRuntime(cid, 615 GenerateCallRuntime(deopt_id,
626 token_pos, 616 token_pos,
627 try_index, 617 try_index,
628 kTypeCheckRuntimeEntry); 618 kTypeCheckRuntimeEntry);
629 // Pop the parameters supplied to the runtime entry. The result of the 619 // Pop the parameters supplied to the runtime entry. The result of the
630 // type check runtime call is the checked value. 620 // type check runtime call is the checked value.
631 __ Drop(7); 621 __ Drop(6);
632 __ popl(EAX); 622 __ popl(EAX);
633 623
634 __ Bind(&is_assignable); 624 __ Bind(&is_assignable);
635 __ popl(EDX); // Remove pushed instantiator type arguments.. 625 __ popl(EDX); // Remove pushed instantiator type arguments..
636 __ popl(ECX); // Remove pushed instantiator. 626 __ popl(ECX); // Remove pushed instantiator.
637 } 627 }
638 628
639 629
640 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { 630 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
641 LocationSummary* locs = instr->locs(); 631 LocationSummary* locs = instr->locs();
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
794 } 784 }
795 785
796 __ Bind(&wrong_num_arguments); 786 __ Bind(&wrong_num_arguments);
797 if (StackSize() != 0) { 787 if (StackSize() != 0) {
798 // We need to unwind the space we reserved for locals and copied parameters. 788 // We need to unwind the space we reserved for locals and copied parameters.
799 // The NoSuchMethodFunction stub does not expect to see that area on the 789 // The NoSuchMethodFunction stub does not expect to see that area on the
800 // stack. 790 // stack.
801 __ addl(ESP, Immediate(StackSize() * kWordSize)); 791 __ addl(ESP, Immediate(StackSize() * kWordSize));
802 } 792 }
803 if (function.IsClosureFunction()) { 793 if (function.IsClosureFunction()) {
804 GenerateCallRuntime(AstNode::kNoId, 794 GenerateCallRuntime(Isolate::kNoDeoptId,
805 0, 795 0,
806 CatchClauseNode::kInvalidTryIndex, 796 CatchClauseNode::kInvalidTryIndex,
807 kClosureArgumentMismatchRuntimeEntry); 797 kClosureArgumentMismatchRuntimeEntry);
808 } else { 798 } else {
809 ASSERT(!IsLeaf()); 799 ASSERT(!IsLeaf());
810 // Invoke noSuchMethod function. 800 // Invoke noSuchMethod function.
811 const int kNumArgsChecked = 1; 801 const int kNumArgsChecked = 1;
812 ICData& ic_data = ICData::ZoneHandle(); 802 ICData& ic_data = ICData::ZoneHandle();
813 ic_data = ICData::New(function, 803 ic_data = ICData::New(function,
814 String::Handle(function.name()), 804 String::Handle(function.name()),
815 AstNode::kNoId, 805 Isolate::kNoDeoptId,
816 kNumArgsChecked); 806 kNumArgsChecked);
817 __ LoadObject(ECX, ic_data); 807 __ LoadObject(ECX, ic_data);
818 // EBP - 4 : PC marker, allows easy identification of RawInstruction obj. 808 // EBP - 4 : PC marker, allows easy identification of RawInstruction obj.
819 // EBP : points to previous frame pointer. 809 // EBP : points to previous frame pointer.
820 // EBP + 4 : points to return address. 810 // EBP + 4 : points to return address.
821 // EBP + 8 : address of last argument (arg n-1). 811 // EBP + 8 : address of last argument (arg n-1).
822 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). 812 // ESP + 8 + 4*(n-1) : address of first argument (arg 0).
823 // ECX : ic-data. 813 // ECX : ic-data.
824 // EDX : arguments descriptor array. 814 // EDX : arguments descriptor array.
825 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); 815 __ call(&StubCode::CallNoSuchMethodFunctionLabel());
826 } 816 }
827 817
828 if (FLAG_trace_functions) { 818 if (FLAG_trace_functions) {
829 __ pushl(EAX); // Preserve result. 819 __ pushl(EAX); // Preserve result.
830 __ PushObject(Function::ZoneHandle(function.raw())); 820 __ PushObject(Function::ZoneHandle(function.raw()));
831 GenerateCallRuntime(AstNode::kNoId, 821 GenerateCallRuntime(Isolate::kNoDeoptId,
832 0, 822 0,
833 CatchClauseNode::kInvalidTryIndex, 823 CatchClauseNode::kInvalidTryIndex,
834 kTraceFunctionExitRuntimeEntry); 824 kTraceFunctionExitRuntimeEntry);
835 __ popl(EAX); // Remove argument. 825 __ popl(EAX); // Remove argument.
836 __ popl(EAX); // Restore result. 826 __ popl(EAX); // Restore result.
837 } 827 }
838 __ LeaveFrame(); 828 __ LeaveFrame();
839 __ ret(); 829 __ ret();
840 830
841 __ Bind(&all_arguments_processed); 831 __ Bind(&all_arguments_processed);
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
942 const bool check_arguments = function.IsClosureFunction(); 932 const bool check_arguments = function.IsClosureFunction();
943 #endif 933 #endif
944 if (check_arguments) { 934 if (check_arguments) {
945 // Check that num_fixed <= argc <= num_params. 935 // Check that num_fixed <= argc <= num_params.
946 Label argc_in_range; 936 Label argc_in_range;
947 // Total number of args is the first Smi in args descriptor array (EDX). 937 // Total number of args is the first Smi in args descriptor array (EDX).
948 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); 938 __ movl(EAX, FieldAddress(EDX, Array::data_offset()));
949 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count))); 939 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count)));
950 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); 940 __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
951 if (function.IsClosureFunction()) { 941 if (function.IsClosureFunction()) {
952 GenerateCallRuntime(AstNode::kNoId, 942 GenerateCallRuntime(Isolate::kNoDeoptId,
953 function.token_pos(), 943 function.token_pos(),
954 CatchClauseNode::kInvalidTryIndex, 944 CatchClauseNode::kInvalidTryIndex,
955 kClosureArgumentMismatchRuntimeEntry); 945 kClosureArgumentMismatchRuntimeEntry);
956 } else { 946 } else {
957 __ Stop("Wrong number of arguments"); 947 __ Stop("Wrong number of arguments");
958 } 948 }
959 __ Bind(&argc_in_range); 949 __ Bind(&argc_in_range);
960 } 950 }
961 } else { 951 } else {
962 CopyParameters(); 952 CopyParameters();
(...skipping 17 matching lines...) Expand all
980 __ movl(Address(EBP, (slot_base - i) * kWordSize), EAX); 970 __ movl(Address(EBP, (slot_base - i) * kWordSize), EAX);
981 } 971 }
982 } 972 }
983 973
984 if (!IsLeaf()) { 974 if (!IsLeaf()) {
985 // Generate stack overflow check. 975 // Generate stack overflow check.
986 __ cmpl(ESP, 976 __ cmpl(ESP,
987 Address::Absolute(Isolate::Current()->stack_limit_address())); 977 Address::Absolute(Isolate::Current()->stack_limit_address()));
988 Label no_stack_overflow; 978 Label no_stack_overflow;
989 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); 979 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump);
990 GenerateCallRuntime(AstNode::kNoId, 980 GenerateCallRuntime(Isolate::kNoDeoptId,
991 function.token_pos(), 981 function.token_pos(),
992 CatchClauseNode::kInvalidTryIndex, 982 CatchClauseNode::kInvalidTryIndex,
993 kStackOverflowRuntimeEntry); 983 kStackOverflowRuntimeEntry);
994 __ Bind(&no_stack_overflow); 984 __ Bind(&no_stack_overflow);
995 } 985 }
996 if (FLAG_print_scopes) { 986 if (FLAG_print_scopes) {
997 // Print the function scope (again) after generating the prologue in order 987 // Print the function scope (again) after generating the prologue in order
998 // to see annotations such as allocation indices of locals. 988 // to see annotations such as allocation indices of locals.
999 if (FLAG_print_ast) { 989 if (FLAG_print_ast) {
1000 // Second printing. 990 // Second printing.
1001 OS::Print("Annotated "); 991 OS::Print("Annotated ");
1002 } 992 }
1003 AstPrinter::PrintFunctionScope(parsed_function()); 993 AstPrinter::PrintFunctionScope(parsed_function());
1004 } 994 }
1005 995
1006 VisitBlocks(); 996 VisitBlocks();
1007 997
1008 __ int3(); 998 __ int3();
1009 GenerateDeferredCode(); 999 GenerateDeferredCode();
1010 // Emit function patching code. This will be swapped with the first 5 bytes 1000 // Emit function patching code. This will be swapped with the first 5 bytes
1011 // at entry point. 1001 // at entry point.
1012 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, 1002 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode,
1013 assembler()->CodeSize(), 1003 assembler()->CodeSize(),
1014 AstNode::kNoId, 1004 Isolate::kNoDeoptId,
1015 0, 1005 0,
1016 -1); 1006 -1);
1017 __ jmp(&StubCode::FixCallersTargetLabel()); 1007 __ jmp(&StubCode::FixCallersTargetLabel());
1018 } 1008 }
1019 1009
1020 1010
1021 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, 1011 void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
1022 intptr_t try_index, 1012 intptr_t try_index,
1023 const ExternalLabel* label, 1013 const ExternalLabel* label,
1024 PcDescriptors::Kind kind) { 1014 PcDescriptors::Kind kind) {
1025 ASSERT(!IsLeaf()); 1015 ASSERT(!IsLeaf());
1026 ASSERT(frame_register_allocator()->IsSpilled()); 1016 ASSERT(frame_register_allocator()->IsSpilled());
1027 __ call(label); 1017 __ call(label);
1028 AddCurrentDescriptor(kind, AstNode::kNoId, token_pos, try_index); 1018 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos, try_index);
1029 } 1019 }
1030 1020
1031 1021
1032 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, 1022 void FlowGraphCompiler::GenerateCallRuntime(intptr_t deopt_id,
1033 intptr_t token_pos, 1023 intptr_t token_pos,
1034 intptr_t try_index, 1024 intptr_t try_index,
1035 const RuntimeEntry& entry) { 1025 const RuntimeEntry& entry) {
1036 ASSERT(!IsLeaf()); 1026 ASSERT(!IsLeaf());
1037 ASSERT(frame_register_allocator()->IsSpilled()); 1027 ASSERT(frame_register_allocator()->IsSpilled());
1038 __ CallRuntime(entry); 1028 __ CallRuntime(entry);
1039 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_pos, try_index); 1029 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos, try_index);
1040 } 1030 }
1041 1031
1042 1032
1043 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, 1033 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
1044 const ICData& ic_data, 1034 const ICData& ic_data,
1045 const Array& arguments_descriptor, 1035 const Array& arguments_descriptor,
1046 intptr_t argument_count) { 1036 intptr_t argument_count) {
1047 ASSERT(!IsLeaf()); 1037 ASSERT(!IsLeaf());
1048 __ LoadObject(ECX, ic_data); 1038 __ LoadObject(ECX, ic_data);
1049 __ LoadObject(EDX, arguments_descriptor); 1039 __ LoadObject(EDX, arguments_descriptor);
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
1245 __ popl(ECX); 1235 __ popl(ECX);
1246 __ popl(EAX); 1236 __ popl(EAX);
1247 } 1237 }
1248 1238
1249 1239
1250 #undef __ 1240 #undef __
1251 1241
1252 } // namespace dart 1242 } // namespace dart
1253 1243
1254 #endif // defined TARGET_ARCH_IA32 1244 #endif // defined TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698