OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1008 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); | 1008 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); |
1009 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1009 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1010 RelocInfo::CODE_TARGET); | 1010 RelocInfo::CODE_TARGET); |
1011 | 1011 |
1012 // Leave internal frame. | 1012 // Leave internal frame. |
1013 } | 1013 } |
1014 __ ret(3 * kPointerSize); // remove this, receiver, and arguments | 1014 __ ret(3 * kPointerSize); // remove this, receiver, and arguments |
1015 } | 1015 } |
1016 | 1016 |
1017 | 1017 |
1018 // Allocate an empty JSArray. The allocated array is put into the result | |
1019 // register. If the parameter initial_capacity is larger than zero an elements | |
1020 // backing store is allocated with this size and filled with the hole values. | |
1021 // Otherwise the elements backing store is set to the empty FixedArray. | |
1022 static void AllocateEmptyJSArray(MacroAssembler* masm, | |
1023 Register array_function, | |
1024 Register result, | |
1025 Register scratch1, | |
1026 Register scratch2, | |
1027 Register scratch3, | |
1028 Label* gc_required) { | |
1029 const int initial_capacity = JSArray::kPreallocatedArrayElements; | |
1030 STATIC_ASSERT(initial_capacity >= 0); | |
1031 | |
1032 __ LoadInitialArrayMap(array_function, scratch2, scratch1, false); | |
1033 | |
1034 // Allocate the JSArray object together with space for a fixed array with the | |
1035 // requested elements. | |
1036 int size = JSArray::kSize; | |
1037 if (initial_capacity > 0) { | |
1038 size += FixedArray::SizeFor(initial_capacity); | |
1039 } | |
1040 __ Allocate(size, result, scratch2, scratch3, gc_required, TAG_OBJECT); | |
1041 | |
1042 // Allocated the JSArray. Now initialize the fields except for the elements | |
1043 // array. | |
1044 // result: JSObject | |
1045 // scratch1: initial map | |
1046 // scratch2: start of next object | |
1047 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1); | |
1048 Factory* factory = masm->isolate()->factory(); | |
1049 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), | |
1050 factory->empty_fixed_array()); | |
1051 // Field JSArray::kElementsOffset is initialized later. | |
1052 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0)); | |
1053 | |
1054 // If no storage is requested for the elements array just set the empty | |
1055 // fixed array. | |
1056 if (initial_capacity == 0) { | |
1057 __ mov(FieldOperand(result, JSArray::kElementsOffset), | |
1058 factory->empty_fixed_array()); | |
1059 return; | |
1060 } | |
1061 | |
1062 // Calculate the location of the elements array and set elements array member | |
1063 // of the JSArray. | |
1064 // result: JSObject | |
1065 // scratch2: start of next object | |
1066 __ lea(scratch1, Operand(result, JSArray::kSize)); | |
1067 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1); | |
1068 | |
1069 // Initialize the FixedArray and fill it with holes. FixedArray length is | |
1070 // stored as a smi. | |
1071 // result: JSObject | |
1072 // scratch1: elements array | |
1073 // scratch2: start of next object | |
1074 __ mov(FieldOperand(scratch1, FixedArray::kMapOffset), | |
1075 factory->fixed_array_map()); | |
1076 __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset), | |
1077 Immediate(Smi::FromInt(initial_capacity))); | |
1078 | |
1079 // Fill the FixedArray with the hole value. Inline the code if short. | |
1080 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed. | |
1081 static const int kLoopUnfoldLimit = 4; | |
1082 if (initial_capacity <= kLoopUnfoldLimit) { | |
1083 // Use a scratch register here to have only one reloc info when unfolding | |
1084 // the loop. | |
1085 __ mov(scratch3, factory->the_hole_value()); | |
1086 for (int i = 0; i < initial_capacity; i++) { | |
1087 __ mov(FieldOperand(scratch1, | |
1088 FixedArray::kHeaderSize + i * kPointerSize), | |
1089 scratch3); | |
1090 } | |
1091 } else { | |
1092 Label loop, entry; | |
1093 __ mov(scratch2, Immediate(initial_capacity)); | |
1094 __ jmp(&entry); | |
1095 __ bind(&loop); | |
1096 __ mov(FieldOperand(scratch1, | |
1097 scratch2, | |
1098 times_pointer_size, | |
1099 FixedArray::kHeaderSize), | |
1100 factory->the_hole_value()); | |
1101 __ bind(&entry); | |
1102 __ dec(scratch2); | |
1103 __ j(not_sign, &loop); | |
1104 } | |
1105 } | |
1106 | |
1107 | |
1108 // Allocate a JSArray with the number of elements stored in a register. The | |
1109 // register array_function holds the built-in Array function and the register | |
1110 // array_size holds the size of the array as a smi. The allocated array is put | |
1111 // into the result register and beginning and end of the FixedArray elements | |
1112 // storage is put into registers elements_array and elements_array_end (see | |
1113 // below for when that is not the case). If the parameter fill_with_holes is | |
1114 // true the allocated elements backing store is filled with the hole values | |
1115 // otherwise it is left uninitialized. When the backing store is filled the | |
1116 // register elements_array is scratched. | |
1117 static void AllocateJSArray(MacroAssembler* masm, | |
1118 Register array_function, // Array function. | |
1119 Register array_size, // As a smi, cannot be 0. | |
1120 Register result, | |
1121 Register elements_array, | |
1122 Register elements_array_end, | |
1123 Register scratch, | |
1124 bool fill_with_hole, | |
1125 Label* gc_required) { | |
1126 ASSERT(scratch.is(edi)); // rep stos destination | |
1127 ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count | |
1128 ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax | |
1129 | |
1130 __ LoadInitialArrayMap(array_function, scratch, | |
1131 elements_array, fill_with_hole); | |
1132 | |
1133 // Allocate the JSArray object together with space for a FixedArray with the | |
1134 // requested elements. | |
1135 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | |
1136 __ Allocate(JSArray::kSize + FixedArray::kHeaderSize, | |
1137 times_pointer_size, | |
1138 array_size, | |
1139 REGISTER_VALUE_IS_SMI, | |
1140 result, | |
1141 elements_array_end, | |
1142 scratch, | |
1143 gc_required, | |
1144 TAG_OBJECT); | |
1145 | |
1146 // Allocated the JSArray. Now initialize the fields except for the elements | |
1147 // array. | |
1148 // result: JSObject | |
1149 // elements_array: initial map | |
1150 // elements_array_end: start of next object | |
1151 // array_size: size of array (smi) | |
1152 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array); | |
1153 Factory* factory = masm->isolate()->factory(); | |
1154 __ mov(elements_array, factory->empty_fixed_array()); | |
1155 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); | |
1156 // Field JSArray::kElementsOffset is initialized later. | |
1157 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size); | |
1158 | |
1159 // Calculate the location of the elements array and set elements array member | |
1160 // of the JSArray. | |
1161 // result: JSObject | |
1162 // elements_array_end: start of next object | |
1163 // array_size: size of array (smi) | |
1164 __ lea(elements_array, Operand(result, JSArray::kSize)); | |
1165 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array); | |
1166 | |
1167 // Initialize the fixed array. FixedArray length is stored as a smi. | |
1168 // result: JSObject | |
1169 // elements_array: elements array | |
1170 // elements_array_end: start of next object | |
1171 // array_size: size of array (smi) | |
1172 __ mov(FieldOperand(elements_array, FixedArray::kMapOffset), | |
1173 factory->fixed_array_map()); | |
1174 // For non-empty JSArrays the length of the FixedArray and the JSArray is the | |
1175 // same. | |
1176 __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size); | |
1177 | |
1178 // Fill the allocated FixedArray with the hole value if requested. | |
1179 // result: JSObject | |
1180 // elements_array: elements array | |
1181 if (fill_with_hole) { | |
1182 __ SmiUntag(array_size); | |
1183 __ lea(edi, Operand(elements_array, | |
1184 FixedArray::kHeaderSize - kHeapObjectTag)); | |
1185 __ mov(eax, factory->the_hole_value()); | |
1186 __ cld(); | |
1187 // Do not use rep stos when filling less than kRepStosThreshold | |
1188 // words. | |
1189 const int kRepStosThreshold = 16; | |
1190 Label loop, entry, done; | |
1191 __ cmp(ecx, kRepStosThreshold); | |
1192 __ j(below, &loop); // Note: ecx > 0. | |
1193 __ rep_stos(); | |
1194 __ jmp(&done); | |
1195 __ bind(&loop); | |
1196 __ stos(); | |
1197 __ bind(&entry); | |
1198 __ cmp(edi, elements_array_end); | |
1199 __ j(below, &loop); | |
1200 __ bind(&done); | |
1201 } | |
1202 } | |
1203 | |
1204 | |
1205 // Create a new array for the built-in Array function. This function allocates | |
1206 // the JSArray object and the FixedArray elements array and initializes these. | |
1207 // If the Array cannot be constructed in native code the runtime is called. This | |
1208 // function assumes the following state: | |
1209 // edi: constructor (built-in Array function) | |
1210 // eax: argc | |
1211 // esp[0]: return address | |
1212 // esp[4]: last argument | |
1213 // This function is used for both construct and normal calls of Array. Whether | |
1214 // it is a construct call or not is indicated by the construct_call parameter. | |
1215 // The only difference between handling a construct call and a normal call is | |
1216 // that for a construct call the constructor function in edi needs to be | |
1217 // preserved for entering the generic code. In both cases argc in eax needs to | |
1218 // be preserved. | |
1219 void ArrayNativeCode(MacroAssembler* masm, | |
1220 bool construct_call, | |
1221 Label* call_generic_code) { | |
1222 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call, | |
1223 empty_array, not_empty_array, finish, cant_transition_map, not_double; | |
1224 | |
1225 // Push the constructor and argc. No need to tag argc as a smi, as there will | |
1226 // be no garbage collection with this on the stack. | |
1227 int push_count = 0; | |
1228 if (construct_call) { | |
1229 push_count++; | |
1230 __ push(edi); | |
1231 } | |
1232 push_count++; | |
1233 __ push(eax); | |
1234 | |
1235 // Check for array construction with zero arguments. | |
1236 __ test(eax, eax); | |
1237 __ j(not_zero, &argc_one_or_more); | |
1238 | |
1239 __ bind(&empty_array); | |
1240 // Handle construction of an empty array. | |
1241 AllocateEmptyJSArray(masm, | |
1242 edi, | |
1243 eax, | |
1244 ebx, | |
1245 ecx, | |
1246 edi, | |
1247 &prepare_generic_code_call); | |
1248 __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1); | |
1249 __ pop(ebx); | |
1250 if (construct_call) { | |
1251 __ pop(edi); | |
1252 } | |
1253 __ ret(kPointerSize); | |
1254 | |
1255 // Check for one argument. Bail out if argument is not smi or if it is | |
1256 // negative. | |
1257 __ bind(&argc_one_or_more); | |
1258 __ cmp(eax, 1); | |
1259 __ j(not_equal, &argc_two_or_more); | |
1260 STATIC_ASSERT(kSmiTag == 0); | |
1261 __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize)); | |
1262 __ test(ecx, ecx); | |
1263 __ j(not_zero, ¬_empty_array); | |
1264 | |
1265 // The single argument passed is zero, so we jump to the code above used to | |
1266 // handle the case of no arguments passed. To adapt the stack for that we move | |
1267 // the return address and the pushed constructor (if pushed) one stack slot up | |
1268 // thereby removing the passed argument. Argc is also on the stack - at the | |
1269 // bottom - and it needs to be changed from 1 to 0 to have the call into the | |
1270 // runtime system work in case a GC is required. | |
1271 for (int i = push_count; i > 0; i--) { | |
1272 __ mov(eax, Operand(esp, i * kPointerSize)); | |
1273 __ mov(Operand(esp, (i + 1) * kPointerSize), eax); | |
1274 } | |
1275 __ Drop(2); // Drop two stack slots. | |
1276 __ push(Immediate(0)); // Treat this as a call with argc of zero. | |
1277 __ jmp(&empty_array); | |
1278 | |
1279 __ bind(¬_empty_array); | |
1280 __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask)); | |
1281 __ j(not_zero, &prepare_generic_code_call); | |
1282 | |
1283 // Handle construction of an empty array of a certain size. Get the size from | |
1284 // the stack and bail out if size is to large to actually allocate an elements | |
1285 // array. | |
1286 __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize); | |
1287 __ j(greater_equal, &prepare_generic_code_call); | |
1288 | |
1289 // edx: array_size (smi) | |
1290 // edi: constructor | |
1291 // esp[0]: argc (cannot be 0 here) | |
1292 // esp[4]: constructor (only if construct_call) | |
1293 // esp[8]: return address | |
1294 // esp[C]: argument | |
1295 AllocateJSArray(masm, | |
1296 edi, | |
1297 ecx, | |
1298 ebx, | |
1299 eax, | |
1300 edx, | |
1301 edi, | |
1302 true, | |
1303 &prepare_generic_code_call); | |
1304 Counters* counters = masm->isolate()->counters(); | |
1305 __ IncrementCounter(counters->array_function_native(), 1); | |
1306 __ mov(eax, ebx); | |
1307 __ pop(ebx); | |
1308 if (construct_call) { | |
1309 __ pop(edi); | |
1310 } | |
1311 __ ret(2 * kPointerSize); | |
1312 | |
1313 // Handle construction of an array from a list of arguments. | |
1314 __ bind(&argc_two_or_more); | |
1315 STATIC_ASSERT(kSmiTag == 0); | |
1316 __ SmiTag(eax); // Convet argc to a smi. | |
1317 // eax: array_size (smi) | |
1318 // edi: constructor | |
1319 // esp[0] : argc | |
1320 // esp[4]: constructor (only if construct_call) | |
1321 // esp[8] : return address | |
1322 // esp[C] : last argument | |
1323 AllocateJSArray(masm, | |
1324 edi, | |
1325 eax, | |
1326 ebx, | |
1327 ecx, | |
1328 edx, | |
1329 edi, | |
1330 false, | |
1331 &prepare_generic_code_call); | |
1332 __ IncrementCounter(counters->array_function_native(), 1); | |
1333 __ push(ebx); | |
1334 __ mov(ebx, Operand(esp, kPointerSize)); | |
1335 // ebx: argc | |
1336 // edx: elements_array_end (untagged) | |
1337 // esp[0]: JSArray | |
1338 // esp[4]: argc | |
1339 // esp[8]: constructor (only if construct_call) | |
1340 // esp[12]: return address | |
1341 // esp[16]: last argument | |
1342 | |
1343 // Location of the last argument | |
1344 int last_arg_offset = (construct_call ? 4 : 3) * kPointerSize; | |
1345 __ lea(edi, Operand(esp, last_arg_offset)); | |
1346 | |
1347 // Location of the first array element (Parameter fill_with_holes to | |
1348 // AllocateJSArray is false, so the FixedArray is returned in ecx). | |
1349 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag)); | |
1350 | |
1351 Label has_non_smi_element; | |
1352 | |
1353 // ebx: argc | |
1354 // edx: location of the first array element | |
1355 // edi: location of the last argument | |
1356 // esp[0]: JSArray | |
1357 // esp[4]: argc | |
1358 // esp[8]: constructor (only if construct_call) | |
1359 // esp[12]: return address | |
1360 // esp[16]: last argument | |
1361 Label loop, entry; | |
1362 __ mov(ecx, ebx); | |
1363 __ jmp(&entry); | |
1364 __ bind(&loop); | |
1365 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0)); | |
1366 if (FLAG_smi_only_arrays) { | |
1367 __ JumpIfNotSmi(eax, &has_non_smi_element); | |
1368 } | |
1369 __ mov(Operand(edx, 0), eax); | |
1370 __ add(edx, Immediate(kPointerSize)); | |
1371 __ bind(&entry); | |
1372 __ dec(ecx); | |
1373 __ j(greater_equal, &loop); | |
1374 | |
1375 // Remove caller arguments from the stack and return. | |
1376 // ebx: argc | |
1377 // esp[0]: JSArray | |
1378 // esp[4]: argc | |
1379 // esp[8]: constructor (only if construct_call) | |
1380 // esp[12]: return address | |
1381 // esp[16]: last argument | |
1382 __ bind(&finish); | |
1383 __ mov(ecx, Operand(esp, last_arg_offset - kPointerSize)); | |
1384 __ pop(eax); | |
1385 __ pop(ebx); | |
1386 __ lea(esp, Operand(esp, ebx, times_pointer_size, | |
1387 last_arg_offset - kPointerSize)); | |
1388 __ jmp(ecx); | |
1389 | |
1390 __ bind(&has_non_smi_element); | |
1391 // Double values are handled by the runtime. | |
1392 __ CheckMap(eax, | |
1393 masm->isolate()->factory()->heap_number_map(), | |
1394 ¬_double, | |
1395 DONT_DO_SMI_CHECK); | |
1396 __ bind(&cant_transition_map); | |
1397 // Throw away the array that's only been partially constructed. | |
1398 __ pop(eax); | |
1399 __ UndoAllocationInNewSpace(eax); | |
1400 __ jmp(&prepare_generic_code_call); | |
1401 | |
1402 __ bind(¬_double); | |
1403 // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS. | |
1404 __ mov(ebx, Operand(esp, 0)); | |
1405 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); | |
1406 __ LoadTransitionedArrayMapConditional( | |
1407 FAST_SMI_ELEMENTS, | |
1408 FAST_ELEMENTS, | |
1409 edi, | |
1410 eax, | |
1411 &cant_transition_map); | |
1412 __ mov(FieldOperand(ebx, HeapObject::kMapOffset), edi); | |
1413 __ RecordWriteField(ebx, HeapObject::kMapOffset, edi, eax, | |
1414 kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | |
1415 | |
1416 // Prepare to re-enter the loop | |
1417 __ lea(edi, Operand(esp, last_arg_offset)); | |
1418 | |
1419 // Finish the array initialization loop. | |
1420 Label loop2; | |
1421 __ bind(&loop2); | |
1422 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0)); | |
1423 __ mov(Operand(edx, 0), eax); | |
1424 __ add(edx, Immediate(kPointerSize)); | |
1425 __ dec(ecx); | |
1426 __ j(greater_equal, &loop2); | |
1427 __ jmp(&finish); | |
1428 | |
1429 // Restore argc and constructor before running the generic code. | |
1430 __ bind(&prepare_generic_code_call); | |
1431 __ pop(eax); | |
1432 if (construct_call) { | |
1433 __ pop(edi); | |
1434 } | |
1435 __ jmp(call_generic_code); | |
1436 } | |
1437 | |
1438 | |
1439 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { | 1018 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
1440 // ----------- S t a t e ------------- | 1019 // ----------- S t a t e ------------- |
1441 // -- eax : argc | 1020 // -- eax : argc |
1442 // -- esp[0] : return address | 1021 // -- esp[0] : return address |
1443 // -- esp[4] : last argument | 1022 // -- esp[4] : last argument |
1444 // ----------------------------------- | 1023 // ----------------------------------- |
1445 Label generic_array_code; | 1024 Label generic_array_code; |
1446 | 1025 |
1447 // Get the InternalArray function. | 1026 // Get the InternalArray function. |
1448 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); | 1027 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); |
1449 | 1028 |
1450 if (FLAG_debug_code) { | 1029 if (FLAG_debug_code) { |
1451 // Initial map for the builtin InternalArray function should be a map. | 1030 // Initial map for the builtin InternalArray function should be a map. |
1452 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | 1031 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
1453 // Will both indicate a NULL and a Smi. | 1032 // Will both indicate a NULL and a Smi. |
1454 __ test(ebx, Immediate(kSmiTagMask)); | 1033 __ test(ebx, Immediate(kSmiTagMask)); |
1455 __ Assert(not_zero, "Unexpected initial map for InternalArray function"); | 1034 __ Assert(not_zero, "Unexpected initial map for InternalArray function"); |
1456 __ CmpObjectType(ebx, MAP_TYPE, ecx); | 1035 __ CmpObjectType(ebx, MAP_TYPE, ecx); |
1457 __ Assert(equal, "Unexpected initial map for InternalArray function"); | 1036 __ Assert(equal, "Unexpected initial map for InternalArray function"); |
1458 } | 1037 } |
1459 | 1038 |
1460 // Run the native code for the InternalArray function called as a normal | 1039 // Run the native code for the InternalArray function called as a normal |
1461 // function. | 1040 // function. |
1462 if (FLAG_optimize_constructed_arrays) { | 1041 // tail call a stub |
1463 // tail call a stub | 1042 InternalArrayConstructorStub stub(masm->isolate()); |
1464 InternalArrayConstructorStub stub(masm->isolate()); | 1043 __ TailCallStub(&stub); |
1465 __ TailCallStub(&stub); | |
1466 } else { | |
1467 ArrayNativeCode(masm, false, &generic_array_code); | |
1468 | |
1469 // Jump to the generic internal array code in case the specialized code | |
1470 // cannot handle the construction. | |
1471 __ bind(&generic_array_code); | |
1472 Handle<Code> array_code = | |
1473 masm->isolate()->builtins()->InternalArrayCodeGeneric(); | |
1474 __ jmp(array_code, RelocInfo::CODE_TARGET); | |
1475 } | |
1476 } | 1044 } |
1477 | 1045 |
1478 | 1046 |
1479 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { | 1047 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { |
1480 // ----------- S t a t e ------------- | 1048 // ----------- S t a t e ------------- |
1481 // -- eax : argc | 1049 // -- eax : argc |
1482 // -- esp[0] : return address | 1050 // -- esp[0] : return address |
1483 // -- esp[4] : last argument | 1051 // -- esp[4] : last argument |
1484 // ----------------------------------- | 1052 // ----------------------------------- |
1485 Label generic_array_code; | 1053 Label generic_array_code; |
1486 | 1054 |
1487 // Get the Array function. | 1055 // Get the Array function. |
1488 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi); | 1056 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi); |
1489 | 1057 |
1490 if (FLAG_debug_code) { | 1058 if (FLAG_debug_code) { |
1491 // Initial map for the builtin Array function should be a map. | 1059 // Initial map for the builtin Array function should be a map. |
1492 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | 1060 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
1493 // Will both indicate a NULL and a Smi. | 1061 // Will both indicate a NULL and a Smi. |
1494 __ test(ebx, Immediate(kSmiTagMask)); | 1062 __ test(ebx, Immediate(kSmiTagMask)); |
1495 __ Assert(not_zero, "Unexpected initial map for Array function"); | 1063 __ Assert(not_zero, "Unexpected initial map for Array function"); |
1496 __ CmpObjectType(ebx, MAP_TYPE, ecx); | 1064 __ CmpObjectType(ebx, MAP_TYPE, ecx); |
1497 __ Assert(equal, "Unexpected initial map for Array function"); | 1065 __ Assert(equal, "Unexpected initial map for Array function"); |
1498 } | 1066 } |
1499 | 1067 |
1500 // Run the native code for the Array function called as a normal function. | 1068 // Run the native code for the Array function called as a normal function. |
1501 if (FLAG_optimize_constructed_arrays) { | 1069 // tail call a stub |
1502 // tail call a stub | 1070 Handle<Object> undefined_sentinel( |
1503 Handle<Object> undefined_sentinel( | 1071 masm->isolate()->heap()->undefined_value(), |
1504 masm->isolate()->heap()->undefined_value(), | 1072 masm->isolate()); |
1505 masm->isolate()); | 1073 __ mov(ebx, Immediate(undefined_sentinel)); |
1506 __ mov(ebx, Immediate(undefined_sentinel)); | 1074 ArrayConstructorStub stub(masm->isolate()); |
1507 ArrayConstructorStub stub(masm->isolate()); | 1075 __ TailCallStub(&stub); |
1508 __ TailCallStub(&stub); | |
1509 } else { | |
1510 ArrayNativeCode(masm, false, &generic_array_code); | |
1511 | |
1512 // Jump to the generic internal array code in case the specialized code | |
1513 // cannot handle the construction. | |
1514 __ bind(&generic_array_code); | |
1515 Handle<Code> array_code = | |
1516 masm->isolate()->builtins()->ArrayCodeGeneric(); | |
1517 __ jmp(array_code, RelocInfo::CODE_TARGET); | |
1518 } | |
1519 } | 1076 } |
1520 | 1077 |
1521 | 1078 |
1522 void Builtins::Generate_CommonArrayConstructCode(MacroAssembler* masm) { | |
1523 // ----------- S t a t e ------------- | |
1524 // -- eax : argc | |
1525 // -- ebx : type info cell | |
1526 // -- edi : constructor | |
1527 // -- esp[0] : return address | |
1528 // -- esp[4] : last argument | |
1529 // ----------------------------------- | |
1530 if (FLAG_debug_code) { | |
1531 // The array construct code is only set for the global and natives | |
1532 // builtin Array functions which always have maps. | |
1533 | |
1534 // Initial map for the builtin Array function should be a map. | |
1535 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | |
1536 // Will both indicate a NULL and a Smi. | |
1537 __ test(ecx, Immediate(kSmiTagMask)); | |
1538 __ Assert(not_zero, "Unexpected initial map for Array function"); | |
1539 __ CmpObjectType(ecx, MAP_TYPE, ecx); | |
1540 __ Assert(equal, "Unexpected initial map for Array function"); | |
1541 } | |
1542 | |
1543 Label generic_constructor; | |
1544 // Run the native code for the Array function called as constructor. | |
1545 ArrayNativeCode(masm, true, &generic_constructor); | |
1546 | |
1547 // Jump to the generic construct code in case the specialized code cannot | |
1548 // handle the construction. | |
1549 __ bind(&generic_constructor); | |
1550 Handle<Code> generic_construct_stub = | |
1551 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
1552 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | |
1553 } | |
1554 | |
1555 | |
1556 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { | 1079 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { |
1557 // ----------- S t a t e ------------- | 1080 // ----------- S t a t e ------------- |
1558 // -- eax : number of arguments | 1081 // -- eax : number of arguments |
1559 // -- edi : constructor function | 1082 // -- edi : constructor function |
1560 // -- esp[0] : return address | 1083 // -- esp[0] : return address |
1561 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1084 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
1562 // -- esp[(argc + 1) * 4] : receiver | 1085 // -- esp[(argc + 1) * 4] : receiver |
1563 // ----------------------------------- | 1086 // ----------------------------------- |
1564 Counters* counters = masm->isolate()->counters(); | 1087 Counters* counters = masm->isolate()->counters(); |
1565 __ IncrementCounter(counters->string_ctor_calls(), 1); | 1088 __ IncrementCounter(counters->string_ctor_calls(), 1); |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1830 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); | 1353 Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); |
1831 generator.Generate(); | 1354 generator.Generate(); |
1832 } | 1355 } |
1833 | 1356 |
1834 | 1357 |
1835 #undef __ | 1358 #undef __ |
1836 } | 1359 } |
1837 } // namespace v8::internal | 1360 } // namespace v8::internal |
1838 | 1361 |
1839 #endif // V8_TARGET_ARCH_IA32 | 1362 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |