| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 // Emit all kMaterializeObject instructions describing objects to be | 56 // Emit all kMaterializeObject instructions describing objects to be |
| 57 // materialized on the deoptimization as a prefix to the deoptimization info. | 57 // materialized on the deoptimization as a prefix to the deoptimization info. |
| 58 EmitMaterializations(deopt_env_, builder); | 58 EmitMaterializations(deopt_env_, builder); |
| 59 | 59 |
| 60 // The real frame starts here. | 60 // The real frame starts here. |
| 61 builder->MarkFrameStart(); | 61 builder->MarkFrameStart(); |
| 62 | 62 |
| 63 // Current PP, FP, and PC. | 63 // Current PP, FP, and PC. |
| 64 builder->AddPp(current->function(), slot_ix++); | 64 builder->AddPp(current->function(), slot_ix++); |
| 65 builder->AddCallerFp(slot_ix++); | 65 builder->AddCallerFp(slot_ix++); |
| 66 builder->AddReturnAddress(current->function(), | 66 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
| 67 deopt_id(), | |
| 68 slot_ix++); | |
| 69 | 67 |
| 70 // Callee's PC marker is not used anymore. Pass Function::null() to set to 0. | 68 // Callee's PC marker is not used anymore. Pass Function::null() to set to 0. |
| 71 builder->AddPcMarker(Function::Handle(), slot_ix++); | 69 builder->AddPcMarker(Function::Handle(), slot_ix++); |
| 72 | 70 |
| 73 // Emit all values that are needed for materialization as a part of the | 71 // Emit all values that are needed for materialization as a part of the |
| 74 // expression stack for the bottom-most frame. This guarantees that GC | 72 // expression stack for the bottom-most frame. This guarantees that GC |
| 75 // will be able to find them during materialization. | 73 // will be able to find them during materialization. |
| 76 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 74 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 77 | 75 |
| 78 // For the innermost environment, set outgoing arguments and the locals. | 76 // For the innermost environment, set outgoing arguments and the locals. |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 return SubtypeTestCache::null(); | 526 return SubtypeTestCache::null(); |
| 529 } | 527 } |
| 530 } | 528 } |
| 531 return GenerateUninstantiatedTypeTest(token_pos, | 529 return GenerateUninstantiatedTypeTest(token_pos, |
| 532 type, | 530 type, |
| 533 is_instance_lbl, | 531 is_instance_lbl, |
| 534 is_not_instance_lbl); | 532 is_not_instance_lbl); |
| 535 } | 533 } |
| 536 | 534 |
| 537 | 535 |
| 536 // If instanceof type test cannot be performed successfully at compile time and |
| 537 // therefore eliminated, optimize it by adding inlined tests for: |
| 538 // - NULL -> return false. |
| 539 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 540 // - Class equality (only if class is not parameterized). |
| 541 // Inputs: |
| 542 // - R0: object. |
| 543 // - R1: instantiator type arguments or raw_null. |
| 544 // - R2: instantiator or raw_null. |
| 545 // Returns: |
| 546 // - true or false in R0. |
| 538 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, | 547 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, |
| 539 intptr_t deopt_id, | 548 intptr_t deopt_id, |
| 540 const AbstractType& type, | 549 const AbstractType& type, |
| 541 bool negate_result, | 550 bool negate_result, |
| 542 LocationSummary* locs) { | 551 LocationSummary* locs) { |
| 543 UNIMPLEMENTED(); | 552 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 553 |
| 554 // Preserve instantiator (R2) and its type arguments (R1). |
| 555 __ PushList((1 << R1) | (1 << R2)); |
| 556 |
| 557 Label is_instance, is_not_instance; |
| 558 // If type is instantiated and non-parameterized, we can inline code |
| 559 // checking whether the tested instance is a Smi. |
| 560 if (type.IsInstantiated()) { |
| 561 // A null object is only an instance of Object and dynamic, which has |
| 562 // already been checked above (if the type is instantiated). So we can |
| 563 // return false here if the instance is null (and if the type is |
| 564 // instantiated). |
| 565 // We can only inline this null check if the type is instantiated at compile |
| 566 // time, since an uninstantiated type at compile time could be Object or |
| 567 // dynamic at run time. |
| 568 __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null())); |
| 569 __ b(&is_not_instance, EQ); |
| 570 } |
| 571 |
| 572 // Generate inline instanceof test. |
| 573 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 574 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 575 &is_instance, &is_not_instance); |
| 576 |
| 577 // test_cache is null if there is no fall-through. |
| 578 Label done; |
| 579 if (!test_cache.IsNull()) { |
| 580 // Generate runtime call. |
| 581 // Load instantiator (R2) and its type arguments (R1). |
| 582 __ ldm(IA, SP, (1 << R1) | (1 << R2)); |
| 583 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 584 __ Push(R0); // Push the instance. |
| 585 __ PushObject(type); // Push the type. |
| 586 // Push instantiator (R2) and its type arguments (R1). |
| 587 __ PushList((1 << R1) | (1 << R2)); |
| 588 __ LoadObject(R0, test_cache); |
| 589 __ Push(R0); |
| 590 GenerateCallRuntime(token_pos, deopt_id, kInstanceofRuntimeEntry, locs); |
| 591 // Pop the parameters supplied to the runtime entry. The result of the |
| 592 // instanceof runtime call will be left as the result of the operation. |
| 593 __ Drop(5); |
| 594 if (negate_result) { |
| 595 __ Pop(R1); |
| 596 __ LoadObject(R0, Bool::True()); |
| 597 __ cmp(R1, ShifterOperand(R0)); |
| 598 __ b(&done, NE); |
| 599 __ LoadObject(R0, Bool::False()); |
| 600 } else { |
| 601 __ Pop(R0); |
| 602 } |
| 603 __ b(&done); |
| 604 } |
| 605 __ Bind(&is_not_instance); |
| 606 __ LoadObject(R0, negate_result ? Bool::True() : Bool::False()); |
| 607 __ b(&done); |
| 608 |
| 609 __ Bind(&is_instance); |
| 610 __ LoadObject(R0, negate_result ? Bool::False() : Bool::True()); |
| 611 __ Bind(&done); |
| 612 // Remove instantiator (R2) and its type arguments (R1). |
| 613 __ Drop(2); |
| 544 } | 614 } |
| 545 | 615 |
| 546 | 616 |
| 547 // Optimize assignable type check by adding inlined tests for: | 617 // Optimize assignable type check by adding inlined tests for: |
| 548 // - NULL -> return NULL. | 618 // - NULL -> return NULL. |
| 549 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 619 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 550 // - Class equality (only if class is not parameterized). | 620 // - Class equality (only if class is not parameterized). |
| 551 // Inputs: | 621 // Inputs: |
| 552 // - R0: instance being type checked. | 622 // - R0: instance being type checked. |
| 553 // - R1: instantiator type arguments or raw_null. | 623 // - R1: instantiator type arguments or raw_null. |
| (...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 // Second printing. | 1164 // Second printing. |
| 1095 OS::Print("Annotated "); | 1165 OS::Print("Annotated "); |
| 1096 } | 1166 } |
| 1097 AstPrinter::PrintFunctionScope(parsed_function()); | 1167 AstPrinter::PrintFunctionScope(parsed_function()); |
| 1098 } | 1168 } |
| 1099 | 1169 |
| 1100 VisitBlocks(); | 1170 VisitBlocks(); |
| 1101 | 1171 |
| 1102 __ bkpt(0); | 1172 __ bkpt(0); |
| 1103 GenerateDeferredCode(); | 1173 GenerateDeferredCode(); |
| 1104 // Emit function patching code. This will be swapped with the first 5 bytes | 1174 // Emit function patching code. This will be swapped with the first 3 |
| 1105 // at entry point. | 1175 // instructions at entry point. |
| 1106 AddCurrentDescriptor(PcDescriptors::kPatchCode, | 1176 AddCurrentDescriptor(PcDescriptors::kPatchCode, |
| 1107 Isolate::kNoDeoptId, | 1177 Isolate::kNoDeoptId, |
| 1108 0); // No token position. | 1178 0); // No token position. |
| 1109 __ Branch(&StubCode::FixCallersTargetLabel()); | 1179 __ BranchPatchable(&StubCode::FixCallersTargetLabel()); |
| 1110 AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump, | 1180 AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump, |
| 1111 Isolate::kNoDeoptId, | 1181 Isolate::kNoDeoptId, |
| 1112 0); // No token position. | 1182 0); // No token position. |
| 1113 __ Branch(&StubCode::DeoptimizeLazyLabel()); | 1183 __ Branch(&StubCode::DeoptimizeLazyLabel()); |
| 1114 } | 1184 } |
| 1115 | 1185 |
| 1116 | 1186 |
| 1117 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1187 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
| 1118 const ExternalLabel* label, | 1188 const ExternalLabel* label, |
| 1119 PcDescriptors::Kind kind, | 1189 PcDescriptors::Kind kind, |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1310 | 1380 |
| 1311 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); | 1381 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); |
| 1312 if (fpu_registers > 0) { | 1382 if (fpu_registers > 0) { |
| 1313 UNIMPLEMENTED(); | 1383 UNIMPLEMENTED(); |
| 1314 } | 1384 } |
| 1315 } | 1385 } |
| 1316 | 1386 |
| 1317 | 1387 |
| 1318 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1388 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
| 1319 Register class_id_reg, | 1389 Register class_id_reg, |
| 1320 intptr_t arg_count, | 1390 intptr_t argument_count, |
| 1321 const Array& arg_names, | 1391 const Array& argument_names, |
| 1322 Label* deopt, | 1392 Label* deopt, |
| 1323 intptr_t deopt_id, | 1393 intptr_t deopt_id, |
| 1324 intptr_t token_index, | 1394 intptr_t token_index, |
| 1325 LocationSummary* locs) { | 1395 LocationSummary* locs) { |
| 1326 UNIMPLEMENTED(); | 1396 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 1397 Label match_found; |
| 1398 const intptr_t len = ic_data.NumberOfChecks(); |
| 1399 GrowableArray<CidTarget> sorted(len); |
| 1400 SortICDataByCount(ic_data, &sorted); |
| 1401 ASSERT(class_id_reg != R4); |
| 1402 ASSERT(len > 0); // Why bother otherwise. |
| 1403 const Array& arguments_descriptor = |
| 1404 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| 1405 argument_names)); |
| 1406 __ LoadObject(R4, arguments_descriptor); |
| 1407 for (intptr_t i = 0; i < len; i++) { |
| 1408 const bool is_last_check = (i == (len - 1)); |
| 1409 Label next_test; |
| 1410 assembler()->CompareImmediate(class_id_reg, sorted[i].cid); |
| 1411 if (is_last_check) { |
| 1412 assembler()->b(deopt, NE); |
| 1413 } else { |
| 1414 assembler()->b(&next_test, NE); |
| 1415 } |
| 1416 // Do not use the code from the function, but let the code be patched so |
| 1417 // that we can record the outgoing edges to other code. |
| 1418 GenerateDartCall(deopt_id, |
| 1419 token_index, |
| 1420 &StubCode::CallStaticFunctionLabel(), |
| 1421 PcDescriptors::kFuncCall, |
| 1422 locs); |
| 1423 const Function& function = *sorted[i].target; |
| 1424 AddStaticCallTarget(function); |
| 1425 __ Drop(argument_count); |
| 1426 if (!is_last_check) { |
| 1427 assembler()->b(&match_found); |
| 1428 } |
| 1429 assembler()->Bind(&next_test); |
| 1430 } |
| 1431 assembler()->Bind(&match_found); |
| 1327 } | 1432 } |
| 1328 | 1433 |
| 1329 | 1434 |
| 1330 void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition, | 1435 void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition, |
| 1331 FpuRegister left, | 1436 FpuRegister left, |
| 1332 FpuRegister right, | 1437 FpuRegister right, |
| 1333 BranchInstr* branch) { | 1438 BranchInstr* branch) { |
| 1334 UNIMPLEMENTED(); | 1439 UNIMPLEMENTED(); |
| 1335 } | 1440 } |
| 1336 | 1441 |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1575 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1680 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1576 __ vldrd(reg, Address(SP, kDoubleSize, Address::PostIndex)); | 1681 __ vldrd(reg, Address(SP, kDoubleSize, Address::PostIndex)); |
| 1577 } | 1682 } |
| 1578 | 1683 |
| 1579 | 1684 |
| 1580 #undef __ | 1685 #undef __ |
| 1581 | 1686 |
| 1582 } // namespace dart | 1687 } // namespace dart |
| 1583 | 1688 |
| 1584 #endif // defined TARGET_ARCH_ARM | 1689 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |