Chromium Code Reviews| 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 |