Commit 70a54d46 authored by jgruber's avatar jgruber Committed by Commit bot

[turbofan] Inline calls to CPP builtins

BUG=

Review-Url: https://codereview.chromium.org/2259883002
Cr-Commit-Position: refs/heads/master@{#38758}
parent 9092f8ac
......@@ -184,6 +184,7 @@ const char* Builtins::Lookup(byte* pc) {
return NULL;
}
// static
const char* Builtins::name(int index) {
switch (index) {
#define CASE(Name, ...) \
......@@ -198,6 +199,74 @@ const char* Builtins::name(int index) {
return "";
}
// static
Address Builtins::CppEntryOf(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return FUNCTION_ADDR(Builtin_##Name);
BUILTIN_LIST_C(CASE)
#undef CASE
default:
return nullptr;
}
UNREACHABLE();
}
// static
bool Builtins::IsCpp(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return true;
#define BUILTIN_LIST_CPP(V) \
BUILTIN_LIST(V, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
BUILTIN_LIST_CPP(CASE)
#undef BUILTIN_LIST_CPP
#undef CASE
default:
return false;
}
UNREACHABLE();
}
// static
bool Builtins::IsApi(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return true;
#define BUILTIN_LIST_API(V) \
BUILTIN_LIST(IGNORE_BUILTIN, V, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
BUILTIN_LIST_API(CASE);
#undef BUILTIN_LIST_API
#undef CASE
default:
return false;
}
UNREACHABLE();
}
// static
bool Builtins::HasCppImplementation(int index) {
DCHECK(0 <= index && index < builtin_count);
switch (index) {
#define CASE(Name, ...) \
case k##Name: \
return true;
BUILTIN_LIST_C(CASE)
#undef CASE
default:
return false;
}
UNREACHABLE();
}
#define DEFINE_BUILTIN_ACCESSOR(Name, ...) \
Handle<Code> Builtins::Name() { \
Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \
......
......@@ -600,7 +600,15 @@ class Builtins {
return reinterpret_cast<Address>(&builtins_[name]);
}
const char* name(int index);
static const char* name(int index);
// Returns the C++ entry point for builtins implemented in C++, and the null
// Address otherwise.
static Address CppEntryOf(int index);
static bool IsCpp(int index);
static bool IsApi(int index);
static bool HasCppImplementation(int index);
bool is_initialized() const { return initialized_; }
......
......@@ -28,6 +28,9 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, Address address,
// -----------------------------------
__ AssertFunction(rdi);
// The logic contained here is mirrored for TurboFan inlining in
// JSTypedLowering::ReduceJSCall{Function,Construct}. Keep these in sync.
// Make sure we operate in the context of the called function (for example
// ConstructStubs implemented in C++ will be run in the context of the caller
// instead of the callee, due to the way that [[Construct]] is defined for
......
......@@ -29,15 +29,23 @@ Node* JSGraph::ToNumberBuiltinConstant() {
HeapConstant(isolate()->builtins()->ToNumber()));
}
Node* JSGraph::CEntryStubConstant(int result_size) {
if (result_size == 1) {
return CACHED(kCEntryStubConstant,
HeapConstant(CEntryStub(isolate(), 1).GetCode()));
Node* JSGraph::CEntryStubConstant(int result_size, SaveFPRegsMode save_doubles,
ArgvMode argv_mode, bool builtin_exit_frame) {
if (save_doubles == kDontSaveFPRegs && argv_mode == kArgvOnStack &&
result_size == 1) {
CachedNode key = builtin_exit_frame
? kCEntryStubWithBuiltinExitFrameConstant
: kCEntryStubConstant;
return CACHED(key,
HeapConstant(CEntryStub(isolate(), result_size, save_doubles,
argv_mode, builtin_exit_frame)
.GetCode()));
}
return HeapConstant(CEntryStub(isolate(), result_size).GetCode());
CEntryStub stub(isolate(), result_size, save_doubles, argv_mode,
builtin_exit_frame);
return HeapConstant(stub.GetCode());
}
Node* JSGraph::EmptyFixedArrayConstant() {
return CACHED(kEmptyFixedArrayConstant,
HeapConstant(factory()->empty_fixed_array()));
......
......@@ -42,7 +42,10 @@ class JSGraph : public ZoneObject {
Node* AllocateInNewSpaceStubConstant();
Node* AllocateInOldSpaceStubConstant();
Node* ToNumberBuiltinConstant();
Node* CEntryStubConstant(int result_size);
Node* CEntryStubConstant(int result_size,
SaveFPRegsMode save_doubles = kDontSaveFPRegs,
ArgvMode argv_mode = kArgvOnStack,
bool builtin_exit_frame = false);
Node* EmptyFixedArrayConstant();
Node* EmptyLiteralsArrayConstant();
Node* EmptyStringConstant();
......@@ -155,6 +158,7 @@ class JSGraph : public ZoneObject {
kAllocateInOldSpaceStubConstant,
kToNumberBuiltinConstant,
kCEntryStubConstant,
kCEntryStubWithBuiltinExitFrameConstant,
kEmptyFixedArrayConstant,
kEmptyLiteralsArrayConstant,
kEmptyStringConstant,
......
......@@ -4,6 +4,7 @@
#include "src/compiler/js-typed-lowering.h"
#include "src/builtins/builtins-utils.h"
#include "src/code-factory.h"
#include "src/compilation-dependencies.h"
#include "src/compiler/access-builder.h"
......@@ -1582,6 +1583,8 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
Handle<JSFunction> function =
Handle<JSFunction>::cast(target_type->AsConstant()->Value());
Handle<SharedFunctionInfo> shared(function->shared(), isolate());
const int builtin_index = shared->code()->builtin_index();
const bool is_builtin = (builtin_index != -1);
// Class constructors are callable, but [[Call]] will raise an exception.
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
......@@ -1613,9 +1616,58 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
Node* new_target = jsgraph()->UndefinedConstant();
Node* argument_count = jsgraph()->Int32Constant(arity);
if (shared->internal_formal_parameter_count() == arity ||
shared->internal_formal_parameter_count() ==
SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
if (is_builtin && Builtins::HasCppImplementation(builtin_index)) {
// Patch {node} to a direct CEntryStub call.
//
// ----------- A r g u m e n t s -----------
// -- 0: CEntryStub
// --- Stack args ---
// -- 1: receiver
// -- [2, 2 + n[: the n actual arguments passed to the builtin
// -- 2 + n: argc, including the receiver and implicit args (Smi)
// -- 2 + n + 1: target
// -- 2 + n + 2: new_target
// --- Register args ---
// -- 2 + n + 3: the C entry point
// -- 2 + n + 4: argc (Int32)
// -----------------------------------
// The logic contained here is mirrored in Builtins::Generate_Adaptor.
// Keep these in sync.
// API and CPP builtins are implemented in C++, and we can inline both.
// CPP builtins create a builtin exit frame, API builtins don't.
const bool create_builtin_exit_frame = Builtins::IsCpp(builtin_index);
Node* stub = jsgraph()->CEntryStubConstant(
1, kDontSaveFPRegs, kArgvOnStack, create_builtin_exit_frame);
node->ReplaceInput(0, stub);
const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
Node* argc_node = jsgraph()->Int32Constant(argc);
Zone* zone = graph()->zone();
node->InsertInput(zone, arity + 2, argc_node);
node->InsertInput(zone, arity + 3, target);
node->InsertInput(zone, arity + 4, new_target);
Address entry = Builtins::CppEntryOf(builtin_index);
ExternalReference entry_ref(ExternalReference(entry, isolate()));
Node* entry_node = jsgraph()->ExternalConstant(entry_ref);
node->InsertInput(zone, arity + 5, entry_node);
node->InsertInput(zone, arity + 6, argc_node);
const int return_count = 1;
Operator::Properties properties = node->op()->properties();
const char* debug_name = Builtins::name(builtin_index);
CallDescriptor* desc = Linkage::GetCEntryStubCallDescriptor(
graph()->zone(), return_count, argc, debug_name, properties, flags);
NodeProperties::ChangeOp(node, common()->Call(desc));
} else if (shared->internal_formal_parameter_count() == arity ||
shared->internal_formal_parameter_count() ==
SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
// Patch {node} to a direct call.
node->InsertInput(graph()->zone(), arity + 2, new_target);
node->InsertInput(graph()->zone(), arity + 3, argument_count);
......
......@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/linkage.h"
#include "src/ast/scopes.h"
#include "src/builtins/builtins-utils.h"
#include "src/code-stubs.h"
#include "src/compiler.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/frame.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node.h"
#include "src/compiler/osr.h"
#include "src/compiler/pipeline.h"
......@@ -222,6 +224,23 @@ bool CallDescriptor::UsesOnlyRegisters() const {
CallDescriptor* Linkage::GetRuntimeCallDescriptor(
Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
Operator::Properties properties, CallDescriptor::Flags flags) {
const Runtime::Function* function = Runtime::FunctionForId(function_id);
const int return_count = function->result_size;
const char* debug_name = function->name;
if (!Linkage::NeedsFrameStateInput(function_id)) {
flags = static_cast<CallDescriptor::Flags>(
flags & ~CallDescriptor::kNeedsFrameState);
}
return GetCEntryStubCallDescriptor(zone, return_count, js_parameter_count,
debug_name, properties, flags);
}
CallDescriptor* Linkage::GetCEntryStubCallDescriptor(
Zone* zone, int return_count, int js_parameter_count,
const char* debug_name, Operator::Properties properties,
CallDescriptor::Flags flags) {
const size_t function_count = 1;
const size_t num_args_count = 1;
const size_t context_count = 1;
......@@ -229,10 +248,8 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
static_cast<size_t>(js_parameter_count) +
num_args_count + context_count;
const Runtime::Function* function = Runtime::FunctionForId(function_id);
const size_t return_count = static_cast<size_t>(function->result_size);
LocationSignature::Builder locations(zone, return_count, parameter_count);
LocationSignature::Builder locations(zone, static_cast<size_t>(return_count),
static_cast<size_t>(parameter_count));
// Add returns.
if (locations.return_count_ > 0) {
......@@ -261,11 +278,6 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
// Add context.
locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
if (!Linkage::NeedsFrameStateInput(function_id)) {
flags = static_cast<CallDescriptor::Flags>(
flags & ~CallDescriptor::kNeedsFrameState);
}
// The target for runtime calls is a code object.
MachineType target_type = MachineType::AnyTagged();
LinkageLocation target_loc =
......@@ -280,10 +292,9 @@ CallDescriptor* Linkage::GetRuntimeCallDescriptor(
kNoCalleeSaved, // callee-saved
kNoCalleeSaved, // callee-saved fp
flags, // flags
function->name); // debug name
debug_name); // debug name
}
CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
int js_parameter_count,
CallDescriptor::Flags flags) {
......
......@@ -343,9 +343,14 @@ class Linkage : public ZoneObject {
CallDescriptor::Flags flags);
static CallDescriptor* GetRuntimeCallDescriptor(
Zone* zone, Runtime::FunctionId function, int parameter_count,
Zone* zone, Runtime::FunctionId function, int js_parameter_count,
Operator::Properties properties, CallDescriptor::Flags flags);
static CallDescriptor* GetCEntryStubCallDescriptor(
Zone* zone, int return_count, int js_parameter_count,
const char* debug_name, Operator::Properties properties,
CallDescriptor::Flags flags);
static CallDescriptor* GetStubCallDescriptor(
Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
int stack_parameter_count, CallDescriptor::Flags flags,
......
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