| 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 |