| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| 11 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/flow_graph_compiler.h" | 13 #include "vm/flow_graph_compiler.h" |
| 14 #include "vm/heap.h" | 14 #include "vm/heap.h" |
| 15 #include "vm/instructions.h" | 15 #include "vm/instructions.h" |
| 16 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 17 #include "vm/stack_frame.h" | 17 #include "vm/stack_frame.h" |
| 18 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 19 #include "vm/tags.h" | 19 #include "vm/tags.h" |
| 20 | 20 |
| 21 #define __ assembler-> | 21 #define __ assembler-> |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); | 25 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 26 DEFINE_FLAG(bool, use_slow_path, false, | 26 DEFINE_FLAG(bool, use_slow_path, false, |
| 27 "Set to true for debugging & verifying the slow paths."); | 27 "Set to true for debugging & verifying the slow paths."); |
| 28 DECLARE_FLAG(bool, trace_optimized_ic_calls); | 28 DECLARE_FLAG(bool, trace_optimized_ic_calls); |
| 29 DECLARE_FLAG(int, optimization_counter_threshold); |
| 29 | 30 |
| 30 // Input parameters: | 31 // Input parameters: |
| 31 // LR : return address. | 32 // LR : return address. |
| 32 // SP : address of last argument in argument array. | 33 // SP : address of last argument in argument array. |
| 33 // SP + 4*R4 - 4 : address of first argument in argument array. | 34 // SP + 4*R4 - 4 : address of first argument in argument array. |
| 34 // SP + 4*R4 : address of return value. | 35 // SP + 4*R4 : address of return value. |
| 35 // R5 : address of the runtime function to call. | 36 // R5 : address of the runtime function to call. |
| 36 // R4 : number of arguments to the call. | 37 // R4 : number of arguments to the call. |
| 37 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 38 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 38 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 39 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| (...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1231 } | 1232 } |
| 1232 __ ldr(R7, FieldAddress(func_reg, Function::usage_counter_offset())); | 1233 __ ldr(R7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1233 __ add(R7, R7, Operand(1)); | 1234 __ add(R7, R7, Operand(1)); |
| 1234 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); | 1235 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1235 } | 1236 } |
| 1236 | 1237 |
| 1237 | 1238 |
| 1238 // Loads function into 'temp_reg'. | 1239 // Loads function into 'temp_reg'. |
| 1239 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1240 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1240 Register temp_reg) { | 1241 Register temp_reg) { |
| 1241 Register ic_reg = R5; | 1242 if (FLAG_optimization_counter_threshold >= 0) { |
| 1242 Register func_reg = temp_reg; | 1243 Register ic_reg = R5; |
| 1243 ASSERT(temp_reg == R6); | 1244 Register func_reg = temp_reg; |
| 1244 __ Comment("Increment function counter"); | 1245 ASSERT(temp_reg == R6); |
| 1245 __ ldr(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); | 1246 __ Comment("Increment function counter"); |
| 1246 __ ldr(R7, FieldAddress(func_reg, Function::usage_counter_offset())); | 1247 __ ldr(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); |
| 1247 __ add(R7, R7, Operand(1)); | 1248 __ ldr(R7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1248 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); | 1249 __ add(R7, R7, Operand(1)); |
| 1250 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1251 } |
| 1249 } | 1252 } |
| 1250 | 1253 |
| 1251 | 1254 |
| 1252 // Note: R5 must be preserved. | 1255 // Note: R5 must be preserved. |
| 1253 // Attempt a quick Smi operation for known operations ('kind'). The ICData | 1256 // Attempt a quick Smi operation for known operations ('kind'). The ICData |
| 1254 // must have been primed with a Smi/Smi check that will be used for counting | 1257 // must have been primed with a Smi/Smi check that will be used for counting |
| 1255 // the invocations. | 1258 // the invocations. |
| 1256 static void EmitFastSmiOp(Assembler* assembler, | 1259 static void EmitFastSmiOp(Assembler* assembler, |
| 1257 Token::Kind kind, | 1260 Token::Kind kind, |
| 1258 intptr_t num_args, | 1261 intptr_t num_args, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 __ ldr(R1, Address(R6, 0)); | 1297 __ ldr(R1, Address(R6, 0)); |
| 1295 __ CompareImmediate(R1, imm_smi_cid); | 1298 __ CompareImmediate(R1, imm_smi_cid); |
| 1296 __ b(&error, NE); | 1299 __ b(&error, NE); |
| 1297 __ ldr(R1, Address(R6, kWordSize)); | 1300 __ ldr(R1, Address(R6, kWordSize)); |
| 1298 __ CompareImmediate(R1, imm_smi_cid); | 1301 __ CompareImmediate(R1, imm_smi_cid); |
| 1299 __ b(&ok, EQ); | 1302 __ b(&ok, EQ); |
| 1300 __ Bind(&error); | 1303 __ Bind(&error); |
| 1301 __ Stop("Incorrect IC data"); | 1304 __ Stop("Incorrect IC data"); |
| 1302 __ Bind(&ok); | 1305 __ Bind(&ok); |
| 1303 #endif | 1306 #endif |
| 1304 // Update counter. | 1307 if (FLAG_optimization_counter_threshold >= 0) { |
| 1305 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1308 // Update counter. |
| 1306 __ LoadFromOffset(kWord, R1, R6, count_offset); | 1309 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1307 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1310 __ LoadFromOffset(kWord, R1, R6, count_offset); |
| 1308 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. | 1311 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1309 __ StoreIntoSmiField(Address(R6, count_offset), R1); | 1312 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1313 __ StoreIntoSmiField(Address(R6, count_offset), R1); |
| 1314 } |
| 1310 __ Ret(); | 1315 __ Ret(); |
| 1311 } | 1316 } |
| 1312 | 1317 |
| 1313 | 1318 |
| 1314 // Generate inline cache check for 'num_args'. | 1319 // Generate inline cache check for 'num_args'. |
| 1315 // LR: return address. | 1320 // LR: return address. |
| 1316 // R5: inline cache data object. | 1321 // R5: inline cache data object. |
| 1317 // Control flow: | 1322 // Control flow: |
| 1318 // - If receiver is null -> jump to IC miss. | 1323 // - If receiver is null -> jump to IC miss. |
| 1319 // - If receiver is Smi -> load Smi class. | 1324 // - If receiver is Smi -> load Smi class. |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 __ LeaveStubFrame(); | 1458 __ LeaveStubFrame(); |
| 1454 Label call_target_function; | 1459 Label call_target_function; |
| 1455 __ b(&call_target_function); | 1460 __ b(&call_target_function); |
| 1456 | 1461 |
| 1457 __ Bind(&found); | 1462 __ Bind(&found); |
| 1458 // R6: pointer to an IC data check group. | 1463 // R6: pointer to an IC data check group. |
| 1459 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 1464 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
| 1460 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1465 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1461 __ LoadFromOffset(kWord, R0, R6, target_offset); | 1466 __ LoadFromOffset(kWord, R0, R6, target_offset); |
| 1462 | 1467 |
| 1463 __ Comment("Update caller's counter"); | 1468 if (FLAG_optimization_counter_threshold >= 0) { |
| 1464 __ LoadFromOffset(kWord, R1, R6, count_offset); | 1469 __ Comment("Update caller's counter"); |
| 1465 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1470 __ LoadFromOffset(kWord, R1, R6, count_offset); |
| 1466 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. | 1471 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1467 __ StoreIntoSmiField(Address(R6, count_offset), R1); | 1472 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1473 __ StoreIntoSmiField(Address(R6, count_offset), R1); |
| 1474 } |
| 1468 | 1475 |
| 1469 __ Comment("Call target"); | 1476 __ Comment("Call target"); |
| 1470 __ Bind(&call_target_function); | 1477 __ Bind(&call_target_function); |
| 1471 // R0: target function. | 1478 // R0: target function. |
| 1472 __ ldr(R2, FieldAddress(R0, Function::instructions_offset())); | 1479 __ ldr(R2, FieldAddress(R0, Function::instructions_offset())); |
| 1473 __ AddImmediate(R2, Instructions::HeaderSize() - kHeapObjectTag); | 1480 __ AddImmediate(R2, Instructions::HeaderSize() - kHeapObjectTag); |
| 1474 if (range_collection_mode == kCollectRanges) { | 1481 if (range_collection_mode == kCollectRanges) { |
| 1475 __ ldr(R1, Address(SP, 0 * kWordSize)); | 1482 __ ldr(R1, Address(SP, 0 * kWordSize)); |
| 1476 if (num_args == 2) { | 1483 if (num_args == 2) { |
| 1477 __ ldr(R3, Address(SP, 1 * kWordSize)); | 1484 __ ldr(R3, Address(SP, 1 * kWordSize)); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1645 __ Bind(&done_stepping); | 1652 __ Bind(&done_stepping); |
| 1646 | 1653 |
| 1647 // R5: IC data object (preserved). | 1654 // R5: IC data object (preserved). |
| 1648 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); | 1655 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); |
| 1649 // R6: ic_data_array with entries: target functions and count. | 1656 // R6: ic_data_array with entries: target functions and count. |
| 1650 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); | 1657 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); |
| 1651 // R6: points directly to the first ic data array element. | 1658 // R6: points directly to the first ic data array element. |
| 1652 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; | 1659 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; |
| 1653 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; | 1660 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; |
| 1654 | 1661 |
| 1655 // Increment count for this call. | 1662 if (FLAG_optimization_counter_threshold >= 0) { |
| 1656 __ LoadFromOffset(kWord, R1, R6, count_offset); | 1663 // Increment count for this call. |
| 1657 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1664 __ LoadFromOffset(kWord, R1, R6, count_offset); |
| 1658 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. | 1665 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1659 __ StoreIntoSmiField(Address(R6, count_offset), R1); | 1666 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1667 __ StoreIntoSmiField(Address(R6, count_offset), R1); |
| 1668 } |
| 1660 | 1669 |
| 1661 // Load arguments descriptor into R4. | 1670 // Load arguments descriptor into R4. |
| 1662 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); | 1671 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); |
| 1663 | 1672 |
| 1664 // Get function and call it, if possible. | 1673 // Get function and call it, if possible. |
| 1665 __ LoadFromOffset(kWord, R0, R6, target_offset); | 1674 __ LoadFromOffset(kWord, R0, R6, target_offset); |
| 1666 __ ldr(R2, FieldAddress(R0, Function::instructions_offset())); | 1675 __ ldr(R2, FieldAddress(R0, Function::instructions_offset())); |
| 1667 | 1676 |
| 1668 // R0: function. | 1677 // R0: function. |
| 1669 // R2: target instructions. | 1678 // R2: target instructions. |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2055 const Register right = R0; | 2064 const Register right = R0; |
| 2056 __ ldr(left, Address(SP, 1 * kWordSize)); | 2065 __ ldr(left, Address(SP, 1 * kWordSize)); |
| 2057 __ ldr(right, Address(SP, 0 * kWordSize)); | 2066 __ ldr(right, Address(SP, 0 * kWordSize)); |
| 2058 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2067 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 2059 __ Ret(); | 2068 __ Ret(); |
| 2060 } | 2069 } |
| 2061 | 2070 |
| 2062 } // namespace dart | 2071 } // namespace dart |
| 2063 | 2072 |
| 2064 #endif // defined TARGET_ARCH_ARM | 2073 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |