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_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
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/instructions.h" | 12 #include "vm/instructions.h" |
13 #include "vm/heap.h" | 13 #include "vm/heap.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 // Input parameters: | 32 // Input parameters: |
32 // ESP : points to return address. | 33 // ESP : points to return address. |
33 // ESP + 4 : address of last argument in argument array. | 34 // ESP + 4 : address of last argument in argument array. |
34 // ESP + 4*EDX : address of first argument in argument array. | 35 // ESP + 4*EDX : address of first argument in argument array. |
35 // ESP + 4*EDX + 4 : address of return value. | 36 // ESP + 4*EDX + 4 : address of return value. |
36 // ECX : address of the runtime function to call. | 37 // ECX : address of the runtime function to call. |
37 // EDX : number of arguments to the call. | 38 // EDX : number of arguments to the call. |
38 // Must preserve callee saved registers EDI and EBX. | 39 // Must preserve callee saved registers EDI and EBX. |
39 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 40 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
(...skipping 1071 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1111 const intptr_t kInstantiatorTypeArgumentsOffset = 1 * kWordSize; | 1112 const intptr_t kInstantiatorTypeArgumentsOffset = 1 * kWordSize; |
1112 const Immediate& raw_null = | 1113 const Immediate& raw_null = |
1113 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1114 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
1114 // The generated code is different if the class is parameterized. | 1115 // The generated code is different if the class is parameterized. |
1115 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; | 1116 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; |
1116 ASSERT(!is_cls_parameterized || | 1117 ASSERT(!is_cls_parameterized || |
1117 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); | 1118 (cls.type_arguments_field_offset() != Class::kNoTypeArguments)); |
1118 // kInlineInstanceSize is a constant used as a threshold for determining | 1119 // kInlineInstanceSize is a constant used as a threshold for determining |
1119 // when the object initialization should be done as a loop or as | 1120 // when the object initialization should be done as a loop or as |
1120 // straight line code. | 1121 // straight line code. |
1121 const int kInlineInstanceSize = 12; | 1122 const int kInlineInstanceSize = 12; // In words. |
1122 const intptr_t instance_size = cls.instance_size(); | 1123 const intptr_t instance_size = cls.instance_size(); |
1123 ASSERT(instance_size > 0); | 1124 ASSERT(instance_size > 0); |
1124 const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize(); | 1125 Label slow_case_with_type_arguments; |
1125 if (FLAG_inline_alloc && | 1126 if (FLAG_inline_alloc && Heap::IsAllocatableInNewSpace(instance_size)) { |
1126 Heap::IsAllocatableInNewSpace(instance_size + type_args_size)) { | 1127 Label slow_case_reload_type_arguments; |
1127 Label slow_case; | 1128 if (is_cls_parameterized) { |
| 1129 // Instantiation of the type arguments vector is only required if an |
| 1130 // instantiator is provided (not kNoInstantiator, but may be null). |
| 1131 __ movl(EDX, Address(ESP, kObjectTypeArgumentsOffset)); |
| 1132 __ movl(EDI, Address(ESP, kInstantiatorTypeArgumentsOffset)); |
| 1133 Label type_arguments_ready; |
| 1134 __ cmpl(EDI, Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1135 __ j(EQUAL, &type_arguments_ready, Assembler::kNearJump); |
| 1136 // Lookup instantiator EDI in instantiations array of type arguments EDX |
| 1137 // and, if found, use cached instantiated type arguments. |
| 1138 __ movl(EAX, FieldAddress(EDX, TypeArguments::instantiations_offset())); |
| 1139 __ movl(EBX, FieldAddress(EAX, Array::length_offset())); |
| 1140 __ leal(EAX, FieldAddress(EAX, Array::data_offset())); |
| 1141 __ leal(EBX, Address(EAX, EBX, TIMES_2, 0)); // EBX is smi. |
| 1142 Label loop, found; |
| 1143 __ Bind(&loop); |
| 1144 __ cmpl(EAX, EBX); |
| 1145 __ j(ABOVE_EQUAL, &slow_case_reload_type_arguments); |
| 1146 __ movl(EDX, Address(EAX, 0 * kWordSize)); // Cached instantiator. |
| 1147 __ cmpl(EDX, EDI); |
| 1148 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1149 __ cmpl(EDX, Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1150 __ j(EQUAL, &slow_case_reload_type_arguments); |
| 1151 __ addl(EAX, Immediate(2 * kWordSize)); |
| 1152 __ jmp(&loop, Assembler::kNearJump); |
| 1153 __ Bind(&found); |
| 1154 __ movl(EDX, Address(EAX, 1 * kWordSize)); // Cached instantiated args. |
| 1155 __ movl(EDI, Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1156 __ Bind(&type_arguments_ready); |
| 1157 // EDX: instantiated type arguments. |
| 1158 // EDI: kNoInstantiator. |
| 1159 } |
| 1160 // Allocate the object and update top to point to |
| 1161 // next object start and initialize the allocated object. |
| 1162 // EDX: instantiated type arguments (if is_cls_parameterized). |
| 1163 // EDI: kNoInstantiator (if is_cls_parameterized). |
1128 Heap* heap = Isolate::Current()->heap(); | 1164 Heap* heap = Isolate::Current()->heap(); |
1129 __ movl(EAX, Address::Absolute(heap->TopAddress())); | 1165 __ movl(EAX, Address::Absolute(heap->TopAddress())); |
1130 __ leal(EBX, Address(EAX, instance_size)); | 1166 __ leal(EBX, Address(EAX, instance_size)); |
1131 if (is_cls_parameterized) { | |
1132 __ movl(ECX, EBX); | |
1133 // A new InstantiatedTypeArguments object only needs to be allocated if | |
1134 // the instantiator is provided (not kNoInstantiator, but may be null). | |
1135 Label no_instantiator; | |
1136 __ cmpl(Address(ESP, kInstantiatorTypeArgumentsOffset), | |
1137 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | |
1138 __ j(EQUAL, &no_instantiator, Assembler::kNearJump); | |
1139 __ addl(EBX, Immediate(type_args_size)); | |
1140 __ Bind(&no_instantiator); | |
1141 // ECX: potential new object end and, if ECX != EBX, potential new | |
1142 // InstantiatedTypeArguments object start. | |
1143 } | |
1144 // Check if the allocation fits into the remaining space. | 1167 // Check if the allocation fits into the remaining space. |
1145 // EAX: potential new object start. | 1168 // EAX: potential new object start. |
1146 // EBX: potential next object start. | 1169 // EBX: potential next object start. |
1147 __ cmpl(EBX, Address::Absolute(heap->EndAddress())); | 1170 __ cmpl(EBX, Address::Absolute(heap->EndAddress())); |
1148 if (FLAG_use_slow_path) { | 1171 if (FLAG_use_slow_path) { |
1149 __ jmp(&slow_case); | 1172 __ jmp(&slow_case_with_type_arguments); |
1150 } else { | 1173 } else { |
1151 __ j(ABOVE_EQUAL, &slow_case); | 1174 __ j(ABOVE_EQUAL, &slow_case_with_type_arguments); |
1152 } | 1175 } |
1153 | |
1154 // Successfully allocated the object(s), now update top to point to | |
1155 // next object start and initialize the object. | |
1156 __ movl(Address::Absolute(heap->TopAddress()), EBX); | 1176 __ movl(Address::Absolute(heap->TopAddress()), EBX); |
1157 __ UpdateAllocationStats(cls.id(), EDI); | 1177 __ UpdateAllocationStats(cls.id(), ECX); |
1158 | |
1159 if (is_cls_parameterized) { | |
1160 // Initialize the type arguments field in the object. | |
1161 // EAX: new object start. | |
1162 // ECX: potential new object end and, if ECX != EBX, potential new | |
1163 // InstantiatedTypeArguments object start. | |
1164 // EBX: next object start. | |
1165 Label type_arguments_ready; | |
1166 __ movl(EDI, Address(ESP, kObjectTypeArgumentsOffset)); | |
1167 __ cmpl(ECX, EBX); | |
1168 __ j(EQUAL, &type_arguments_ready, Assembler::kNearJump); | |
1169 // Initialize InstantiatedTypeArguments object at ECX. | |
1170 __ movl(Address(ECX, | |
1171 InstantiatedTypeArguments::uninstantiated_type_arguments_offset()), | |
1172 EDI); | |
1173 __ movl(EDX, Address(ESP, kInstantiatorTypeArgumentsOffset)); | |
1174 __ movl(Address(ECX, | |
1175 InstantiatedTypeArguments::instantiator_type_arguments_offset()), | |
1176 EDX); | |
1177 const Class& ita_cls = | |
1178 Class::ZoneHandle(Object::instantiated_type_arguments_class()); | |
1179 // Set the tags. | |
1180 uword tags = 0; | |
1181 tags = RawObject::SizeTag::update(type_args_size, tags); | |
1182 tags = RawObject::ClassIdTag::update(ita_cls.id(), tags); | |
1183 __ movl(Address(ECX, Instance::tags_offset()), Immediate(tags)); | |
1184 // Set the new InstantiatedTypeArguments object (ECX) as the type | |
1185 // arguments (EDI) of the new object (EAX). | |
1186 __ movl(EDI, ECX); | |
1187 __ addl(EDI, Immediate(kHeapObjectTag)); | |
1188 // Set EBX to new object end. | |
1189 __ movl(EBX, ECX); | |
1190 __ Bind(&type_arguments_ready); | |
1191 // EAX: new object. | |
1192 // EDI: new object type arguments. | |
1193 } | |
1194 | 1178 |
1195 // EAX: new object start. | 1179 // EAX: new object start. |
1196 // EBX: next object start. | 1180 // EBX: next object start. |
1197 // EDI: new object type arguments (if is_cls_parameterized). | 1181 // EDX: new object type arguments (if is_cls_parameterized). |
1198 // Set the tags. | 1182 // Set the tags. |
1199 uword tags = 0; | 1183 uword tags = 0; |
1200 tags = RawObject::SizeTag::update(instance_size, tags); | 1184 tags = RawObject::SizeTag::update(instance_size, tags); |
1201 ASSERT(cls.id() != kIllegalCid); | 1185 ASSERT(cls.id() != kIllegalCid); |
1202 tags = RawObject::ClassIdTag::update(cls.id(), tags); | 1186 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
1203 __ movl(Address(EAX, Instance::tags_offset()), Immediate(tags)); | 1187 __ movl(Address(EAX, Instance::tags_offset()), Immediate(tags)); |
1204 | 1188 |
1205 // Initialize the remaining words of the object. | 1189 // Initialize the remaining words of the object. |
1206 const Immediate& raw_null = | 1190 const Immediate& raw_null = |
1207 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1191 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
1208 | 1192 |
1209 // EAX: new object start. | 1193 // EAX: new object start. |
1210 // EBX: next object start. | 1194 // EBX: next object start. |
1211 // EDI: new object type arguments (if is_cls_parameterized). | 1195 // EDX: new object type arguments (if is_cls_parameterized). |
1212 // First try inlining the initialization without a loop. | 1196 // First try inlining the initialization without a loop. |
1213 if (instance_size < (kInlineInstanceSize * kWordSize)) { | 1197 if (instance_size < (kInlineInstanceSize * kWordSize)) { |
1214 // Check if the object contains any non-header fields. | 1198 // Check if the object contains any non-header fields. |
1215 // Small objects are initialized using a consecutive set of writes. | 1199 // Small objects are initialized using a consecutive set of writes. |
1216 for (intptr_t current_offset = Instance::NextFieldOffset(); | 1200 for (intptr_t current_offset = Instance::NextFieldOffset(); |
1217 current_offset < instance_size; | 1201 current_offset < instance_size; |
1218 current_offset += kWordSize) { | 1202 current_offset += kWordSize) { |
1219 __ movl(Address(EAX, current_offset), raw_null); | 1203 __ movl(Address(EAX, current_offset), raw_null); |
1220 } | 1204 } |
1221 } else { | 1205 } else { |
1222 __ leal(ECX, Address(EAX, Instance::NextFieldOffset())); | 1206 __ leal(ECX, Address(EAX, Instance::NextFieldOffset())); |
1223 // Loop until the whole object is initialized. | 1207 // Loop until the whole object is initialized. |
1224 // EAX: new object. | 1208 // EAX: new object. |
1225 // EBX: next object start. | 1209 // EBX: next object start. |
1226 // ECX: next word to be initialized. | 1210 // ECX: next word to be initialized. |
1227 // EDI: new object type arguments (if is_cls_parameterized). | 1211 // EDX: new object type arguments (if is_cls_parameterized). |
1228 Label init_loop; | 1212 Label init_loop; |
1229 Label done; | 1213 Label done; |
1230 __ Bind(&init_loop); | 1214 __ Bind(&init_loop); |
1231 __ cmpl(ECX, EBX); | 1215 __ cmpl(ECX, EBX); |
1232 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); | 1216 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
1233 __ movl(Address(ECX, 0), raw_null); | 1217 __ movl(Address(ECX, 0), raw_null); |
1234 __ addl(ECX, Immediate(kWordSize)); | 1218 __ addl(ECX, Immediate(kWordSize)); |
1235 __ jmp(&init_loop, Assembler::kNearJump); | 1219 __ jmp(&init_loop, Assembler::kNearJump); |
1236 __ Bind(&done); | 1220 __ Bind(&done); |
1237 } | 1221 } |
1238 if (is_cls_parameterized) { | 1222 if (is_cls_parameterized) { |
1239 // EDI: new object type arguments. | 1223 // EDX: new object type arguments. |
1240 // Set the type arguments in the new object. | 1224 // Set the type arguments in the new object. |
1241 __ movl(Address(EAX, cls.type_arguments_field_offset()), EDI); | 1225 __ movl(Address(EAX, cls.type_arguments_field_offset()), EDX); |
1242 } | 1226 } |
1243 // Done allocating and initializing the instance. | 1227 // Done allocating and initializing the instance. |
1244 // EAX: new object. | 1228 // EAX: new object. |
1245 __ addl(EAX, Immediate(kHeapObjectTag)); | 1229 __ addl(EAX, Immediate(kHeapObjectTag)); |
1246 __ ret(); | 1230 __ ret(); |
1247 | 1231 |
1248 __ Bind(&slow_case); | 1232 __ Bind(&slow_case_reload_type_arguments); |
1249 } | 1233 } |
1250 if (is_cls_parameterized) { | 1234 if (is_cls_parameterized) { |
1251 __ movl(EAX, Address(ESP, kObjectTypeArgumentsOffset)); | 1235 __ movl(EDX, Address(ESP, kObjectTypeArgumentsOffset)); |
1252 __ movl(EDX, Address(ESP, kInstantiatorTypeArgumentsOffset)); | 1236 __ movl(EDI, Address(ESP, kInstantiatorTypeArgumentsOffset)); |
1253 } | 1237 } |
| 1238 __ Bind(&slow_case_with_type_arguments); |
| 1239 // If is_cls_parameterized: |
| 1240 // EDX: new object type arguments (instantiated or not). |
| 1241 // EDI: instantiator type arguments or kNoInstantiator. |
1254 // Create a stub frame as we are pushing some objects on the stack before | 1242 // Create a stub frame as we are pushing some objects on the stack before |
1255 // calling into the runtime. | 1243 // calling into the runtime. |
1256 __ EnterStubFrame(); | 1244 __ EnterStubFrame(); |
1257 __ pushl(raw_null); // Setup space on stack for return value. | 1245 __ pushl(raw_null); // Setup space on stack for return value. |
1258 __ PushObject(cls); // Push class of object to be allocated. | 1246 __ PushObject(cls); // Push class of object to be allocated. |
1259 if (is_cls_parameterized) { | 1247 if (is_cls_parameterized) { |
1260 __ pushl(EAX); // Push type arguments of object to be allocated. | 1248 __ pushl(EDX); // Push type arguments of object to be allocated. |
1261 __ pushl(EDX); // Push type arguments of instantiator. | 1249 __ pushl(EDI); // Push type arguments of instantiator. |
1262 } else { | 1250 } else { |
1263 __ pushl(raw_null); // Push null type arguments. | 1251 __ pushl(raw_null); // Push null type arguments. |
1264 __ pushl(Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | 1252 __ pushl(Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
1265 } | 1253 } |
1266 __ CallRuntime(kAllocateObjectRuntimeEntry, 3); // Allocate object. | 1254 __ CallRuntime(kAllocateObjectRuntimeEntry, 3); // Allocate object. |
1267 __ popl(EAX); // Pop argument (instantiator). | 1255 __ popl(EAX); // Pop argument (instantiator). |
1268 __ popl(EAX); // Pop argument (type arguments of object). | 1256 __ popl(EAX); // Pop argument (type arguments of object). |
1269 __ popl(EAX); // Pop argument (class of object). | 1257 __ popl(EAX); // Pop argument (class of object). |
1270 __ popl(EAX); // Pop result (newly allocated object). | 1258 __ popl(EAX); // Pop result (newly allocated object). |
1271 // EAX: new object | 1259 // EAX: new object |
(...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2169 const Register temp = ECX; | 2157 const Register temp = ECX; |
2170 __ movl(left, Address(ESP, 2 * kWordSize)); | 2158 __ movl(left, Address(ESP, 2 * kWordSize)); |
2171 __ movl(right, Address(ESP, 1 * kWordSize)); | 2159 __ movl(right, Address(ESP, 1 * kWordSize)); |
2172 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2160 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
2173 __ ret(); | 2161 __ ret(); |
2174 } | 2162 } |
2175 | 2163 |
2176 } // namespace dart | 2164 } // namespace dart |
2177 | 2165 |
2178 #endif // defined TARGET_ARCH_IA32 | 2166 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |