Skip to content
Permalink
Browse files

[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}
  • Loading branch information...
Michael Starzinger Commit Bot
Michael Starzinger authored and Commit Bot committed Aug 8, 2017
1 parent 2070a4f commit 1d92fd2edf771d4d5739dd473f8614af87f722f8
@@ -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);

0 comments on commit 1d92fd2

Please sign in to comment.
You can’t perform that action at this time.