OLD | NEW |
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 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 } | 163 } |
164 | 164 |
165 | 165 |
166 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 166 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
167 // type test is conclusive, otherwise fallthrough if a type test could not | 167 // type test is conclusive, otherwise fallthrough if a type test could not |
168 // be completed. | 168 // be completed. |
169 // EAX: instance (must survive). | 169 // EAX: instance (must survive). |
170 // Clobbers ECX, EDI. | 170 // Clobbers ECX, EDI. |
171 RawSubtypeTestCache* | 171 RawSubtypeTestCache* |
172 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 172 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
173 intptr_t cid, | |
174 intptr_t token_pos, | 173 intptr_t token_pos, |
175 const AbstractType& type, | 174 const AbstractType& type, |
176 Label* is_instance_lbl, | 175 Label* is_instance_lbl, |
177 Label* is_not_instance_lbl) { | 176 Label* is_not_instance_lbl) { |
178 ASSERT(type.IsInstantiated()); | 177 ASSERT(type.IsInstantiated()); |
179 const Class& type_class = Class::ZoneHandle(type.type_class()); | 178 const Class& type_class = Class::ZoneHandle(type.type_class()); |
180 ASSERT(type_class.HasTypeArguments()); | 179 ASSERT(type_class.HasTypeArguments()); |
181 const Register kInstanceReg = EAX; | 180 const Register kInstanceReg = EAX; |
182 // A Smi object cannot be the instance of a parameterized class. | 181 // A Smi object cannot be the instance of a parameterized class. |
183 __ testl(kInstanceReg, Immediate(kSmiTagMask)); | 182 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
184 __ j(ZERO, is_not_instance_lbl); | 183 __ j(ZERO, is_not_instance_lbl); |
185 const AbstractTypeArguments& type_arguments = | 184 const AbstractTypeArguments& type_arguments = |
186 AbstractTypeArguments::ZoneHandle(type.arguments()); | 185 AbstractTypeArguments::ZoneHandle(type.arguments()); |
187 const bool is_raw_type = type_arguments.IsNull() || | 186 const bool is_raw_type = type_arguments.IsNull() || |
188 type_arguments.IsRaw(type_arguments.Length()); | 187 type_arguments.IsRaw(type_arguments.Length()); |
189 if (is_raw_type) { | 188 if (is_raw_type) { |
190 const Register kClassIdReg = ECX; | 189 const Register kClassIdReg = ECX; |
191 // Dynamic type argument, check only classes. | 190 // Dynamic type argument, check only classes. |
192 // List is a very common case. | 191 // List is a very common case. |
193 __ LoadClassId(kClassIdReg, kInstanceReg); | 192 __ LoadClassId(kClassIdReg, kInstanceReg); |
194 if (!type_class.is_interface()) { | 193 if (!type_class.is_interface()) { |
195 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 194 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
196 __ j(EQUAL, is_instance_lbl); | 195 __ j(EQUAL, is_instance_lbl); |
197 } | 196 } |
198 if (type.IsListInterface()) { | 197 if (type.IsListInterface()) { |
199 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 198 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
200 } | 199 } |
201 return GenerateSubtype1TestCacheLookup( | 200 return GenerateSubtype1TestCacheLookup( |
202 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 201 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
203 } | 202 } |
204 // If one type argument only, check if type argument is Object or Dynamic. | 203 // If one type argument only, check if type argument is Object or Dynamic. |
205 if (type_arguments.Length() == 1) { | 204 if (type_arguments.Length() == 1) { |
206 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 205 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
207 type_arguments.TypeAt(0)); | 206 type_arguments.TypeAt(0)); |
208 ASSERT(!tp_argument.IsMalformed()); | 207 ASSERT(!tp_argument.IsMalformed()); |
209 if (tp_argument.IsType()) { | 208 if (tp_argument.IsType()) { |
210 ASSERT(tp_argument.HasResolvedTypeClass()); | 209 ASSERT(tp_argument.HasResolvedTypeClass()); |
211 // Check if type argument is dynamic or Object. | 210 // Check if type argument is dynamic or Object. |
212 const Type& object_type = Type::Handle(Type::ObjectType()); | 211 const Type& object_type = Type::Handle(Type::ObjectType()); |
213 if (object_type.IsSubtypeOf(tp_argument, NULL)) { | 212 if (object_type.IsSubtypeOf(tp_argument, NULL)) { |
214 // Instance class test only necessary. | 213 // Instance class test only necessary. |
215 return GenerateSubtype1TestCacheLookup( | 214 return GenerateSubtype1TestCacheLookup( |
216 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 215 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
217 } | 216 } |
218 } | 217 } |
219 } | 218 } |
220 // Regular subtype test cache involving instance's type arguments. | 219 // Regular subtype test cache involving instance's type arguments. |
221 const Register kTypeArgumentsReg = kNoRegister; | 220 const Register kTypeArgumentsReg = kNoRegister; |
222 const Register kTempReg = EDI; | 221 const Register kTempReg = EDI; |
223 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, | 222 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, |
224 kInstanceReg, | 223 kInstanceReg, |
225 kTypeArgumentsReg, | 224 kTypeArgumentsReg, |
226 kTempReg, | 225 kTempReg, |
(...skipping 13 matching lines...) Expand all Loading... |
240 __ jmp(is_not_equal_lbl); | 239 __ jmp(is_not_equal_lbl); |
241 } | 240 } |
242 | 241 |
243 | 242 |
244 // Testing against an instantiated type with no arguments, without | 243 // Testing against an instantiated type with no arguments, without |
245 // SubtypeTestCache. | 244 // SubtypeTestCache. |
246 // EAX: instance to test against (preserved). | 245 // EAX: instance to test against (preserved). |
247 // Clobbers ECX, EDI. | 246 // Clobbers ECX, EDI. |
248 // Returns true if there is a fallthrough. | 247 // Returns true if there is a fallthrough. |
249 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 248 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
250 intptr_t cid, | |
251 intptr_t token_pos, | 249 intptr_t token_pos, |
252 const AbstractType& type, | 250 const AbstractType& type, |
253 Label* is_instance_lbl, | 251 Label* is_instance_lbl, |
254 Label* is_not_instance_lbl) { | 252 Label* is_not_instance_lbl) { |
255 ASSERT(type.IsInstantiated()); | 253 ASSERT(type.IsInstantiated()); |
256 const Class& type_class = Class::Handle(type.type_class()); | 254 const Class& type_class = Class::Handle(type.type_class()); |
257 ASSERT(!type_class.HasTypeArguments()); | 255 ASSERT(!type_class.HasTypeArguments()); |
258 | 256 |
259 const Register kInstanceReg = EAX; | 257 const Register kInstanceReg = EAX; |
260 Label compare_classes; | 258 Label compare_classes; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 | 313 |
316 | 314 |
317 // Uses SubtypeTestCache to store instance class and result. | 315 // Uses SubtypeTestCache to store instance class and result. |
318 // EAX: instance to test. | 316 // EAX: instance to test. |
319 // Clobbers EDI, ECX. | 317 // Clobbers EDI, ECX. |
320 // Immediate class test already done. | 318 // Immediate class test already done. |
321 // TODO(srdjan): Implement a quicker subtype check, as type test | 319 // TODO(srdjan): Implement a quicker subtype check, as type test |
322 // arrays can grow too high, but they may be useful when optimizing | 320 // arrays can grow too high, but they may be useful when optimizing |
323 // code (type-feedback). | 321 // code (type-feedback). |
324 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 322 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
325 intptr_t cid, | |
326 intptr_t token_pos, | 323 intptr_t token_pos, |
327 const Class& type_class, | 324 const Class& type_class, |
328 Label* is_instance_lbl, | 325 Label* is_instance_lbl, |
329 Label* is_not_instance_lbl) { | 326 Label* is_not_instance_lbl) { |
330 const Register kInstanceReg = EAX; | 327 const Register kInstanceReg = EAX; |
331 __ LoadClass(ECX, kInstanceReg, EDI); | 328 __ LoadClass(ECX, kInstanceReg, EDI); |
332 // ECX: instance class. | 329 // ECX: instance class. |
333 // Check immediate superclass equality. | 330 // Check immediate superclass equality. |
334 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 331 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
335 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 332 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
336 __ CompareObject(EDI, type_class); | 333 __ CompareObject(EDI, type_class); |
337 __ j(EQUAL, is_instance_lbl); | 334 __ j(EQUAL, is_instance_lbl); |
338 | 335 |
339 const Register kTypeArgumentsReg = kNoRegister; | 336 const Register kTypeArgumentsReg = kNoRegister; |
340 const Register kTempReg = EDI; | 337 const Register kTempReg = EDI; |
341 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 338 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
342 kInstanceReg, | 339 kInstanceReg, |
343 kTypeArgumentsReg, | 340 kTypeArgumentsReg, |
344 kTempReg, | 341 kTempReg, |
345 is_instance_lbl, | 342 is_instance_lbl, |
346 is_not_instance_lbl); | 343 is_not_instance_lbl); |
347 } | 344 } |
348 | 345 |
349 | 346 |
350 // Generates inlined check if 'type' is a type parameter or type itsef | 347 // Generates inlined check if 'type' is a type parameter or type itsef |
351 // EAX: instance (preserved). | 348 // EAX: instance (preserved). |
352 // Clobbers EDX, EDI, ECX. | 349 // Clobbers EDX, EDI, ECX. |
353 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 350 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
354 intptr_t cid, | |
355 intptr_t token_pos, | 351 intptr_t token_pos, |
356 const AbstractType& type, | 352 const AbstractType& type, |
357 Label* is_instance_lbl, | 353 Label* is_instance_lbl, |
358 Label* is_not_instance_lbl) { | 354 Label* is_not_instance_lbl) { |
359 ASSERT(!type.IsInstantiated()); | 355 ASSERT(!type.IsInstantiated()); |
360 // Skip check if destination is a dynamic type. | 356 // Skip check if destination is a dynamic type. |
361 const Immediate raw_null = | 357 const Immediate raw_null = |
362 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 358 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
363 if (type.IsTypeParameter()) { | 359 if (type.IsTypeParameter()) { |
364 const TypeParameter& type_param = TypeParameter::Cast(type); | 360 const TypeParameter& type_param = TypeParameter::Cast(type); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 // Inputs: | 432 // Inputs: |
437 // - EAX: instance to test against (preserved). | 433 // - EAX: instance to test against (preserved). |
438 // - EDX: optional instantiator type arguments (preserved). | 434 // - EDX: optional instantiator type arguments (preserved). |
439 // Clobbers ECX, EDI. | 435 // Clobbers ECX, EDI. |
440 // Returns: | 436 // Returns: |
441 // - preserved instance in EAX and optional instantiator type arguments in EDX. | 437 // - preserved instance in EAX and optional instantiator type arguments in EDX. |
442 // Note that this inlined code must be followed by the runtime_call code, as it | 438 // Note that this inlined code must be followed by the runtime_call code, as it |
443 // may fall through to it. Otherwise, this inline code will jump to the label | 439 // may fall through to it. Otherwise, this inline code will jump to the label |
444 // is_instance or to the label is_not_instance. | 440 // is_instance or to the label is_not_instance. |
445 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 441 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
446 intptr_t cid, | |
447 intptr_t token_pos, | 442 intptr_t token_pos, |
448 const AbstractType& type, | 443 const AbstractType& type, |
449 Label* is_instance_lbl, | 444 Label* is_instance_lbl, |
450 Label* is_not_instance_lbl) { | 445 Label* is_not_instance_lbl) { |
451 if (type.IsVoidType()) { | 446 if (type.IsVoidType()) { |
452 // A non-null value is returned from a void function, which will result in a | 447 // A non-null value is returned from a void function, which will result in a |
453 // type error. A null value is handled prior to executing this inline code. | 448 // type error. A null value is handled prior to executing this inline code. |
454 return SubtypeTestCache::null(); | 449 return SubtypeTestCache::null(); |
455 } | 450 } |
456 if (type.IsInstantiated()) { | 451 if (type.IsInstantiated()) { |
457 const Class& type_class = Class::ZoneHandle(type.type_class()); | 452 const Class& type_class = Class::ZoneHandle(type.type_class()); |
458 // A Smi object cannot be the instance of a parameterized class. | 453 // A Smi object cannot be the instance of a parameterized class. |
459 // A class equality check is only applicable with a dst type of a | 454 // A class equality check is only applicable with a dst type of a |
460 // non-parameterized class or with a raw dst type of a parameterized class. | 455 // non-parameterized class or with a raw dst type of a parameterized class. |
461 if (type_class.HasTypeArguments()) { | 456 if (type_class.HasTypeArguments()) { |
462 return GenerateInstantiatedTypeWithArgumentsTest(cid, | 457 return GenerateInstantiatedTypeWithArgumentsTest(token_pos, |
463 token_pos, | |
464 type, | 458 type, |
465 is_instance_lbl, | 459 is_instance_lbl, |
466 is_not_instance_lbl); | 460 is_not_instance_lbl); |
467 // Fall through to runtime call. | 461 // Fall through to runtime call. |
468 } | 462 } |
469 const bool has_fall_through = | 463 const bool has_fall_through = |
470 GenerateInstantiatedTypeNoArgumentsTest(cid, | 464 GenerateInstantiatedTypeNoArgumentsTest(token_pos, |
471 token_pos, | |
472 type, | 465 type, |
473 is_instance_lbl, | 466 is_instance_lbl, |
474 is_not_instance_lbl); | 467 is_not_instance_lbl); |
475 if (has_fall_through) { | 468 if (has_fall_through) { |
476 // If test non-conclusive so far, try the inlined type-test cache. | 469 // If test non-conclusive so far, try the inlined type-test cache. |
477 // 'type' is known at compile time. | 470 // 'type' is known at compile time. |
478 return GenerateSubtype1TestCacheLookup( | 471 return GenerateSubtype1TestCacheLookup( |
479 cid, token_pos, type_class, | 472 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
480 is_instance_lbl, is_not_instance_lbl); | |
481 } else { | 473 } else { |
482 return SubtypeTestCache::null(); | 474 return SubtypeTestCache::null(); |
483 } | 475 } |
484 } | 476 } |
485 return GenerateUninstantiatedTypeTest(cid, | 477 return GenerateUninstantiatedTypeTest(token_pos, |
486 token_pos, | |
487 type, | 478 type, |
488 is_instance_lbl, | 479 is_instance_lbl, |
489 is_not_instance_lbl); | 480 is_not_instance_lbl); |
490 } | 481 } |
491 | 482 |
492 | 483 |
493 // If instanceof type test cannot be performed successfully at compile time and | 484 // If instanceof type test cannot be performed successfully at compile time and |
494 // therefore eliminated, optimize it by adding inlined tests for: | 485 // therefore eliminated, optimize it by adding inlined tests for: |
495 // - NULL -> return false. | 486 // - NULL -> return false. |
496 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 487 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
497 // - Class equality (only if class is not parameterized). | 488 // - Class equality (only if class is not parameterized). |
498 // Inputs: | 489 // Inputs: |
499 // - EAX: object. | 490 // - EAX: object. |
500 // - EDX: instantiator type arguments or raw_null. | 491 // - EDX: instantiator type arguments or raw_null. |
501 // - ECX: instantiator or raw_null. | 492 // - ECX: instantiator or raw_null. |
502 // Clobbers ECX and EDX. | 493 // Clobbers ECX and EDX. |
503 // Returns: | 494 // Returns: |
504 // - true or false in EAX. | 495 // - true or false in EAX. |
505 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, | 496 void FlowGraphCompiler::GenerateInstanceOf(intptr_t deopt_id, |
506 intptr_t token_pos, | 497 intptr_t token_pos, |
507 intptr_t try_index, | 498 intptr_t try_index, |
508 const AbstractType& type, | 499 const AbstractType& type, |
509 bool negate_result) { | 500 bool negate_result) { |
510 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 501 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
511 | 502 |
512 const Immediate raw_null = | 503 const Immediate raw_null = |
513 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 504 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
514 Label is_instance, is_not_instance; | 505 Label is_instance, is_not_instance; |
515 __ pushl(ECX); // Store instantiator on stack. | 506 __ pushl(ECX); // Store instantiator on stack. |
516 __ pushl(EDX); // Store instantiator type arguments. | 507 __ pushl(EDX); // Store instantiator type arguments. |
517 // If type is instantiated and non-parameterized, we can inline code | 508 // If type is instantiated and non-parameterized, we can inline code |
518 // checking whether the tested instance is a Smi. | 509 // checking whether the tested instance is a Smi. |
519 if (type.IsInstantiated()) { | 510 if (type.IsInstantiated()) { |
520 // A null object is only an instance of Object and Dynamic, which has | 511 // A null object is only an instance of Object and Dynamic, which has |
521 // already been checked above (if the type is instantiated). So we can | 512 // already been checked above (if the type is instantiated). So we can |
522 // return false here if the instance is null (and if the type is | 513 // return false here if the instance is null (and if the type is |
523 // instantiated). | 514 // instantiated). |
524 // We can only inline this null check if the type is instantiated at compile | 515 // We can only inline this null check if the type is instantiated at compile |
525 // time, since an uninstantiated type at compile time could be Object or | 516 // time, since an uninstantiated type at compile time could be Object or |
526 // Dynamic at run time. | 517 // Dynamic at run time. |
527 __ cmpl(EAX, raw_null); | 518 __ cmpl(EAX, raw_null); |
528 __ j(EQUAL, &is_not_instance); | 519 __ j(EQUAL, &is_not_instance); |
529 } | 520 } |
530 | 521 |
531 // Generate inline instanceof test. | 522 // Generate inline instanceof test. |
532 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 523 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
533 test_cache = GenerateInlineInstanceof(cid, token_pos, type, | 524 test_cache = GenerateInlineInstanceof(token_pos, type, |
534 &is_instance, &is_not_instance); | 525 &is_instance, &is_not_instance); |
535 | 526 |
536 // test_cache is null if there is no fall-through. | 527 // test_cache is null if there is no fall-through. |
537 Label done; | 528 Label done; |
538 if (!test_cache.IsNull()) { | 529 if (!test_cache.IsNull()) { |
539 // Generate runtime call. | 530 // Generate runtime call. |
540 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 531 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
541 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 532 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
542 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 533 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
543 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. | |
544 __ pushl(EAX); // Push the instance. | 534 __ pushl(EAX); // Push the instance. |
545 __ PushObject(type); // Push the type. | 535 __ PushObject(type); // Push the type. |
546 __ pushl(ECX); // Instantiator. | 536 __ pushl(ECX); // Instantiator. |
547 __ pushl(EDX); // Instantiator type arguments. | 537 __ pushl(EDX); // Instantiator type arguments. |
548 __ LoadObject(EAX, test_cache); | 538 __ LoadObject(EAX, test_cache); |
549 __ pushl(EAX); | 539 __ pushl(EAX); |
550 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry); | 540 GenerateCallRuntime(deopt_id, token_pos, try_index, |
| 541 kInstanceofRuntimeEntry); |
551 // Pop the parameters supplied to the runtime entry. The result of the | 542 // Pop the parameters supplied to the runtime entry. The result of the |
552 // instanceof runtime call will be left as the result of the operation. | 543 // instanceof runtime call will be left as the result of the operation. |
553 __ Drop(6); | 544 __ Drop(5); |
554 if (negate_result) { | 545 if (negate_result) { |
555 __ popl(EDX); | 546 __ popl(EDX); |
556 __ LoadObject(EAX, bool_true()); | 547 __ LoadObject(EAX, bool_true()); |
557 __ cmpl(EDX, EAX); | 548 __ cmpl(EDX, EAX); |
558 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 549 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
559 __ LoadObject(EAX, bool_false()); | 550 __ LoadObject(EAX, bool_false()); |
560 } else { | 551 } else { |
561 __ popl(EAX); | 552 __ popl(EAX); |
562 } | 553 } |
563 __ jmp(&done, Assembler::kNearJump); | 554 __ jmp(&done, Assembler::kNearJump); |
(...skipping 15 matching lines...) Expand all Loading... |
579 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 570 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
580 // - Class equality (only if class is not parameterized). | 571 // - Class equality (only if class is not parameterized). |
581 // Inputs: | 572 // Inputs: |
582 // - EAX: object. | 573 // - EAX: object. |
583 // - EDX: instantiator type arguments or raw_null. | 574 // - EDX: instantiator type arguments or raw_null. |
584 // - ECX: instantiator or raw_null. | 575 // - ECX: instantiator or raw_null. |
585 // Returns: | 576 // Returns: |
586 // - object in EAX for successful assignable check (or throws TypeError). | 577 // - object in EAX for successful assignable check (or throws TypeError). |
587 // Performance notes: positive checks must be quick, negative checks can be slow | 578 // Performance notes: positive checks must be quick, negative checks can be slow |
588 // as they throw an exception. | 579 // as they throw an exception. |
589 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, | 580 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t deopt_id, |
590 intptr_t token_pos, | 581 intptr_t token_pos, |
591 intptr_t try_index, | 582 intptr_t try_index, |
592 const AbstractType& dst_type, | 583 const AbstractType& dst_type, |
593 const String& dst_name) { | 584 const String& dst_name) { |
594 ASSERT(token_pos >= 0); | 585 ASSERT(token_pos >= 0); |
595 ASSERT(!dst_type.IsNull()); | 586 ASSERT(!dst_type.IsNull()); |
596 ASSERT(dst_type.IsFinalized()); | 587 ASSERT(dst_type.IsFinalized()); |
597 // Assignable check is skipped in FlowGraphBuilder, not here. | 588 // Assignable check is skipped in FlowGraphBuilder, not here. |
598 ASSERT(dst_type.IsMalformed() || | 589 ASSERT(dst_type.IsMalformed() || |
599 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 590 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
600 __ pushl(ECX); // Store instantiator. | 591 __ pushl(ECX); // Store instantiator. |
601 __ pushl(EDX); // Store instantiator type arguments. | 592 __ pushl(EDX); // Store instantiator type arguments. |
602 // A null object is always assignable and is returned as result. | 593 // A null object is always assignable and is returned as result. |
603 const Immediate raw_null = | 594 const Immediate raw_null = |
604 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 595 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
605 Label is_assignable, runtime_call; | 596 Label is_assignable, runtime_call; |
606 __ cmpl(EAX, raw_null); | 597 __ cmpl(EAX, raw_null); |
607 __ j(EQUAL, &is_assignable); | 598 __ j(EQUAL, &is_assignable); |
608 | 599 |
609 // Generate throw new TypeError() if the type is malformed. | 600 // Generate throw new TypeError() if the type is malformed. |
610 if (dst_type.IsMalformed()) { | 601 if (dst_type.IsMalformed()) { |
611 const Error& error = Error::Handle(dst_type.malformed_error()); | 602 const Error& error = Error::Handle(dst_type.malformed_error()); |
612 const String& error_message = String::ZoneHandle( | 603 const String& error_message = String::ZoneHandle( |
613 Symbols::New(error.ToErrorCString())); | 604 Symbols::New(error.ToErrorCString())); |
614 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 605 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
615 __ pushl(EAX); // Push the source object. | 606 __ pushl(EAX); // Push the source object. |
616 __ PushObject(dst_name); // Push the name of the destination. | 607 __ PushObject(dst_name); // Push the name of the destination. |
617 __ PushObject(error_message); | 608 __ PushObject(error_message); |
618 GenerateCallRuntime(cid, | 609 GenerateCallRuntime(deopt_id, |
619 token_pos, | 610 token_pos, |
620 try_index, | 611 try_index, |
621 kMalformedTypeErrorRuntimeEntry); | 612 kMalformedTypeErrorRuntimeEntry); |
622 // We should never return here. | 613 // We should never return here. |
623 __ int3(); | 614 __ int3(); |
624 | 615 |
625 __ Bind(&is_assignable); // For a null object. | 616 __ Bind(&is_assignable); // For a null object. |
626 return; | 617 return; |
627 } | 618 } |
628 | 619 |
629 // Generate inline type check, linking to runtime call if not assignable. | 620 // Generate inline type check, linking to runtime call if not assignable. |
630 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 621 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
631 test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type, | 622 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
632 &is_assignable, &runtime_call); | 623 &is_assignable, &runtime_call); |
633 | 624 |
634 __ Bind(&runtime_call); | 625 __ Bind(&runtime_call); |
635 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 626 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
636 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 627 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
637 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 628 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
638 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. | |
639 __ pushl(EAX); // Push the source object. | 629 __ pushl(EAX); // Push the source object. |
640 __ PushObject(dst_type); // Push the type of the destination. | 630 __ PushObject(dst_type); // Push the type of the destination. |
641 __ pushl(ECX); // Instantiator. | 631 __ pushl(ECX); // Instantiator. |
642 __ pushl(EDX); // Instantiator type arguments. | 632 __ pushl(EDX); // Instantiator type arguments. |
643 __ PushObject(dst_name); // Push the name of the destination. | 633 __ PushObject(dst_name); // Push the name of the destination. |
644 __ LoadObject(EAX, test_cache); | 634 __ LoadObject(EAX, test_cache); |
645 __ pushl(EAX); | 635 __ pushl(EAX); |
646 GenerateCallRuntime(cid, | 636 GenerateCallRuntime(deopt_id, |
647 token_pos, | 637 token_pos, |
648 try_index, | 638 try_index, |
649 kTypeCheckRuntimeEntry); | 639 kTypeCheckRuntimeEntry); |
650 // Pop the parameters supplied to the runtime entry. The result of the | 640 // Pop the parameters supplied to the runtime entry. The result of the |
651 // type check runtime call is the checked value. | 641 // type check runtime call is the checked value. |
652 __ Drop(7); | 642 __ Drop(6); |
653 __ popl(EAX); | 643 __ popl(EAX); |
654 | 644 |
655 __ Bind(&is_assignable); | 645 __ Bind(&is_assignable); |
656 __ popl(EDX); // Remove pushed instantiator type arguments.. | 646 __ popl(EDX); // Remove pushed instantiator type arguments.. |
657 __ popl(ECX); // Remove pushed instantiator. | 647 __ popl(ECX); // Remove pushed instantiator. |
658 } | 648 } |
659 | 649 |
660 | 650 |
661 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { | 651 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { |
662 LocationSummary* locs = instr->locs(); | 652 LocationSummary* locs = instr->locs(); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
815 } | 805 } |
816 | 806 |
817 __ Bind(&wrong_num_arguments); | 807 __ Bind(&wrong_num_arguments); |
818 if (StackSize() != 0) { | 808 if (StackSize() != 0) { |
819 // We need to unwind the space we reserved for locals and copied parameters. | 809 // We need to unwind the space we reserved for locals and copied parameters. |
820 // The NoSuchMethodFunction stub does not expect to see that area on the | 810 // The NoSuchMethodFunction stub does not expect to see that area on the |
821 // stack. | 811 // stack. |
822 __ addl(ESP, Immediate(StackSize() * kWordSize)); | 812 __ addl(ESP, Immediate(StackSize() * kWordSize)); |
823 } | 813 } |
824 if (function.IsClosureFunction()) { | 814 if (function.IsClosureFunction()) { |
825 GenerateCallRuntime(AstNode::kNoId, | 815 GenerateCallRuntime(Isolate::kNoDeoptId, |
826 0, | 816 0, |
827 CatchClauseNode::kInvalidTryIndex, | 817 CatchClauseNode::kInvalidTryIndex, |
828 kClosureArgumentMismatchRuntimeEntry); | 818 kClosureArgumentMismatchRuntimeEntry); |
829 } else { | 819 } else { |
830 ASSERT(!IsLeaf()); | 820 ASSERT(!IsLeaf()); |
831 // Invoke noSuchMethod function. | 821 // Invoke noSuchMethod function. |
832 const int kNumArgsChecked = 1; | 822 const int kNumArgsChecked = 1; |
833 ICData& ic_data = ICData::ZoneHandle(); | 823 ICData& ic_data = ICData::ZoneHandle(); |
834 ic_data = ICData::New(function, | 824 ic_data = ICData::New(function, |
835 String::Handle(function.name()), | 825 String::Handle(function.name()), |
836 AstNode::kNoId, | 826 Isolate::kNoDeoptId, |
837 kNumArgsChecked); | 827 kNumArgsChecked); |
838 __ LoadObject(ECX, ic_data); | 828 __ LoadObject(ECX, ic_data); |
839 // EBP - 4 : PC marker, allows easy identification of RawInstruction obj. | 829 // EBP - 4 : PC marker, allows easy identification of RawInstruction obj. |
840 // EBP : points to previous frame pointer. | 830 // EBP : points to previous frame pointer. |
841 // EBP + 4 : points to return address. | 831 // EBP + 4 : points to return address. |
842 // EBP + 8 : address of last argument (arg n-1). | 832 // EBP + 8 : address of last argument (arg n-1). |
843 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). | 833 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). |
844 // ECX : ic-data. | 834 // ECX : ic-data. |
845 // EDX : arguments descriptor array. | 835 // EDX : arguments descriptor array. |
846 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); | 836 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); |
847 } | 837 } |
848 | 838 |
849 if (FLAG_trace_functions) { | 839 if (FLAG_trace_functions) { |
850 __ pushl(EAX); // Preserve result. | 840 __ pushl(EAX); // Preserve result. |
851 __ PushObject(Function::ZoneHandle(function.raw())); | 841 __ PushObject(Function::ZoneHandle(function.raw())); |
852 GenerateCallRuntime(AstNode::kNoId, | 842 GenerateCallRuntime(Isolate::kNoDeoptId, |
853 0, | 843 0, |
854 CatchClauseNode::kInvalidTryIndex, | 844 CatchClauseNode::kInvalidTryIndex, |
855 kTraceFunctionExitRuntimeEntry); | 845 kTraceFunctionExitRuntimeEntry); |
856 __ popl(EAX); // Remove argument. | 846 __ popl(EAX); // Remove argument. |
857 __ popl(EAX); // Restore result. | 847 __ popl(EAX); // Restore result. |
858 } | 848 } |
859 __ LeaveFrame(); | 849 __ LeaveFrame(); |
860 __ ret(); | 850 __ ret(); |
861 | 851 |
862 __ Bind(&all_arguments_processed); | 852 __ Bind(&all_arguments_processed); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
963 const bool check_arguments = function.IsClosureFunction(); | 953 const bool check_arguments = function.IsClosureFunction(); |
964 #endif | 954 #endif |
965 if (check_arguments) { | 955 if (check_arguments) { |
966 // Check that num_fixed <= argc <= num_params. | 956 // Check that num_fixed <= argc <= num_params. |
967 Label argc_in_range; | 957 Label argc_in_range; |
968 // Total number of args is the first Smi in args descriptor array (EDX). | 958 // Total number of args is the first Smi in args descriptor array (EDX). |
969 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); | 959 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
970 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count))); | 960 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count))); |
971 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 961 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
972 if (function.IsClosureFunction()) { | 962 if (function.IsClosureFunction()) { |
973 GenerateCallRuntime(AstNode::kNoId, | 963 GenerateCallRuntime(Isolate::kNoDeoptId, |
974 function.token_pos(), | 964 function.token_pos(), |
975 CatchClauseNode::kInvalidTryIndex, | 965 CatchClauseNode::kInvalidTryIndex, |
976 kClosureArgumentMismatchRuntimeEntry); | 966 kClosureArgumentMismatchRuntimeEntry); |
977 } else { | 967 } else { |
978 __ Stop("Wrong number of arguments"); | 968 __ Stop("Wrong number of arguments"); |
979 } | 969 } |
980 __ Bind(&argc_in_range); | 970 __ Bind(&argc_in_range); |
981 } | 971 } |
982 } else { | 972 } else { |
983 CopyParameters(); | 973 CopyParameters(); |
(...skipping 17 matching lines...) Expand all Loading... |
1001 __ movl(Address(EBP, (slot_base - i) * kWordSize), EAX); | 991 __ movl(Address(EBP, (slot_base - i) * kWordSize), EAX); |
1002 } | 992 } |
1003 } | 993 } |
1004 | 994 |
1005 if (!IsLeaf()) { | 995 if (!IsLeaf()) { |
1006 // Generate stack overflow check. | 996 // Generate stack overflow check. |
1007 __ cmpl(ESP, | 997 __ cmpl(ESP, |
1008 Address::Absolute(Isolate::Current()->stack_limit_address())); | 998 Address::Absolute(Isolate::Current()->stack_limit_address())); |
1009 Label no_stack_overflow; | 999 Label no_stack_overflow; |
1010 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); | 1000 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); |
1011 GenerateCallRuntime(AstNode::kNoId, | 1001 GenerateCallRuntime(Isolate::kNoDeoptId, |
1012 function.token_pos(), | 1002 function.token_pos(), |
1013 CatchClauseNode::kInvalidTryIndex, | 1003 CatchClauseNode::kInvalidTryIndex, |
1014 kStackOverflowRuntimeEntry); | 1004 kStackOverflowRuntimeEntry); |
1015 __ Bind(&no_stack_overflow); | 1005 __ Bind(&no_stack_overflow); |
1016 } | 1006 } |
1017 if (FLAG_print_scopes) { | 1007 if (FLAG_print_scopes) { |
1018 // Print the function scope (again) after generating the prologue in order | 1008 // Print the function scope (again) after generating the prologue in order |
1019 // to see annotations such as allocation indices of locals. | 1009 // to see annotations such as allocation indices of locals. |
1020 if (FLAG_print_ast) { | 1010 if (FLAG_print_ast) { |
1021 // Second printing. | 1011 // Second printing. |
1022 OS::Print("Annotated "); | 1012 OS::Print("Annotated "); |
1023 } | 1013 } |
1024 AstPrinter::PrintFunctionScope(parsed_function()); | 1014 AstPrinter::PrintFunctionScope(parsed_function()); |
1025 } | 1015 } |
1026 | 1016 |
1027 VisitBlocks(); | 1017 VisitBlocks(); |
1028 | 1018 |
1029 __ int3(); | 1019 __ int3(); |
1030 GenerateDeferredCode(); | 1020 GenerateDeferredCode(); |
1031 // Emit function patching code. This will be swapped with the first 5 bytes | 1021 // Emit function patching code. This will be swapped with the first 5 bytes |
1032 // at entry point. | 1022 // at entry point. |
1033 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, | 1023 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, |
1034 assembler()->CodeSize(), | 1024 assembler()->CodeSize(), |
1035 AstNode::kNoId, | 1025 Isolate::kNoDeoptId, |
1036 0, | 1026 0, |
1037 -1); | 1027 -1); |
1038 __ jmp(&StubCode::FixCallersTargetLabel()); | 1028 __ jmp(&StubCode::FixCallersTargetLabel()); |
1039 } | 1029 } |
1040 | 1030 |
1041 | 1031 |
1042 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1032 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
1043 intptr_t try_index, | 1033 intptr_t try_index, |
1044 const ExternalLabel* label, | 1034 const ExternalLabel* label, |
1045 PcDescriptors::Kind kind) { | 1035 PcDescriptors::Kind kind) { |
1046 ASSERT(!IsLeaf()); | 1036 ASSERT(!IsLeaf()); |
1047 ASSERT(frame_register_allocator()->IsSpilled()); | 1037 ASSERT(frame_register_allocator()->IsSpilled()); |
1048 __ call(label); | 1038 __ call(label); |
1049 AddCurrentDescriptor(kind, AstNode::kNoId, token_pos, try_index); | 1039 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos, try_index); |
1050 } | 1040 } |
1051 | 1041 |
1052 | 1042 |
1053 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, | 1043 void FlowGraphCompiler::GenerateCallRuntime(intptr_t deopt_id, |
1054 intptr_t token_pos, | 1044 intptr_t token_pos, |
1055 intptr_t try_index, | 1045 intptr_t try_index, |
1056 const RuntimeEntry& entry) { | 1046 const RuntimeEntry& entry) { |
1057 ASSERT(!IsLeaf()); | 1047 ASSERT(!IsLeaf()); |
1058 ASSERT(frame_register_allocator()->IsSpilled()); | 1048 ASSERT(frame_register_allocator()->IsSpilled()); |
1059 __ CallRuntime(entry); | 1049 __ CallRuntime(entry); |
1060 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_pos, try_index); | 1050 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos, try_index); |
1061 } | 1051 } |
1062 | 1052 |
1063 | 1053 |
1064 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1054 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
1065 const ICData& ic_data, | 1055 const ICData& ic_data, |
1066 const Array& arguments_descriptor, | 1056 const Array& arguments_descriptor, |
1067 intptr_t argument_count) { | 1057 intptr_t argument_count) { |
1068 ASSERT(!IsLeaf()); | 1058 ASSERT(!IsLeaf()); |
1069 __ LoadObject(ECX, ic_data); | 1059 __ LoadObject(ECX, ic_data); |
1070 __ LoadObject(EDX, arguments_descriptor); | 1060 __ LoadObject(EDX, arguments_descriptor); |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1266 __ popl(ECX); | 1256 __ popl(ECX); |
1267 __ popl(EAX); | 1257 __ popl(EAX); |
1268 } | 1258 } |
1269 | 1259 |
1270 | 1260 |
1271 #undef __ | 1261 #undef __ |
1272 | 1262 |
1273 } // namespace dart | 1263 } // namespace dart |
1274 | 1264 |
1275 #endif // defined TARGET_ARCH_IA32 | 1265 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |