Skip to content

Commit 9fb02b5

Browse files
hashseedCommit Bot
authored andcommitted
Allow function callbacks to have Proxy as receiver.
R=verwaest@chromium.org Bug: v8:5773 Change-Id: Ifd29a1116ee8c86b8d8d24485bbfd19e260ab66b Reviewed-on: https://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}
1 parent 6f72af2 commit 9fb02b5

2 files changed

Lines changed: 49 additions & 20 deletions

File tree

src/builtins/builtins-api.cc

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,21 @@ namespace {
2222
// Returns the holder JSObject if the function can legally be called with this
2323
// receiver. Returns nullptr if the call is illegal.
2424
// TODO(dcarney): CallOptimization duplicates this logic, merge.
25-
JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
26-
JSObject* receiver) {
25+
JSReceiver* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
26+
JSReceiver* receiver) {
2727
Object* recv_type = info->signature();
2828
// No signature, return holder.
2929
if (!recv_type->IsFunctionTemplateInfo()) return receiver;
30+
// A Proxy cannot have been created from the signature template.
31+
if (!receiver->IsJSObject()) return nullptr;
32+
33+
JSObject* js_obj_receiver = JSObject::cast(receiver);
3034
FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
3135

3236
// Check the receiver. Fast path for receivers with no hidden prototypes.
33-
if (signature->IsTemplateFor(receiver)) return receiver;
34-
if (!receiver->map()->has_hidden_prototype()) return nullptr;
35-
for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
37+
if (signature->IsTemplateFor(js_obj_receiver)) return receiver;
38+
if (!js_obj_receiver->map()->has_hidden_prototype()) return nullptr;
39+
for (PrototypeIterator iter(isolate, js_obj_receiver, kStartAtPrototype,
3640
PrototypeIterator::END_AT_NON_HIDDEN);
3741
!iter.IsAtEnd(); iter.Advance()) {
3842
JSObject* current = iter.GetCurrent<JSObject>();
@@ -46,8 +50,8 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Object> HandleApiCallHelper(
4650
Isolate* isolate, Handle<HeapObject> function,
4751
Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
4852
Handle<Object> receiver, BuiltinArguments args) {
49-
Handle<JSObject> js_receiver;
50-
JSObject* raw_holder;
53+
Handle<JSReceiver> js_receiver;
54+
JSReceiver* raw_holder;
5155
if (is_construct) {
5256
DCHECK(args.receiver()->IsTheHole(isolate));
5357
if (fun_data->instance_template()->IsUndefined(isolate)) {
@@ -69,21 +73,18 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Object> HandleApiCallHelper(
6973
raw_holder = *js_receiver;
7074
} else {
7175
DCHECK(receiver->IsJSReceiver());
72-
73-
if (!receiver->IsJSObject()) {
74-
// This function cannot be called with the given receiver. Abort!
75-
THROW_NEW_ERROR(
76-
isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
77-
}
78-
79-
js_receiver = Handle<JSObject>::cast(receiver);
76+
js_receiver = Handle<JSReceiver>::cast(receiver);
8077

8178
if (!fun_data->accept_any_receiver() &&
82-
js_receiver->IsAccessCheckNeeded() &&
83-
!isolate->MayAccess(handle(isolate->context()), js_receiver)) {
84-
isolate->ReportFailedAccessCheck(js_receiver);
85-
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
86-
return isolate->factory()->undefined_value();
79+
js_receiver->IsAccessCheckNeeded()) {
80+
// Proxies never need access checks.
81+
DCHECK(js_receiver->IsJSObject());
82+
Handle<JSObject> js_obj_receiver = Handle<JSObject>::cast(js_receiver);
83+
if (!isolate->MayAccess(handle(isolate->context()), js_obj_receiver)) {
84+
isolate->ReportFailedAccessCheck(js_obj_receiver);
85+
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
86+
return isolate->factory()->undefined_value();
87+
}
8788
}
8889

8990
raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);

test/cctest/test-api.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,34 @@ THREADED_PROFILED_TEST(FunctionTemplate) {
10881088
TestFunctionTemplateAccessor(construct_callback, Return239Callback);
10891089
}
10901090

1091+
static void FunctionCallbackForProxyTest(
1092+
const v8::FunctionCallbackInfo<Value>& info) {
1093+
info.GetReturnValue().Set(info.This());
1094+
}
1095+
1096+
THREADED_TEST(FunctionTemplateWithProxy) {
1097+
LocalContext env;
1098+
v8::Isolate* isolate = env->GetIsolate();
1099+
v8::HandleScope scope(isolate);
1100+
1101+
v8::Local<v8::FunctionTemplate> function_template =
1102+
v8::FunctionTemplate::New(isolate, FunctionCallbackForProxyTest);
1103+
v8::Local<v8::Function> function =
1104+
function_template->GetFunction(env.local()).ToLocalChecked();
1105+
CHECK((*env)->Global()->Set(env.local(), v8_str("f"), function).FromJust());
1106+
v8::Local<v8::Value> proxy =
1107+
CompileRun("var proxy = new Proxy({}, {}); proxy");
1108+
CHECK(proxy->IsProxy());
1109+
1110+
v8::Local<v8::Value> result = CompileRun("f(proxy)");
1111+
CHECK(result->Equals(env.local(), (*env)->Global()).FromJust());
1112+
1113+
result = CompileRun("f.call(proxy)");
1114+
CHECK(result->Equals(env.local(), proxy).FromJust());
1115+
1116+
result = CompileRun("Reflect.apply(f, proxy, [1])");
1117+
CHECK(result->Equals(env.local(), proxy).FromJust());
1118+
}
10911119

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

0 commit comments

Comments
 (0)