[turbofan] Fix missing holder lookup in AccessInfoFactory.
This makes sure we perform a proper holder lookup when trying to inline API accessors calls in TurboFan. Inlining is completely disabled in case the holder is not found, otherwise the appropriate holder is passed via the {PropertyAccessInfo} structure (if different from the receiver). R=bmeurer@chromium.org TEST=cctest/test-api/ReceiverSignature BUG=chromium:752149 Change-Id: I7b192724afd99d651b6477b2f2c8b403a10efb9d Reviewed-on: https://chromium-review.googlesource.com/603615 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#47216}
This commit is contained in:
parent
2070a4fee4
commit
1d92fd2edf
@ -409,9 +409,15 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
|
||||
isolate());
|
||||
if (!accessor->IsJSFunction()) {
|
||||
CallOptimization optimization(accessor);
|
||||
if (!optimization.is_simple_api_call()) {
|
||||
return false;
|
||||
}
|
||||
if (!optimization.is_simple_api_call()) return false;
|
||||
CallOptimization::HolderLookup lookup;
|
||||
holder =
|
||||
optimization.LookupHolderOfExpectedType(receiver_map, &lookup);
|
||||
if (lookup == CallOptimization::kHolderNotFound) return false;
|
||||
DCHECK_IMPLIES(lookup == CallOptimization::kHolderIsReceiver,
|
||||
holder.is_null());
|
||||
DCHECK_IMPLIES(lookup == CallOptimization::kHolderFound,
|
||||
!holder.is_null());
|
||||
if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
|
||||
}
|
||||
if (access_mode == AccessMode::kLoad) {
|
||||
|
@ -1451,8 +1451,13 @@ Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
|
||||
Handle<FunctionTemplateInfo> function_template_info(
|
||||
Handle<FunctionTemplateInfo>::cast(access_info.constant()));
|
||||
DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
|
||||
value = InlineApiCall(receiver, context, target, frame_state0, nullptr,
|
||||
effect, control, shared_info, function_template_info);
|
||||
Node* holder =
|
||||
access_info.holder().is_null()
|
||||
? receiver
|
||||
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
|
||||
value =
|
||||
InlineApiCall(receiver, holder, context, target, frame_state0, nullptr,
|
||||
effect, control, shared_info, function_template_info);
|
||||
}
|
||||
// Remember to rewire the IfException edge if this is inside a try-block.
|
||||
if (if_exceptions != nullptr) {
|
||||
@ -1498,8 +1503,13 @@ Node* JSNativeContextSpecialization::InlinePropertySetterCall(
|
||||
Handle<FunctionTemplateInfo> function_template_info(
|
||||
Handle<FunctionTemplateInfo>::cast(access_info.constant()));
|
||||
DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
|
||||
value = InlineApiCall(receiver, context, target, frame_state0, value,
|
||||
effect, control, shared_info, function_template_info);
|
||||
Node* holder =
|
||||
access_info.holder().is_null()
|
||||
? receiver
|
||||
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
|
||||
value =
|
||||
InlineApiCall(receiver, holder, context, target, frame_state0, value,
|
||||
effect, control, shared_info, function_template_info);
|
||||
}
|
||||
// Remember to rewire the IfException edge if this is inside a try-block.
|
||||
if (if_exceptions != nullptr) {
|
||||
@ -1514,8 +1524,9 @@ Node* JSNativeContextSpecialization::InlinePropertySetterCall(
|
||||
}
|
||||
|
||||
Node* JSNativeContextSpecialization::InlineApiCall(
|
||||
Node* receiver, Node* context, Node* target, Node* frame_state, Node* value,
|
||||
Node** effect, Node** control, Handle<SharedFunctionInfo> shared_info,
|
||||
Node* receiver, Node* holder, Node* context, Node* target,
|
||||
Node* frame_state, Node* value, Node** effect, Node** control,
|
||||
Handle<SharedFunctionInfo> shared_info,
|
||||
Handle<FunctionTemplateInfo> function_template_info) {
|
||||
Handle<CallHandlerInfo> call_handler_info = handle(
|
||||
CallHandlerInfo::cast(function_template_info->call_code()), isolate());
|
||||
@ -1544,8 +1555,7 @@ Node* JSNativeContextSpecialization::InlineApiCall(
|
||||
Node* code = jsgraph()->HeapConstant(stub.GetCode());
|
||||
|
||||
// Add CallApiCallbackStub's register argument as well.
|
||||
Node* inputs[11] = {
|
||||
code, target, data, receiver /* holder */, function_reference, receiver};
|
||||
Node* inputs[11] = {code, target, data, holder, function_reference, receiver};
|
||||
int index = 6 + argc;
|
||||
inputs[index++] = context;
|
||||
inputs[index++] = frame_state;
|
||||
|
@ -146,7 +146,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
Node** control,
|
||||
ZoneVector<Node*>* if_exceptions,
|
||||
PropertyAccessInfo const& access_info);
|
||||
Node* InlineApiCall(Node* receiver, Node* context, Node* target,
|
||||
Node* InlineApiCall(Node* receiver, Node* holder, Node* context, Node* target,
|
||||
Node* frame_state, Node* value, Node** effect,
|
||||
Node** control, Handle<SharedFunctionInfo> shared_info,
|
||||
Handle<FunctionTemplateInfo> function_template_info);
|
||||
|
@ -195,15 +195,14 @@ THREADED_TEST(IsolateOfContext) {
|
||||
CHECK(env->GetIsolate() == CcTest::isolate());
|
||||
}
|
||||
|
||||
|
||||
static void TestSignature(const char* loop_js, Local<Value> receiver,
|
||||
v8::Isolate* isolate) {
|
||||
static void TestSignatureLooped(const char* operation, Local<Value> receiver,
|
||||
v8::Isolate* isolate) {
|
||||
i::ScopedVector<char> source(200);
|
||||
i::SNPrintF(source,
|
||||
"for (var i = 0; i < 10; i++) {"
|
||||
" %s"
|
||||
"}",
|
||||
loop_js);
|
||||
operation);
|
||||
signature_callback_count = 0;
|
||||
signature_expected_receiver = receiver;
|
||||
bool expected_to_throw = receiver.IsEmpty();
|
||||
@ -222,8 +221,44 @@ static void TestSignature(const char* loop_js, Local<Value> receiver,
|
||||
}
|
||||
}
|
||||
|
||||
static void TestSignatureOptimized(const char* operation, Local<Value> receiver,
|
||||
v8::Isolate* isolate) {
|
||||
i::ScopedVector<char> source(200);
|
||||
i::SNPrintF(source,
|
||||
"function test() {"
|
||||
" %s"
|
||||
"}"
|
||||
"try { test() } catch(e) {}"
|
||||
"try { test() } catch(e) {}"
|
||||
"%%OptimizeFunctionOnNextCall(test);"
|
||||
"test()",
|
||||
operation);
|
||||
signature_callback_count = 0;
|
||||
signature_expected_receiver = receiver;
|
||||
bool expected_to_throw = receiver.IsEmpty();
|
||||
v8::TryCatch try_catch(isolate);
|
||||
CompileRun(source.start());
|
||||
CHECK_EQ(expected_to_throw, try_catch.HasCaught());
|
||||
if (!expected_to_throw) {
|
||||
CHECK_EQ(3, signature_callback_count);
|
||||
} else {
|
||||
CHECK(v8_str("TypeError: Illegal invocation")
|
||||
->Equals(isolate->GetCurrentContext(),
|
||||
try_catch.Exception()
|
||||
->ToString(isolate->GetCurrentContext())
|
||||
.ToLocalChecked())
|
||||
.FromJust());
|
||||
}
|
||||
}
|
||||
|
||||
static void TestSignature(const char* operation, Local<Value> receiver,
|
||||
v8::Isolate* isolate) {
|
||||
TestSignatureLooped(operation, receiver, isolate);
|
||||
TestSignatureOptimized(operation, receiver, isolate);
|
||||
}
|
||||
|
||||
THREADED_TEST(ReceiverSignature) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
@ -281,13 +316,14 @@ THREADED_TEST(ReceiverSignature) {
|
||||
" }"
|
||||
"}"
|
||||
""
|
||||
"var obj = {};"
|
||||
"copy_props(obj);"
|
||||
"var unrel = new UnrelFun();"
|
||||
"copy_props(unrel);");
|
||||
"var plain = {};"
|
||||
"copy_props(plain);"
|
||||
"var unrelated = new UnrelFun();"
|
||||
"copy_props(unrelated);"
|
||||
"var inherited = { __proto__: fun_instance };");
|
||||
// Test with and without ICs
|
||||
const char* test_objects[] = {
|
||||
"fun_instance", "sub_fun_instance", "obj", "unrel" };
|
||||
const char* test_objects[] = {"fun_instance", "sub_fun_instance", "plain",
|
||||
"unrelated", "inherited"};
|
||||
unsigned bad_signature_start_offset = 2;
|
||||
for (unsigned i = 0; i < arraysize(test_objects); i++) {
|
||||
i::ScopedVector<char> source(200);
|
||||
|
Loading…
Reference in New Issue
Block a user