Chromium Code Reviews| Index: src/compiler/js-call-reducer.cc |
| diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc |
| index e42b4ca1dc53d685165960e4542a4fe688488931..90722fb08cd8aedd522b42c02699314e27042b90 100644 |
| --- a/src/compiler/js-call-reducer.cc |
| +++ b/src/compiler/js-call-reducer.cc |
| @@ -4,7 +4,9 @@ |
| #include "src/compiler/js-call-reducer.h" |
| +#include "src/code-stubs.h" |
| #include "src/compiler/js-graph.h" |
| +#include "src/compiler/linkage.h" |
| #include "src/compiler/node-matchers.h" |
| #include "src/compiler/simplified-operator.h" |
| #include "src/objects-inl.h" |
| @@ -257,8 +259,55 @@ MaybeHandle<Map> InferReceiverMap(Node* node) { |
| } |
| } |
| +bool CanInlineApiCall(Isolate* isolate, Node* node, |
| + Handle<FunctionTemplateInfo> function_template_info) { |
| + DCHECK(node->opcode() == IrOpcode::kJSCallFunction); |
| + if (function_template_info->call_code()->IsUndefined(isolate)) { |
| + return false; |
| + } |
| + CallFunctionParameters const& params = CallFunctionParametersOf(node->op()); |
| + int const argc = static_cast<int>(params.arity()) - 2; |
|
Jarin
2016/12/08 12:31:53
As discussed before, it would be good to describe
epertoso
2016/12/08 13:33:19
Done here and in ReduceCallApiFunction.
|
| + if (argc > CallApiCallbackStub::kArgMax || !params.feedback().IsValid()) { |
| + return false; |
| + } |
| + HeapObjectMatcher receiver(NodeProperties::GetValueInput(node, 1)); |
| + if (!receiver.HasValue()) { |
| + return false; |
| + } |
| + return receiver.Value()->IsUndefined(isolate) || |
| + (receiver.Value()->map()->IsJSObjectMap() && |
| + !receiver.Value()->map()->is_access_check_needed()); |
| +} |
| + |
| } // namespace |
| +JSCallReducer::HolderLookup JSCallReducer::LookupHolder( |
| + Handle<JSObject> object, |
| + Handle<FunctionTemplateInfo> function_template_info, |
| + Handle<JSObject>* holder) { |
| + DCHECK(object->map()->IsJSObjectMap()); |
| + Handle<Map> object_map(object->map()); |
| + Handle<FunctionTemplateInfo> expected_receiver_type; |
| + if (!function_template_info->signature()->IsUndefined(isolate())) { |
| + expected_receiver_type = |
| + handle(FunctionTemplateInfo::cast(function_template_info->signature())); |
|
Jarin
2016/12/08 12:31:53
Hmm, signature of FunctionTemplateInfo is Function
epertoso
2016/12/08 13:33:19
Yes. Not my fault.
|
| + } |
| + if (expected_receiver_type.is_null() || |
| + expected_receiver_type->IsTemplateFor(*object_map)) { |
| + *holder = Handle<JSObject>::null(); |
| + return kHolderIsReceiver; |
| + } |
| + while (object_map->has_hidden_prototype()) { |
| + Handle<JSObject> prototype(JSObject::cast(object_map->prototype())); |
| + object_map = handle(prototype->map()); |
| + if (expected_receiver_type->IsTemplateFor(*object_map)) { |
| + *holder = prototype; |
| + return kHolderFound; |
| + } |
| + } |
| + return kHolderNotFound; |
| +} |
| + |
| // ES6 section B.2.2.1.1 get Object.prototype.__proto__ |
| Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { |
| DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); |
| @@ -280,6 +329,66 @@ Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { |
| return NoChange(); |
| } |
| +Reduction JSCallReducer::ReduceCallApiFunction( |
| + Node* node, Node* target, |
| + Handle<FunctionTemplateInfo> function_template_info) { |
| + Isolate* isolate = this->isolate(); |
| + CHECK(!isolate->serializer_enabled()); |
| + HeapObjectMatcher m(target); |
| + DCHECK(m.HasValue() && m.Value()->IsJSFunction()); |
| + if (!CanInlineApiCall(isolate, node, function_template_info)) { |
| + return NoChange(); |
| + } |
| + Handle<CallHandlerInfo> call_handler_info( |
| + handle(CallHandlerInfo::cast(function_template_info->call_code()))); |
| + Handle<Object> data(call_handler_info->data(), isolate); |
| + |
| + Node* receiver_node = NodeProperties::GetValueInput(node, 1); |
| + CallFunctionParameters const& params = CallFunctionParametersOf(node->op()); |
| + |
| + Handle<HeapObject> receiver = HeapObjectMatcher(receiver_node).Value(); |
| + bool const receiver_is_undefined = receiver->IsUndefined(isolate); |
| + if (receiver_is_undefined) { |
| + receiver = handle(Handle<JSFunction>::cast(m.Value())->global_proxy()); |
| + } else { |
| + DCHECK(receiver->map()->IsJSObjectMap() && |
| + !receiver->map()->is_access_check_needed()); |
| + } |
| + |
| + Handle<JSObject> holder; |
| + HolderLookup lookup = LookupHolder(Handle<JSObject>::cast(receiver), |
| + function_template_info, &holder); |
| + if (lookup == kHolderNotFound) return NoChange(); |
| + if (receiver_is_undefined) { |
| + receiver_node = jsgraph()->HeapConstant(receiver); |
| + NodeProperties::ReplaceValueInput(node, receiver_node, 1); |
| + } |
| + Node* holder_node = |
| + lookup == kHolderFound ? jsgraph()->HeapConstant(holder) : receiver_node; |
| + |
| + Zone* zone = graph()->zone(); |
| + int const argc = static_cast<int>(params.arity() - 2); |
| + CallApiCallbackStub stub(isolate, argc, data->IsUndefined(isolate), false); |
| + CallInterfaceDescriptor cid = stub.GetCallInterfaceDescriptor(); |
| + CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor( |
| + isolate, zone, cid, |
| + cid.GetStackParameterCount() + argc + 1 /* including receiver */, |
| + CallDescriptor::kNeedsFrameState, Operator::kNoProperties, |
| + MachineType::AnyTagged(), 1); |
| + ApiFunction api_function(v8::ToCData<Address>(call_handler_info->callback())); |
| + ExternalReference function_reference( |
| + &api_function, ExternalReference::DIRECT_API_CALL, isolate); |
| + |
| + // CallApiCallbackStub's register arguments: code, target, call data, holder, |
| + // function address. |
| + node->InsertInput(zone, 0, jsgraph()->HeapConstant(stub.GetCode())); |
| + node->InsertInput(zone, 2, jsgraph()->Constant(data)); |
| + node->InsertInput(zone, 3, holder_node); |
| + node->InsertInput(zone, 4, jsgraph()->ExternalConstant(function_reference)); |
| + NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); |
| + return Changed(node); |
| +} |
| + |
| Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { |
| DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); |
| CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); |
| @@ -323,6 +432,12 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { |
| if (*function == function->native_context()->array_function()) { |
| return ReduceArrayConstructor(node); |
| } |
| + |
| + if (shared->IsApiFunction()) { |
| + return ReduceCallApiFunction( |
| + node, target, |
| + handle(FunctionTemplateInfo::cast(shared->function_data()))); |
| + } |
| } else if (m.Value()->IsJSBoundFunction()) { |
| Handle<JSBoundFunction> function = |
| Handle<JSBoundFunction>::cast(m.Value()); |