Commit 9bfd7b9d authored by verwaest's avatar verwaest Committed by Commit bot

Optimize HandleApiCallHelper and friends

BUG=chromium:595492

Review-Url: https://codereview.chromium.org/2084923003
Cr-Commit-Position: refs/heads/master@{#37153}
parent 2c8ca9ad
...@@ -3913,11 +3913,10 @@ Local<Object> v8::Object::FindInstanceInPrototypeChain( ...@@ -3913,11 +3913,10 @@ Local<Object> v8::Object::FindInstanceInPrototypeChain(
i::PrototypeIterator iter(isolate, *Utils::OpenHandle(this), i::PrototypeIterator iter(isolate, *Utils::OpenHandle(this),
i::kStartAtReceiver); i::kStartAtReceiver);
auto tmpl_info = *Utils::OpenHandle(*tmpl); auto tmpl_info = *Utils::OpenHandle(*tmpl);
while (!tmpl_info->IsTemplateFor(iter.GetCurrent())) { while (!tmpl_info->IsTemplateFor(iter.GetCurrent<i::JSObject>())) {
iter.Advance(); iter.Advance();
if (iter.IsAtEnd()) { if (iter.IsAtEnd()) return Local<Object>();
return Local<Object>(); if (!iter.GetCurrent()->IsJSObject()) return Local<Object>();
}
} }
// IsTemplateFor() ensures that iter.GetCurrent() can't be a Proxy here. // IsTemplateFor() ensures that iter.GetCurrent() can't be a Proxy here.
return Utils::ToLocal(i::handle(iter.GetCurrent<i::JSObject>(), isolate)); return Utils::ToLocal(i::handle(iter.GetCurrent<i::JSObject>(), isolate));
...@@ -5810,7 +5809,7 @@ Local<v8::Function> FunctionTemplate::GetFunction() { ...@@ -5810,7 +5809,7 @@ Local<v8::Function> FunctionTemplate::GetFunction() {
bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) { bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
auto self = Utils::OpenHandle(this); auto self = Utils::OpenHandle(this);
auto obj = Utils::OpenHandle(*value); auto obj = Utils::OpenHandle(*value);
return self->IsTemplateFor(*obj); return obj->IsJSObject() && self->IsTemplateFor(i::JSObject::cast(*obj));
} }
......
...@@ -5101,13 +5101,35 @@ BUILTIN(RestrictedStrictArgumentsPropertiesThrower) { ...@@ -5101,13 +5101,35 @@ BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
namespace { 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, MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate,
BuiltinArguments args) { BuiltinArguments args) {
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<HeapObject> function = args.target<HeapObject>(); Handle<HeapObject> function = args.target<HeapObject>();
Handle<HeapObject> new_target = args.new_target(); Handle<HeapObject> new_target = args.new_target();
bool is_construct = !new_target->IsUndefined(isolate); bool is_construct = !new_target->IsUndefined(isolate);
Handle<JSReceiver> receiver; Handle<JSObject> receiver;
DCHECK(function->IsFunctionTemplateInfo() || DCHECK(function->IsFunctionTemplateInfo() ||
Handle<JSFunction>::cast(function)->shared()->IsApiFunction()); Handle<JSFunction>::cast(function)->shared()->IsApiFunction());
...@@ -5116,6 +5138,7 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate, ...@@ -5116,6 +5138,7 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate,
function->IsFunctionTemplateInfo() function->IsFunctionTemplateInfo()
? Handle<FunctionTemplateInfo>::cast(function) ? Handle<FunctionTemplateInfo>::cast(function)
: handle(JSFunction::cast(*function)->shared()->get_api_func_data()); : handle(JSFunction::cast(*function)->shared()->get_api_func_data());
JSObject* raw_holder;
if (is_construct) { if (is_construct) {
DCHECK(args.receiver()->IsTheHole(isolate)); DCHECK(args.receiver()->IsTheHole(isolate));
if (fun_data->instance_template()->IsUndefined(isolate)) { if (fun_data->instance_template()->IsUndefined(isolate)) {
...@@ -5133,27 +5156,33 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate, ...@@ -5133,27 +5156,33 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate,
Object); Object);
args[0] = *receiver; args[0] = *receiver;
DCHECK_EQ(*receiver, *args.receiver()); DCHECK_EQ(*receiver, *args.receiver());
raw_holder = *receiver;
} else { } else {
DCHECK(args.receiver()->IsJSReceiver()); DCHECK(args.receiver()->IsJSReceiver());
receiver = args.at<JSReceiver>(0);
}
if (!is_construct && !fun_data->accept_any_receiver()) { Handle<JSReceiver> object = args.at<JSReceiver>(0);
if (receiver->IsJSObject() && receiver->IsAccessCheckNeeded()) { if (!object->IsJSObject()) {
Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); // This function cannot be called with the given receiver. Abort!
if (!isolate->MayAccess(handle(isolate->context()), js_receiver)) { THROW_NEW_ERROR(
isolate->ReportFailedAccessCheck(js_receiver); isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, 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)) { if (raw_holder == nullptr) {
// This function cannot be called with the given receiver. Abort! // This function cannot be called with the given receiver. Abort!
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIllegalInvocation), THROW_NEW_ERROR(
Object); isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
}
} }
Object* raw_call_data = fun_data->call_code(); Object* raw_call_data = fun_data->call_code();
...@@ -5166,7 +5195,6 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate, ...@@ -5166,7 +5195,6 @@ MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(Isolate* isolate,
Object* data_obj = call_data->data(); Object* data_obj = call_data->data();
LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver()))); LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
DCHECK(raw_holder->IsJSObject());
FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder, FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
*new_target, &args[0] - 1, *new_target, &args[0] - 1,
......
...@@ -988,10 +988,8 @@ bool Object::ToInt32(int32_t* value) { ...@@ -988,10 +988,8 @@ bool Object::ToInt32(int32_t* value) {
return false; return false;
} }
bool FunctionTemplateInfo::IsTemplateFor(JSObject* object) {
bool FunctionTemplateInfo::IsTemplateFor(Object* object) { return IsTemplateFor(object->map());
if (!object->IsHeapObject()) return false;
return IsTemplateFor(HeapObject::cast(object)->map());
} }
...@@ -1014,26 +1012,6 @@ bool FunctionTemplateInfo::IsTemplateFor(Map* map) { ...@@ -1014,26 +1012,6 @@ bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
} }
// TODO(dcarney): CallOptimization duplicates this logic, merge.
Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
Object* receiver) {
// API calls are only supported with JSObject receivers.
if (!receiver->IsJSObject()) return isolate->heap()->null_value();
Object* recv_type = this->signature();
// No signature, return holder.
if (recv_type->IsUndefined(isolate)) return receiver;
FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
// Check the receiver.
for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
kStartAtReceiver,
PrototypeIterator::END_AT_NON_HIDDEN);
!iter.IsAtEnd(); iter.Advance()) {
if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
}
return isolate->heap()->null_value();
}
// static // static
MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
Handle<JSReceiver> new_target, Handle<JSReceiver> new_target,
......
...@@ -10553,13 +10553,9 @@ class FunctionTemplateInfo: public TemplateInfo { ...@@ -10553,13 +10553,9 @@ class FunctionTemplateInfo: public TemplateInfo {
static const int kSize = kLengthOffset + kPointerSize; static const int kSize = kLengthOffset + kPointerSize;
// Returns true if |object| is an instance of this function template. // Returns true if |object| is an instance of this function template.
bool IsTemplateFor(Object* object); bool IsTemplateFor(JSObject* object);
bool IsTemplateFor(Map* map); bool IsTemplateFor(Map* map);
// Returns the holder JSObject if the function can legally be called with this
// receiver. Returns Heap::null_value() if the call is illegal.
Object* GetCompatibleReceiver(Isolate* isolate, Object* receiver);
private: private:
// Bit position in the flag, from least significant bit position. // Bit position in the flag, from least significant bit position.
static const int kHiddenPrototypeBit = 0; static const int kHiddenPrototypeBit = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment