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

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
« no previous file with comments | « runtime/vm/flow_graph_compiler_ia32.h ('k') | runtime/vm/flow_graph_compiler_x64.h » ('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) 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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_ia32.h ('k') | runtime/vm/flow_graph_compiler_x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698