follow up named interceptor miss with api callback getter
BUG= Review URL: https://codereview.chromium.org/885763004 Cr-Commit-Position: refs/heads/master@{#26395}
This commit is contained in:
parent
ba8409d2f6
commit
70bba702e0
@ -49,8 +49,14 @@ Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
|
||||
bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
|
||||
Handle<JSObject> holder) const {
|
||||
DCHECK(is_simple_api_call());
|
||||
if (!receiver->IsJSObject()) return false;
|
||||
Handle<Map> map(JSObject::cast(*receiver)->map());
|
||||
if (!receiver->IsHeapObject()) return false;
|
||||
Handle<Map> map(HeapObject::cast(*receiver)->map());
|
||||
return IsCompatibleReceiverType(map, holder);
|
||||
}
|
||||
|
||||
|
||||
bool CallOptimization::IsCompatibleReceiverType(Handle<Map> map,
|
||||
Handle<JSObject> holder) const {
|
||||
HolderLookup holder_lookup;
|
||||
Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
|
||||
switch (holder_lookup) {
|
||||
|
@ -45,6 +45,10 @@ class CallOptimization BASE_EMBEDDED {
|
||||
bool IsCompatibleReceiver(Handle<Object> receiver,
|
||||
Handle<JSObject> holder) const;
|
||||
|
||||
// Check if the api holder is between the receiver and the holder.
|
||||
bool IsCompatibleReceiverType(Handle<Map> receiver_map,
|
||||
Handle<JSObject> holder) const;
|
||||
|
||||
private:
|
||||
void Initialize(Handle<JSFunction> function);
|
||||
|
||||
|
@ -289,13 +289,25 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
|
||||
break;
|
||||
case LookupIterator::ACCESSOR: {
|
||||
Handle<Object> accessors = it->GetAccessors();
|
||||
inline_followup = accessors->IsExecutableAccessorInfo();
|
||||
if (!inline_followup) break;
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(accessors);
|
||||
inline_followup = info->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(
|
||||
isolate(), info, type());
|
||||
if (accessors->IsExecutableAccessorInfo()) {
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(accessors);
|
||||
inline_followup = info->getter() != NULL &&
|
||||
ExecutableAccessorInfo::IsCompatibleReceiverType(
|
||||
isolate(), info, type());
|
||||
} else if (accessors->IsAccessorPair()) {
|
||||
Handle<JSObject> property_holder(it->GetHolder<JSObject>());
|
||||
Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
|
||||
isolate());
|
||||
if (!getter->IsJSFunction()) break;
|
||||
if (!property_holder->HasFastProperties()) break;
|
||||
auto function = Handle<JSFunction>::cast(getter);
|
||||
CallOptimization call_optimization(function);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
|
||||
inline_followup = call_optimization.is_simple_api_call() &&
|
||||
call_optimization.IsCompatibleReceiverType(
|
||||
receiver_map, property_holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,10 +357,20 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
break;
|
||||
}
|
||||
case LookupIterator::ACCESSOR:
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(it->GetAccessors());
|
||||
DCHECK_NOT_NULL(info->getter());
|
||||
GenerateLoadCallback(reg, info);
|
||||
if (it->GetAccessors()->IsExecutableAccessorInfo()) {
|
||||
Handle<ExecutableAccessorInfo> info =
|
||||
Handle<ExecutableAccessorInfo>::cast(it->GetAccessors());
|
||||
DCHECK_NOT_NULL(info->getter());
|
||||
GenerateLoadCallback(reg, info);
|
||||
} else {
|
||||
auto function = handle(JSFunction::cast(
|
||||
AccessorPair::cast(*it->GetAccessors())->getter()));
|
||||
CallOptimization call_optimization(function);
|
||||
Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
|
||||
GenerateApiAccessorCall(masm(), call_optimization, receiver_map,
|
||||
receiver(), scratch2(), false, no_reg, reg,
|
||||
it->GetAccessorIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,11 @@ static void IncrementingSignatureCallback(
|
||||
}
|
||||
|
||||
|
||||
static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
info.GetReturnValue().Set(42);
|
||||
}
|
||||
|
||||
|
||||
// Tests that call v8::V8::Dispose() cannot be threaded.
|
||||
UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
|
||||
CHECK(v8::V8::Initialize());
|
||||
@ -2225,6 +2230,33 @@ THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(EmptyInterceptorDoesNotShadowApiAccessors) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
|
||||
auto returns_42 = FunctionTemplate::New(isolate, Returns42);
|
||||
parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
|
||||
Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
|
||||
child->Inherit(parent);
|
||||
AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
|
||||
LocalContext env;
|
||||
env->Global()->Set(v8_str("Child"), child->GetFunction());
|
||||
CompileRun(
|
||||
"var child = new Child;"
|
||||
"var parent = child.__proto__;");
|
||||
ExpectBoolean("child.hasOwnProperty('age')", false);
|
||||
ExpectInt32("child.age", 42);
|
||||
// Check interceptor followup.
|
||||
ExpectInt32(
|
||||
"var result;"
|
||||
"for (var i = 0; i < 4; ++i) {"
|
||||
" result = child.age;"
|
||||
"}"
|
||||
"result",
|
||||
42);
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
@ -23500,11 +23532,6 @@ TEST(FunctionCallOptimization) {
|
||||
}
|
||||
|
||||
|
||||
static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
info.GetReturnValue().Set(42);
|
||||
}
|
||||
|
||||
|
||||
TEST(FunctionCallOptimizationMultipleArgs) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
LocalContext context;
|
||||
|
Loading…
Reference in New Issue
Block a user