Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index d1cbbc4b3ffb638d34dea2bf22f7210d5f8f3f97..6562067686e12f4057d7d9fcd740c716740365aa 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -5101,13 +5101,35 @@ BUILTIN(RestrictedStrictArgumentsPropertiesThrower) { |
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) { |
+ Object* recv_type = info->signature(); |
+ // No signature, return holder. |
+ if (!recv_type->IsFunctionTemplateInfo()) return 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, |
+ PrototypeIterator::END_AT_NON_HIDDEN); |
+ !iter.IsAtEnd(); iter.Advance()) { |
+ JSObject* current = iter.GetCurrent<JSObject>(); |
+ if (signature->IsTemplateFor(current)) return current; |
+ } |
+ return nullptr; |
+} |
+ |
MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate, |
BuiltinArguments args) { |
HandleScope scope(isolate); |
Handle<HeapObject> function = args.target<HeapObject>(); |
Handle<HeapObject> new_target = args.new_target(); |
bool is_construct = !new_target->IsUndefined(isolate); |
- Handle<JSReceiver> receiver; |
+ Handle<JSObject> receiver; |
DCHECK(function->IsFunctionTemplateInfo() || |
Handle<JSFunction>::cast(function)->shared()->IsApiFunction()); |
@@ -5116,6 +5138,7 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate, |
function->IsFunctionTemplateInfo() |
? Handle<FunctionTemplateInfo>::cast(function) |
: handle(JSFunction::cast(*function)->shared()->get_api_func_data()); |
+ JSObject* raw_holder; |
if (is_construct) { |
DCHECK(args.receiver()->IsTheHole(isolate)); |
if (fun_data->instance_template()->IsUndefined(isolate)) { |
@@ -5133,27 +5156,33 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate, |
Object); |
args[0] = *receiver; |
DCHECK_EQ(*receiver, *args.receiver()); |
+ |
+ raw_holder = *receiver; |
} else { |
DCHECK(args.receiver()->IsJSReceiver()); |
- receiver = args.at<JSReceiver>(0); |
- } |
- if (!is_construct && !fun_data->accept_any_receiver()) { |
- if (receiver->IsJSObject() && receiver->IsAccessCheckNeeded()) { |
- Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); |
- if (!isolate->MayAccess(handle(isolate->context()), js_receiver)) { |
- isolate->ReportFailedAccessCheck(js_receiver); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
- } |
+ Handle<JSReceiver> object = args.at<JSReceiver>(0); |
+ if (!object->IsJSObject()) { |
+ // This function cannot be called with the given receiver. Abort! |
+ THROW_NEW_ERROR( |
+ isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object); |
} |
- } |
- Object* raw_holder = fun_data->GetCompatibleReceiver(isolate, *receiver); |
+ receiver = Handle<JSObject>::cast(object); |
+ |
+ if (!fun_data->accept_any_receiver() && receiver->IsAccessCheckNeeded() && |
+ !isolate->MayAccess(handle(isolate->context()), receiver)) { |
+ isolate->ReportFailedAccessCheck(receiver); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
+ } |
+ |
+ raw_holder = GetCompatibleReceiver(isolate, *fun_data, *receiver); |
- if (raw_holder->IsNull(isolate)) { |
- // This function cannot be called with the given receiver. Abort! |
- THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIllegalInvocation), |
- Object); |
+ if (raw_holder == nullptr) { |
+ // This function cannot be called with the given receiver. Abort! |
+ THROW_NEW_ERROR( |
+ isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object); |
+ } |
} |
Object* raw_call_data = fun_data->call_code(); |
@@ -5166,7 +5195,6 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate, |
Object* data_obj = call_data->data(); |
LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver()))); |
- DCHECK(raw_holder->IsJSObject()); |
FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder, |
*new_target, &args[0] - 1, |