| 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 |