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