Commit ca1e6573 authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

[turbofan] Fast API calls support for default fallback

This change adds a has_error parameter on the stack
which allows the fast callback to report an error. In case
this parameter is set to non-zero, the generated code calls
the slow (default) callback, which can throw the exception.

Bug: chromium:1052746

Change-Id: Ib11f6b0bef37d5eb1d04cd6d0a3ef59028dcc448
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2183929Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68871}
parent 1905c05c
......@@ -331,13 +331,17 @@ struct GetCType<T**> : public GetCTypePointerPointerImpl<T> {};
template <typename T>
struct GetCType<T*> : public GetCTypePointerImpl<T> {};
template <typename R, typename... Args>
template <typename R, bool RaisesException, typename... Args>
class CFunctionInfoImpl : public CFunctionInfo {
public:
static constexpr int kHasErrorArgCount = (RaisesException ? 1 : 0);
static constexpr int kReceiverCount = 1;
CFunctionInfoImpl()
: return_info_(internal::GetCType<R>::Get()),
arg_count_(sizeof...(Args)),
arg_count_(sizeof...(Args) - kHasErrorArgCount),
arg_info_{internal::GetCType<Args>::Get()...} {
static_assert(sizeof...(Args) >= kHasErrorArgCount + kReceiverCount,
"The receiver or the has_error argument is missing.");
static_assert(
internal::GetCType<R>::Get().GetType() == CTypeInfo::Type::kVoid,
"Only void return types are currently supported.");
......@@ -351,9 +355,9 @@ class CFunctionInfoImpl : public CFunctionInfo {
}
private:
CTypeInfo return_info_;
const CTypeInfo return_info_;
const unsigned int arg_count_;
CTypeInfo arg_info_[sizeof...(Args)];
const CTypeInfo arg_info_[sizeof...(Args)];
};
} // namespace internal
......@@ -378,6 +382,11 @@ class V8_EXPORT CFunction {
return ArgUnwrap<F*>::Make(func);
}
template <typename F>
static CFunction MakeRaisesException(F* func) {
return ArgUnwrap<F*>::MakeRaisesException(func);
}
template <typename F>
static CFunction Make(F* func, const CFunctionInfo* type_info) {
return CFunction(reinterpret_cast<const void*>(func), type_info);
......@@ -389,9 +398,9 @@ class V8_EXPORT CFunction {
CFunction(const void* address, const CFunctionInfo* type_info);
template <typename R, typename... Args>
template <typename R, bool RaisesException, typename... Args>
static CFunctionInfo* GetCFunctionInfo() {
static internal::CFunctionInfoImpl<R, Args...> instance;
static internal::CFunctionInfoImpl<R, RaisesException, Args...> instance;
return &instance;
}
......@@ -406,7 +415,11 @@ class V8_EXPORT CFunction {
public:
static CFunction Make(R (*func)(Args...)) {
return CFunction(reinterpret_cast<const void*>(func),
GetCFunctionInfo<R, Args...>());
GetCFunctionInfo<R, false, Args...>());
}
static CFunction MakeRaisesException(R (*func)(Args...)) {
return CFunction(reinterpret_cast<const void*>(func),
GetCFunctionInfo<R, true, Args...>());
}
};
};
......
......@@ -4,6 +4,7 @@
#include "src/compiler/effect-control-linearizer.h"
#include "include/v8-fast-api-calls.h"
#include "src/base/bits.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/machine-type.h"
......@@ -185,6 +186,7 @@ class EffectControlLinearizer {
void LowerTransitionElementsKind(Node* node);
Node* LowerLoadFieldByIndex(Node* node);
Node* LowerLoadMessage(Node* node);
Node* LowerFastApiCall(Node* node);
Node* LowerLoadTypedElement(Node* node);
Node* LowerLoadDataViewElement(Node* node);
Node* LowerLoadStackArgument(Node* node);
......@@ -1246,6 +1248,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStoreMessage:
LowerStoreMessage(node);
break;
case IrOpcode::kFastApiCall:
result = LowerFastApiCall(node);
break;
case IrOpcode::kLoadFieldByIndex:
result = LowerLoadFieldByIndex(node);
break;
......@@ -4798,6 +4803,121 @@ void EffectControlLinearizer::LowerStoreMessage(Node* node) {
__ StoreField(AccessBuilder::ForExternalIntPtr(), offset, object_pattern);
}
// TODO(mslekova): Avoid code duplication with simplified lowering.
static MachineType MachineTypeFor(CTypeInfo::Type type) {
switch (type) {
case CTypeInfo::Type::kVoid:
return MachineType::AnyTagged();
case CTypeInfo::Type::kBool:
return MachineType::Bool();
case CTypeInfo::Type::kInt32:
return MachineType::Int32();
case CTypeInfo::Type::kUint32:
return MachineType::Uint32();
case CTypeInfo::Type::kInt64:
return MachineType::Int64();
case CTypeInfo::Type::kUint64:
return MachineType::Uint64();
case CTypeInfo::Type::kFloat32:
return MachineType::Float32();
case CTypeInfo::Type::kFloat64:
return MachineType::Float64();
case CTypeInfo::Type::kUnwrappedApiObject:
return MachineType::Pointer();
}
}
Node* EffectControlLinearizer::LowerFastApiCall(Node* node) {
FastApiCallNode n(node);
FastApiCallParameters const& params = n.Parameters();
const CFunctionInfo* c_signature = params.signature();
const int c_arg_count = c_signature->ArgumentCount();
CallDescriptor* js_call_descriptor = params.descriptor();
int js_arg_count = static_cast<int>(js_call_descriptor->ParameterCount());
const int value_input_count = node->op()->ValueInputCount();
CHECK_EQ(FastApiCallNode::ArityForArgc(c_arg_count, js_arg_count),
value_input_count);
// Add the { has_error } output parameter.
int kAlign = 4;
int kSize = 4;
Node* has_error = __ StackSlot(kSize, kAlign);
// Generate the store to `has_error`.
__ Store(StoreRepresentation(MachineRepresentation::kWord32, kNoWriteBarrier),
has_error, 0, jsgraph()->ZeroConstant());
MachineSignature::Builder builder(
graph()->zone(), 1, c_arg_count + FastApiCallNode::kHasErrorInputCount);
MachineType return_type = MachineTypeFor(c_signature->ReturnInfo().GetType());
builder.AddReturn(return_type);
for (int i = 0; i < c_arg_count; ++i) {
MachineType machine_type =
MachineTypeFor(c_signature->ArgumentInfo(i).GetType());
builder.AddParam(machine_type);
}
builder.AddParam(MachineType::Pointer()); // has_error
CallDescriptor* call_descriptor = Linkage::GetSimplifiedCDescriptor(
graph()->zone(), builder.Build(), CallDescriptor::kNoFlags);
call_descriptor->SetCFunctionInfo(c_signature);
Node** const inputs = graph()->zone()->NewArray<Node*>(
c_arg_count + FastApiCallNode::kFastCallExtraInputCount);
for (int i = 0; i < c_arg_count + FastApiCallNode::kFastTargetInputCount;
++i) {
inputs[i] = NodeProperties::GetValueInput(node, i);
}
inputs[c_arg_count + 1] = has_error;
inputs[c_arg_count + 2] = __ effect();
inputs[c_arg_count + 3] = __ control();
__ Call(call_descriptor,
c_arg_count + FastApiCallNode::kFastCallExtraInputCount, inputs);
// Generate the load from `has_error`.
Node* load = __ Load(MachineType::Int32(), has_error, 0);
TNode<Boolean> cond =
TNode<Boolean>::UncheckedCast(__ Word32Equal(load, __ Int32Constant(0)));
// Hint to true.
auto if_success = __ MakeLabel();
auto if_error = __ MakeDeferredLabel();
auto merge = __ MakeLabel(MachineRepresentation::kTagged);
__ Branch(cond, &if_success, &if_error);
// Generate fast call.
__ Bind(&if_success);
Node* then_result = [&]() { return __ UndefinedConstant(); }();
__ Goto(&merge, then_result);
// Generate direct slow call.
__ Bind(&if_error);
Node* else_result = [&]() {
Node** const slow_inputs = graph()->zone()->NewArray<Node*>(
n.SlowCallArgumentCount() +
FastApiCallNode::kEffectAndControlInputCount);
int fast_call_params = c_arg_count + FastApiCallNode::kFastTargetInputCount;
CHECK_EQ(value_input_count - fast_call_params, n.SlowCallArgumentCount());
int index = 0;
for (; index < n.SlowCallArgumentCount(); ++index) {
slow_inputs[index] = n.SlowCallArgument(index);
}
slow_inputs[index] = __ effect();
slow_inputs[index + 1] = __ control();
Node* slow_call = __ Call(
params.descriptor(),
index + FastApiCallNode::kEffectAndControlInputCount, slow_inputs);
return slow_call;
}();
__ Goto(&merge, else_result);
__ Bind(&merge);
return merge.PhiAt(0);
}
Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) {
Node* object = node->InputAt(0);
Node* index = node->InputAt(1);
......
......@@ -736,6 +736,17 @@ Node* GraphAssembler::DeoptimizeIfNot(DeoptimizeReason reason,
condition, frame_state, effect(), control()));
}
TNode<Object> GraphAssembler::Call(const CallDescriptor* call_descriptor,
int inputs_size, Node** inputs) {
return Call(common()->Call(call_descriptor), inputs_size, inputs);
}
TNode<Object> GraphAssembler::Call(const Operator* op, int inputs_size,
Node** inputs) {
DCHECK_EQ(IrOpcode::kCall, op->opcode());
return AddNode<Object>(graph()->NewNode(op, inputs_size, inputs));
}
void GraphAssembler::BranchWithCriticalSafetyCheck(
Node* condition, GraphAssemblerLabel<0u>* if_true,
GraphAssemblerLabel<0u>* if_false) {
......
......@@ -297,10 +297,14 @@ class V8_EXPORT_PRIVATE GraphAssembler {
DeoptimizeReason reason, FeedbackSource const& feedback, Node* condition,
Node* frame_state,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
TNode<Object> Call(const CallDescriptor* call_descriptor, int inputs_size,
Node** inputs);
TNode<Object> Call(const Operator* op, int inputs_size, Node** inputs);
template <typename... Args>
Node* Call(const CallDescriptor* call_descriptor, Args... args);
TNode<Object> Call(const CallDescriptor* call_descriptor, Node* first_arg,
Args... args);
template <typename... Args>
Node* Call(const Operator* op, Args... args);
TNode<Object> Call(const Operator* op, Node* first_arg, Args... args);
// Basic control operations.
template <size_t VarCount>
......@@ -720,19 +724,19 @@ void GraphAssembler::GotoIfNot(Node* condition,
}
template <typename... Args>
Node* GraphAssembler::Call(const CallDescriptor* call_descriptor,
Args... args) {
TNode<Object> GraphAssembler::Call(const CallDescriptor* call_descriptor,
Node* first_arg, Args... args) {
const Operator* op = common()->Call(call_descriptor);
return Call(op, args...);
return Call(op, first_arg, args...);
}
template <typename... Args>
Node* GraphAssembler::Call(const Operator* op, Args... args) {
DCHECK_EQ(IrOpcode::kCall, op->opcode());
Node* args_array[] = {args..., effect(), control()};
int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
TNode<Object> GraphAssembler::Call(const Operator* op, Node* first_arg,
Args... args) {
Node* args_array[] = {first_arg, args..., effect(), control()};
int size = static_cast<int>(1 + sizeof...(args)) + op->EffectInputCount() +
op->ControlInputCount();
return AddNode(graph()->NewNode(op, size, args_array));
return Call(op, size, args_array);
}
class V8_EXPORT_PRIVATE JSGraphAssembler : public GraphAssembler {
......
......@@ -874,63 +874,115 @@ class PromiseBuiltinReducerAssembler : public JSCallReducerAssembler {
class FastApiCallReducerAssembler : public JSCallReducerAssembler {
public:
FastApiCallReducerAssembler(JSGraph* jsgraph, Zone* zone, Node* node,
Address c_function,
const CFunctionInfo* c_signature)
FastApiCallReducerAssembler(
JSGraph* jsgraph, Zone* zone, Node* node, Address c_function,
const CFunctionInfo* c_signature,
const FunctionTemplateInfoRef function_template_info, Node* receiver,
Node* holder, const SharedFunctionInfoRef shared, Node* target,
const int arity, Node* effect)
: JSCallReducerAssembler(jsgraph, zone, node),
c_function_(c_function),
c_signature_(c_signature) {
c_signature_(c_signature),
function_template_info_(function_template_info),
receiver_(receiver),
holder_(holder),
shared_(shared),
target_(target),
arity_(arity) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
DCHECK_NE(c_function_, kNullAddress);
CHECK_NOT_NULL(c_signature_);
InitializeEffectControl(effect, NodeProperties::GetControlInput(node));
}
TNode<Object> ReduceFastApiCall() {
JSCallNode n(node_ptr());
// C arguments include the receiver at index 0. Thus C index 1 corresponds
// to the JS argument 0, etc.
static constexpr int kReceiver = 1;
const int c_argument_count =
static_cast<int>(c_signature_->ArgumentCount());
const bool c_arguments_contain_receiver = c_argument_count > 0;
CHECK_GE(c_argument_count, kReceiver);
int cursor = 0;
base::SmallVector<Node*, kInlineSize + kExtraInputsCount> inputs(
c_argument_count + kExtraInputsCount);
base::SmallVector<Node*, kInlineSize> inputs(c_argument_count + arity_ +
kExtraInputsCount);
inputs[cursor++] = ExternalConstant(ExternalReference::Create(c_function_));
if (c_arguments_contain_receiver) {
inputs[cursor++] = MaybeUnwrapApiObject(
c_signature_->ArgumentInfo(0).GetType(), ReceiverInput());
}
inputs[cursor++] = MaybeUnwrapApiObject(
c_signature_->ArgumentInfo(0).GetType(), n.receiver());
// TODO(jgruber,mslekova): Consider refactoring CFunctionInfo to distinguish
// TODO(turbofan): Consider refactoring CFunctionInfo to distinguish
// between receiver and arguments, simplifying this (and related) spots.
for (int i = 0; i < c_argument_count - kReceiver; ++i) {
if (i < ArgumentCount()) {
int js_args_count = c_argument_count - kReceiver;
for (int i = 0; i < js_args_count; ++i) {
if (i < n.ArgumentCount()) {
CTypeInfo::Type type =
c_signature_->ArgumentInfo(i + kReceiver).GetType();
inputs[cursor++] = MaybeUnwrapApiObject(type, Argument(i));
inputs[cursor++] = MaybeUnwrapApiObject(type, n.Argument(i));
} else {
inputs[cursor++] = UndefinedConstant();
}
}
// Here we add the arguments for the slow call, which will be
// reconstructed at a later phase. Those are effectively the same
// arguments as for the fast call, but we want to have them as
// separate inputs, so that SimplifiedLowering can provide the best
// possible UseInfos for each of them. The inputs to FastApiCall
// look like:
// [fast callee, receiver, ... C arguments,
// call code, external constant for function, argc, call handler info data,
// holder, receiver, ... JS arguments, context, new frame state]
CallHandlerInfoRef call_handler_info = *function_template_info_.call_code();
Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
CallInterfaceDescriptor cid = call_api_callback.descriptor();
CallDescriptor* call_descriptor =
Linkage::GetStubCallDescriptor(graph()->zone(), cid, arity_ + kReceiver,
CallDescriptor::kNeedsFrameState);
ApiFunction api_function(call_handler_info.callback());
ExternalReference function_reference = ExternalReference::Create(
&api_function, ExternalReference::DIRECT_API_CALL);
Node* continuation_frame_state =
CreateGenericLazyDeoptContinuationFrameState(
jsgraph(), shared_, target_, ContextInput(), receiver_,
FrameStateInput());
inputs[cursor++] = HeapConstant(call_api_callback.code());
inputs[cursor++] = ExternalConstant(function_reference);
inputs[cursor++] = NumberConstant(arity_);
inputs[cursor++] = Constant(call_handler_info.data());
inputs[cursor++] = holder_;
inputs[cursor++] = receiver_;
for (int i = 0; i < arity_; ++i) {
inputs[cursor++] = Argument(i);
}
inputs[cursor++] = ContextInput();
inputs[cursor++] = continuation_frame_state;
inputs[cursor++] = effect();
inputs[cursor++] = control();
DCHECK_EQ(cursor, c_argument_count + kExtraInputsCount);
return FastApiCall(inputs.begin(), inputs.size());
DCHECK_EQ(cursor, c_argument_count + arity_ + kExtraInputsCount);
return FastApiCall(call_descriptor, inputs.begin(), inputs.size());
}
private:
static constexpr int kTargetEffectAndControl = 3;
static constexpr int kExtraInputsCount = kTargetEffectAndControl;
static constexpr int kInlineSize = 10;
TNode<Object> FastApiCall(Node** inputs, size_t inputs_size) {
return AddNode<Object>(
graph()->NewNode(simplified()->FastApiCall(c_signature_, feedback()),
static_cast<int>(inputs_size), inputs));
static constexpr int kTarget = 1;
static constexpr int kEffectAndControl = 2;
static constexpr int kContextAndFrameState = 2;
static constexpr int kCallCodeDataAndArgc = 3;
static constexpr int kHolder = 1, kReceiver = 1;
static constexpr int kExtraInputsCount =
kTarget * 2 + kEffectAndControl + kContextAndFrameState +
kCallCodeDataAndArgc + kHolder + kReceiver;
static constexpr int kInlineSize = 12;
TNode<Object> FastApiCall(CallDescriptor* descriptor, Node** inputs,
size_t inputs_size) {
return AddNode<Object>(graph()->NewNode(
simplified()->FastApiCall(c_signature_, feedback(), descriptor),
static_cast<int>(inputs_size), inputs));
}
TNode<RawPtrT> UnwrapApiObject(TNode<JSObject> node) {
......@@ -961,6 +1013,12 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
const Address c_function_;
const CFunctionInfo* const c_signature_;
const FunctionTemplateInfoRef function_template_info_;
Node* const receiver_;
Node* const holder_;
const SharedFunctionInfoRef shared_;
Node* const target_;
const int arity_;
};
TNode<Number> JSCallReducerAssembler::SpeculativeToNumber(
......@@ -3580,18 +3638,22 @@ Reduction JSCallReducer::ReduceCallApiFunction(
if (FLAG_turbo_fast_api_calls && c_function != kNullAddress) {
const CFunctionInfo* c_signature = function_template_info.c_signature();
FastApiCallReducerAssembler a(jsgraph(), graph()->zone(), node, c_function,
c_signature);
Node* c_call = a.ReduceFastApiCall();
ReplaceWithSubgraph(&a, c_call);
return Replace(c_call);
c_signature, function_template_info, receiver,
holder, shared, target, argc,
receiver /* The ConvertReceiver node needs to
be connected in the effect chain.*/);
Node* fast_call_subgraph = a.ReduceFastApiCall();
ReplaceWithSubgraph(&a, fast_call_subgraph);
return Replace(fast_call_subgraph);
}
CallHandlerInfoRef call_handler_info = *function_template_info.call_code();
Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
CallInterfaceDescriptor cid = call_api_callback.descriptor();
auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), cid, argc + 1 /* implicit receiver */,
CallDescriptor::kNeedsFrameState);
auto call_descriptor =
Linkage::GetStubCallDescriptor(graph()->zone(), cid, argc + 1 /*
implicit receiver */, CallDescriptor::kNeedsFrameState);
ApiFunction api_function(call_handler_info.callback());
ExternalReference function_reference = ExternalReference::Create(
&api_function, ExternalReference::DIRECT_API_CALL);
......@@ -3607,9 +3669,10 @@ Reduction JSCallReducer::ReduceCallApiFunction(
node->InsertInput(graph()->zone(), 3,
jsgraph()->Constant(call_handler_info.data()));
node->InsertInput(graph()->zone(), 4, holder);
node->ReplaceInput(5, receiver); // Update receiver input.
node->ReplaceInput(7 + argc, continuation_frame_state);
node->ReplaceInput(8 + argc, effect); // Update effect input.
node->ReplaceInput(5, receiver); // Update receiver input.
// 6 + argc is context input.
node->ReplaceInput(6 + argc + 1, continuation_frame_state);
node->ReplaceInput(6 + argc + 2, effect);
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
return Changed(node);
}
......
......@@ -1709,7 +1709,7 @@ class RepresentationSelector {
static MachineType MachineTypeFor(CTypeInfo::Type type) {
switch (type) {
case CTypeInfo::Type::kVoid:
return MachineType::Int32();
return MachineType::AnyTagged();
case CTypeInfo::Type::kBool:
return MachineType::Bool();
case CTypeInfo::Type::kInt32:
......@@ -1759,48 +1759,48 @@ class RepresentationSelector {
static constexpr int kInitialArgumentsCount = 10;
template <Phase T>
void VisitFastApiCall(Node* node) {
FastApiCallParameters const& params = FastApiCallParametersOf(node->op());
const CFunctionInfo* c_signature = params.signature();
int c_arg_count = c_signature->ArgumentCount();
int value_input_count = node->op()->ValueInputCount();
// function, ... C args
CHECK_EQ(c_arg_count + 1, value_input_count);
void VisitFastApiCall(Node* node, SimplifiedLowering* lowering) {
FastApiCallParameters const& op_params =
FastApiCallParametersOf(node->op());
const CFunctionInfo* c_signature = op_params.signature();
const int c_arg_count = c_signature->ArgumentCount();
CallDescriptor* call_descriptor = op_params.descriptor();
int js_arg_count = static_cast<int>(call_descriptor->ParameterCount());
const int value_input_count = node->op()->ValueInputCount();
CHECK_EQ(FastApiCallNode::ArityForArgc(c_arg_count, js_arg_count),
value_input_count);
base::SmallVector<UseInfo, kInitialArgumentsCount> arg_use_info(
c_arg_count);
// The target of the fast call.
ProcessInput<T>(node, 0, UseInfo::Word());
// Propagate representation information from TypeInfo.
for (int i = 0; i < c_arg_count; i++) {
arg_use_info[i] = UseInfoForFastApiCallArgument(
c_signature->ArgumentInfo(i).GetType(), params.feedback());
ProcessInput<T>(node, i + 1, arg_use_info[i]);
c_signature->ArgumentInfo(i).GetType(), op_params.feedback());
ProcessInput<T>(node, i + FastApiCallNode::kFastTargetInputCount,
arg_use_info[i]);
}
// The call code for the slow call.
ProcessInput<T>(node, c_arg_count + FastApiCallNode::kFastTargetInputCount,
UseInfo::AnyTagged());
for (int i = 1; i <= js_arg_count; i++) {
ProcessInput<T>(node,
c_arg_count + FastApiCallNode::kFastTargetInputCount + i,
TruncatingUseInfoFromRepresentation(
call_descriptor->GetInputType(i).representation()));
}
for (int i = c_arg_count + FastApiCallNode::kFastTargetInputCount +
js_arg_count;
i < value_input_count; ++i) {
ProcessInput<T>(node, i, UseInfo::AnyTagged());
}
ProcessRemainingInputs<T>(node, value_input_count);
MachineType return_type =
MachineTypeFor(c_signature->ReturnInfo().GetType());
SetOutput<T>(node, return_type.representation());
if (lower<T>()) {
MachineSignature::Builder builder(graph()->zone(), 1, c_arg_count);
builder.AddReturn(return_type);
for (int i = 0; i < c_arg_count; ++i) {
MachineType machine_type =
MachineTypeFor(c_signature->ArgumentInfo(i).GetType());
// Here the arg_use_info are indexed starting from 1 because of the
// function input, while this loop is only over the actual arguments.
DCHECK_EQ(arg_use_info[i].representation(),
machine_type.representation());
builder.AddParam(machine_type);
}
CallDescriptor* call_descriptor = Linkage::GetSimplifiedCDescriptor(
graph()->zone(), builder.Build(), CallDescriptor::kNoFlags);
call_descriptor->SetCFunctionInfo(c_signature);
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
}
}
// Dispatching routine for visiting the node {node} with the usage {use}.
......@@ -3686,7 +3686,7 @@ class RepresentationSelector {
}
case IrOpcode::kFastApiCall: {
VisitFastApiCall<T>(node);
VisitFastApiCall<T>(node, lowering);
return;
}
......
......@@ -6,6 +6,7 @@
#include "include/v8-fast-api-calls.h"
#include "src/base/lazy-instance.h"
#include "src/compiler/linkage.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
#include "src/compiler/types.h"
......@@ -1292,16 +1293,6 @@ const Operator* SimplifiedOperatorBuilder::AssertType(Type type) {
"AssertType", 1, 0, 0, 1, 0, 0, type);
}
const Operator* SimplifiedOperatorBuilder::FastApiCall(
const CFunctionInfo* signature, FeedbackSource const& feedback) {
// function, c args
int value_input_count = signature->ArgumentCount() + 1;
return zone()->New<Operator1<FastApiCallParameters>>(
IrOpcode::kFastApiCall, Operator::kNoThrow, "FastApiCall",
value_input_count, 1, 1, 1, 1, 0,
FastApiCallParameters(signature, feedback));
}
const Operator* SimplifiedOperatorBuilder::CheckIf(
DeoptimizeReason reason, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
......@@ -1709,6 +1700,27 @@ CheckIfParameters const& CheckIfParametersOf(Operator const* op) {
return OpParameter<CheckIfParameters>(op);
}
FastApiCallParameters const& FastApiCallParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kFastApiCall, op->opcode());
return OpParameter<FastApiCallParameters>(op);
}
std::ostream& operator<<(std::ostream& os, FastApiCallParameters const& p) {
return os << p.signature() << ", " << p.feedback() << ", " << p.descriptor();
}
size_t hash_value(FastApiCallParameters const& p) {
return base::hash_combine(p.signature(), FeedbackSource::Hash()(p.feedback()),
p.descriptor());
}
bool operator==(FastApiCallParameters const& lhs,
FastApiCallParameters const& rhs) {
return lhs.signature() == rhs.signature() &&
lhs.feedback() == rhs.feedback() &&
lhs.descriptor() == rhs.descriptor();
}
const Operator* SimplifiedOperatorBuilder::NewDoubleElements(
AllocationType allocation) {
return zone()->New<Operator1<AllocationType>>( // --
......@@ -1744,25 +1756,6 @@ int NewArgumentsElementsMappedCountOf(const Operator* op) {
return OpParameter<int>(op);
}
FastApiCallParameters const& FastApiCallParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kFastApiCall, op->opcode());
return OpParameter<FastApiCallParameters>(op);
}
std::ostream& operator<<(std::ostream& os, FastApiCallParameters const& p) {
return os << p.signature() << ", " << p.feedback();
}
size_t hash_value(FastApiCallParameters const& p) {
return base::hash_combine(p.signature(),
FeedbackSource::Hash()(p.feedback()));
}
bool operator==(FastApiCallParameters const& lhs,
FastApiCallParameters const& rhs) {
return lhs.signature() == rhs.signature() && lhs.feedback() == rhs.feedback();
}
const Operator* SimplifiedOperatorBuilder::Allocate(Type type,
AllocationType allocation) {
return zone()->New<Operator1<AllocateParameters>>(
......@@ -1900,6 +1893,35 @@ const Operator* SimplifiedOperatorBuilder::TransitionAndStoreNonNumberElement(
"TransitionAndStoreNonNumberElement", 3, 1, 1, 0, 1, 0, parameters);
}
const Operator* SimplifiedOperatorBuilder::FastApiCall(
const CFunctionInfo* signature, FeedbackSource const& feedback,
CallDescriptor* descriptor) {
int value_input_count =
(signature->ArgumentCount() +
FastApiCallNode::kFastTargetInputCount) + // fast call
static_cast<int>(descriptor->ParameterCount()) + // slow call
FastApiCallNode::kEffectAndControlInputCount;
return new (zone_) Operator1<FastApiCallParameters>(
IrOpcode::kFastApiCall, Operator::kNoThrow, "FastApiCall",
value_input_count, 1, 1, 1, 1, 0,
FastApiCallParameters(signature, feedback, descriptor));
}
int FastApiCallNode::FastCallArgumentCount() const {
FastApiCallParameters p = FastApiCallParametersOf(node()->op());
const CFunctionInfo* signature = p.signature();
CHECK_NOT_NULL(signature);
return signature->ArgumentCount();
}
int FastApiCallNode::SlowCallArgumentCount() const {
FastApiCallParameters p = FastApiCallParametersOf(node()->op());
CallDescriptor* descriptor = p.descriptor();
CHECK_NOT_NULL(descriptor);
return static_cast<int>(descriptor->ParameterCount()) +
kContextAndFrameStateInputCount;
}
#undef PURE_OP_LIST
#undef EFFECT_DEPENDENT_OP_LIST
#undef SPECULATIVE_NUMBER_BINOP_LIST
......
......@@ -9,8 +9,11 @@
#include "src/base/compiler-specific.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/tnode.h"
#include "src/common/globals.h"
#include "src/compiler/feedback-source.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/operator.h"
#include "src/compiler/types.h"
#include "src/compiler/write-barrier-kind.h"
......@@ -22,6 +25,8 @@
#include "src/zone/zone-handle-set.h"
namespace v8 {
class CFunctionInfo;
namespace internal {
// Forward declarations.
......@@ -33,6 +38,7 @@ namespace compiler {
// Forward declarations.
class Operator;
struct SimplifiedOperatorGlobalCache;
class CallDescriptor;
enum BaseTaggedness : uint8_t { kUntaggedBase, kTaggedBase };
......@@ -594,15 +600,18 @@ int NewArgumentsElementsMappedCountOf(const Operator* op) V8_WARN_UNUSED_RESULT;
class FastApiCallParameters {
public:
explicit FastApiCallParameters(const CFunctionInfo* signature,
FeedbackSource const& feedback)
: signature_(signature), feedback_(feedback) {}
FeedbackSource const& feedback,
CallDescriptor* descriptor)
: signature_(signature), feedback_(feedback), descriptor_(descriptor) {}
const CFunctionInfo* signature() const { return signature_; }
FeedbackSource const& feedback() const { return feedback_; }
CallDescriptor* descriptor() const { return descriptor_; }
private:
const CFunctionInfo* signature_;
const FeedbackSource feedback_;
CallDescriptor* descriptor_;
};
FastApiCallParameters const& FastApiCallParametersOf(const Operator* op)
......@@ -959,9 +968,10 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* DateNow();
// Stores the signature and feedback of a fast C call
// Represents the inputs necessary to construct a fast and a slow API call.
const Operator* FastApiCall(const CFunctionInfo* signature,
FeedbackSource const& feedback);
FeedbackSource const& feedback,
CallDescriptor* descriptor);
private:
Zone* zone() const { return zone_; }
......@@ -972,6 +982,86 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorBuilder);
};
#define DEFINE_INPUT_ACCESSORS(Name, name, TheIndex, Type) \
static constexpr int Name##Index() { return TheIndex; } \
TNode<Type> name() const { \
return TNode<Type>::UncheckedCast( \
NodeProperties::GetValueInput(node(), TheIndex)); \
}
class FastApiCallNode final : public NodeWrapper {
public:
explicit constexpr FastApiCallNode(Node* node) : NodeWrapper(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kFastApiCall);
}
const FastApiCallParameters& Parameters() const {
return FastApiCallParametersOf(node()->op());
}
#define INPUTS(V) \
V(Target, target, 0, Object) \
V(Receiver, receiver, 1, Object)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
// Besides actual arguments, FastApiCall nodes also take:
static constexpr int kFastTargetInputCount = 1;
static constexpr int kSlowTargetInputCount = 1;
static constexpr int kFastReceiverInputCount = 1;
static constexpr int kSlowReceiverInputCount = 1;
static constexpr int kExtraInputCount =
kFastTargetInputCount + kFastReceiverInputCount;
static constexpr int kHasErrorInputCount = 1;
static constexpr int kArityInputCount = 1;
static constexpr int kNewTargetInputCount = 1;
static constexpr int kHolderInputCount = 1;
static constexpr int kContextAndFrameStateInputCount = 2;
static constexpr int kEffectAndControlInputCount = 2;
static constexpr int kFastCallExtraInputCount =
kFastTargetInputCount + kHasErrorInputCount + kEffectAndControlInputCount;
static constexpr int kSlowCallExtraInputCount =
kSlowTargetInputCount + kArityInputCount + kNewTargetInputCount +
kSlowReceiverInputCount + kHolderInputCount +
kContextAndFrameStateInputCount + kEffectAndControlInputCount;
// This is the arity fed into FastApiCallArguments.
static constexpr int ArityForArgc(int c_arg_count, int js_arg_count) {
return c_arg_count + kFastTargetInputCount + js_arg_count +
kEffectAndControlInputCount;
}
int FastCallArgumentCount() const;
int SlowCallArgumentCount() const;
constexpr int FirstFastCallArgumentIndex() const {
return ReceiverIndex() + 1;
}
constexpr int FastCallArgumentIndex(int i) const {
return FirstFastCallArgumentIndex() + i;
}
TNode<Object> FastCallArgument(int i) const {
DCHECK_LT(i, FastCallArgumentCount());
return TNode<Object>::UncheckedCast(
NodeProperties::GetValueInput(node(), FastCallArgumentIndex(i)));
}
int FirstSlowCallArgumentIndex() const {
return FastCallArgumentCount() + FastApiCallNode::kFastTargetInputCount;
}
int SlowCallArgumentIndex(int i) const {
return FirstSlowCallArgumentIndex() + i;
}
TNode<Object> SlowCallArgument(int i) const {
DCHECK_LT(i, SlowCallArgumentCount());
return TNode<Object>::UncheckedCast(
NodeProperties::GetValueInput(node(), SlowCallArgumentIndex(i)));
}
};
#undef DEFINE_INPUT_ACCESSORS
} // namespace compiler
} // namespace internal
} // namespace v8
......
......@@ -1605,8 +1605,9 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckTypeIs(node, Type::BigInt());
break;
case IrOpcode::kFastApiCall:
CHECK_GE(value_count, 1);
CheckValueInputIs(node, 0, Type::ExternalPointer());
CHECK_GE(value_count, 2);
CheckValueInputIs(node, 0, Type::ExternalPointer()); // callee
CheckValueInputIs(node, 1, Type::Any()); // receiver
break;
// Machine operators
......
This diff is collapsed.
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