Commit 2547ec87 authored by epertoso's avatar epertoso Committed by Commit bot

[turbofan] Inlining of API functions.

BUG=

Review-Url: https://codereview.chromium.org/2555223002
Cr-Commit-Position: refs/heads/master@{#41590}
parent 7b64e8d1
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
#include "src/compiler/js-call-reducer.h" #include "src/compiler/js-call-reducer.h"
#include "src/code-stubs.h"
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
...@@ -257,8 +259,58 @@ MaybeHandle<Map> InferReceiverMap(Node* node) { ...@@ -257,8 +259,58 @@ 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());
// CallApiCallbackStub expects the target in a register, so we count it out,
// and counts the receiver as an implicit argument, so we count the receiver
// out too.
int const argc = static_cast<int>(params.arity()) - 2;
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 } // 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()));
}
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__ // ES6 section B.2.2.1.1 get Object.prototype.__proto__
Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
...@@ -280,6 +332,69 @@ Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { ...@@ -280,6 +332,69 @@ Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
return NoChange(); 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();
// Same as CanInlineApiCall: exclude the target (which goes in a register) and
// the receiver (which is implicitly counted by CallApiCallbackStub) from the
// arguments count.
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 /* implicit 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) { Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
...@@ -323,6 +438,12 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { ...@@ -323,6 +438,12 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
if (*function == function->native_context()->array_function()) { if (*function == function->native_context()->array_function()) {
return ReduceArrayConstructor(node); return ReduceArrayConstructor(node);
} }
if (shared->IsApiFunction()) {
return ReduceCallApiFunction(
node, target,
handle(FunctionTemplateInfo::cast(shared->function_data())));
}
} else if (m.Value()->IsJSBoundFunction()) { } else if (m.Value()->IsJSBoundFunction()) {
Handle<JSBoundFunction> function = Handle<JSBoundFunction> function =
Handle<JSBoundFunction>::cast(m.Value()); Handle<JSBoundFunction>::cast(m.Value());
......
...@@ -41,6 +41,9 @@ class JSCallReducer final : public AdvancedReducer { ...@@ -41,6 +41,9 @@ class JSCallReducer final : public AdvancedReducer {
private: private:
Reduction ReduceArrayConstructor(Node* node); Reduction ReduceArrayConstructor(Node* node);
Reduction ReduceCallApiFunction(
Node* node, Node* target,
Handle<FunctionTemplateInfo> function_template_info);
Reduction ReduceNumberConstructor(Node* node); Reduction ReduceNumberConstructor(Node* node);
Reduction ReduceFunctionPrototypeApply(Node* node); Reduction ReduceFunctionPrototypeApply(Node* node);
Reduction ReduceFunctionPrototypeCall(Node* node); Reduction ReduceFunctionPrototypeCall(Node* node);
...@@ -49,6 +52,12 @@ class JSCallReducer final : public AdvancedReducer { ...@@ -49,6 +52,12 @@ class JSCallReducer final : public AdvancedReducer {
Reduction ReduceJSCallConstruct(Node* node); Reduction ReduceJSCallConstruct(Node* node);
Reduction ReduceJSCallFunction(Node* node); Reduction ReduceJSCallFunction(Node* node);
enum HolderLookup { kHolderNotFound, kHolderIsReceiver, kHolderFound };
HolderLookup LookupHolder(Handle<JSObject> object,
Handle<FunctionTemplateInfo> function_template_info,
Handle<JSObject>* holder);
Graph* graph() const; Graph* graph() const;
Flags flags() const { return flags_; } Flags flags() const { return flags_; }
JSGraph* jsgraph() const { return jsgraph_; } JSGraph* jsgraph() const { return jsgraph_; }
......
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