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_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
12 #include "vm/heap.h" | 12 #include "vm/heap.h" |
13 #include "vm/instructions.h" | 13 #include "vm/instructions.h" |
14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
15 #include "vm/resolver.h" | 15 #include "vm/resolver.h" |
16 #include "vm/scavenger.h" | 16 #include "vm/scavenger.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 | 19 |
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(int, optimization_counter_threshold); | 29 DECLARE_FLAG(int, optimization_counter_threshold); |
29 DECLARE_FLAG(bool, trace_optimized_ic_calls); | |
30 | 30 |
31 | 31 |
32 // Input parameters: | 32 // Input parameters: |
33 // RSP : points to return address. | 33 // RSP : points to return address. |
34 // RSP + 8 : address of last argument in argument array. | 34 // RSP + 8 : address of last argument in argument array. |
35 // RSP + 8*R10 : address of first argument in argument array. | 35 // RSP + 8*R10 : address of first argument in argument array. |
36 // RSP + 8*R10 + 8 : address of return value. | 36 // RSP + 8*R10 + 8 : address of return value. |
37 // RBX : address of the runtime function to call. | 37 // RBX : address of the runtime function to call. |
38 // R10 : number of arguments to the call. | 38 // R10 : number of arguments to the call. |
39 // Must preserve callee saved registers R12 and R13. | 39 // Must preserve callee saved registers R12 and R13. |
(...skipping 1067 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1107 // The generated code is different if the class is parameterized. | 1107 // The generated code is different if the class is parameterized. |
1108 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; | 1108 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; |
1109 ASSERT(!is_cls_parameterized || | 1109 ASSERT(!is_cls_parameterized || |
1110 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); | 1110 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); |
1111 // kInlineInstanceSize is a constant used as a threshold for determining | 1111 // kInlineInstanceSize is a constant used as a threshold for determining |
1112 // when the object initialization should be done as a loop or as | 1112 // when the object initialization should be done as a loop or as |
1113 // straight line code. | 1113 // straight line code. |
1114 const int kInlineInstanceSize = 12; // In words. | 1114 const int kInlineInstanceSize = 12; // In words. |
1115 const intptr_t instance_size = cls.instance_size(); | 1115 const intptr_t instance_size = cls.instance_size(); |
1116 ASSERT(instance_size > 0); | 1116 ASSERT(instance_size > 0); |
1117 const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize(); | |
1118 __ LoadObject(R12, Object::null_object(), PP); | 1117 __ LoadObject(R12, Object::null_object(), PP); |
1119 if (FLAG_inline_alloc && | 1118 Label slow_case_with_type_arguments; |
1120 Heap::IsAllocatableInNewSpace(instance_size + type_args_size)) { | 1119 if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size)) { |
1121 Label slow_case; | 1120 Label slow_case_reload_type_arguments; |
| 1121 if (is_cls_parameterized) { |
| 1122 // Instantiation of the type arguments vector is only required if an |
| 1123 // instantiator is provided (not kNoInstantiator, but may be null). |
| 1124 __ movq(RDX, Address(RSP, kObjectTypeArgumentsOffset)); |
| 1125 __ movq(RDI, Address(RSP, kInstantiatorTypeArgumentsOffset)); |
| 1126 Label type_arguments_ready; |
| 1127 __ cmpq(RDI, Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1128 __ j(EQUAL, &type_arguments_ready, Assembler::kNearJump); |
| 1129 // Lookup instantiator RDI in instantiations array of type arguments RDX |
| 1130 // and, if found, use cached instantiated type arguments. |
| 1131 __ movq(RAX, FieldAddress(RDX, TypeArguments::instantiations_offset())); |
| 1132 __ movq(RBX, FieldAddress(RAX, Array::length_offset())); |
| 1133 __ leaq(RAX, FieldAddress(RAX, Array::data_offset())); |
| 1134 __ leaq(RBX, Address(RAX, RBX, TIMES_4, 0)); // RBX is smi. |
| 1135 Label loop, found; |
| 1136 __ Bind(&loop); |
| 1137 __ cmpq(RAX, RBX); |
| 1138 __ j(ABOVE_EQUAL, &slow_case_reload_type_arguments); |
| 1139 __ movq(RDX, Address(RAX, 0 * kWordSize)); // Cached instantiator. |
| 1140 __ cmpq(RDX, RDI); |
| 1141 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1142 __ cmpq(RDX, Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1143 __ j(EQUAL, &slow_case_reload_type_arguments); |
| 1144 __ addq(RAX, Immediate(2 * kWordSize)); |
| 1145 __ jmp(&loop, Assembler::kNearJump); |
| 1146 __ Bind(&found); |
| 1147 __ movq(RDX, Address(RAX, 1 * kWordSize)); // Cached instantiated args. |
| 1148 __ movq(RDI, Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1149 __ Bind(&type_arguments_ready); |
| 1150 // RDX: instantiated type arguments. |
| 1151 // RDI: kNoInstantiator. |
| 1152 } |
| 1153 // Allocate the object and update top to point to |
| 1154 // next object start and initialize the allocated object. |
| 1155 // RDX: instantiated type arguments (if is_cls_parameterized). |
| 1156 // RDI: kNoInstantiator (if is_cls_parameterized). |
1122 Heap* heap = Isolate::Current()->heap(); | 1157 Heap* heap = Isolate::Current()->heap(); |
1123 __ movq(RAX, Immediate(heap->TopAddress())); | 1158 __ movq(RCX, Immediate(heap->TopAddress())); |
1124 __ movq(RAX, Address(RAX, 0)); | 1159 __ movq(RAX, Address(RCX, 0)); |
1125 __ leaq(RBX, Address(RAX, instance_size)); | 1160 __ leaq(RBX, Address(RAX, instance_size)); |
1126 if (is_cls_parameterized) { | |
1127 __ movq(RCX, RBX); | |
1128 // A new InstantiatedTypeArguments object only needs to be allocated if | |
1129 // the instantiator is provided (not kNoInstantiator, but may be null). | |
1130 Label no_instantiator; | |
1131 __ cmpq(Address(RSP, kInstantiatorTypeArgumentsOffset), | |
1132 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | |
1133 __ j(EQUAL, &no_instantiator, Assembler::kNearJump); | |
1134 __ addq(RBX, Immediate(type_args_size)); | |
1135 __ Bind(&no_instantiator); | |
1136 // RCX: potential new object end and, if RCX != RBX, potential new | |
1137 // InstantiatedTypeArguments object start. | |
1138 } | |
1139 // Check if the allocation fits into the remaining space. | 1161 // Check if the allocation fits into the remaining space. |
1140 // RAX: potential new object start. | 1162 // RAX: potential new object start. |
1141 // RBX: potential next object start. | 1163 // RBX: potential next object start. |
1142 __ movq(RDI, Immediate(heap->EndAddress())); | 1164 // RCX: heap top address. |
1143 __ cmpq(RBX, Address(RDI, 0)); | 1165 __ movq(R13, Immediate(heap->EndAddress())); |
| 1166 __ cmpq(RBX, Address(R13, 0)); |
1144 if (FLAG_use_slow_path) { | 1167 if (FLAG_use_slow_path) { |
1145 __ jmp(&slow_case); | 1168 __ jmp(&slow_case_with_type_arguments); |
1146 } else { | 1169 } else { |
1147 __ j(ABOVE_EQUAL, &slow_case); | 1170 __ j(ABOVE_EQUAL, &slow_case_with_type_arguments); |
1148 } | 1171 } |
1149 | 1172 __ movq(Address(RCX, 0), RBX); |
1150 // Successfully allocated the object(s), now update top to point to | |
1151 // next object start and initialize the object. | |
1152 __ movq(RDI, Immediate(heap->TopAddress())); | |
1153 __ movq(Address(RDI, 0), RBX); | |
1154 __ UpdateAllocationStats(cls.id()); | 1173 __ UpdateAllocationStats(cls.id()); |
1155 | 1174 |
1156 if (is_cls_parameterized) { | |
1157 // Initialize the type arguments field in the object. | |
1158 // RAX: new object start. | |
1159 // RCX: potential new object end and, if RCX != RBX, potential new | |
1160 // InstantiatedTypeArguments object start. | |
1161 // RBX: next object start. | |
1162 Label type_arguments_ready; | |
1163 __ movq(RDI, Address(RSP, kObjectTypeArgumentsOffset)); | |
1164 __ cmpq(RCX, RBX); | |
1165 __ j(EQUAL, &type_arguments_ready, Assembler::kNearJump); | |
1166 // Initialize InstantiatedTypeArguments object at RCX. | |
1167 __ movq(Address(RCX, | |
1168 InstantiatedTypeArguments::uninstantiated_type_arguments_offset()), | |
1169 RDI); | |
1170 __ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset)); | |
1171 __ movq(Address(RCX, | |
1172 InstantiatedTypeArguments::instantiator_type_arguments_offset()), | |
1173 RDX); | |
1174 const Class& ita_cls = | |
1175 Class::ZoneHandle(Object::instantiated_type_arguments_class()); | |
1176 // Set the tags. | |
1177 uword tags = 0; | |
1178 tags = RawObject::SizeTag::update(type_args_size, tags); | |
1179 tags = RawObject::ClassIdTag::update(ita_cls.id(), tags); | |
1180 __ movq(Address(RCX, Instance::tags_offset()), Immediate(tags)); | |
1181 // Set the new InstantiatedTypeArguments object (RCX) as the type | |
1182 // arguments (RDI) of the new object (RAX). | |
1183 __ movq(RDI, RCX); | |
1184 __ addq(RDI, Immediate(kHeapObjectTag)); | |
1185 // Set RBX to new object end. | |
1186 __ movq(RBX, RCX); | |
1187 __ Bind(&type_arguments_ready); | |
1188 // RAX: new object. | |
1189 // RDI: new object type arguments. | |
1190 } | |
1191 | |
1192 // RAX: new object start. | 1175 // RAX: new object start. |
1193 // RBX: next object start. | 1176 // RBX: next object start. |
1194 // RDI: new object type arguments (if is_cls_parameterized). | 1177 // RDX: new object type arguments (if is_cls_parameterized). |
1195 // Set the tags. | 1178 // Set the tags. |
1196 uword tags = 0; | 1179 uword tags = 0; |
1197 tags = RawObject::SizeTag::update(instance_size, tags); | 1180 tags = RawObject::SizeTag::update(instance_size, tags); |
1198 ASSERT(cls.id() != kIllegalCid); | 1181 ASSERT(cls.id() != kIllegalCid); |
1199 tags = RawObject::ClassIdTag::update(cls.id(), tags); | 1182 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
1200 __ movq(Address(RAX, Instance::tags_offset()), Immediate(tags)); | 1183 __ movq(Address(RAX, Instance::tags_offset()), Immediate(tags)); |
1201 | 1184 |
1202 // Initialize the remaining words of the object. | 1185 // Initialize the remaining words of the object. |
1203 // RAX: new object start. | 1186 // RAX: new object start. |
1204 // RBX: next object start. | 1187 // RBX: next object start. |
1205 // RDI: new object type arguments (if is_cls_parameterized). | 1188 // RDX: new object type arguments (if is_cls_parameterized). |
| 1189 // R12: raw null. |
1206 // First try inlining the initialization without a loop. | 1190 // First try inlining the initialization without a loop. |
1207 if (instance_size < (kInlineInstanceSize * kWordSize)) { | 1191 if (instance_size < (kInlineInstanceSize * kWordSize)) { |
1208 // Check if the object contains any non-header fields. | 1192 // Check if the object contains any non-header fields. |
1209 // Small objects are initialized using a consecutive set of writes. | 1193 // Small objects are initialized using a consecutive set of writes. |
1210 for (intptr_t current_offset = Instance::NextFieldOffset(); | 1194 for (intptr_t current_offset = Instance::NextFieldOffset(); |
1211 current_offset < instance_size; | 1195 current_offset < instance_size; |
1212 current_offset += kWordSize) { | 1196 current_offset += kWordSize) { |
1213 __ movq(Address(RAX, current_offset), R12); | 1197 __ movq(Address(RAX, current_offset), R12); |
1214 } | 1198 } |
1215 } else { | 1199 } else { |
1216 __ leaq(RCX, Address(RAX, Instance::NextFieldOffset())); | 1200 __ leaq(RCX, Address(RAX, Instance::NextFieldOffset())); |
1217 // Loop until the whole object is initialized. | 1201 // Loop until the whole object is initialized. |
1218 // RAX: new object. | 1202 // RAX: new object. |
1219 // RBX: next object start. | 1203 // RBX: next object start. |
1220 // RCX: next word to be initialized. | 1204 // RCX: next word to be initialized. |
1221 // RDI: new object type arguments (if is_cls_parameterized). | 1205 // RDX: new object type arguments (if is_cls_parameterized). |
1222 Label init_loop; | 1206 Label init_loop; |
1223 Label done; | 1207 Label done; |
1224 __ Bind(&init_loop); | 1208 __ Bind(&init_loop); |
1225 __ cmpq(RCX, RBX); | 1209 __ cmpq(RCX, RBX); |
1226 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); | 1210 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
1227 __ movq(Address(RCX, 0), R12); | 1211 __ movq(Address(RCX, 0), R12); |
1228 __ addq(RCX, Immediate(kWordSize)); | 1212 __ addq(RCX, Immediate(kWordSize)); |
1229 __ jmp(&init_loop, Assembler::kNearJump); | 1213 __ jmp(&init_loop, Assembler::kNearJump); |
1230 __ Bind(&done); | 1214 __ Bind(&done); |
1231 } | 1215 } |
1232 if (is_cls_parameterized) { | 1216 if (is_cls_parameterized) { |
1233 // RDI: new object type arguments. | 1217 // RDX: new object type arguments. |
1234 // Set the type arguments in the new object. | 1218 // Set the type arguments in the new object. |
1235 __ movq(Address(RAX, cls.type_arguments_field_offset()), RDI); | 1219 __ movq(Address(RAX, cls.type_arguments_field_offset()), RDX); |
1236 } | 1220 } |
1237 // Done allocating and initializing the instance. | 1221 // Done allocating and initializing the instance. |
1238 // RAX: new object. | 1222 // RAX: new object. |
1239 __ addq(RAX, Immediate(kHeapObjectTag)); | 1223 __ addq(RAX, Immediate(kHeapObjectTag)); |
1240 __ ret(); | 1224 __ ret(); |
1241 | 1225 |
1242 __ Bind(&slow_case); | 1226 __ Bind(&slow_case_reload_type_arguments); |
1243 } | 1227 } |
1244 if (is_cls_parameterized) { | 1228 if (is_cls_parameterized) { |
1245 __ movq(RAX, Address(RSP, kObjectTypeArgumentsOffset)); | 1229 __ movq(RDX, Address(RSP, kObjectTypeArgumentsOffset)); |
1246 __ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset)); | 1230 __ movq(RDI, Address(RSP, kInstantiatorTypeArgumentsOffset)); |
1247 } | 1231 } |
| 1232 __ Bind(&slow_case_with_type_arguments); |
| 1233 // If is_cls_parameterized: |
| 1234 // RDX: new object type arguments (instantiated or not). |
| 1235 // RDI: instantiator type arguments or kNoInstantiator. |
1248 // Create a stub frame. | 1236 // Create a stub frame. |
1249 __ EnterStubFrame(true); // Uses PP to access class object. | 1237 __ EnterStubFrame(true); // Uses PP to access class object. |
1250 __ pushq(R12); // Setup space on stack for return value. | 1238 __ pushq(R12); // Setup space on stack for return value. |
1251 __ PushObject(cls, PP); // Push class of object to be allocated. | 1239 __ PushObject(cls, PP); // Push class of object to be allocated. |
1252 if (is_cls_parameterized) { | 1240 if (is_cls_parameterized) { |
1253 __ pushq(RAX); // Push type arguments of object to be allocated. | 1241 __ pushq(RDX); // Push type arguments of object to be allocated. |
1254 __ pushq(RDX); // Push type arguments of instantiator. | 1242 __ pushq(RDI); // Push type arguments of instantiator. |
1255 } else { | 1243 } else { |
1256 __ pushq(R12); // Push null type arguments. | 1244 __ pushq(R12); // Push null type arguments. |
1257 __ pushq(Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | 1245 __ pushq(Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
1258 } | 1246 } |
1259 __ CallRuntime(kAllocateObjectRuntimeEntry, 3); // Allocate object. | 1247 __ CallRuntime(kAllocateObjectRuntimeEntry, 3); // Allocate object. |
1260 __ popq(RAX); // Pop argument (instantiator). | 1248 __ popq(RAX); // Pop argument (instantiator). |
1261 __ popq(RAX); // Pop argument (type arguments of object). | 1249 __ popq(RAX); // Pop argument (type arguments of object). |
1262 __ popq(RAX); // Pop argument (class of object). | 1250 __ popq(RAX); // Pop argument (class of object). |
1263 __ popq(RAX); // Pop result (newly allocated object). | 1251 __ popq(RAX); // Pop result (newly allocated object). |
1264 // RAX: new object | 1252 // RAX: new object |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1627 __ addq(Address(R12, count_offset), Immediate(Smi::RawValue(1))); | 1615 __ addq(Address(R12, count_offset), Immediate(Smi::RawValue(1))); |
1628 __ j(NO_OVERFLOW, &call_target_function, Assembler::kNearJump); | 1616 __ j(NO_OVERFLOW, &call_target_function, Assembler::kNearJump); |
1629 __ movq(Address(R12, count_offset), | 1617 __ movq(Address(R12, count_offset), |
1630 Immediate(Smi::RawValue(Smi::kMaxValue))); | 1618 Immediate(Smi::RawValue(Smi::kMaxValue))); |
1631 | 1619 |
1632 __ Bind(&call_target_function); | 1620 __ Bind(&call_target_function); |
1633 // RAX: Target function. | 1621 // RAX: Target function. |
1634 Label is_compiled; | 1622 Label is_compiled; |
1635 __ movq(RCX, FieldAddress(RAX, Function::code_offset())); | 1623 __ movq(RCX, FieldAddress(RAX, Function::code_offset())); |
1636 if (FLAG_collect_code) { | 1624 if (FLAG_collect_code) { |
1637 // If code might be GC'd, then EBX might be null. If it is, recompile. | 1625 // If code might be GC'd, then RBX might be null. If it is, recompile. |
1638 __ CompareObject(RCX, Object::null_object(), PP); | 1626 __ CompareObject(RCX, Object::null_object(), PP); |
1639 __ j(NOT_EQUAL, &is_compiled, Assembler::kNearJump); | 1627 __ j(NOT_EQUAL, &is_compiled, Assembler::kNearJump); |
1640 __ EnterStubFrame(); | 1628 __ EnterStubFrame(); |
1641 __ pushq(R10); // Preserve arguments descriptor array. | 1629 __ pushq(R10); // Preserve arguments descriptor array. |
1642 __ pushq(RBX); // Preserve IC data object. | 1630 __ pushq(RBX); // Preserve IC data object. |
1643 __ pushq(RAX); // Pass function. | 1631 __ pushq(RAX); // Pass function. |
1644 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); | 1632 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); |
1645 __ popq(RAX); // Restore function. | 1633 __ popq(RAX); // Restore function. |
1646 __ popq(RBX); // Restore IC data array. | 1634 __ popq(RBX); // Restore IC data array. |
1647 __ popq(R10); // Restore arguments descriptor array. | 1635 __ popq(R10); // Restore arguments descriptor array. |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2148 | 2136 |
2149 __ movq(left, Address(RSP, 2 * kWordSize)); | 2137 __ movq(left, Address(RSP, 2 * kWordSize)); |
2150 __ movq(right, Address(RSP, 1 * kWordSize)); | 2138 __ movq(right, Address(RSP, 1 * kWordSize)); |
2151 GenerateIdenticalWithNumberCheckStub(assembler, left, right); | 2139 GenerateIdenticalWithNumberCheckStub(assembler, left, right); |
2152 __ ret(); | 2140 __ ret(); |
2153 } | 2141 } |
2154 | 2142 |
2155 } // namespace dart | 2143 } // namespace dart |
2156 | 2144 |
2157 #endif // defined TARGET_ARCH_X64 | 2145 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |