Skip to content

Commit

Permalink
v8: backport 9fb02b526f1cd3b859a530a01adb08bc0d089f4f
Browse files Browse the repository at this point in the history
Refs: v8/v8@9fb02b5

Original commit message:

    Allow function callbacks to have Proxy as receiver.

    R=verwaest@chromium.org

    Bug: v8:5773
    Change-Id: Ifd29a1116ee8c86b8d8d24485bbfd19e260ab66b
    Reviewed-on: chromium-review.googlesource.com/1046088
    Commit-Queue: Yang Guo <yangguo@chromium.org>
    Reviewed-by: Camillo Bruni <cbruni@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#53015}

PR-URL: #20575
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information
devsnek authored and targos committed May 12, 2018
1 parent 1f34c04 commit 105f606
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 21 deletions.
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.6',
'v8_embedder_string': '-node.7',

# Enable disassembler for `--print-code` v8 options
'v8_enable_disassembler': 1,
Expand Down
41 changes: 21 additions & 20 deletions deps/v8/src/builtins/builtins-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,21 @@ namespace {
// Returns the holder JSObject if the function can legally be called with this
// receiver. Returns nullptr if the call is illegal.
// TODO(dcarney): CallOptimization duplicates this logic, merge.
JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
JSObject* receiver) {
JSReceiver* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
JSReceiver* receiver) {
Object* recv_type = info->signature();
// No signature, return holder.
if (!recv_type->IsFunctionTemplateInfo()) return receiver;
// A Proxy cannot have been created from the signature template.
if (!receiver->IsJSObject()) return nullptr;

JSObject* js_obj_receiver = JSObject::cast(receiver);
FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);

// Check the receiver. Fast path for receivers with no hidden prototypes.
if (signature->IsTemplateFor(receiver)) return receiver;
if (!receiver->map()->has_hidden_prototype()) return nullptr;
for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
if (signature->IsTemplateFor(js_obj_receiver)) return receiver;
if (!js_obj_receiver->map()->has_hidden_prototype()) return nullptr;
for (PrototypeIterator iter(isolate, js_obj_receiver, kStartAtPrototype,
PrototypeIterator::END_AT_NON_HIDDEN);
!iter.IsAtEnd(); iter.Advance()) {
JSObject* current = iter.GetCurrent<JSObject>();
Expand All @@ -45,8 +49,8 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
Isolate* isolate, Handle<HeapObject> function,
Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
Handle<Object> receiver, BuiltinArguments args) {
Handle<JSObject> js_receiver;
JSObject* raw_holder;
Handle<JSReceiver> js_receiver;
JSReceiver* raw_holder;
if (is_construct) {
DCHECK(args.receiver()->IsTheHole(isolate));
if (fun_data->instance_template()->IsUndefined(isolate)) {
Expand All @@ -68,21 +72,18 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
raw_holder = *js_receiver;
} else {
DCHECK(receiver->IsJSReceiver());

if (!receiver->IsJSObject()) {
// This function cannot be called with the given receiver. Abort!
THROW_NEW_ERROR(
isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
}

js_receiver = Handle<JSObject>::cast(receiver);
js_receiver = Handle<JSReceiver>::cast(receiver);

if (!fun_data->accept_any_receiver() &&
js_receiver->IsAccessCheckNeeded() &&
!isolate->MayAccess(handle(isolate->context()), js_receiver)) {
isolate->ReportFailedAccessCheck(js_receiver);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
return isolate->factory()->undefined_value();
js_receiver->IsAccessCheckNeeded()) {
// Proxies never need access checks.
DCHECK(js_receiver->IsJSObject());
Handle<JSObject> js_obj_receiver = Handle<JSObject>::cast(js_receiver);
if (!isolate->MayAccess(handle(isolate->context()), js_obj_receiver)) {
isolate->ReportFailedAccessCheck(js_obj_receiver);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
return isolate->factory()->undefined_value();
}
}

raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
Expand Down
28 changes: 28 additions & 0 deletions deps/v8/test/cctest/test-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,34 @@ THREADED_PROFILED_TEST(FunctionTemplate) {
TestFunctionTemplateAccessor(construct_callback, Return239Callback);
}

static void FunctionCallbackForProxyTest(
const v8::FunctionCallbackInfo<Value>& info) {
info.GetReturnValue().Set(info.This());
}

THREADED_TEST(FunctionTemplateWithProxy) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);

v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(isolate, FunctionCallbackForProxyTest);
v8::Local<v8::Function> function =
function_template->GetFunction(env.local()).ToLocalChecked();
CHECK((*env)->Global()->Set(env.local(), v8_str("f"), function).FromJust());
v8::Local<v8::Value> proxy =
CompileRun("var proxy = new Proxy({}, {}); proxy");
CHECK(proxy->IsProxy());

v8::Local<v8::Value> result = CompileRun("f(proxy)");
CHECK(result->Equals(env.local(), (*env)->Global()).FromJust());

result = CompileRun("f.call(proxy)");
CHECK(result->Equals(env.local(), proxy).FromJust());

result = CompileRun("Reflect.apply(f, proxy, [1])");
CHECK(result->Equals(env.local(), proxy).FromJust());
}

static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
ApiTestFuzzer::Fuzz();
Expand Down

0 comments on commit 105f606

Please sign in to comment.