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 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 __ PushReturnAddressFrom(scratch1); | 461 __ PushReturnAddressFrom(scratch1); |
462 // Stack now matches JSFunction abi. | 462 // Stack now matches JSFunction abi. |
463 GenerateFastApiCallBody(masm, | 463 GenerateFastApiCallBody(masm, |
464 optimization, | 464 optimization, |
465 argc, | 465 argc, |
466 receiver, | 466 receiver, |
467 true); | 467 true); |
468 } | 468 } |
469 | 469 |
470 | 470 |
471 class CallInterceptorCompiler BASE_EMBEDDED { | |
472 public: | |
473 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | |
474 Register name) | |
475 : stub_compiler_(stub_compiler), | |
476 name_(name) {} | |
477 | |
478 void Compile(MacroAssembler* masm, | |
479 Handle<JSObject> object, | |
480 Handle<JSObject> holder, | |
481 Handle<Name> name, | |
482 LookupResult* lookup, | |
483 Register receiver, | |
484 Register scratch1, | |
485 Register scratch2, | |
486 Register scratch3, | |
487 Label* miss) { | |
488 ASSERT(holder->HasNamedInterceptor()); | |
489 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
490 | |
491 // Check that the receiver isn't a smi. | |
492 __ JumpIfSmi(receiver, miss); | |
493 | |
494 CallOptimization optimization(lookup); | |
495 if (optimization.is_constant_call()) { | |
496 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, | |
497 holder, lookup, name, optimization, miss); | |
498 } else { | |
499 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, | |
500 name, holder, miss); | |
501 } | |
502 } | |
503 | |
504 private: | |
505 void CompileCacheable(MacroAssembler* masm, | |
506 Handle<JSObject> object, | |
507 Register receiver, | |
508 Register scratch1, | |
509 Register scratch2, | |
510 Register scratch3, | |
511 Handle<JSObject> interceptor_holder, | |
512 LookupResult* lookup, | |
513 Handle<Name> name, | |
514 const CallOptimization& optimization, | |
515 Label* miss_label) { | |
516 ASSERT(optimization.is_constant_call()); | |
517 ASSERT(!lookup->holder()->IsGlobalObject()); | |
518 | |
519 Counters* counters = masm->isolate()->counters(); | |
520 __ IncrementCounter(counters->call_const_interceptor(), 1); | |
521 | |
522 // Check that the maps from receiver to interceptor's holder | |
523 // haven't changed and thus we can invoke interceptor. | |
524 Label miss_cleanup; | |
525 Register holder = | |
526 stub_compiler_->CheckPrototypes( | |
527 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
528 interceptor_holder, scratch1, scratch2, scratch3, | |
529 name, miss_label); | |
530 | |
531 // Invoke an interceptor and if it provides a value, | |
532 // branch to |regular_invoke|. | |
533 Label regular_invoke; | |
534 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | |
535 ®ular_invoke); | |
536 | |
537 // Interceptor returned nothing for this property. Try to use cached | |
538 // constant function. | |
539 | |
540 // Check that the maps from interceptor's holder to constant function's | |
541 // holder haven't changed and thus we can use cached constant function. | |
542 if (*interceptor_holder != lookup->holder()) { | |
543 stub_compiler_->CheckPrototypes( | |
544 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | |
545 handle(lookup->holder()), scratch1, scratch2, scratch3, | |
546 name, miss_label); | |
547 } | |
548 | |
549 Handle<JSFunction> fun = optimization.constant_function(); | |
550 stub_compiler_->GenerateJumpFunction(object, fun); | |
551 | |
552 // Invoke a regular function. | |
553 __ bind(®ular_invoke); | |
554 } | |
555 | |
556 void CompileRegular(MacroAssembler* masm, | |
557 Handle<JSObject> object, | |
558 Register receiver, | |
559 Register scratch1, | |
560 Register scratch2, | |
561 Register scratch3, | |
562 Handle<Name> name, | |
563 Handle<JSObject> interceptor_holder, | |
564 Label* miss_label) { | |
565 Register holder = | |
566 stub_compiler_->CheckPrototypes( | |
567 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
568 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label); | |
569 | |
570 FrameScope scope(masm, StackFrame::INTERNAL); | |
571 // Save the name_ register across the call. | |
572 __ push(name_); | |
573 | |
574 CompileCallLoadPropertyWithInterceptor( | |
575 masm, receiver, holder, name_, interceptor_holder, | |
576 IC::kLoadPropertyWithInterceptorForCall); | |
577 | |
578 // Restore the name_ register. | |
579 __ pop(name_); | |
580 | |
581 // Leave the internal frame. | |
582 } | |
583 | |
584 void LoadWithInterceptor(MacroAssembler* masm, | |
585 Register receiver, | |
586 Register holder, | |
587 Handle<JSObject> holder_obj, | |
588 Label* interceptor_succeeded) { | |
589 { | |
590 FrameScope scope(masm, StackFrame::INTERNAL); | |
591 __ push(receiver); | |
592 __ push(holder); | |
593 __ push(name_); | |
594 | |
595 CompileCallLoadPropertyWithInterceptor( | |
596 masm, receiver, holder, name_, holder_obj, | |
597 IC::kLoadPropertyWithInterceptorOnly); | |
598 | |
599 __ pop(name_); | |
600 __ pop(holder); | |
601 __ pop(receiver); | |
602 // Leave the internal frame. | |
603 } | |
604 | |
605 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); | |
606 __ j(not_equal, interceptor_succeeded); | |
607 } | |
608 | |
609 CallStubCompiler* stub_compiler_; | |
610 Register name_; | |
611 }; | |
612 | |
613 | |
614 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, | 471 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, |
615 Label* label, | 472 Label* label, |
616 Handle<Name> name) { | 473 Handle<Name> name) { |
617 if (!label->is_unused()) { | 474 if (!label->is_unused()) { |
618 __ bind(label); | 475 __ bind(label); |
619 __ Move(this->name(), name); | 476 __ Move(this->name(), name); |
620 } | 477 } |
621 } | 478 } |
622 | 479 |
623 | 480 |
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1254 this->name(), interceptor_holder); | 1111 this->name(), interceptor_holder); |
1255 __ PushReturnAddressFrom(scratch2()); | 1112 __ PushReturnAddressFrom(scratch2()); |
1256 | 1113 |
1257 ExternalReference ref = ExternalReference( | 1114 ExternalReference ref = ExternalReference( |
1258 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); | 1115 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); |
1259 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); | 1116 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); |
1260 } | 1117 } |
1261 } | 1118 } |
1262 | 1119 |
1263 | 1120 |
1264 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { | |
1265 if (kind_ == Code::KEYED_CALL_IC) { | |
1266 __ Cmp(rcx, name); | |
1267 __ j(not_equal, miss); | |
1268 } | |
1269 } | |
1270 | |
1271 | |
1272 void CallStubCompiler::GenerateFunctionCheck(Register function, | |
1273 Register scratch, | |
1274 Label* miss) { | |
1275 __ JumpIfSmi(function, miss); | |
1276 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); | |
1277 __ j(not_equal, miss); | |
1278 } | |
1279 | |
1280 | |
1281 void CallStubCompiler::GenerateLoadFunctionFromCell( | |
1282 Handle<Cell> cell, | |
1283 Handle<JSFunction> function, | |
1284 Label* miss) { | |
1285 // Get the value from the cell. | |
1286 __ Move(rdi, cell); | |
1287 __ movp(rdi, FieldOperand(rdi, Cell::kValueOffset)); | |
1288 | |
1289 // Check that the cell contains the same function. | |
1290 if (heap()->InNewSpace(*function)) { | |
1291 // We can't embed a pointer to a function in new space so we have | |
1292 // to verify that the shared function info is unchanged. This has | |
1293 // the nice side effect that multiple closures based on the same | |
1294 // function can all use this call IC. Before we load through the | |
1295 // function, we have to verify that it still is a function. | |
1296 GenerateFunctionCheck(rdi, rax, miss); | |
1297 | |
1298 // Check the shared function info. Make sure it hasn't changed. | |
1299 __ Move(rax, Handle<SharedFunctionInfo>(function->shared())); | |
1300 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax); | |
1301 } else { | |
1302 __ Cmp(rdi, function); | |
1303 } | |
1304 __ j(not_equal, miss); | |
1305 } | |
1306 | |
1307 | |
1308 void CallStubCompiler::GenerateMissBranch() { | |
1309 Handle<Code> code = | |
1310 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | |
1311 kind_, | |
1312 extra_state()); | |
1313 __ Jump(code, RelocInfo::CODE_TARGET); | |
1314 } | |
1315 | |
1316 | |
1317 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | |
1318 Handle<JSObject> holder, | |
1319 PropertyIndex index, | |
1320 Handle<Name> name) { | |
1321 Label miss; | |
1322 | |
1323 Register reg = HandlerFrontendHeader( | |
1324 object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
1325 | |
1326 GenerateFastPropertyLoad(masm(), rdi, reg, index.is_inobject(holder), | |
1327 index.translate(holder), Representation::Tagged()); | |
1328 GenerateJumpFunction(object, rdi, &miss); | |
1329 | |
1330 HandlerFrontendFooter(&miss); | |
1331 | |
1332 // Return the generated code. | |
1333 return GetCode(Code::FAST, name); | |
1334 } | |
1335 | |
1336 | |
1337 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1121 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
1338 Label success; | 1122 Label success; |
1339 // Check that the object is a boolean. | 1123 // Check that the object is a boolean. |
1340 __ CompareRoot(object, Heap::kTrueValueRootIndex); | 1124 __ Cmp(object, factory()->true_value()); |
1341 __ j(equal, &success); | 1125 __ j(equal, &success); |
1342 __ CompareRoot(object, Heap::kFalseValueRootIndex); | 1126 __ Cmp(object, factory()->false_value()); |
1343 __ j(not_equal, miss); | 1127 __ j(not_equal, miss); |
1344 __ bind(&success); | 1128 __ bind(&success); |
1345 } | 1129 } |
1346 | 1130 |
1347 | 1131 |
1348 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) { | |
1349 if (object->IsGlobalObject()) { | |
1350 StackArgumentsAccessor args(rsp, arguments()); | |
1351 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | |
1352 __ movp(args.GetReceiverOperand(), rdx); | |
1353 } | |
1354 } | |
1355 | |
1356 | |
1357 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, | |
1358 Handle<JSObject> holder, | |
1359 Handle<Name> name, | |
1360 CheckType check, | |
1361 Label* miss) { | |
1362 GenerateNameCheck(name, miss); | |
1363 | |
1364 Register reg = rdx; | |
1365 | |
1366 StackArgumentsAccessor args(rsp, arguments()); | |
1367 __ movp(reg, args.GetReceiverOperand()); | |
1368 | |
1369 // Check that the receiver isn't a smi. | |
1370 if (check != NUMBER_CHECK) { | |
1371 __ JumpIfSmi(reg, miss); | |
1372 } | |
1373 | |
1374 // Make sure that it's okay not to patch the on stack receiver | |
1375 // unless we're doing a receiver map check. | |
1376 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | |
1377 | |
1378 Counters* counters = isolate()->counters(); | |
1379 switch (check) { | |
1380 case RECEIVER_MAP_CHECK: | |
1381 __ IncrementCounter(counters->call_const(), 1); | |
1382 | |
1383 // Check that the maps haven't changed. | |
1384 reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), reg, holder, | |
1385 rbx, rax, rdi, name, miss); | |
1386 break; | |
1387 | |
1388 case STRING_CHECK: { | |
1389 // Check that the object is a string. | |
1390 __ CmpObjectType(reg, FIRST_NONSTRING_TYPE, rax); | |
1391 __ j(above_equal, miss); | |
1392 // Check that the maps starting from the prototype haven't changed. | |
1393 GenerateDirectLoadGlobalFunctionPrototype( | |
1394 masm(), Context::STRING_FUNCTION_INDEX, rax, miss); | |
1395 break; | |
1396 } | |
1397 case SYMBOL_CHECK: { | |
1398 // Check that the object is a symbol. | |
1399 __ CmpObjectType(reg, SYMBOL_TYPE, rax); | |
1400 __ j(not_equal, miss); | |
1401 // Check that the maps starting from the prototype haven't changed. | |
1402 GenerateDirectLoadGlobalFunctionPrototype( | |
1403 masm(), Context::SYMBOL_FUNCTION_INDEX, rax, miss); | |
1404 break; | |
1405 } | |
1406 case NUMBER_CHECK: { | |
1407 Label fast; | |
1408 // Check that the object is a smi or a heap number. | |
1409 __ JumpIfSmi(reg, &fast); | |
1410 __ CmpObjectType(reg, HEAP_NUMBER_TYPE, rax); | |
1411 __ j(not_equal, miss); | |
1412 __ bind(&fast); | |
1413 // Check that the maps starting from the prototype haven't changed. | |
1414 GenerateDirectLoadGlobalFunctionPrototype( | |
1415 masm(), Context::NUMBER_FUNCTION_INDEX, rax, miss); | |
1416 break; | |
1417 } | |
1418 case BOOLEAN_CHECK: { | |
1419 GenerateBooleanCheck(reg, miss); | |
1420 // Check that the maps starting from the prototype haven't changed. | |
1421 GenerateDirectLoadGlobalFunctionPrototype( | |
1422 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, miss); | |
1423 break; | |
1424 } | |
1425 } | |
1426 | |
1427 if (check != RECEIVER_MAP_CHECK) { | |
1428 Handle<Object> prototype(object->GetPrototype(isolate()), isolate()); | |
1429 reg = CheckPrototypes( | |
1430 IC::CurrentTypeOf(prototype, isolate()), | |
1431 rax, holder, rbx, rdx, rdi, name, miss); | |
1432 } | |
1433 | |
1434 return reg; | |
1435 } | |
1436 | |
1437 | |
1438 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, | |
1439 Register function, | |
1440 Label* miss) { | |
1441 // Check that the function really is a function. | |
1442 GenerateFunctionCheck(function, rbx, miss); | |
1443 | |
1444 if (!function.is(rdi)) __ movp(rdi, function); | |
1445 PatchImplicitReceiver(object); | |
1446 | |
1447 // Invoke the function. | |
1448 __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, NullCallWrapper()); | |
1449 } | |
1450 | |
1451 | |
1452 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, | |
1453 Handle<JSObject> holder, | |
1454 Handle<Name> name) { | |
1455 Label miss; | |
1456 GenerateNameCheck(name, &miss); | |
1457 | |
1458 LookupResult lookup(isolate()); | |
1459 LookupPostInterceptor(holder, name, &lookup); | |
1460 | |
1461 // Get the receiver from the stack. | |
1462 StackArgumentsAccessor args(rsp, arguments()); | |
1463 __ movp(rdx, args.GetReceiverOperand()); | |
1464 | |
1465 CallInterceptorCompiler compiler(this, rcx); | |
1466 compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax, | |
1467 &miss); | |
1468 | |
1469 // Restore receiver. | |
1470 __ movp(rdx, args.GetReceiverOperand()); | |
1471 | |
1472 GenerateJumpFunction(object, rax, &miss); | |
1473 | |
1474 HandlerFrontendFooter(&miss); | |
1475 | |
1476 // Return the generated code. | |
1477 return GetCode(Code::FAST, name); | |
1478 } | |
1479 | |
1480 | |
1481 Handle<Code> CallStubCompiler::CompileCallGlobal( | |
1482 Handle<JSObject> object, | |
1483 Handle<GlobalObject> holder, | |
1484 Handle<PropertyCell> cell, | |
1485 Handle<JSFunction> function, | |
1486 Handle<Name> name) { | |
1487 Label miss; | |
1488 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
1489 // Potentially loads a closure that matches the shared function info of the | |
1490 // function, rather than function. | |
1491 GenerateLoadFunctionFromCell(cell, function, &miss); | |
1492 Counters* counters = isolate()->counters(); | |
1493 __ IncrementCounter(counters->call_global_inline(), 1); | |
1494 GenerateJumpFunction(object, rdi, function); | |
1495 HandlerFrontendFooter(&miss); | |
1496 | |
1497 // Return the generated code. | |
1498 return GetCode(Code::NORMAL, name); | |
1499 } | |
1500 | |
1501 | |
1502 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1132 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
1503 Handle<JSObject> object, | 1133 Handle<JSObject> object, |
1504 Handle<JSObject> holder, | 1134 Handle<JSObject> holder, |
1505 Handle<Name> name, | 1135 Handle<Name> name, |
1506 Handle<ExecutableAccessorInfo> callback) { | 1136 Handle<ExecutableAccessorInfo> callback) { |
1507 Register holder_reg = HandlerFrontend( | 1137 Register holder_reg = HandlerFrontend( |
1508 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); | 1138 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
1509 | 1139 |
1510 __ PopReturnAddressTo(scratch1()); | 1140 __ PopReturnAddressTo(scratch1()); |
1511 __ push(receiver()); | 1141 __ push(receiver()); |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1744 | 1374 |
1745 // Check for deleted property if property can actually be deleted. | 1375 // Check for deleted property if property can actually be deleted. |
1746 if (!is_dont_delete) { | 1376 if (!is_dont_delete) { |
1747 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 1377 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); |
1748 __ j(equal, &miss); | 1378 __ j(equal, &miss); |
1749 } else if (FLAG_debug_code) { | 1379 } else if (FLAG_debug_code) { |
1750 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 1380 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); |
1751 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); | 1381 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); |
1752 } | 1382 } |
1753 | 1383 |
1754 HandlerFrontendFooter(name, &miss); | |
1755 | |
1756 Counters* counters = isolate()->counters(); | 1384 Counters* counters = isolate()->counters(); |
1757 __ IncrementCounter(counters->named_load_global_stub(), 1); | 1385 __ IncrementCounter(counters->named_load_global_stub(), 1); |
1758 __ movp(rax, rbx); | 1386 __ movp(rax, rbx); |
1759 __ ret(0); | 1387 __ ret(0); |
1760 | 1388 |
| 1389 HandlerFrontendFooter(name, &miss); |
| 1390 |
1761 // Return the generated code. | 1391 // Return the generated code. |
1762 return GetCode(kind(), Code::NORMAL, name); | 1392 return GetCode(kind(), Code::NORMAL, name); |
1763 } | 1393 } |
1764 | 1394 |
1765 | 1395 |
1766 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 1396 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
1767 TypeHandleList* types, | 1397 TypeHandleList* types, |
1768 CodeHandleList* handlers, | 1398 CodeHandleList* handlers, |
1769 Handle<Name> name, | 1399 Handle<Name> name, |
1770 Code::StubType type, | 1400 Code::StubType type, |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1855 // ----------------------------------- | 1485 // ----------------------------------- |
1856 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1486 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
1857 } | 1487 } |
1858 | 1488 |
1859 | 1489 |
1860 #undef __ | 1490 #undef __ |
1861 | 1491 |
1862 } } // namespace v8::internal | 1492 } } // namespace v8::internal |
1863 | 1493 |
1864 #endif // V8_TARGET_ARCH_X64 | 1494 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |