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 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
429 class LoadInterceptorCompiler BASE_EMBEDDED { | 429 class LoadInterceptorCompiler BASE_EMBEDDED { |
430 public: | 430 public: |
431 explicit LoadInterceptorCompiler(Register name) : name_(name) {} | 431 explicit LoadInterceptorCompiler(Register name) : name_(name) {} |
432 | 432 |
433 void CompileCacheable(MacroAssembler* masm, | 433 void CompileCacheable(MacroAssembler* masm, |
434 StubCompiler* stub_compiler, | 434 StubCompiler* stub_compiler, |
435 Register receiver, | 435 Register receiver, |
436 Register holder, | 436 Register holder, |
437 Register scratch1, | 437 Register scratch1, |
438 Register scratch2, | 438 Register scratch2, |
439 JSObject* holder_obj, | 439 JSObject* interceptor_holder, |
440 LookupResult* lookup, | 440 LookupResult* lookup, |
441 String* name, | 441 String* name, |
442 Label* miss_label) { | 442 Label* miss_label) { |
443 AccessorInfo* callback = NULL; | 443 AccessorInfo* callback = NULL; |
444 bool optimize = false; | 444 bool optimize = false; |
445 // So far the most popular follow ups for interceptor loads are FIELD | 445 // So far the most popular follow ups for interceptor loads are FIELD |
446 // and CALLBACKS, so inline only them, other cases may be added | 446 // and CALLBACKS, so inline only them, other cases may be added |
447 // later. | 447 // later. |
448 if (lookup->type() == FIELD) { | 448 if (lookup->type() == FIELD) { |
449 optimize = true; | 449 optimize = true; |
450 } else if (lookup->type() == CALLBACKS) { | 450 } else if (lookup->type() == CALLBACKS) { |
451 Object* callback_object = lookup->GetCallbackObject(); | 451 Object* callback_object = lookup->GetCallbackObject(); |
452 if (callback_object->IsAccessorInfo()) { | 452 if (callback_object->IsAccessorInfo()) { |
453 callback = AccessorInfo::cast(callback_object); | 453 callback = AccessorInfo::cast(callback_object); |
454 optimize = callback->getter() != NULL; | 454 optimize = callback->getter() != NULL; |
455 } | 455 } |
456 } | 456 } |
457 | 457 |
458 if (!optimize) { | 458 if (!optimize) { |
459 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 459 CompileRegular(masm, receiver, holder, scratch2, interceptor_holder, |
460 miss_label); | |
460 return; | 461 return; |
461 } | 462 } |
462 | 463 |
463 // Note: starting a frame here makes GC aware of pointers pushed below. | 464 // Note: starting a frame here makes GC aware of pointers pushed below. |
464 __ EnterInternalFrame(); | 465 __ EnterInternalFrame(); |
465 | 466 |
466 __ push(receiver); | 467 __ push(receiver); |
467 __ Push(holder, name_); | 468 __ Push(holder, name_); |
468 | 469 |
470 // Invoke an interceptor. Note: map checks from receiver to | |
471 // interceptor's holder has been compiled before (see a caller | |
472 // of this method.) | |
469 CompileCallLoadPropertyWithInterceptor(masm, | 473 CompileCallLoadPropertyWithInterceptor(masm, |
470 receiver, | 474 receiver, |
471 holder, | 475 holder, |
472 name_, | 476 name_, |
473 holder_obj); | 477 interceptor_holder); |
474 | 478 |
479 // Check if interceptor provided a value for property. If it's | |
480 // the case, return immediately. | |
475 Label interceptor_failed; | 481 Label interceptor_failed; |
476 // Compare with no_interceptor_result_sentinel. | |
477 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); | 482 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); |
478 __ cmp(r0, scratch1); | 483 __ cmp(r0, scratch1); |
479 __ b(eq, &interceptor_failed); | 484 __ b(eq, &interceptor_failed); |
480 __ LeaveInternalFrame(); | 485 __ LeaveInternalFrame(); |
481 __ Ret(); | 486 __ Ret(); |
482 | 487 |
483 __ bind(&interceptor_failed); | 488 __ bind(&interceptor_failed); |
484 __ pop(name_); | 489 __ pop(name_); |
485 __ pop(holder); | 490 __ pop(holder); |
486 __ pop(receiver); | 491 __ pop(receiver); |
487 | 492 |
488 __ LeaveInternalFrame(); | 493 __ LeaveInternalFrame(); |
489 | 494 |
490 if (lookup->type() == FIELD) { | 495 if (lookup->type() == FIELD) { |
491 holder = stub_compiler->CheckPrototypes(holder_obj, | 496 // We found FIELD property in prototype chain of interceptor's holder. |
497 // Check that the maps from interceptor's holder to field's holder | |
498 // haven't changed... | |
499 holder = stub_compiler->CheckPrototypes(interceptor_holder, | |
492 holder, | 500 holder, |
493 lookup->holder(), | 501 lookup->holder(), |
494 scratch1, | 502 scratch1, |
495 scratch2, | 503 scratch2, |
496 name, | 504 name, |
497 miss_label); | 505 miss_label); |
506 // ... and retrieve a field from field's holder. | |
498 stub_compiler->GenerateFastPropertyLoad(masm, | 507 stub_compiler->GenerateFastPropertyLoad(masm, |
499 r0, | 508 r0, |
500 holder, | 509 holder, |
501 lookup->holder(), | 510 lookup->holder(), |
502 lookup->GetFieldIndex()); | 511 lookup->GetFieldIndex()); |
503 __ Ret(); | 512 __ Ret(); |
504 } else { | 513 } else { |
514 // We found CALLBACKS property in prototype chain of interceptor's | |
515 // holder. | |
505 ASSERT(lookup->type() == CALLBACKS); | 516 ASSERT(lookup->type() == CALLBACKS); |
506 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); | 517 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); |
507 ASSERT(callback != NULL); | 518 ASSERT(callback != NULL); |
508 ASSERT(callback->getter() != NULL); | 519 ASSERT(callback->getter() != NULL); |
509 | 520 |
521 // Prepare for tail call: push receiver to stack. | |
510 Label cleanup; | 522 Label cleanup; |
511 __ push(receiver); | 523 __ push(receiver); |
512 | 524 |
513 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, | |
514 lookup->holder(), scratch1, | 528 lookup->holder(), scratch1, |
515 scratch2, | 529 scratch2, |
516 name, | 530 name, |
517 &cleanup); | 531 &cleanup); |
518 | 532 |
533 // Continue tail call preparation: push remaining parameters. | |
519 __ push(holder); | 534 __ push(holder); |
520 __ Move(holder, Handle<AccessorInfo>(callback)); | 535 __ Move(holder, Handle<AccessorInfo>(callback)); |
521 __ push(holder); | 536 __ push(holder); |
522 __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset)); | 537 __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset)); |
523 __ Push(scratch1, name_); | 538 __ Push(scratch1, name_); |
524 | 539 |
540 // Tail call to runtime. | |
525 ExternalReference ref = | 541 ExternalReference ref = |
526 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); | 542 ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
527 __ TailCallExternalReference(ref, 5, 1); | 543 __ TailCallExternalReference(ref, 5, 1); |
528 | 544 |
545 // Clean up code: we pushed receiver and need to remove it. | |
529 __ bind(&cleanup); | 546 __ bind(&cleanup); |
530 __ pop(scratch2); | 547 __ pop(scratch2); |
531 } | 548 } |
532 } | 549 } |
533 | 550 |
534 | 551 |
535 void CompileRegular(MacroAssembler* masm, | 552 void CompileRegular(MacroAssembler* masm, |
536 Register receiver, | 553 Register receiver, |
537 Register holder, | 554 Register holder, |
538 Register scratch, | 555 Register scratch, |
539 JSObject* holder_obj, | 556 JSObject* interceptor_holder, |
540 Label* miss_label) { | 557 Label* miss_label) { |
541 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); | 558 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); |
542 | 559 |
543 ExternalReference ref = ExternalReference( | 560 ExternalReference ref = ExternalReference( |
544 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | 561 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
545 __ TailCallExternalReference(ref, 5, 1); | 562 __ TailCallExternalReference(ref, 5, 1); |
546 } | 563 } |
547 | 564 |
548 private: | 565 private: |
549 Register name_; | 566 Register name_; |
550 }; | 567 }; |
551 | 568 |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
707 miss); | 724 miss); |
708 } | 725 } |
709 } | 726 } |
710 | 727 |
711 private: | 728 private: |
712 void CompileCacheable(MacroAssembler* masm, | 729 void CompileCacheable(MacroAssembler* masm, |
713 JSObject* object, | 730 JSObject* object, |
714 Register receiver, | 731 Register receiver, |
715 Register scratch1, | 732 Register scratch1, |
716 Register scratch2, | 733 Register scratch2, |
717 JSObject* holder_obj, | 734 JSObject* interceptor_holder, |
718 LookupResult* lookup, | 735 LookupResult* lookup, |
719 String* name, | 736 String* name, |
720 const CallOptimization& optimization, | 737 const CallOptimization& optimization, |
721 Label* miss_label) { | 738 Label* miss_label) { |
722 ASSERT(optimization.is_constant_call()); | 739 ASSERT(optimization.is_constant_call()); |
723 ASSERT(!lookup->holder()->IsGlobalObject()); | 740 ASSERT(!lookup->holder()->IsGlobalObject()); |
724 | 741 |
725 int depth1 = kInvalidProtoDepth; | 742 int depth1 = kInvalidProtoDepth; |
726 int depth2 = kInvalidProtoDepth; | 743 int depth2 = kInvalidProtoDepth; |
727 bool can_do_fast_api_call = false; | 744 bool can_do_fast_api_call = false; |
728 if (optimization.is_simple_api_call() && | 745 if (optimization.is_simple_api_call() && |
729 !lookup->holder()->IsGlobalObject()) { | 746 !lookup->holder()->IsGlobalObject()) { |
730 depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); | 747 depth1 = |
748 optimization.GetPrototypeDepthOfExpectedType(object, | |
749 interceptor_holder); | |
731 if (depth1 == kInvalidProtoDepth) { | 750 if (depth1 == kInvalidProtoDepth) { |
732 depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, | 751 depth2 = |
733 lookup->holder()); | 752 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, |
753 lookup->holder()); | |
734 } | 754 } |
735 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || | 755 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || |
736 (depth2 != kInvalidProtoDepth); | 756 (depth2 != kInvalidProtoDepth); |
737 } | 757 } |
738 | 758 |
739 __ IncrementCounter(&Counters::call_const_interceptor, 1, | 759 __ IncrementCounter(&Counters::call_const_interceptor, 1, |
740 scratch1, scratch2); | 760 scratch1, scratch2); |
741 | 761 |
742 if (can_do_fast_api_call) { | 762 if (can_do_fast_api_call) { |
743 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1, | 763 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1, |
744 scratch1, scratch2); | 764 scratch1, scratch2); |
745 ReserveSpaceForFastApiCall(masm, scratch1); | 765 ReserveSpaceForFastApiCall(masm, scratch1); |
746 } | 766 } |
747 | 767 |
768 // Check that the maps from receiver to interceptor's holder | |
769 // haven't changed and thus we can invoke interceptor. | |
748 Label miss_cleanup; | 770 Label miss_cleanup; |
749 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | 771 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
750 Register holder = | 772 Register holder = |
751 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, scratch1, | 773 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
752 scratch2, name, depth1, miss); | 774 scratch1, scratch2, name, |
775 depth1, miss); | |
753 | 776 |
777 // Invoke an interceptor and if it provides a value, | |
778 // branch to |regular_invoke|. | |
754 Label regular_invoke; | 779 Label regular_invoke; |
755 LoadWithInterceptor(masm, receiver, holder, holder_obj, scratch2, | 780 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, |
756 ®ular_invoke); | 781 ®ular_invoke); |
757 | 782 |
758 // Generate code for the failed interceptor case. | 783 // Interceptor returned nothing for this property. Try to use cached |
784 // constant function. | |
759 | 785 |
760 // Check the lookup is still valid. | 786 // Check that the maps from interceptor's holder to constant function's |
761 stub_compiler_->CheckPrototypes(holder_obj, receiver, | 787 // holder haven't changed and thus we can use cached constant function. |
Søren Thygesen Gjesse
2010/05/25 14:07:29
I am wondering whether this check can be skipped i
antonm
2010/05/25 14:15:10
That's a good point and it indeed could happen. L
| |
788 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, | |
762 lookup->holder(), scratch1, | 789 lookup->holder(), scratch1, |
763 scratch2, name, depth2, miss); | 790 scratch2, name, depth2, miss); |
764 | 791 |
792 // Invoke function. | |
765 if (can_do_fast_api_call) { | 793 if (can_do_fast_api_call) { |
766 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 794 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
767 } else { | 795 } else { |
768 __ InvokeFunction(optimization.constant_function(), arguments_, | 796 __ InvokeFunction(optimization.constant_function(), arguments_, |
769 JUMP_FUNCTION); | 797 JUMP_FUNCTION); |
770 } | 798 } |
771 | 799 |
800 // Deferred code for fast API call case---clean preallocated space. | |
772 if (can_do_fast_api_call) { | 801 if (can_do_fast_api_call) { |
773 __ bind(&miss_cleanup); | 802 __ bind(&miss_cleanup); |
774 FreeSpaceForFastApiCall(masm); | 803 FreeSpaceForFastApiCall(masm); |
775 __ b(miss_label); | 804 __ b(miss_label); |
776 } | 805 } |
777 | 806 |
807 // Invoke a regular function. | |
778 __ bind(®ular_invoke); | 808 __ bind(®ular_invoke); |
779 if (can_do_fast_api_call) { | 809 if (can_do_fast_api_call) { |
780 FreeSpaceForFastApiCall(masm); | 810 FreeSpaceForFastApiCall(masm); |
781 } | 811 } |
782 } | 812 } |
783 | 813 |
784 void CompileRegular(MacroAssembler* masm, | 814 void CompileRegular(MacroAssembler* masm, |
785 JSObject* object, | 815 JSObject* object, |
786 Register receiver, | 816 Register receiver, |
787 Register scratch1, | 817 Register scratch1, |
788 Register scratch2, | 818 Register scratch2, |
789 String* name, | 819 String* name, |
790 JSObject* holder_obj, | 820 JSObject* interceptor_holder, |
791 Label* miss_label) { | 821 Label* miss_label) { |
792 Register holder = | 822 Register holder = |
793 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, | 823 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
794 scratch1, scratch2, name, | 824 scratch1, scratch2, name, |
795 miss_label); | 825 miss_label); |
796 | 826 |
797 // Call a runtime function to load the interceptor property. | 827 // Call a runtime function to load the interceptor property. |
798 __ EnterInternalFrame(); | 828 __ EnterInternalFrame(); |
799 // Save the name_ register across the call. | 829 // Save the name_ register across the call. |
800 __ push(name_); | 830 __ push(name_); |
801 | 831 |
802 PushInterceptorArguments(masm, | 832 PushInterceptorArguments(masm, |
803 receiver, | 833 receiver, |
804 holder, | 834 holder, |
805 name_, | 835 name_, |
806 holder_obj); | 836 interceptor_holder); |
807 | 837 |
808 __ CallExternalReference( | 838 __ CallExternalReference( |
809 ExternalReference( | 839 ExternalReference( |
810 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), | 840 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), |
811 5); | 841 5); |
812 | 842 |
813 // Restore the name_ register. | 843 // Restore the name_ register. |
814 __ pop(name_); | 844 __ pop(name_); |
815 __ LeaveInternalFrame(); | 845 __ LeaveInternalFrame(); |
816 } | 846 } |
(...skipping 1317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2134 // Return the generated code. | 2164 // Return the generated code. |
2135 return GetCode(); | 2165 return GetCode(); |
2136 } | 2166 } |
2137 | 2167 |
2138 | 2168 |
2139 #undef __ | 2169 #undef __ |
2140 | 2170 |
2141 } } // namespace v8::internal | 2171 } } // namespace v8::internal |
2142 | 2172 |
2143 #endif // V8_TARGET_ARCH_ARM | 2173 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |