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 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 __ push(scratch1); | 490 __ push(scratch1); |
491 // Stack now matches JSFunction abi. | 491 // Stack now matches JSFunction abi. |
492 GenerateFastApiCallBody(masm, | 492 GenerateFastApiCallBody(masm, |
493 optimization, | 493 optimization, |
494 argc, | 494 argc, |
495 receiver, | 495 receiver, |
496 true); | 496 true); |
497 } | 497 } |
498 | 498 |
499 | 499 |
500 class CallInterceptorCompiler BASE_EMBEDDED { | |
501 public: | |
502 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | |
503 Register name) | |
504 : stub_compiler_(stub_compiler), | |
505 name_(name) {} | |
506 | |
507 void Compile(MacroAssembler* masm, | |
508 Handle<JSObject> object, | |
509 Handle<JSObject> holder, | |
510 Handle<Name> name, | |
511 LookupResult* lookup, | |
512 Register receiver, | |
513 Register scratch1, | |
514 Register scratch2, | |
515 Register scratch3, | |
516 Label* miss) { | |
517 ASSERT(holder->HasNamedInterceptor()); | |
518 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
519 | |
520 // Check that the receiver isn't a smi. | |
521 __ JumpIfSmi(receiver, miss); | |
522 | |
523 CallOptimization optimization(lookup); | |
524 if (optimization.is_constant_call()) { | |
525 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, | |
526 holder, lookup, name, optimization, miss); | |
527 } else { | |
528 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, | |
529 name, holder, miss); | |
530 } | |
531 } | |
532 | |
533 private: | |
534 void CompileCacheable(MacroAssembler* masm, | |
535 Handle<JSObject> object, | |
536 Register receiver, | |
537 Register scratch1, | |
538 Register scratch2, | |
539 Register scratch3, | |
540 Handle<JSObject> interceptor_holder, | |
541 LookupResult* lookup, | |
542 Handle<Name> name, | |
543 const CallOptimization& optimization, | |
544 Label* miss_label) { | |
545 ASSERT(optimization.is_constant_call()); | |
546 ASSERT(!lookup->holder()->IsGlobalObject()); | |
547 | |
548 Counters* counters = masm->isolate()->counters(); | |
549 __ IncrementCounter(counters->call_const_interceptor(), 1); | |
550 | |
551 // Check that the maps from receiver to interceptor's holder | |
552 // haven't changed and thus we can invoke interceptor. | |
553 Register holder = | |
554 stub_compiler_->CheckPrototypes( | |
555 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
556 interceptor_holder, scratch1, scratch2, scratch3, | |
557 name, miss_label); | |
558 | |
559 // Invoke an interceptor and if it provides a value, | |
560 // branch to |regular_invoke|. | |
561 Label regular_invoke; | |
562 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | |
563 ®ular_invoke); | |
564 | |
565 // Interceptor returned nothing for this property. Try to use cached | |
566 // constant function. | |
567 | |
568 // Check that the maps from interceptor's holder to constant function's | |
569 // holder haven't changed and thus we can use cached constant function. | |
570 if (*interceptor_holder != lookup->holder()) { | |
571 stub_compiler_->CheckPrototypes( | |
572 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | |
573 handle(lookup->holder()), scratch1, scratch2, scratch3, | |
574 name, miss_label); | |
575 } | |
576 | |
577 Handle<JSFunction> fun = optimization.constant_function(); | |
578 stub_compiler_->GenerateJumpFunction(object, fun); | |
579 | |
580 // Invoke a regular function. | |
581 __ bind(®ular_invoke); | |
582 } | |
583 | |
584 void CompileRegular(MacroAssembler* masm, | |
585 Handle<JSObject> object, | |
586 Register receiver, | |
587 Register scratch1, | |
588 Register scratch2, | |
589 Register scratch3, | |
590 Handle<Name> name, | |
591 Handle<JSObject> interceptor_holder, | |
592 Label* miss_label) { | |
593 Register holder = | |
594 stub_compiler_->CheckPrototypes( | |
595 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
596 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label); | |
597 | |
598 FrameScope scope(masm, StackFrame::INTERNAL); | |
599 // Save the name_ register across the call. | |
600 __ push(name_); | |
601 | |
602 CompileCallLoadPropertyWithInterceptor( | |
603 masm, receiver, holder, name_, interceptor_holder, | |
604 IC::kLoadPropertyWithInterceptorForCall); | |
605 | |
606 // Restore the name_ register. | |
607 __ pop(name_); | |
608 | |
609 // Leave the internal frame. | |
610 } | |
611 | |
612 void LoadWithInterceptor(MacroAssembler* masm, | |
613 Register receiver, | |
614 Register holder, | |
615 Handle<JSObject> holder_obj, | |
616 Label* interceptor_succeeded) { | |
617 { | |
618 FrameScope scope(masm, StackFrame::INTERNAL); | |
619 __ push(receiver); | |
620 __ push(holder); | |
621 __ push(name_); | |
622 | |
623 CompileCallLoadPropertyWithInterceptor( | |
624 masm, receiver, holder, name_, holder_obj, | |
625 IC::kLoadPropertyWithInterceptorOnly); | |
626 | |
627 __ pop(name_); | |
628 __ pop(holder); | |
629 __ pop(receiver); | |
630 // Leave the internal frame. | |
631 } | |
632 | |
633 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); | |
634 __ j(not_equal, interceptor_succeeded); | |
635 } | |
636 | |
637 CallStubCompiler* stub_compiler_; | |
638 Register name_; | |
639 }; | |
640 | |
641 | |
642 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, | 500 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, |
643 Label* label, | 501 Label* label, |
644 Handle<Name> name) { | 502 Handle<Name> name) { |
645 if (!label->is_unused()) { | 503 if (!label->is_unused()) { |
646 __ bind(label); | 504 __ bind(label); |
647 __ mov(this->name(), Immediate(name)); | 505 __ mov(this->name(), Immediate(name)); |
648 } | 506 } |
649 } | 507 } |
650 | 508 |
651 | 509 |
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1359 __ push(scratch2()); // restore old return address | 1217 __ push(scratch2()); // restore old return address |
1360 | 1218 |
1361 ExternalReference ref = | 1219 ExternalReference ref = |
1362 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1220 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
1363 isolate()); | 1221 isolate()); |
1364 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); | 1222 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); |
1365 } | 1223 } |
1366 } | 1224 } |
1367 | 1225 |
1368 | 1226 |
1369 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { | |
1370 if (kind_ == Code::KEYED_CALL_IC) { | |
1371 __ cmp(ecx, Immediate(name)); | |
1372 __ j(not_equal, miss); | |
1373 } | |
1374 } | |
1375 | |
1376 | |
1377 void CallStubCompiler::GenerateFunctionCheck(Register function, | |
1378 Register scratch, | |
1379 Label* miss) { | |
1380 __ JumpIfSmi(function, miss); | |
1381 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); | |
1382 __ j(not_equal, miss); | |
1383 } | |
1384 | |
1385 | |
1386 void CallStubCompiler::GenerateLoadFunctionFromCell( | |
1387 Handle<Cell> cell, | |
1388 Handle<JSFunction> function, | |
1389 Label* miss) { | |
1390 // Get the value from the cell. | |
1391 if (Serializer::enabled()) { | |
1392 __ mov(edi, Immediate(cell)); | |
1393 __ mov(edi, FieldOperand(edi, Cell::kValueOffset)); | |
1394 } else { | |
1395 __ mov(edi, Operand::ForCell(cell)); | |
1396 } | |
1397 | |
1398 // Check that the cell contains the same function. | |
1399 if (isolate()->heap()->InNewSpace(*function)) { | |
1400 // We can't embed a pointer to a function in new space so we have | |
1401 // to verify that the shared function info is unchanged. This has | |
1402 // the nice side effect that multiple closures based on the same | |
1403 // function can all use this call IC. Before we load through the | |
1404 // function, we have to verify that it still is a function. | |
1405 GenerateFunctionCheck(edi, ebx, miss); | |
1406 | |
1407 // Check the shared function info. Make sure it hasn't changed. | |
1408 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | |
1409 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | |
1410 } else { | |
1411 __ cmp(edi, Immediate(function)); | |
1412 } | |
1413 __ j(not_equal, miss); | |
1414 } | |
1415 | |
1416 | |
1417 void CallStubCompiler::GenerateMissBranch() { | |
1418 Handle<Code> code = | |
1419 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | |
1420 kind_, | |
1421 extra_state()); | |
1422 __ jmp(code, RelocInfo::CODE_TARGET); | |
1423 } | |
1424 | |
1425 | |
1426 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | |
1427 Handle<JSObject> holder, | |
1428 PropertyIndex index, | |
1429 Handle<Name> name) { | |
1430 Label miss; | |
1431 | |
1432 Register reg = HandlerFrontendHeader( | |
1433 object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
1434 | |
1435 GenerateFastPropertyLoad( | |
1436 masm(), edi, reg, index.is_inobject(holder), | |
1437 index.translate(holder), Representation::Tagged()); | |
1438 GenerateJumpFunction(object, edi, &miss); | |
1439 | |
1440 HandlerFrontendFooter(&miss); | |
1441 | |
1442 // Return the generated code. | |
1443 return GetCode(Code::FAST, name); | |
1444 } | |
1445 | |
1446 | |
1447 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1227 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
1448 Label success; | 1228 Label success; |
1449 // Check that the object is a boolean. | 1229 // Check that the object is a boolean. |
1450 __ cmp(object, factory()->true_value()); | 1230 __ cmp(object, factory()->true_value()); |
1451 __ j(equal, &success); | 1231 __ j(equal, &success); |
1452 __ cmp(object, factory()->false_value()); | 1232 __ cmp(object, factory()->false_value()); |
1453 __ j(not_equal, miss); | 1233 __ j(not_equal, miss); |
1454 __ bind(&success); | 1234 __ bind(&success); |
1455 } | 1235 } |
1456 | 1236 |
1457 | 1237 |
1458 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) { | |
1459 if (object->IsGlobalObject()) { | |
1460 const int argc = arguments().immediate(); | |
1461 const int receiver_offset = (argc + 1) * kPointerSize; | |
1462 __ mov(Operand(esp, receiver_offset), | |
1463 isolate()->factory()->undefined_value()); | |
1464 } | |
1465 } | |
1466 | |
1467 | |
1468 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, | |
1469 Handle<JSObject> holder, | |
1470 Handle<Name> name, | |
1471 CheckType check, | |
1472 Label* miss) { | |
1473 GenerateNameCheck(name, miss); | |
1474 | |
1475 Register reg = edx; | |
1476 | |
1477 const int argc = arguments().immediate(); | |
1478 const int receiver_offset = (argc + 1) * kPointerSize; | |
1479 __ mov(reg, Operand(esp, receiver_offset)); | |
1480 | |
1481 // Check that the receiver isn't a smi. | |
1482 if (check != NUMBER_CHECK) { | |
1483 __ JumpIfSmi(reg, miss); | |
1484 } | |
1485 | |
1486 // Make sure that it's okay not to patch the on stack receiver | |
1487 // unless we're doing a receiver map check. | |
1488 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | |
1489 switch (check) { | |
1490 case RECEIVER_MAP_CHECK: | |
1491 __ IncrementCounter(isolate()->counters()->call_const(), 1); | |
1492 | |
1493 // Check that the maps haven't changed. | |
1494 reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), reg, holder, | |
1495 ebx, eax, edi, name, miss); | |
1496 | |
1497 break; | |
1498 | |
1499 case STRING_CHECK: { | |
1500 // Check that the object is a string. | |
1501 __ CmpObjectType(reg, FIRST_NONSTRING_TYPE, eax); | |
1502 __ j(above_equal, miss); | |
1503 // Check that the maps starting from the prototype haven't changed. | |
1504 GenerateDirectLoadGlobalFunctionPrototype( | |
1505 masm(), Context::STRING_FUNCTION_INDEX, eax, miss); | |
1506 break; | |
1507 } | |
1508 case SYMBOL_CHECK: { | |
1509 // Check that the object is a symbol. | |
1510 __ CmpObjectType(reg, SYMBOL_TYPE, eax); | |
1511 __ j(not_equal, miss); | |
1512 // Check that the maps starting from the prototype haven't changed. | |
1513 GenerateDirectLoadGlobalFunctionPrototype( | |
1514 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, miss); | |
1515 break; | |
1516 } | |
1517 case NUMBER_CHECK: { | |
1518 Label fast; | |
1519 // Check that the object is a smi or a heap number. | |
1520 __ JumpIfSmi(reg, &fast); | |
1521 __ CmpObjectType(reg, HEAP_NUMBER_TYPE, eax); | |
1522 __ j(not_equal, miss); | |
1523 __ bind(&fast); | |
1524 // Check that the maps starting from the prototype haven't changed. | |
1525 GenerateDirectLoadGlobalFunctionPrototype( | |
1526 masm(), Context::NUMBER_FUNCTION_INDEX, eax, miss); | |
1527 break; | |
1528 } | |
1529 case BOOLEAN_CHECK: { | |
1530 GenerateBooleanCheck(reg, miss); | |
1531 // Check that the maps starting from the prototype haven't changed. | |
1532 GenerateDirectLoadGlobalFunctionPrototype( | |
1533 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, miss); | |
1534 break; | |
1535 } | |
1536 } | |
1537 | |
1538 if (check != RECEIVER_MAP_CHECK) { | |
1539 Handle<Object> prototype(object->GetPrototype(isolate()), isolate()); | |
1540 reg = CheckPrototypes( | |
1541 IC::CurrentTypeOf(prototype, isolate()), | |
1542 eax, holder, ebx, edx, edi, name, miss); | |
1543 } | |
1544 | |
1545 return reg; | |
1546 } | |
1547 | |
1548 | |
1549 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, | |
1550 Register function, | |
1551 Label* miss) { | |
1552 // Check that the function really is a function. | |
1553 GenerateFunctionCheck(function, ebx, miss); | |
1554 | |
1555 if (!function.is(edi)) __ mov(edi, function); | |
1556 PatchImplicitReceiver(object); | |
1557 | |
1558 // Invoke the function. | |
1559 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, NullCallWrapper()); | |
1560 } | |
1561 | |
1562 | |
1563 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, | |
1564 Handle<JSObject> holder, | |
1565 Handle<Name> name) { | |
1566 Label miss; | |
1567 | |
1568 GenerateNameCheck(name, &miss); | |
1569 | |
1570 // Get the number of arguments. | |
1571 const int argc = arguments().immediate(); | |
1572 | |
1573 LookupResult lookup(isolate()); | |
1574 LookupPostInterceptor(holder, name, &lookup); | |
1575 | |
1576 // Get the receiver from the stack. | |
1577 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1578 | |
1579 CallInterceptorCompiler compiler(this, ecx); | |
1580 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax, | |
1581 &miss); | |
1582 | |
1583 // Restore receiver. | |
1584 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1585 | |
1586 GenerateJumpFunction(object, eax, &miss); | |
1587 | |
1588 HandlerFrontendFooter(&miss); | |
1589 | |
1590 // Return the generated code. | |
1591 return GetCode(Code::FAST, name); | |
1592 } | |
1593 | |
1594 | |
1595 Handle<Code> CallStubCompiler::CompileCallGlobal( | |
1596 Handle<JSObject> object, | |
1597 Handle<GlobalObject> holder, | |
1598 Handle<PropertyCell> cell, | |
1599 Handle<JSFunction> function, | |
1600 Handle<Name> name) { | |
1601 Label miss; | |
1602 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
1603 // Potentially loads a closure that matches the shared function info of the | |
1604 // function, rather than function. | |
1605 GenerateLoadFunctionFromCell(cell, function, &miss); | |
1606 GenerateJumpFunction(object, edi, function); | |
1607 | |
1608 HandlerFrontendFooter(&miss); | |
1609 | |
1610 // Return the generated code. | |
1611 return GetCode(Code::NORMAL, name); | |
1612 } | |
1613 | |
1614 | |
1615 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1238 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
1616 Handle<JSObject> object, | 1239 Handle<JSObject> object, |
1617 Handle<JSObject> holder, | 1240 Handle<JSObject> holder, |
1618 Handle<Name> name, | 1241 Handle<Name> name, |
1619 Handle<ExecutableAccessorInfo> callback) { | 1242 Handle<ExecutableAccessorInfo> callback) { |
1620 Register holder_reg = HandlerFrontend( | 1243 Register holder_reg = HandlerFrontend( |
1621 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); | 1244 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
1622 | 1245 |
1623 __ pop(scratch1()); // remove the return address | 1246 __ pop(scratch1()); // remove the return address |
1624 __ push(receiver()); | 1247 __ push(receiver()); |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1846 | 1469 |
1847 // Check for deleted property if property can actually be deleted. | 1470 // Check for deleted property if property can actually be deleted. |
1848 if (!is_dont_delete) { | 1471 if (!is_dont_delete) { |
1849 __ cmp(eax, factory()->the_hole_value()); | 1472 __ cmp(eax, factory()->the_hole_value()); |
1850 __ j(equal, &miss); | 1473 __ j(equal, &miss); |
1851 } else if (FLAG_debug_code) { | 1474 } else if (FLAG_debug_code) { |
1852 __ cmp(eax, factory()->the_hole_value()); | 1475 __ cmp(eax, factory()->the_hole_value()); |
1853 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); | 1476 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); |
1854 } | 1477 } |
1855 | 1478 |
1856 HandlerFrontendFooter(name, &miss); | |
1857 | |
1858 Counters* counters = isolate()->counters(); | 1479 Counters* counters = isolate()->counters(); |
1859 __ IncrementCounter(counters->named_load_global_stub(), 1); | 1480 __ IncrementCounter(counters->named_load_global_stub(), 1); |
1860 // The code above already loads the result into the return register. | 1481 // The code above already loads the result into the return register. |
1861 __ ret(0); | 1482 __ ret(0); |
1862 | 1483 |
| 1484 HandlerFrontendFooter(name, &miss); |
| 1485 |
1863 // Return the generated code. | 1486 // Return the generated code. |
1864 return GetCode(kind(), Code::NORMAL, name); | 1487 return GetCode(kind(), Code::NORMAL, name); |
1865 } | 1488 } |
1866 | 1489 |
1867 | 1490 |
1868 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 1491 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
1869 TypeHandleList* types, | 1492 TypeHandleList* types, |
1870 CodeHandleList* handlers, | 1493 CodeHandleList* handlers, |
1871 Handle<Name> name, | 1494 Handle<Name> name, |
1872 Code::StubType type, | 1495 Code::StubType type, |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1958 // ----------------------------------- | 1581 // ----------------------------------- |
1959 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1582 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
1960 } | 1583 } |
1961 | 1584 |
1962 | 1585 |
1963 #undef __ | 1586 #undef __ |
1964 | 1587 |
1965 } } // namespace v8::internal | 1588 } } // namespace v8::internal |
1966 | 1589 |
1967 #endif // V8_TARGET_ARCH_IA32 | 1590 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |