OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 class LoadInterceptorCompiler BASE_EMBEDDED { | 423 class LoadInterceptorCompiler BASE_EMBEDDED { |
424 public: | 424 public: |
425 explicit LoadInterceptorCompiler(Register name) : name_(name) {} | 425 explicit LoadInterceptorCompiler(Register name) : name_(name) {} |
426 | 426 |
427 void CompileCacheable(MacroAssembler* masm, | 427 void CompileCacheable(MacroAssembler* masm, |
428 StubCompiler* stub_compiler, | 428 StubCompiler* stub_compiler, |
429 Register receiver, | 429 Register receiver, |
430 Register holder, | 430 Register holder, |
431 Register scratch1, | 431 Register scratch1, |
432 Register scratch2, | 432 Register scratch2, |
433 JSObject* holder_obj, | 433 JSObject* interceptor_holder, |
434 LookupResult* lookup, | 434 LookupResult* lookup, |
435 String* name, | 435 String* name, |
436 Label* miss_label) { | 436 Label* miss_label) { |
437 AccessorInfo* callback = NULL; | 437 AccessorInfo* callback = NULL; |
438 bool optimize = false; | 438 bool optimize = false; |
439 // So far the most popular follow ups for interceptor loads are FIELD | 439 // So far the most popular follow ups for interceptor loads are FIELD |
440 // and CALLBACKS, so inline only them, other cases may be added | 440 // and CALLBACKS, so inline only them, other cases may be added |
441 // later. | 441 // later. |
442 if (lookup->type() == FIELD) { | 442 if (lookup->type() == FIELD) { |
443 optimize = true; | 443 optimize = true; |
444 } else if (lookup->type() == CALLBACKS) { | 444 } else if (lookup->type() == CALLBACKS) { |
445 Object* callback_object = lookup->GetCallbackObject(); | 445 Object* callback_object = lookup->GetCallbackObject(); |
446 if (callback_object->IsAccessorInfo()) { | 446 if (callback_object->IsAccessorInfo()) { |
447 callback = AccessorInfo::cast(callback_object); | 447 callback = AccessorInfo::cast(callback_object); |
448 optimize = callback->getter() != NULL; | 448 optimize = callback->getter() != NULL; |
449 } | 449 } |
450 } | 450 } |
451 | 451 |
452 if (!optimize) { | 452 if (!optimize) { |
453 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 453 CompileRegular(masm, receiver, holder, scratch2, interceptor_holder, |
| 454 miss_label); |
454 return; | 455 return; |
455 } | 456 } |
456 | 457 |
457 // Note: starting a frame here makes GC aware of pointers pushed below. | 458 // Note: starting a frame here makes GC aware of pointers pushed below. |
458 __ EnterInternalFrame(); | 459 __ EnterInternalFrame(); |
459 | 460 |
460 if (lookup->type() == CALLBACKS) { | 461 if (lookup->type() == CALLBACKS) { |
461 __ push(receiver); | 462 __ push(receiver); |
462 } | 463 } |
463 __ push(holder); | 464 __ push(holder); |
464 __ push(name_); | 465 __ push(name_); |
465 | 466 |
| 467 // Invoke an interceptor. Note: map checks from receiver to |
| 468 // interceptor's holder has been compiled before (see a caller |
| 469 // of this method.) |
466 CompileCallLoadPropertyWithInterceptor(masm, | 470 CompileCallLoadPropertyWithInterceptor(masm, |
467 receiver, | 471 receiver, |
468 holder, | 472 holder, |
469 name_, | 473 name_, |
470 holder_obj); | 474 interceptor_holder); |
471 | 475 |
| 476 // Check if interceptor provided a value for property. If it's |
| 477 // the case, return immediately. |
472 Label interceptor_failed; | 478 Label interceptor_failed; |
473 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); | 479 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
474 __ j(equal, &interceptor_failed); | 480 __ j(equal, &interceptor_failed); |
475 __ LeaveInternalFrame(); | 481 __ LeaveInternalFrame(); |
476 __ ret(0); | 482 __ ret(0); |
477 | 483 |
478 __ bind(&interceptor_failed); | 484 __ bind(&interceptor_failed); |
479 __ pop(name_); | 485 __ pop(name_); |
480 __ pop(holder); | 486 __ pop(holder); |
481 if (lookup->type() == CALLBACKS) { | 487 if (lookup->type() == CALLBACKS) { |
482 __ pop(receiver); | 488 __ pop(receiver); |
483 } | 489 } |
484 | 490 |
485 __ LeaveInternalFrame(); | 491 __ LeaveInternalFrame(); |
486 | 492 |
487 if (lookup->type() == FIELD) { | 493 if (lookup->type() == FIELD) { |
488 holder = stub_compiler->CheckPrototypes(holder_obj, | 494 // We found FIELD property in prototype chain of interceptor's holder. |
| 495 // Check that the maps from interceptor's holder to field's holder |
| 496 // haven't changed... |
| 497 holder = stub_compiler->CheckPrototypes(interceptor_holder, |
489 holder, | 498 holder, |
490 lookup->holder(), | 499 lookup->holder(), |
491 scratch1, | 500 scratch1, |
492 scratch2, | 501 scratch2, |
493 name, | 502 name, |
494 miss_label); | 503 miss_label); |
| 504 // ... and retrieve a field from field's holder. |
495 stub_compiler->GenerateFastPropertyLoad(masm, | 505 stub_compiler->GenerateFastPropertyLoad(masm, |
496 rax, | 506 rax, |
497 holder, | 507 holder, |
498 lookup->holder(), | 508 lookup->holder(), |
499 lookup->GetFieldIndex()); | 509 lookup->GetFieldIndex()); |
500 __ ret(0); | 510 __ ret(0); |
501 } else { | 511 } else { |
| 512 // We found CALLBACKS property in prototype chain of interceptor's |
| 513 // holder. |
502 ASSERT(lookup->type() == CALLBACKS); | 514 ASSERT(lookup->type() == CALLBACKS); |
503 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); | 515 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); |
504 ASSERT(callback != NULL); | 516 ASSERT(callback != NULL); |
505 ASSERT(callback->getter() != NULL); | 517 ASSERT(callback->getter() != NULL); |
506 | 518 |
| 519 // Prepare for tail call. Push receiver to stack after return address. |
507 Label cleanup; | 520 Label cleanup; |
508 __ pop(scratch2); | 521 __ pop(scratch2); // return address |
509 __ push(receiver); | 522 __ push(receiver); |
510 __ push(scratch2); | 523 __ push(scratch2); |
511 | 524 |
512 holder = stub_compiler->CheckPrototypes(holder_obj, holder, | 525 // Check that the maps from interceptor's holder to callback's holder |
| 526 // haven't changed. |
| 527 holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, |
513 lookup->holder(), scratch1, | 528 lookup->holder(), scratch1, |
514 scratch2, | 529 scratch2, |
515 name, | 530 name, |
516 &cleanup); | 531 &cleanup); |
517 | 532 |
518 __ pop(scratch2); // save old return address | 533 // Continue tail call preparation: push remaining parameters after |
| 534 // return address. |
| 535 __ pop(scratch2); // return address |
519 __ push(holder); | 536 __ push(holder); |
520 __ Move(holder, Handle<AccessorInfo>(callback)); | 537 __ Move(holder, Handle<AccessorInfo>(callback)); |
521 __ push(holder); | 538 __ push(holder); |
522 __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); | 539 __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); |
523 __ push(name_); | 540 __ push(name_); |
524 __ push(scratch2); // restore old return address | 541 __ push(scratch2); // restore return address |
525 | 542 |
| 543 // Tail call to runtime. |
526 ExternalReference ref = | 544 ExternalReference ref = |
527 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); | 545 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
528 __ TailCallExternalReference(ref, 5, 1); | 546 __ TailCallExternalReference(ref, 5, 1); |
529 | 547 |
| 548 // Clean up code: we pushed receiver after return address and |
| 549 // need to remove it from there. |
530 __ bind(&cleanup); | 550 __ bind(&cleanup); |
531 __ pop(scratch1); | 551 __ pop(scratch1); // return address |
532 __ pop(scratch2); | 552 __ pop(scratch2); // receiver |
533 __ push(scratch1); | 553 __ push(scratch1); |
534 } | 554 } |
535 } | 555 } |
536 | 556 |
537 | 557 |
538 void CompileRegular(MacroAssembler* masm, | 558 void CompileRegular(MacroAssembler* masm, |
539 Register receiver, | 559 Register receiver, |
540 Register holder, | 560 Register holder, |
541 Register scratch, | 561 Register scratch, |
542 JSObject* holder_obj, | 562 JSObject* interceptor_holder, |
543 Label* miss_label) { | 563 Label* miss_label) { |
544 __ pop(scratch); // save old return address | 564 __ pop(scratch); // save old return address |
545 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); | 565 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); |
546 __ push(scratch); // restore old return address | 566 __ push(scratch); // restore old return address |
547 | 567 |
548 ExternalReference ref = ExternalReference( | 568 ExternalReference ref = ExternalReference( |
549 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | 569 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
550 __ TailCallExternalReference(ref, 5, 1); | 570 __ TailCallExternalReference(ref, 5, 1); |
551 } | 571 } |
552 | 572 |
553 private: | 573 private: |
554 Register name_; | 574 Register name_; |
555 }; | 575 }; |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
697 miss); | 717 miss); |
698 } | 718 } |
699 } | 719 } |
700 | 720 |
701 private: | 721 private: |
702 void CompileCacheable(MacroAssembler* masm, | 722 void CompileCacheable(MacroAssembler* masm, |
703 JSObject* object, | 723 JSObject* object, |
704 Register receiver, | 724 Register receiver, |
705 Register scratch1, | 725 Register scratch1, |
706 Register scratch2, | 726 Register scratch2, |
707 JSObject* holder_obj, | 727 JSObject* interceptor_holder, |
708 LookupResult* lookup, | 728 LookupResult* lookup, |
709 String* name, | 729 String* name, |
710 const CallOptimization& optimization, | 730 const CallOptimization& optimization, |
711 Label* miss_label) { | 731 Label* miss_label) { |
712 ASSERT(optimization.is_constant_call()); | 732 ASSERT(optimization.is_constant_call()); |
713 ASSERT(!lookup->holder()->IsGlobalObject()); | 733 ASSERT(!lookup->holder()->IsGlobalObject()); |
714 | 734 |
715 int depth1 = kInvalidProtoDepth; | 735 int depth1 = kInvalidProtoDepth; |
716 int depth2 = kInvalidProtoDepth; | 736 int depth2 = kInvalidProtoDepth; |
717 bool can_do_fast_api_call = false; | 737 bool can_do_fast_api_call = false; |
718 if (optimization.is_simple_api_call() && | 738 if (optimization.is_simple_api_call() && |
719 !lookup->holder()->IsGlobalObject()) { | 739 !lookup->holder()->IsGlobalObject()) { |
720 depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); | 740 depth1 = |
| 741 optimization.GetPrototypeDepthOfExpectedType(object, |
| 742 interceptor_holder); |
721 if (depth1 == kInvalidProtoDepth) { | 743 if (depth1 == kInvalidProtoDepth) { |
722 depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, | 744 depth2 = |
723 lookup->holder()); | 745 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, |
| 746 lookup->holder()); |
724 } | 747 } |
725 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || | 748 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || |
726 (depth2 != kInvalidProtoDepth); | 749 (depth2 != kInvalidProtoDepth); |
727 } | 750 } |
728 | 751 |
729 __ IncrementCounter(&Counters::call_const_interceptor, 1); | 752 __ IncrementCounter(&Counters::call_const_interceptor, 1); |
730 | 753 |
731 if (can_do_fast_api_call) { | 754 if (can_do_fast_api_call) { |
732 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); | 755 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); |
733 ReserveSpaceForFastApiCall(masm, scratch1); | 756 ReserveSpaceForFastApiCall(masm, scratch1); |
734 } | 757 } |
735 | 758 |
| 759 // Check that the maps from receiver to interceptor's holder |
| 760 // haven't changed and thus we can invoke interceptor. |
736 Label miss_cleanup; | 761 Label miss_cleanup; |
737 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | 762 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
738 Register holder = | 763 Register holder = |
739 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, | 764 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
740 scratch1, scratch2, name, | 765 scratch1, scratch2, name, |
741 depth1, miss); | 766 depth1, miss); |
742 | 767 |
| 768 // Invoke an interceptor and if it provides a value, |
| 769 // branch to |regular_invoke|. |
743 Label regular_invoke; | 770 Label regular_invoke; |
744 LoadWithInterceptor(masm, receiver, holder, holder_obj, ®ular_invoke); | 771 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
| 772 ®ular_invoke); |
745 | 773 |
746 // Generate code for the failed interceptor case. | 774 // Interceptor returned nothing for this property. Try to use cached |
| 775 // constant function. |
747 | 776 |
748 // Check the lookup is still valid. | 777 // Check that the maps from interceptor's holder to constant function's |
749 stub_compiler_->CheckPrototypes(holder_obj, receiver, | 778 // holder haven't changed and thus we can use cached constant function. |
| 779 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, |
750 lookup->holder(), | 780 lookup->holder(), |
751 scratch1, scratch2, name, | 781 scratch1, scratch2, name, |
752 depth2, miss); | 782 depth2, miss); |
753 | 783 |
| 784 // Invoke function. |
754 if (can_do_fast_api_call) { | 785 if (can_do_fast_api_call) { |
755 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 786 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
756 } else { | 787 } else { |
757 __ InvokeFunction(optimization.constant_function(), arguments_, | 788 __ InvokeFunction(optimization.constant_function(), arguments_, |
758 JUMP_FUNCTION); | 789 JUMP_FUNCTION); |
759 } | 790 } |
760 | 791 |
| 792 // Deferred code for fast API call case---clean preallocated space. |
761 if (can_do_fast_api_call) { | 793 if (can_do_fast_api_call) { |
762 __ bind(&miss_cleanup); | 794 __ bind(&miss_cleanup); |
763 FreeSpaceForFastApiCall(masm, scratch1); | 795 FreeSpaceForFastApiCall(masm, scratch1); |
764 __ jmp(miss_label); | 796 __ jmp(miss_label); |
765 } | 797 } |
766 | 798 |
| 799 // Invoke a regular function. |
767 __ bind(®ular_invoke); | 800 __ bind(®ular_invoke); |
768 if (can_do_fast_api_call) { | 801 if (can_do_fast_api_call) { |
769 FreeSpaceForFastApiCall(masm, scratch1); | 802 FreeSpaceForFastApiCall(masm, scratch1); |
770 } | 803 } |
771 } | 804 } |
772 | 805 |
773 void CompileRegular(MacroAssembler* masm, | 806 void CompileRegular(MacroAssembler* masm, |
774 JSObject* object, | 807 JSObject* object, |
775 Register receiver, | 808 Register receiver, |
776 Register scratch1, | 809 Register scratch1, |
777 Register scratch2, | 810 Register scratch2, |
778 String* name, | 811 String* name, |
779 JSObject* holder_obj, | 812 JSObject* interceptor_holder, |
780 Label* miss_label) { | 813 Label* miss_label) { |
781 Register holder = | 814 Register holder = |
782 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, | 815 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
783 scratch1, scratch2, name, | 816 scratch1, scratch2, name, |
784 miss_label); | 817 miss_label); |
785 | 818 |
786 __ EnterInternalFrame(); | 819 __ EnterInternalFrame(); |
787 // Save the name_ register across the call. | 820 // Save the name_ register across the call. |
788 __ push(name_); | 821 __ push(name_); |
789 | 822 |
790 PushInterceptorArguments(masm, | 823 PushInterceptorArguments(masm, |
791 receiver, | 824 receiver, |
792 holder, | 825 holder, |
793 name_, | 826 name_, |
794 holder_obj); | 827 interceptor_holder); |
795 | 828 |
796 __ CallExternalReference( | 829 __ CallExternalReference( |
797 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), | 830 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), |
798 5); | 831 5); |
799 | 832 |
800 // Restore the name_ register. | 833 // Restore the name_ register. |
801 __ pop(name_); | 834 __ pop(name_); |
802 __ LeaveInternalFrame(); | 835 __ LeaveInternalFrame(); |
803 } | 836 } |
804 | 837 |
(...skipping 1554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2359 // Return the generated code. | 2392 // Return the generated code. |
2360 return GetCode(); | 2393 return GetCode(); |
2361 } | 2394 } |
2362 | 2395 |
2363 | 2396 |
2364 #undef __ | 2397 #undef __ |
2365 | 2398 |
2366 } } // namespace v8::internal | 2399 } } // namespace v8::internal |
2367 | 2400 |
2368 #endif // V8_TARGET_ARCH_X64 | 2401 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |