| Index: src/x64/stub-cache-x64.cc
|
| diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
|
| index 504482d9314e1ec407e86034dc08fc38bbc616dd..f068f5f953784feec00e2f78b3ff7218c68773ce 100644
|
| --- a/src/x64/stub-cache-x64.cc
|
| +++ b/src/x64/stub-cache-x64.cc
|
| @@ -727,94 +727,80 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
| }
|
|
|
|
|
| -void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg,
|
| - LookupResult* lookup,
|
| - Handle<Name> name) {
|
| +void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
|
| + LookupIterator* it, Register holder_reg) {
|
| DCHECK(holder()->HasNamedInterceptor());
|
| DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
|
|
|
| - // So far the most popular follow ups for interceptor loads are FIELD
|
| - // and CALLBACKS, so inline only them, other cases may be added
|
| - // later.
|
| - bool compile_followup_inline = false;
|
| - if (lookup->IsFound() && lookup->IsCacheable()) {
|
| - if (lookup->IsField()) {
|
| - compile_followup_inline = true;
|
| - } else if (lookup->type() == CALLBACKS &&
|
| - lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
|
| - Handle<ExecutableAccessorInfo> callback(
|
| - ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
|
| - compile_followup_inline =
|
| - callback->getter() != NULL &&
|
| - ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), callback,
|
| - type());
|
| - }
|
| - }
|
| + // Compile the interceptor call, followed by inline code to load the
|
| + // property from further up the prototype chain if the call fails.
|
| + // Check that the maps haven't changed.
|
| + DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
|
| +
|
| + // Preserve the receiver register explicitly whenever it is different from the
|
| + // holder and it is needed should the interceptor return without any result.
|
| + // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
|
| + // case might cause a miss during the prototype check.
|
| + bool must_perfrom_prototype_check =
|
| + !holder().is_identical_to(it->GetHolder<JSObject>());
|
| + bool must_preserve_receiver_reg =
|
| + !receiver().is(holder_reg) &&
|
| + (it->property_kind() == LookupIterator::ACCESSOR ||
|
| + must_perfrom_prototype_check);
|
| +
|
| + // Save necessary data before invoking an interceptor.
|
| + // Requires a frame to make GC aware of pushed pointers.
|
| + {
|
| + FrameScope frame_scope(masm(), StackFrame::INTERNAL);
|
|
|
| - if (compile_followup_inline) {
|
| - // Compile the interceptor call, followed by inline code to load the
|
| - // property from further up the prototype chain if the call fails.
|
| - // Check that the maps haven't changed.
|
| - DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
|
| -
|
| - // Preserve the receiver register explicitly whenever it is different from
|
| - // the holder and it is needed should the interceptor return without any
|
| - // result. The CALLBACKS case needs the receiver to be passed into C++ code,
|
| - // the FIELD case might cause a miss during the prototype check.
|
| - bool must_perfrom_prototype_check = *holder() != lookup->holder();
|
| - bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
|
| - (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
|
| -
|
| - // Save necessary data before invoking an interceptor.
|
| - // Requires a frame to make GC aware of pushed pointers.
|
| - {
|
| - FrameScope frame_scope(masm(), StackFrame::INTERNAL);
|
| -
|
| - if (must_preserve_receiver_reg) {
|
| - __ Push(receiver());
|
| - }
|
| - __ Push(holder_reg);
|
| - __ Push(this->name());
|
| -
|
| - // Invoke an interceptor. Note: map checks from receiver to
|
| - // interceptor's holder has been compiled before (see a caller
|
| - // of this method.)
|
| - CompileCallLoadPropertyWithInterceptor(
|
| - masm(), receiver(), holder_reg, this->name(), holder(),
|
| - IC::kLoadPropertyWithInterceptorOnly);
|
| -
|
| - // Check if interceptor provided a value for property. If it's
|
| - // the case, return immediately.
|
| - Label interceptor_failed;
|
| - __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
|
| - __ j(equal, &interceptor_failed);
|
| - frame_scope.GenerateLeaveFrame();
|
| - __ ret(0);
|
| -
|
| - __ bind(&interceptor_failed);
|
| - __ Pop(this->name());
|
| - __ Pop(holder_reg);
|
| - if (must_preserve_receiver_reg) {
|
| - __ Pop(receiver());
|
| - }
|
| + if (must_preserve_receiver_reg) {
|
| + __ Push(receiver());
|
| + }
|
| + __ Push(holder_reg);
|
| + __ Push(this->name());
|
| +
|
| + // Invoke an interceptor. Note: map checks from receiver to
|
| + // interceptor's holder has been compiled before (see a caller
|
| + // of this method.)
|
| + CompileCallLoadPropertyWithInterceptor(
|
| + masm(), receiver(), holder_reg, this->name(), holder(),
|
| + IC::kLoadPropertyWithInterceptorOnly);
|
| +
|
| + // Check if interceptor provided a value for property. If it's
|
| + // the case, return immediately.
|
| + Label interceptor_failed;
|
| + __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
|
| + __ j(equal, &interceptor_failed);
|
| + frame_scope.GenerateLeaveFrame();
|
| + __ ret(0);
|
|
|
| - // Leave the internal frame.
|
| + __ bind(&interceptor_failed);
|
| + __ Pop(this->name());
|
| + __ Pop(holder_reg);
|
| + if (must_preserve_receiver_reg) {
|
| + __ Pop(receiver());
|
| }
|
|
|
| - GenerateLoadPostInterceptor(holder_reg, name, lookup);
|
| - } else { // !compile_followup_inline
|
| - // Call the runtime system to load the interceptor.
|
| - // Check that the maps haven't changed.
|
| - __ PopReturnAddressTo(scratch2());
|
| - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
|
| - holder());
|
| - __ PushReturnAddressFrom(scratch2());
|
| -
|
| - ExternalReference ref = ExternalReference(
|
| - IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
|
| - __ TailCallExternalReference(
|
| - ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
|
| + // Leave the internal frame.
|
| }
|
| +
|
| + GenerateLoadPostInterceptor(it, holder_reg);
|
| +}
|
| +
|
| +
|
| +void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
| + // Call the runtime system to load the interceptor.
|
| + DCHECK(holder()->HasNamedInterceptor());
|
| + DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
|
| + __ PopReturnAddressTo(scratch2());
|
| + PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
|
| + holder());
|
| + __ PushReturnAddressFrom(scratch2());
|
| +
|
| + ExternalReference ref = ExternalReference(
|
| + IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
|
| + __ TailCallExternalReference(
|
| + ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
|
| }
|
|
|
|
|
|
|