| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| 11 #include "vm/code_generator.h" | 11 #include "vm/code_generator.h" |
| 12 #include "vm/disassembler.h" | 12 #include "vm/disassembler.h" |
| 13 #include "vm/longjump.h" | 13 #include "vm/longjump.h" |
| 14 #include "vm/object_store.h" |
| 14 #include "vm/parser.h" | 15 #include "vm/parser.h" |
| 15 #include "vm/stub_code.h" | 16 #include "vm/stub_code.h" |
| 16 | 17 |
| 17 namespace dart { | 18 namespace dart { |
| 18 | 19 |
| 19 DECLARE_FLAG(bool, print_ast); | 20 DECLARE_FLAG(bool, print_ast); |
| 20 DECLARE_FLAG(bool, print_scopes); | 21 DECLARE_FLAG(bool, print_scopes); |
| 21 DECLARE_FLAG(bool, trace_functions); | 22 DECLARE_FLAG(bool, trace_functions); |
| 22 | 23 |
| 23 FlowGraphCompiler::FlowGraphCompiler( | 24 FlowGraphCompiler::FlowGraphCompiler( |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 Label done; | 321 Label done; |
| 321 LoadValue(RDX, comp->value()); | 322 LoadValue(RDX, comp->value()); |
| 322 __ LoadObject(RAX, bool_true); | 323 __ LoadObject(RAX, bool_true); |
| 323 __ cmpq(RAX, RDX); | 324 __ cmpq(RAX, RDX); |
| 324 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 325 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 325 __ LoadObject(RAX, bool_false); | 326 __ LoadObject(RAX, bool_false); |
| 326 __ Bind(&done); | 327 __ Bind(&done); |
| 327 } | 328 } |
| 328 | 329 |
| 329 | 330 |
| 331 static const Class* CoreClass(const char* c_name) { |
| 332 const String& class_name = String::Handle(String::NewSymbol(c_name)); |
| 333 const Class& cls = Class::ZoneHandle(Library::Handle( |
| 334 Library::CoreImplLibrary()).LookupClass(class_name)); |
| 335 ASSERT(!cls.IsNull()); |
| 336 return &cls; |
| 337 } |
| 338 |
| 339 |
| 340 void FlowGraphCompiler::GenerateInstantiatorTypeArguments( |
| 341 intptr_t token_index) { |
| 342 Bailout("FlowGraphCompiler::GenerateInstantiatorTypeArguments"); |
| 343 } |
| 344 |
| 345 |
| 346 // Copied from CodeGenerator. |
| 347 // Optimize instanceof type test by adding inlined tests for: |
| 348 // - NULL -> return false. |
| 349 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 350 // - Class equality (only if class is not parameterized). |
| 351 // Inputs: |
| 352 // - RAX: object. |
| 353 // Destroys RCX. |
| 354 // Returns: |
| 355 // - true or false in RAX. |
| 356 void FlowGraphCompiler::GenerateInstanceOf(intptr_t node_id, |
| 357 intptr_t token_index, |
| 358 const AbstractType& type, |
| 359 bool negate_result) { |
| 360 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 361 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 362 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 363 |
| 364 // All instances are of a subtype of the Object type. |
| 365 const Type& object_type = |
| 366 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 367 Error& malformed_error = Error::Handle(); |
| 368 if (type.IsInstantiated() && |
| 369 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 370 __ LoadObject(RAX, negate_result ? bool_false : bool_true); |
| 371 return; |
| 372 } |
| 373 |
| 374 const Immediate raw_null = |
| 375 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 376 Label done; |
| 377 // If type is instantiated and non-parameterized, we can inline code |
| 378 // checking whether the tested instance is a Smi. |
| 379 if (type.IsInstantiated()) { |
| 380 // A null object is only an instance of Object and Dynamic, which has |
| 381 // already been checked above (if the type is instantiated). So we can |
| 382 // return false here if the instance is null (and if the type is |
| 383 // instantiated). |
| 384 // We can only inline this null check if the type is instantiated at compile |
| 385 // time, since an uninstantiated type at compile time could be Object or |
| 386 // Dynamic at run time. |
| 387 Label non_null; |
| 388 __ cmpq(RAX, raw_null); |
| 389 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); |
| 390 __ PushObject(negate_result ? bool_true : bool_false); |
| 391 __ jmp(&done); |
| 392 |
| 393 __ Bind(&non_null); |
| 394 |
| 395 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 396 const bool requires_type_arguments = type_class.HasTypeArguments(); |
| 397 // A Smi object cannot be the instance of a parameterized class. |
| 398 // A class equality check is only applicable with a dst type of a |
| 399 // non-parameterized class or with a raw dst type of a parameterized class. |
| 400 if (requires_type_arguments) { |
| 401 const AbstractTypeArguments& type_arguments = |
| 402 AbstractTypeArguments::Handle(type.arguments()); |
| 403 const bool is_raw_type = type_arguments.IsNull() || |
| 404 type_arguments.IsDynamicTypes(type_arguments.Length()); |
| 405 Label runtime_call; |
| 406 __ testq(RAX, Immediate(kSmiTagMask)); |
| 407 __ j(ZERO, &runtime_call, Assembler::kNearJump); |
| 408 // Object not Smi. |
| 409 if (is_raw_type) { |
| 410 if (type.IsListInterface()) { |
| 411 Label push_result; |
| 412 // TODO(srdjan) also accept List<Object>. |
| 413 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 414 __ CompareObject(RCX, *CoreClass("ObjectArray")); |
| 415 __ j(EQUAL, &push_result, Assembler::kNearJump); |
| 416 __ CompareObject(RCX, *CoreClass("GrowableObjectArray")); |
| 417 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 418 __ Bind(&push_result); |
| 419 __ PushObject(negate_result ? bool_false : bool_true); |
| 420 __ jmp(&done); |
| 421 } else if (!type_class.is_interface()) { |
| 422 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 423 __ CompareObject(RCX, type_class); |
| 424 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 425 __ PushObject(negate_result ? bool_false : bool_true); |
| 426 __ jmp(&done); |
| 427 } |
| 428 } |
| 429 __ Bind(&runtime_call); |
| 430 // Fall through to runtime call. |
| 431 } else { |
| 432 Label compare_classes; |
| 433 __ testq(RAX, Immediate(kSmiTagMask)); |
| 434 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 435 // Object is Smi. |
| 436 const Class& smi_class = Class::Handle(Smi::Class()); |
| 437 // TODO(regis): We should introduce a SmiType. |
| 438 Error& malformed_error = Error::Handle(); |
| 439 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 440 type_class, |
| 441 TypeArguments::Handle(), |
| 442 &malformed_error)) { |
| 443 __ PushObject(negate_result ? bool_false : bool_true); |
| 444 } else { |
| 445 __ PushObject(negate_result ? bool_true : bool_false); |
| 446 } |
| 447 __ jmp(&done); |
| 448 |
| 449 // Compare if the classes are equal. |
| 450 __ Bind(&compare_classes); |
| 451 const Class* compare_class = NULL; |
| 452 if (type.IsStringInterface()) { |
| 453 compare_class = &Class::ZoneHandle( |
| 454 Isolate::Current()->object_store()->one_byte_string_class()); |
| 455 } else if (type.IsBoolInterface()) { |
| 456 compare_class = &Class::ZoneHandle( |
| 457 Isolate::Current()->object_store()->bool_class()); |
| 458 } else if (!type_class.is_interface()) { |
| 459 compare_class = &type_class; |
| 460 } |
| 461 if (compare_class != NULL) { |
| 462 Label runtime_call; |
| 463 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 464 __ CompareObject(RCX, *compare_class); |
| 465 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 466 __ PushObject(negate_result ? bool_false : bool_true); |
| 467 __ jmp(&done, Assembler::kNearJump); |
| 468 __ Bind(&runtime_call); |
| 469 } |
| 470 } |
| 471 } |
| 472 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 473 const Immediate location = |
| 474 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); |
| 475 __ pushq(location); // Push the source location. |
| 476 __ pushq(RAX); // Push the instance. |
| 477 __ PushObject(type); // Push the type. |
| 478 if (!type.IsInstantiated()) { |
| 479 GenerateInstantiatorTypeArguments(token_index); |
| 480 } else { |
| 481 __ pushq(raw_null); // Null instantiator. |
| 482 } |
| 483 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 484 // Pop the two parameters supplied to the runtime entry. The result of the |
| 485 // instanceof runtime call will be left as the result of the operation. |
| 486 __ addq(RSP, Immediate(4 * kWordSize)); |
| 487 if (negate_result) { |
| 488 Label negate_done; |
| 489 __ popq(RDX); |
| 490 __ LoadObject(RAX, bool_true); |
| 491 __ cmpq(RDX, RAX); |
| 492 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); |
| 493 __ LoadObject(RAX, bool_false); |
| 494 __ Bind(&negate_done); |
| 495 __ pushq(RAX); |
| 496 } |
| 497 __ Bind(&done); |
| 498 __ popq(RAX); |
| 499 } |
| 500 |
| 501 |
| 330 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { | 502 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { |
| 331 Bailout("InstanceOf"); | 503 __ popq(RAX); |
| 504 GenerateInstanceOf(comp->node_id(), |
| 505 comp->token_index(), |
| 506 comp->type(), |
| 507 comp->negate_result()); |
| 332 } | 508 } |
| 333 | 509 |
| 334 | 510 |
| 335 void FlowGraphCompiler::VisitAllocateObject(AllocateObjectComp* comp) { | 511 void FlowGraphCompiler::VisitAllocateObject(AllocateObjectComp* comp) { |
| 336 const Class& cls = Class::ZoneHandle(comp->constructor().owner()); | 512 const Class& cls = Class::ZoneHandle(comp->constructor().owner()); |
| 337 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); | 513 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); |
| 338 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); | 514 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); |
| 339 GenerateCall(comp->token_index(), &label, PcDescriptors::kOther); | 515 GenerateCall(comp->token_index(), &label, PcDescriptors::kOther); |
| 340 for (intptr_t i = 0; i < comp->arguments().length(); i++) { | 516 for (intptr_t i = 0; i < comp->arguments().length(); i++) { |
| 341 __ popq(RCX); // Discard allocation argument | 517 __ popq(RCX); // Discard allocation argument |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { | 808 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { |
| 633 // We don't compile exception handlers yet. | 809 // We don't compile exception handlers yet. |
| 634 code.set_exception_handlers( | 810 code.set_exception_handlers( |
| 635 ExceptionHandlers::Handle(ExceptionHandlers::New(0))); | 811 ExceptionHandlers::Handle(ExceptionHandlers::New(0))); |
| 636 } | 812 } |
| 637 | 813 |
| 638 | 814 |
| 639 } // namespace dart | 815 } // namespace dart |
| 640 | 816 |
| 641 #endif // defined TARGET_ARCH_X64 | 817 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |