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(
i::PrototypeIterator iter(isolate, *Utils::OpenHandle(this),
i::kStartAtReceiver);
auto tmpl_info = *Utils::OpenHandle(*tmpl);
while (!tmpl_info->IsTemplateFor(iter.GetCurrent())) {
while (!tmpl_info->IsTemplateFor(iter.GetCurrent<i::JSObject>())) {
iter.Advance();
if (iter.IsAtEnd()) {
return Local<Object>();
}
if (iter.IsAtEnd()) return Local<Object>();
if (!iter.GetCurrent()->IsJSObject()) return Local<Object>();
}
// IsTemplateFor() ensures that iter.GetCurrent() can't be a Proxy here.
return Utils::ToLocal(i::handle(iter.GetCurrent<i::JSObject>(), isolate));
......@@ -5810,7 +5809,7 @@ Local<v8::Function> FunctionTemplate::GetFunction() {
bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
auto self = Utils::OpenHandle(this);
auto obj = Utils::OpenHandle(*value);
return self->IsTemplateFor(*obj);
return obj->IsJSObject() && self->IsTemplateFor(i::JSObject::cast(*obj));
}
......
......@@ -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,
......
......@@ -988,10 +988,8 @@ bool Object::ToInt32(int32_t* value) {
return false;
}
bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
if (!object->IsHeapObject()) return false;
return IsTemplateFor(HeapObject::cast(object)->map());
bool FunctionTemplateInfo::IsTemplateFor(JSObject* object) {
return IsTemplateFor(object->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
MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
Handle<JSReceiver> new_target,
......
......@@ -10553,13 +10553,9 @@ class FunctionTemplateInfo: public TemplateInfo {
static const int kSize = kLengthOffset + kPointerSize;
// Returns true if |object| is an instance of this function template.
bool IsTemplateFor(Object* object);
bool IsTemplateFor(JSObject* object);
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:
// Bit position in the flag, from least significant bit position.
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