| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 if (function == NULL || !function->is_compiled()) return; | 542 if (function == NULL || !function->is_compiled()) return; |
| 543 | 543 |
| 544 constant_function_ = function; | 544 constant_function_ = function; |
| 545 AnalyzePossibleApiFunction(function); | 545 AnalyzePossibleApiFunction(function); |
| 546 } | 546 } |
| 547 | 547 |
| 548 // Determines whether the given function can be called using the | 548 // Determines whether the given function can be called using the |
| 549 // fast api call builtin. | 549 // fast api call builtin. |
| 550 void AnalyzePossibleApiFunction(JSFunction* function) { | 550 void AnalyzePossibleApiFunction(JSFunction* function) { |
| 551 SharedFunctionInfo* sfi = function->shared(); | 551 SharedFunctionInfo* sfi = function->shared(); |
| 552 if (sfi->function_data()->IsUndefined()) return; | 552 if (!sfi->IsApiFunction()) return; |
| 553 FunctionTemplateInfo* info = | 553 FunctionTemplateInfo* info = sfi->get_api_func_data(); |
| 554 FunctionTemplateInfo::cast(sfi->function_data()); | |
| 555 | 554 |
| 556 // Require a C++ callback. | 555 // Require a C++ callback. |
| 557 if (info->call_code()->IsUndefined()) return; | 556 if (info->call_code()->IsUndefined()) return; |
| 558 api_call_info_ = CallHandlerInfo::cast(info->call_code()); | 557 api_call_info_ = CallHandlerInfo::cast(info->call_code()); |
| 559 | 558 |
| 560 // Accept signatures that either have no restrictions at all or | 559 // Accept signatures that either have no restrictions at all or |
| 561 // only have restrictions on the receiver. | 560 // only have restrictions on the receiver. |
| 562 if (!info->signature()->IsUndefined()) { | 561 if (!info->signature()->IsUndefined()) { |
| 563 SignatureInfo* signature = SignatureInfo::cast(info->signature()); | 562 SignatureInfo* signature = SignatureInfo::cast(info->signature()); |
| 564 if (!signature->args()->IsUndefined()) return; | 563 if (!signature->args()->IsUndefined()) return; |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 Label* miss) { | 690 Label* miss) { |
| 692 ASSERT(holder->HasNamedInterceptor()); | 691 ASSERT(holder->HasNamedInterceptor()); |
| 693 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 692 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 694 | 693 |
| 695 // Check that the receiver isn't a smi. | 694 // Check that the receiver isn't a smi. |
| 696 __ test(receiver, Immediate(kSmiTagMask)); | 695 __ test(receiver, Immediate(kSmiTagMask)); |
| 697 __ j(zero, miss, not_taken); | 696 __ j(zero, miss, not_taken); |
| 698 | 697 |
| 699 CallOptimization optimization(lookup); | 698 CallOptimization optimization(lookup); |
| 700 | 699 |
| 701 if (optimization.is_constant_call() && | 700 if (optimization.is_constant_call()) { |
| 702 !Top::CanHaveSpecialFunctions(holder)) { | |
| 703 CompileCacheable(masm, | 701 CompileCacheable(masm, |
| 704 object, | 702 object, |
| 705 receiver, | 703 receiver, |
| 706 scratch1, | 704 scratch1, |
| 707 scratch2, | 705 scratch2, |
| 708 holder, | 706 holder, |
| 709 lookup, | 707 lookup, |
| 710 name, | 708 name, |
| 711 optimization, | 709 optimization, |
| 712 miss); | 710 miss); |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 // Handle call cache miss. | 1202 // Handle call cache miss. |
| 1205 __ bind(&miss); | 1203 __ bind(&miss); |
| 1206 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 1204 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1207 __ jmp(ic, RelocInfo::CODE_TARGET); | 1205 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 1208 | 1206 |
| 1209 // Return the generated code. | 1207 // Return the generated code. |
| 1210 return GetCode(FIELD, name); | 1208 return GetCode(FIELD, name); |
| 1211 } | 1209 } |
| 1212 | 1210 |
| 1213 | 1211 |
| 1212 Object* CallStubCompiler::CompileArrayPushCall(Object* object, |
| 1213 JSObject* holder, |
| 1214 JSFunction* function, |
| 1215 String* name, |
| 1216 CheckType check) { |
| 1217 // ----------- S t a t e ------------- |
| 1218 // -- ecx : name |
| 1219 // -- esp[0] : return address |
| 1220 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1221 // -- ... |
| 1222 // -- esp[(argc + 1) * 4] : receiver |
| 1223 // ----------------------------------- |
| 1224 ASSERT(check == RECEIVER_MAP_CHECK); |
| 1225 |
| 1226 Label miss; |
| 1227 |
| 1228 // Get the receiver from the stack. |
| 1229 const int argc = arguments().immediate(); |
| 1230 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1231 |
| 1232 // Check that the receiver isn't a smi. |
| 1233 __ test(edx, Immediate(kSmiTagMask)); |
| 1234 __ j(zero, &miss); |
| 1235 |
| 1236 CheckPrototypes(JSObject::cast(object), edx, |
| 1237 holder, ebx, |
| 1238 eax, name, &miss); |
| 1239 |
| 1240 if (argc == 0) { |
| 1241 // Noop, return the length. |
| 1242 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1243 __ ret((argc + 1) * kPointerSize); |
| 1244 } else { |
| 1245 // Get the elements array of the object. |
| 1246 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1247 |
| 1248 // Check that the elements are in fast mode (not dictionary). |
| 1249 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1250 Immediate(Factory::fixed_array_map())); |
| 1251 __ j(not_equal, &miss); |
| 1252 |
| 1253 if (argc == 1) { // Otherwise fall through to call builtin. |
| 1254 Label call_builtin, exit, with_rset_update, |
| 1255 attempt_to_grow_elements, finish_push; |
| 1256 |
| 1257 // Get the array's length into eax and calculate new length. |
| 1258 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1259 STATIC_ASSERT(kSmiTagSize == 1); |
| 1260 STATIC_ASSERT(kSmiTag == 0); |
| 1261 __ add(Operand(eax), Immediate(argc << 1)); |
| 1262 |
| 1263 // Get the element's length into ecx. |
| 1264 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); |
| 1265 __ SmiTag(ecx); |
| 1266 |
| 1267 // Check if we could survive without allocation. |
| 1268 __ cmp(eax, Operand(ecx)); |
| 1269 __ j(greater, &attempt_to_grow_elements); |
| 1270 |
| 1271 // Save new length. |
| 1272 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1273 |
| 1274 // Push the element. |
| 1275 __ lea(edx, FieldOperand(ebx, |
| 1276 eax, times_half_pointer_size, |
| 1277 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1278 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 1279 __ mov(Operand(edx, 0), ecx); |
| 1280 |
| 1281 __ bind(&finish_push); |
| 1282 |
| 1283 // Check if value is a smi. |
| 1284 __ test(ecx, Immediate(kSmiTagMask)); |
| 1285 __ j(not_zero, &with_rset_update); |
| 1286 |
| 1287 __ bind(&exit); |
| 1288 __ ret((argc + 1) * kPointerSize); |
| 1289 |
| 1290 __ bind(&with_rset_update); |
| 1291 |
| 1292 __ InNewSpace(ebx, ecx, equal, &exit); |
| 1293 |
| 1294 RecordWriteStub stub(ebx, edx, ecx); |
| 1295 __ CallStub(&stub); |
| 1296 __ ret((argc + 1) * kPointerSize); |
| 1297 |
| 1298 __ bind(&attempt_to_grow_elements); |
| 1299 ExternalReference new_space_allocation_top = |
| 1300 ExternalReference::new_space_allocation_top_address(); |
| 1301 ExternalReference new_space_allocation_limit = |
| 1302 ExternalReference::new_space_allocation_limit_address(); |
| 1303 |
| 1304 const int kAllocationDelta = 4; |
| 1305 // Load top. |
| 1306 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top)); |
| 1307 |
| 1308 // Check if it's the end of elements. |
| 1309 __ lea(edx, FieldOperand(ebx, |
| 1310 eax, times_half_pointer_size, |
| 1311 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1312 __ cmp(edx, Operand(ecx)); |
| 1313 __ j(not_equal, &call_builtin); |
| 1314 __ add(Operand(ecx), Immediate(kAllocationDelta * kPointerSize)); |
| 1315 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); |
| 1316 __ j(greater, &call_builtin); |
| 1317 |
| 1318 // We fit and could grow elements. |
| 1319 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); |
| 1320 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 1321 __ mov(Operand(edx, 0), ecx); |
| 1322 for (int i = 1; i < kAllocationDelta; i++) { |
| 1323 __ mov(Operand(edx, i * kPointerSize), |
| 1324 Immediate(Factory::undefined_value())); |
| 1325 } |
| 1326 |
| 1327 // Restore receiver to edx as finish sequence assumes it's here. |
| 1328 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1329 |
| 1330 // Increment element's and array's sizes. |
| 1331 __ add(FieldOperand(ebx, FixedArray::kLengthOffset), |
| 1332 Immediate(kAllocationDelta)); |
| 1333 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1334 |
| 1335 __ jmp(&finish_push); |
| 1336 |
| 1337 __ bind(&call_builtin); |
| 1338 } |
| 1339 |
| 1340 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), |
| 1341 argc + 1, |
| 1342 1); |
| 1343 } |
| 1344 |
| 1345 __ bind(&miss); |
| 1346 |
| 1347 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1348 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 1349 |
| 1350 // Return the generated code. |
| 1351 String* function_name = NULL; |
| 1352 if (function->shared()->name()->IsString()) { |
| 1353 function_name = String::cast(function->shared()->name()); |
| 1354 } |
| 1355 return GetCode(CONSTANT_FUNCTION, function_name); |
| 1356 } |
| 1357 |
| 1358 |
| 1359 Object* CallStubCompiler::CompileArrayPopCall(Object* object, |
| 1360 JSObject* holder, |
| 1361 JSFunction* function, |
| 1362 String* name, |
| 1363 CheckType check) { |
| 1364 // ----------- S t a t e ------------- |
| 1365 // -- ecx : name |
| 1366 // -- esp[0] : return address |
| 1367 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1368 // -- ... |
| 1369 // -- esp[(argc + 1) * 4] : receiver |
| 1370 // ----------------------------------- |
| 1371 ASSERT(check == RECEIVER_MAP_CHECK); |
| 1372 |
| 1373 Label miss, empty_array, call_builtin; |
| 1374 |
| 1375 // Get the receiver from the stack. |
| 1376 const int argc = arguments().immediate(); |
| 1377 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1378 |
| 1379 // Check that the receiver isn't a smi. |
| 1380 __ test(edx, Immediate(kSmiTagMask)); |
| 1381 __ j(zero, &miss); |
| 1382 |
| 1383 CheckPrototypes(JSObject::cast(object), edx, |
| 1384 holder, ebx, |
| 1385 eax, name, &miss); |
| 1386 |
| 1387 // Get the elements array of the object. |
| 1388 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1389 |
| 1390 // Check that the elements are in fast mode (not dictionary). |
| 1391 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1392 Immediate(Factory::fixed_array_map())); |
| 1393 __ j(not_equal, &miss); |
| 1394 |
| 1395 // Get the array's length into ecx and calculate new length. |
| 1396 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1397 __ sub(Operand(ecx), Immediate(Smi::FromInt(1))); |
| 1398 __ j(negative, &empty_array); |
| 1399 |
| 1400 // Get the last element. |
| 1401 STATIC_ASSERT(kSmiTagSize == 1); |
| 1402 STATIC_ASSERT(kSmiTag == 0); |
| 1403 __ mov(eax, FieldOperand(ebx, |
| 1404 ecx, times_half_pointer_size, |
| 1405 FixedArray::kHeaderSize)); |
| 1406 __ cmp(Operand(eax), Immediate(Factory::the_hole_value())); |
| 1407 __ j(equal, &call_builtin); |
| 1408 |
| 1409 // Set the array's length. |
| 1410 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); |
| 1411 |
| 1412 // Fill with the hole. |
| 1413 __ mov(FieldOperand(ebx, |
| 1414 ecx, times_half_pointer_size, |
| 1415 FixedArray::kHeaderSize), |
| 1416 Immediate(Factory::the_hole_value())); |
| 1417 __ ret((argc + 1) * kPointerSize); |
| 1418 |
| 1419 __ bind(&empty_array); |
| 1420 __ mov(eax, Immediate(Factory::undefined_value())); |
| 1421 __ ret((argc + 1) * kPointerSize); |
| 1422 |
| 1423 __ bind(&call_builtin); |
| 1424 |
| 1425 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), |
| 1426 argc + 1, |
| 1427 1); |
| 1428 |
| 1429 __ bind(&miss); |
| 1430 |
| 1431 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1432 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 1433 |
| 1434 // Return the generated code. |
| 1435 String* function_name = NULL; |
| 1436 if (function->shared()->name()->IsString()) { |
| 1437 function_name = String::cast(function->shared()->name()); |
| 1438 } |
| 1439 return GetCode(CONSTANT_FUNCTION, function_name); |
| 1440 } |
| 1441 |
| 1442 |
| 1214 Object* CallStubCompiler::CompileCallConstant(Object* object, | 1443 Object* CallStubCompiler::CompileCallConstant(Object* object, |
| 1215 JSObject* holder, | 1444 JSObject* holder, |
| 1216 JSFunction* function, | 1445 JSFunction* function, |
| 1217 String* name, | 1446 String* name, |
| 1218 CheckType check) { | 1447 CheckType check) { |
| 1219 // ----------- S t a t e ------------- | 1448 // ----------- S t a t e ------------- |
| 1220 // -- ecx : name | 1449 // -- ecx : name |
| 1221 // -- esp[0] : return address | 1450 // -- esp[0] : return address |
| 1222 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1451 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1223 // -- ... | 1452 // -- ... |
| 1224 // -- esp[(argc + 1) * 4] : receiver | 1453 // -- esp[(argc + 1) * 4] : receiver |
| 1225 // ----------------------------------- | 1454 // ----------------------------------- |
| 1455 |
| 1456 SharedFunctionInfo* function_info = function->shared(); |
| 1457 if (false && function_info->HasCustomCallGenerator()) { |
| 1458 CustomCallGenerator generator = |
| 1459 ToCData<CustomCallGenerator>(function_info->function_data()); |
| 1460 return generator(this, object, holder, function, name, check); |
| 1461 } |
| 1462 |
| 1226 Label miss_in_smi_check; | 1463 Label miss_in_smi_check; |
| 1227 | 1464 |
| 1228 // Get the receiver from the stack. | 1465 // Get the receiver from the stack. |
| 1229 const int argc = arguments().immediate(); | 1466 const int argc = arguments().immediate(); |
| 1230 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1467 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1231 | 1468 |
| 1232 // Check that the receiver isn't a smi. | 1469 // Check that the receiver isn't a smi. |
| 1233 if (check != NUMBER_CHECK) { | 1470 if (check != NUMBER_CHECK) { |
| 1234 __ test(edx, Immediate(kSmiTagMask)); | 1471 __ test(edx, Immediate(kSmiTagMask)); |
| 1235 __ j(zero, &miss_in_smi_check, not_taken); | 1472 __ j(zero, &miss_in_smi_check, not_taken); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1326 // Check that the maps starting from the prototype haven't changed. | 1563 // Check that the maps starting from the prototype haven't changed. |
| 1327 GenerateLoadGlobalFunctionPrototype(masm(), | 1564 GenerateLoadGlobalFunctionPrototype(masm(), |
| 1328 Context::BOOLEAN_FUNCTION_INDEX, | 1565 Context::BOOLEAN_FUNCTION_INDEX, |
| 1329 eax); | 1566 eax); |
| 1330 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 1567 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 1331 ebx, edx, name, &miss); | 1568 ebx, edx, name, &miss); |
| 1332 } | 1569 } |
| 1333 break; | 1570 break; |
| 1334 } | 1571 } |
| 1335 | 1572 |
| 1336 case JSARRAY_HAS_FAST_ELEMENTS_CHECK: | |
| 1337 CheckPrototypes(JSObject::cast(object), edx, holder, | |
| 1338 ebx, eax, name, &miss); | |
| 1339 // Make sure object->HasFastElements(). | |
| 1340 // Get the elements array of the object. | |
| 1341 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); | |
| 1342 // Check that the object is in fast mode (not dictionary). | |
| 1343 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | |
| 1344 Immediate(Factory::fixed_array_map())); | |
| 1345 __ j(not_equal, &miss, not_taken); | |
| 1346 break; | |
| 1347 | |
| 1348 default: | 1573 default: |
| 1349 UNREACHABLE(); | 1574 UNREACHABLE(); |
| 1350 } | 1575 } |
| 1351 | 1576 |
| 1352 if (depth != kInvalidProtoDepth) { | 1577 if (depth != kInvalidProtoDepth) { |
| 1353 GenerateFastApiCall(masm(), optimization, argc); | 1578 GenerateFastApiCall(masm(), optimization, argc); |
| 1354 } else { | 1579 } else { |
| 1355 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 1580 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); |
| 1356 } | 1581 } |
| 1357 | 1582 |
| (...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2199 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 2424 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 2200 | 2425 |
| 2201 // Return the generated code. | 2426 // Return the generated code. |
| 2202 return GetCode(); | 2427 return GetCode(); |
| 2203 } | 2428 } |
| 2204 | 2429 |
| 2205 | 2430 |
| 2206 #undef __ | 2431 #undef __ |
| 2207 | 2432 |
| 2208 } } // namespace v8::internal | 2433 } } // namespace v8::internal |
| OLD | NEW |