Revert "Faster JS-to-Wasm calls"

This reverts commit 860fcb1bd2.

Reason for revert: https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Linux%20-%20arm%20-%20sim%20-%20lite/13831/overview

Original change's description:
> Faster JS-to-Wasm calls
>
> This replaces https://chromium-review.googlesource.com/c/v8/v8/+/2376165/.
>
> Currently JS-to-Wasm calls go through a wrapper/trampoline, built on
> the basis of the signature of a Wasm function to call, and whose task
> is to:
> - set "thread_in_wasm_flag" to true
> - convert the arguments from tagged types into Wasm native types
> - calculate the address of the Wasm function to call and call it
> - convert back the result from Wasm native types into tagged types
> - reset "thread_in_wasm_flag" to false.
>
> This CL tries to improve the performance of JS-to-Wasm calls by
> inlining the code of the JS-to-Wasm wrappers in the call site.
>
> It introduces a new IR operand, JSWasmCall, which replaces JSCall for
> this kind of calls. A 'JSWasmCall' node is associated to
> WasmCallParameters, which contain information about the signature of
> the Wasm function to call.
>
> WasmWrapperGraphBuilder::BuildJSToWasmWrapper is modified to avoid generating code to convert the types for the arguments
> of the Wasm function, when the conversion is not necessary.
> The actual inlining of the graph generated for this wrapper happens in
> the simplified-lowering phase.
>
> A new builtin, JSToWasmLazyDeoptContinuation, is introduced to manage
> lazy deoptimizations that can happen if the Wasm function callee calls
> back some JS code that invalidates the compiled JS caller function.
>
> Bug: v8:11092
> Change-Id: I3174c1c1f59b39107b333d1929ecc0584486b8ad
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2557538
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
> Reviewed-by: Georg Neis (ooo until January 5) <neis@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Reviewed-by: Maya Lekova <mslekova@chromium.org>
> Reviewed-by: Andreas Haas <ahaas@chromium.org>
> Commit-Queue: Paolo Severini <paolosev@microsoft.com>
> Cr-Commit-Position: refs/heads/master@{#71824}

TBR=neis@chromium.org,ahaas@chromium.org,jgruber@chromium.org,tebbi@chromium.org,ishell@chromium.org,mslekova@chromium.org,nicohartmann@chromium.org,paolosev@microsoft.com

Change-Id: I214cbdee74c1a2aaad907ffc84662ed25631983e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:11092
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2595438
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71825}
This commit is contained in:
Nico Hartmann 2020-12-17 13:53:09 +00:00 committed by Commit Bot
parent 860fcb1bd2
commit de50785ed5
45 changed files with 255 additions and 2131 deletions

View File

@ -3424,7 +3424,6 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/streaming-decoder.h",
"src/wasm/struct-types.h",
"src/wasm/sync-streaming-decoder.cc",
"src/wasm/value-type.cc",
"src/wasm/value-type.h",
"src/wasm/wasm-arguments.h",
"src/wasm/wasm-code-manager.cc",

View File

@ -202,7 +202,7 @@ namespace internal {
TFC(I32PairToBigInt, I32PairToBigInt) \
\
/* Type conversions continuations */ \
TFC(ToBooleanLazyDeoptContinuation, SingleParameterOnStack) \
TFC(ToBooleanLazyDeoptContinuation, TypeConversionStackParameter) \
\
/* Handlers */ \
TFH(KeyedLoadIC_PolymorphicName, LoadWithVector) \
@ -817,7 +817,6 @@ namespace internal {
TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \
TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \
TFS(WasmAllocatePair, kValue1, kValue2) \
TFC(JSToWasmLazyDeoptContinuation, SingleParameterOnStack) \
\
/* WeakMap */ \
TFJ(WeakMapConstructor, kDontAdaptArgumentsSentinel) \

View File

@ -129,20 +129,5 @@ TF_BUILTIN(WasmAllocatePair, WasmBuiltinsAssembler) {
Return(result);
}
TF_BUILTIN(JSToWasmLazyDeoptContinuation, WasmBuiltinsAssembler) {
// Reset thread_in_wasm_flag.
TNode<ExternalReference> thread_in_wasm_flag_address_address =
ExternalConstant(
ExternalReference::thread_in_wasm_flag_address_address(isolate()));
auto thread_in_wasm_flag_address =
Load<RawPtrT>(thread_in_wasm_flag_address_address);
StoreNoWriteBarrier(MachineRepresentation::kWord32,
thread_in_wasm_flag_address, Int32Constant(0));
// Return the argument.
auto value = Parameter<Object>(Descriptor::kArgument);
Return(value);
}
} // namespace internal
} // namespace v8

View File

@ -485,11 +485,6 @@ ExternalReference::address_of_enable_experimental_regexp_engine() {
return ExternalReference(&FLAG_enable_experimental_regexp_engine);
}
ExternalReference ExternalReference::thread_in_wasm_flag_address_address(
Isolate* isolate) {
return ExternalReference(isolate->thread_in_wasm_flag_address_address());
}
ExternalReference ExternalReference::is_profiling_address(Isolate* isolate) {
return ExternalReference(isolate->is_profiling_address());
}

View File

@ -78,8 +78,6 @@ class StatsCounter;
V(address_of_regexp_stack_memory_top_address, \
"RegExpStack::memory_top_address_address()") \
V(address_of_static_offsets_vector, "OffsetsVector::static_offsets_vector") \
V(thread_in_wasm_flag_address_address, \
"Isolate::thread_in_wasm_flag_address_address") \
V(re_case_insensitive_compare_unicode, \
"NativeRegExpMacroAssembler::CaseInsensitiveCompareUnicode()") \
V(re_case_insensitive_compare_non_unicode, \

View File

@ -293,7 +293,7 @@ void TypeConversionNoContextDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void SingleParameterOnStackDescriptor::InitializePlatformSpecific(
void TypeConversionStackParameterDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
data->InitializePlatformSpecific(0, nullptr);
}

View File

@ -81,7 +81,6 @@ namespace internal {
V(LoadWithVector) \
V(LoadWithReceiverAndVector) \
V(NoContext) \
V(SingleParameterOnStack) \
V(RecordWrite) \
V(ResumeGenerator) \
V(RunMicrotasks) \
@ -96,6 +95,7 @@ namespace internal {
V(StringSubstring) \
V(TypeConversion) \
V(TypeConversionNoContext) \
V(TypeConversionStackParameter) \
V(Typeof) \
V(UnaryOp_WithFeedback) \
V(Void) \
@ -935,11 +935,13 @@ class TypeConversionNoContextDescriptor final : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(TypeConversionNoContextDescriptor, CallInterfaceDescriptor)
};
class SingleParameterOnStackDescriptor final : public CallInterfaceDescriptor {
class TypeConversionStackParameterDescriptor final
: public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kArgument)
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged())
DECLARE_DESCRIPTOR(SingleParameterOnStackDescriptor, CallInterfaceDescriptor)
DECLARE_DESCRIPTOR(TypeConversionStackParameterDescriptor,
CallInterfaceDescriptor)
};
class AsyncFunctionStackParameterDescriptor final

View File

@ -1188,14 +1188,6 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
height);
break;
}
case FrameStateType::kJSToWasmBuiltinContinuation: {
const JSToWasmFrameStateDescriptor* js_to_wasm_descriptor =
static_cast<const JSToWasmFrameStateDescriptor*>(descriptor);
translation->BeginJSToWasmBuiltinContinuationFrame(
bailout_id, shared_info_id, height,
js_to_wasm_descriptor->return_type());
break;
}
case FrameStateType::kJavaScriptBuiltinContinuation: {
translation->BeginJavaScriptBuiltinContinuationFrame(
bailout_id, shared_info_id, height);

View File

@ -3339,15 +3339,6 @@ FrameStateDescriptor* GetFrameStateDescriptorInternal(Zone* zone, Node* state) {
outer_state = GetFrameStateDescriptorInternal(zone, outer_node);
}
if (state_info.type() == FrameStateType::kJSToWasmBuiltinContinuation) {
auto function_info = static_cast<const JSToWasmFrameStateFunctionInfo*>(
state_info.function_info());
return zone->New<JSToWasmFrameStateDescriptor>(
zone, state_info.type(), state_info.bailout_id(),
state_info.state_combine(), parameters, locals, stack,
state_info.shared_info(), outer_state, function_info->signature());
}
return zone->New<FrameStateDescriptor>(
zone, state_info.type(), state_info.bailout_id(),
state_info.state_combine(), parameters, locals, stack,

View File

@ -14,10 +14,8 @@
#include "src/compiler/graph.h"
#include "src/compiler/node.h"
#include "src/compiler/schedule.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frames.h"
#include "src/utils/ostreams.h"
#include "src/wasm/value-type.h"
namespace v8 {
namespace internal {
@ -1019,7 +1017,6 @@ size_t GetConservativeFrameSizeInBytes(FrameStateType type,
return info.frame_size_in_bytes();
}
case FrameStateType::kBuiltinContinuation:
case FrameStateType::kJSToWasmBuiltinContinuation:
case FrameStateType::kJavaScriptBuiltinContinuation:
case FrameStateType::kJavaScriptBuiltinContinuationWithCatch: {
const RegisterConfiguration* config = RegisterConfiguration::Default();
@ -1074,7 +1071,6 @@ size_t FrameStateDescriptor::GetHeight() const {
case FrameStateType::kInterpretedFunction:
return locals_count(); // The accumulator is *not* included.
case FrameStateType::kBuiltinContinuation:
case FrameStateType::kJSToWasmBuiltinContinuation:
// Custom, non-JS calling convention (that does not have a notion of
// a receiver or context).
return parameters_count();
@ -1126,17 +1122,6 @@ size_t FrameStateDescriptor::GetJSFrameCount() const {
return count;
}
JSToWasmFrameStateDescriptor::JSToWasmFrameStateDescriptor(
Zone* zone, FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine, size_t parameters_count,
size_t locals_count, size_t stack_count,
MaybeHandle<SharedFunctionInfo> shared_info,
FrameStateDescriptor* outer_state, const wasm::FunctionSig* wasm_signature)
: FrameStateDescriptor(zone, type, bailout_id, state_combine,
parameters_count, locals_count, stack_count,
shared_info, outer_state),
return_type_(wasm::WasmReturnTypeFromSignature(wasm_signature)) {}
std::ostream& operator<<(std::ostream& os, const RpoNumber& rpo) {
return os << rpo.ToSize();
}

View File

@ -1318,7 +1318,6 @@ class FrameStateDescriptor : public ZoneObject {
bool HasContext() const {
return FrameStateFunctionInfo::IsJSFunctionType(type_) ||
type_ == FrameStateType::kBuiltinContinuation ||
type_ == FrameStateType::kJSToWasmBuiltinContinuation ||
type_ == FrameStateType::kConstructStub;
}
@ -1358,25 +1357,6 @@ class FrameStateDescriptor : public ZoneObject {
FrameStateDescriptor* const outer_state_;
};
class JSToWasmFrameStateDescriptor : public FrameStateDescriptor {
public:
JSToWasmFrameStateDescriptor(Zone* zone, FrameStateType type,
BailoutId bailout_id,
OutputFrameStateCombine state_combine,
size_t parameters_count, size_t locals_count,
size_t stack_count,
MaybeHandle<SharedFunctionInfo> shared_info,
FrameStateDescriptor* outer_state,
const wasm::FunctionSig* wasm_signature);
base::Optional<wasm::ValueType::Kind> return_type() const {
return return_type_;
}
private:
base::Optional<wasm::ValueType::Kind> return_type_;
};
// A deoptimization entry is a pair of the reason why we deoptimize and the
// frame state descriptor that we have to go back to.
class DeoptimizationEntry final {

View File

@ -1620,15 +1620,9 @@ const Operator* CommonOperatorBuilder::ResizeMergeOrPhi(const Operator* op,
const FrameStateFunctionInfo*
CommonOperatorBuilder::CreateFrameStateFunctionInfo(
FrameStateType type, int parameter_count, int local_count,
Handle<SharedFunctionInfo> shared_info,
const wasm::FunctionSig* signature) {
DCHECK_EQ(type == FrameStateType::kJSToWasmBuiltinContinuation,
signature != nullptr);
return type == FrameStateType::kJSToWasmBuiltinContinuation
? zone()->New<JSToWasmFrameStateFunctionInfo>(
type, parameter_count, local_count, shared_info, signature)
: zone()->New<FrameStateFunctionInfo>(type, parameter_count,
local_count, shared_info);
Handle<SharedFunctionInfo> shared_info) {
return zone()->New<FrameStateFunctionInfo>(type, parameter_count, local_count,
shared_info);
}
const Operator* CommonOperatorBuilder::DeadValue(MachineRepresentation rep) {

View File

@ -560,8 +560,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
// Constructs function info for frame state construction.
const FrameStateFunctionInfo* CreateFrameStateFunctionInfo(
FrameStateType type, int parameter_count, int local_count,
Handle<SharedFunctionInfo> shared_info,
const wasm::FunctionSig* signature = nullptr);
Handle<SharedFunctionInfo> shared_info);
const Operator* MarkAsSafetyCheck(const Operator* op,
IsSafetyCheck safety_check);

View File

@ -11,7 +11,6 @@
#include "src/compiler/node.h"
#include "src/handles/handles-inl.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/value-type.h"
namespace v8 {
namespace internal {
@ -66,9 +65,6 @@ std::ostream& operator<<(std::ostream& os, FrameStateType type) {
case FrameStateType::kBuiltinContinuation:
os << "BUILTIN_CONTINUATION_FRAME";
break;
case FrameStateType::kJSToWasmBuiltinContinuation:
os << "JS_TO_WASM_BUILTIN_CONTINUATION_FRAME";
break;
case FrameStateType::kJavaScriptBuiltinContinuation:
os << "JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME";
break;
@ -92,7 +88,7 @@ std::ostream& operator<<(std::ostream& os, FrameStateInfo const& info) {
namespace {
// Lazy deopt points where the frame state is associated with a call get an
// Lazy deopt points where the frame state is assocated with a call get an
// additional parameter for the return result from the call. The return result
// is added by the deoptimizer and not explicitly specified in the frame state.
// Lazy deopt points which can catch exceptions further get an additional
@ -114,8 +110,7 @@ FrameState CreateBuiltinContinuationFrameStateCommon(
JSGraph* jsgraph, FrameStateType frame_type, Builtins::Name name,
Node* closure, Node* context, Node** parameters, int parameter_count,
Node* outer_frame_state,
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(),
const wasm::FunctionSig* signature = nullptr) {
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>()) {
Graph* const graph = jsgraph->graph();
CommonOperatorBuilder* const common = jsgraph->common();
@ -126,7 +121,7 @@ FrameState CreateBuiltinContinuationFrameStateCommon(
BailoutId bailout_id = Builtins::GetContinuationBailoutId(name);
const FrameStateFunctionInfo* state_info =
common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0,
shared, signature);
shared);
const Operator* op = common->FrameState(
bailout_id, OutputFrameStateCombine::Ignore(), state_info);
return FrameState(graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
@ -139,7 +134,7 @@ FrameState CreateBuiltinContinuationFrameStateCommon(
FrameState CreateStubBuiltinContinuationFrameState(
JSGraph* jsgraph, Builtins::Name name, Node* context,
Node* const* parameters, int parameter_count, Node* outer_frame_state,
ContinuationFrameStateMode mode, const wasm::FunctionSig* signature) {
ContinuationFrameStateMode mode) {
Callable callable = Builtins::CallableFor(jsgraph->isolate(), name);
CallInterfaceDescriptor descriptor = callable.descriptor();
@ -168,29 +163,10 @@ FrameState CreateStubBuiltinContinuationFrameState(
actual_parameters.push_back(parameters[i]);
}
FrameStateType frame_state_type = FrameStateType::kBuiltinContinuation;
if (name == Builtins::kJSToWasmLazyDeoptContinuation) {
CHECK_NOT_NULL(signature);
frame_state_type = FrameStateType::kJSToWasmBuiltinContinuation;
}
return CreateBuiltinContinuationFrameStateCommon(
jsgraph, frame_state_type, name, jsgraph->UndefinedConstant(), context,
actual_parameters.data(), static_cast<int>(actual_parameters.size()),
outer_frame_state, Handle<SharedFunctionInfo>(), signature);
}
FrameState CreateJSWasmCallBuiltinContinuationFrameState(
JSGraph* jsgraph, Node* context, Node* outer_frame_state,
const wasm::FunctionSig* signature) {
base::Optional<wasm::ValueType::Kind> wasm_return_type =
wasm::WasmReturnTypeFromSignature(signature);
Node* node_return_type =
jsgraph->SmiConstant(wasm_return_type ? wasm_return_type.value() : -1);
Node* lazy_deopt_parameters[] = {node_return_type};
return CreateStubBuiltinContinuationFrameState(
jsgraph, Builtins::kJSToWasmLazyDeoptContinuation, context,
lazy_deopt_parameters, arraysize(lazy_deopt_parameters),
outer_frame_state, ContinuationFrameStateMode::LAZY, signature);
jsgraph, FrameStateType::kBuiltinContinuation, name,
jsgraph->UndefinedConstant(), context, actual_parameters.data(),
static_cast<int>(actual_parameters.size()), outer_frame_state);
}
FrameState CreateJavaScriptBuiltinContinuationFrameState(

View File

@ -66,8 +66,6 @@ enum class FrameStateType {
kArgumentsAdaptor, // Represents an ArgumentsAdaptorFrame.
kConstructStub, // Represents a ConstructStubFrame.
kBuiltinContinuation, // Represents a continuation to a stub.
kJSToWasmBuiltinContinuation, // Represents a lazy deopt continuation for a
// JS to Wasm call.
kJavaScriptBuiltinContinuation, // Represents a continuation to a JavaScipt
// builtin.
kJavaScriptBuiltinContinuationWithCatch // Represents a continuation to a
@ -103,22 +101,6 @@ class FrameStateFunctionInfo {
Handle<SharedFunctionInfo> const shared_info_;
};
class JSToWasmFrameStateFunctionInfo : public FrameStateFunctionInfo {
public:
JSToWasmFrameStateFunctionInfo(FrameStateType type, int parameter_count,
int local_count,
Handle<SharedFunctionInfo> shared_info,
const wasm::FunctionSig* signature)
: FrameStateFunctionInfo(type, parameter_count, local_count, shared_info),
signature_(signature) {
DCHECK_NOT_NULL(signature);
}
const wasm::FunctionSig* signature() const { return signature_; }
private:
const wasm::FunctionSig* const signature_;
};
class FrameStateInfo final {
public:
@ -172,12 +154,7 @@ enum class ContinuationFrameStateMode { EAGER, LAZY, LAZY_WITH_CATCH };
FrameState CreateStubBuiltinContinuationFrameState(
JSGraph* graph, Builtins::Name name, Node* context, Node* const* parameters,
int parameter_count, Node* outer_frame_state,
ContinuationFrameStateMode mode,
const wasm::FunctionSig* signature = nullptr);
FrameState CreateJSWasmCallBuiltinContinuationFrameState(
JSGraph* jsgraph, Node* context, Node* outer_frame_state,
const wasm::FunctionSig* signature);
ContinuationFrameStateMode mode);
FrameState CreateJavaScriptBuiltinContinuationFrameState(
JSGraph* graph, const SharedFunctionInfoRef& shared, Builtins::Name name,

View File

@ -230,8 +230,6 @@ std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info,
}
std::replace(filename.begin(), filename.begin() + filename.length(), ' ',
'_');
std::replace(filename.begin(), filename.begin() + filename.length(), ':',
'-');
EmbeddedVector<char, 256> base_dir;
if (optional_base_dir != nullptr) {

View File

@ -31,13 +31,6 @@ class JSRegExp;
class JSTypedArray;
class NativeContext;
class ScriptContextTable;
template <typename>
class Signature;
namespace wasm {
class ValueType;
struct WasmModule;
} // namespace wasm
namespace compiler {
@ -794,22 +787,20 @@ class ScopeInfoRef : public HeapObjectRef {
void SerializeScopeInfoChain();
};
#define BROKER_SFI_FIELDS(V) \
V(int, internal_formal_parameter_count) \
V(bool, has_duplicate_parameters) \
V(int, function_map_index) \
V(FunctionKind, kind) \
V(LanguageMode, language_mode) \
V(bool, native) \
V(bool, HasBreakInfo) \
V(bool, HasBuiltinId) \
V(bool, construct_as_builtin) \
V(bool, HasBytecodeArray) \
V(int, StartPosition) \
V(bool, is_compiled) \
V(bool, IsUserJavaScript) \
V(const wasm::WasmModule*, wasm_module) \
V(const wasm::FunctionSig*, wasm_function_signature)
#define BROKER_SFI_FIELDS(V) \
V(int, internal_formal_parameter_count) \
V(bool, has_duplicate_parameters) \
V(int, function_map_index) \
V(FunctionKind, kind) \
V(LanguageMode, language_mode) \
V(bool, native) \
V(bool, HasBreakInfo) \
V(bool, HasBuiltinId) \
V(bool, construct_as_builtin) \
V(bool, HasBytecodeArray) \
V(int, StartPosition) \
V(bool, is_compiled) \
V(bool, IsUserJavaScript)
class V8_EXPORT_PRIVATE SharedFunctionInfoRef : public HeapObjectRef {
public:

View File

@ -3429,82 +3429,6 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
return ReplaceWithSubgraph(&a, subgraph);
}
namespace {
bool CanInlineJSToWasmCall(const wasm::FunctionSig* wasm_signature) {
if (!FLAG_turbo_inline_js_wasm_calls || wasm_signature->return_count() > 1) {
return false;
}
for (auto type : wasm_signature->all()) {
#if defined(V8_TARGET_ARCH_32_BIT)
if (type == wasm::kWasmI64) return false;
#endif
if (type != wasm::kWasmI32 && type != wasm::kWasmI64 &&
type != wasm::kWasmF32 && type != wasm::kWasmF64) {
return false;
}
}
return true;
}
} // namespace
Reduction JSCallReducer::ReduceCallWasmFunction(
Node* node, const SharedFunctionInfoRef& shared) {
JSCallNode n(node);
const CallParameters& p = n.Parameters();
// Avoid deoptimization loops
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
// Don't inline if we are in a try/catch.
// WasmWrapperGraphBuilder::BuildJSToWasmWrapper generates Call nodes that are
// not part of the control chain and this breaks the inlining of IfSuccess
// nodes.
if (NodeProperties::IsExceptionalCall(node)) {
return NoChange();
}
const wasm::FunctionSig* wasm_signature = shared.wasm_function_signature();
if (!CanInlineJSToWasmCall(wasm_signature)) {
return NoChange();
}
const wasm::WasmModule* wasm_module = shared.wasm_module();
const Operator* op =
javascript()->CallWasm(wasm_module, wasm_signature, p.feedback());
// Remove additional inputs
size_t actual_arity = n.ArgumentCount();
DCHECK(JSCallNode::kFeedbackVectorIsLastInput);
DCHECK_EQ(actual_arity + JSWasmCallNode::kExtraInputCount - 1,
n.FeedbackVectorIndex());
size_t expected_arity = wasm_signature->parameter_count();
while (actual_arity > expected_arity) {
int removal_index =
static_cast<int>(n.FirstArgumentIndex() + expected_arity);
DCHECK_LT(removal_index, static_cast<int>(node->InputCount()));
node->RemoveInput(removal_index);
actual_arity--;
}
// Add missing inputs
while (actual_arity < expected_arity) {
int insertion_index = n.ArgumentIndex(n.ArgumentCount());
node->InsertInput(graph()->zone(), insertion_index,
jsgraph()->UndefinedConstant());
actual_arity++;
}
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
#ifndef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
namespace {
bool HasFPParamsInSignature(const CFunctionInfo* c_signature) {
@ -4609,11 +4533,6 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
if (shared.function_template_info().has_value()) {
return ReduceCallApiFunction(node, shared);
}
if (shared.wasm_function_signature()) {
return ReduceCallWasmFunction(node, shared);
}
return NoChange();
}

View File

@ -73,8 +73,6 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceBooleanConstructor(Node* node);
Reduction ReduceCallApiFunction(Node* node,
const SharedFunctionInfoRef& shared);
Reduction ReduceCallWasmFunction(Node* node,
const SharedFunctionInfoRef& shared);
Reduction ReduceFunctionPrototypeApply(Node* node);
Reduction ReduceFunctionPrototypeBind(Node* node);
Reduction ReduceFunctionPrototypeCall(Node* node);

View File

@ -1251,9 +1251,6 @@ void JSGenericLowering::LowerJSCallRuntime(Node* node) {
ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity()));
}
// Will be lowered in SimplifiedLowering.
void JSGenericLowering::LowerJSWasmCall(Node* node) {}
void JSGenericLowering::LowerJSForInPrepare(Node* node) {
JSForInPrepareNode n(node);
Effect effect(node); // {node} is kept in the effect chain.

View File

@ -676,50 +676,6 @@ ForInParameters const& ForInParametersOf(const Operator* op) {
return OpParameter<ForInParameters>(op);
}
JSWasmCallParameters const& JSWasmCallParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kJSWasmCall, op->opcode());
return OpParameter<JSWasmCallParameters>(op);
}
std::ostream& operator<<(std::ostream& os, JSWasmCallParameters const& p) {
return os << p.module() << ", " << p.signature() << ", " << p.feedback();
}
size_t hash_value(JSWasmCallParameters const& p) {
return base::hash_combine(p.module(), p.signature(),
FeedbackSource::Hash()(p.feedback()));
}
bool operator==(JSWasmCallParameters const& lhs,
JSWasmCallParameters const& rhs) {
return lhs.module() == rhs.module() && lhs.signature() == rhs.signature() &&
lhs.feedback() == rhs.feedback();
}
int JSWasmCallParameters::arity_without_implicit_args() const {
return static_cast<int>(signature_->parameter_count());
}
int JSWasmCallParameters::input_count() const {
return static_cast<int>(signature_->parameter_count()) +
JSWasmCallNode::kExtraInputCount;
}
// static
Type JSWasmCallNode::TypeForWasmReturnType(const wasm::ValueType& type) {
switch (type.kind()) {
case wasm::ValueType::kI32:
return Type::Signed32();
case wasm::ValueType::kI64:
return Type::BigInt();
case wasm::ValueType::kF32:
case wasm::ValueType::kF64:
return Type::Number();
default:
UNREACHABLE();
}
}
#define CACHED_OP_LIST(V) \
V(ToLength, Operator::kNoProperties, 1, 1) \
V(ToName, Operator::kNoProperties, 1, 1) \
@ -918,17 +874,6 @@ const Operator* JSOperatorBuilder::CallRuntime(const Runtime::Function* f,
parameters); // parameter
}
const Operator* JSOperatorBuilder::CallWasm(
const wasm::WasmModule* wasm_module,
const wasm::FunctionSig* wasm_signature, FeedbackSource const& feedback) {
JSWasmCallParameters parameters(wasm_module, wasm_signature, feedback);
return zone()->New<Operator1<JSWasmCallParameters>>(
IrOpcode::kJSWasmCall, Operator::kNoProperties, // opcode
"JSWasmCall", // name
parameters.input_count(), 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::ConstructForwardVarargs(
size_t arity, uint32_t start_index) {
ConstructForwardVarargsParameters parameters(arity, start_index);

View File

@ -25,10 +25,6 @@ class ArrayBoilerplateDescription;
class FeedbackCell;
class SharedFunctionInfo;
namespace wasm {
class ValueType;
}
namespace compiler {
// Forward declarations.
@ -820,35 +816,6 @@ size_t hash_value(ForInParameters const&);
std::ostream& operator<<(std::ostream&, ForInParameters const&);
const ForInParameters& ForInParametersOf(const Operator* op);
class JSWasmCallParameters {
public:
explicit JSWasmCallParameters(const wasm::WasmModule* module,
const wasm::FunctionSig* signature,
FeedbackSource const& feedback)
: module_(module), signature_(signature), feedback_(feedback) {
DCHECK_NOT_NULL(module);
DCHECK_NOT_NULL(signature);
}
const wasm::WasmModule* module() const { return module_; }
const wasm::FunctionSig* signature() const { return signature_; }
FeedbackSource const& feedback() const { return feedback_; }
int input_count() const;
int arity_without_implicit_args() const;
private:
const wasm::WasmModule* const module_;
const wasm::FunctionSig* const signature_;
const FeedbackSource feedback_;
};
JSWasmCallParameters const& JSWasmCallParametersOf(const Operator* op)
V8_WARN_UNUSED_RESULT;
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
JSWasmCallParameters const&);
size_t hash_value(JSWasmCallParameters const&);
bool operator==(JSWasmCallParameters const&, JSWasmCallParameters const&);
int RegisterCountOf(Operator const* op) V8_WARN_UNUSED_RESULT;
int GeneratorStoreValueCountOf(const Operator* op) V8_WARN_UNUSED_RESULT;
@ -958,10 +925,6 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
const Operator* CallRuntime(const Runtime::Function* function, size_t arity);
const Operator* CallWasm(const wasm::WasmModule* wasm_module,
const wasm::FunctionSig* wasm_signature,
FeedbackSource const& feedback);
const Operator* ConstructForwardVarargs(size_t arity, uint32_t start_index);
const Operator* Construct(uint32_t arity,
CallFrequency const& frequency = CallFrequency(),
@ -1284,8 +1247,7 @@ class JSCallOrConstructNode : public JSNodeWrapperBase {
node->opcode() == IrOpcode::kJSCallWithSpread ||
node->opcode() == IrOpcode::kJSConstruct ||
node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
node->opcode() == IrOpcode::kJSConstructWithSpread ||
node->opcode() == IrOpcode::kJSWasmCall);
node->opcode() == IrOpcode::kJSConstructWithSpread);
}
#define INPUTS(V) \
@ -1297,8 +1259,8 @@ class JSCallOrConstructNode : public JSNodeWrapperBase {
// Besides actual arguments, JSCall nodes (and variants) also take the
// following. Note that we rely on the fact that all variants (JSCall,
// JSCallWithArrayLike, JSCallWithSpread, JSConstruct,
// JSConstructWithArrayLike, JSConstructWithSpread, JSWasmCall) have the same
// underlying node layout.
// JSConstructWithArrayLike, JSConstructWithSpread) have the same underlying
// node layout.
static constexpr int kTargetInputCount = 1;
static constexpr int kReceiverOrNewTargetInputCount = 1;
static constexpr int kFeedbackVectorInputCount = 1;
@ -1393,35 +1355,6 @@ using JSCallNode = JSCallNodeBase<IrOpcode::kJSCall>;
using JSCallWithSpreadNode = JSCallNodeBase<IrOpcode::kJSCallWithSpread>;
using JSCallWithArrayLikeNode = JSCallNodeBase<IrOpcode::kJSCallWithArrayLike>;
class JSWasmCallNode final : public JSCallOrConstructNode {
public:
explicit constexpr JSWasmCallNode(Node* node) : JSCallOrConstructNode(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSWasmCall);
}
const JSWasmCallParameters& Parameters() const {
return OpParameter<JSWasmCallParameters>(node()->op());
}
#define INPUTS(V) \
V(Target, target, 0, Object) \
V(Receiver, receiver, 1, Object)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
static constexpr int kReceiverInputCount = 1;
STATIC_ASSERT(kReceiverInputCount ==
JSCallOrConstructNode::kReceiverOrNewTargetInputCount);
int ArgumentCount() const override {
// Note: The count reported by this function depends only on the parameter
// count, thus adding/removing inputs will not affect it.
return Parameters().arity_without_implicit_args();
}
static Type TypeForWasmReturnType(const wasm::ValueType& type);
};
template <int kOpcode>
class JSConstructNodeBase final : public JSCallOrConstructNode {
public:

View File

@ -196,8 +196,7 @@
V(JSCall) \
V(JSCallForwardVarargs) \
V(JSCallWithArrayLike) \
V(JSCallWithSpread) \
V(JSWasmCall)
V(JSCallWithSpread)
#define JS_CONSTRUCT_OP_LIST(V) \
V(JSConstructForwardVarargs) \

View File

@ -223,7 +223,6 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSCall:
case IrOpcode::kJSCallWithArrayLike:
case IrOpcode::kJSCallWithSpread:
case IrOpcode::kJSWasmCall:
// Misc operations
case IrOpcode::kJSAsyncFunctionEnter:

View File

@ -25,11 +25,9 @@
#include "src/compiler/representation-change.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/type-cache.h"
#include "src/compiler/wasm-compiler.h"
#include "src/numbers/conversions-inl.h"
#include "src/objects/objects.h"
#include "src/utils/address-map.h"
#include "src/wasm/value-type.h"
namespace v8 {
namespace internal {
@ -1809,120 +1807,6 @@ class RepresentationSelector {
SetOutput<T>(node, return_type.representation());
}
static MachineType MachineTypeForWasmReturnType(wasm::ValueType type) {
switch (type.kind()) {
case wasm::ValueType::kI32:
return MachineType::Int32();
case wasm::ValueType::kF32:
return MachineType::Float32();
case wasm::ValueType::kF64:
return MachineType::Float64();
case wasm::ValueType::kI64:
// Not used for i64, see VisitJSWasmCall().
default:
UNREACHABLE();
}
}
UseInfo UseInfoForJSWasmCallArgument(Node* input, wasm::ValueType type,
FeedbackSource const& feedback) {
// If the input type is a Number or Oddball, we can directly convert the
// input into the Wasm native type of the argument. If not, we return
// UseInfo::AnyTagged to signal that WasmWrapperGraphBuilder will need to
// add Nodes to perform the conversion (in WasmWrapperGraphBuilder::FromJS).
switch (type.kind()) {
case wasm::ValueType::kI32:
return UseInfo::CheckedNumberOrOddballAsWord32(feedback);
case wasm::ValueType::kI64:
return UseInfo::AnyTagged();
case wasm::ValueType::kF32:
case wasm::ValueType::kF64:
// For Float32, TruncateFloat64ToFloat32 will be inserted later in
// WasmWrapperGraphBuilder::BuildJSToWasmWrapper.
return UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
feedback);
default:
UNREACHABLE();
}
}
template <Phase T>
void VisitJSWasmCall(Node* node, SimplifiedLowering* lowering) {
DCHECK_EQ(JSWasmCallNode::TargetIndex(), 0);
DCHECK_EQ(JSWasmCallNode::ReceiverIndex(), 1);
DCHECK_EQ(JSWasmCallNode::FirstArgumentIndex(), 2);
JSWasmCallNode n(node);
JSWasmCallParameters const& params = n.Parameters();
const wasm::FunctionSig* wasm_signature = params.signature();
int wasm_arg_count = static_cast<int>(wasm_signature->parameter_count());
DCHECK_EQ(wasm_arg_count, n.ArgumentCount());
base::SmallVector<UseInfo, kInitialArgumentsCount> arg_use_info(
wasm_arg_count);
// Visit JSFunction and Receiver nodes.
ProcessInput<T>(node, JSWasmCallNode::TargetIndex(), UseInfo::Any());
ProcessInput<T>(node, JSWasmCallNode::ReceiverIndex(), UseInfo::Any());
JSWasmCallData js_wasm_call_data;
// Propagate representation information from TypeInfo.
for (int i = 0; i < wasm_arg_count; i++) {
TNode<Object> input = n.Argument(i);
DCHECK_NOT_NULL(input);
wasm::ValueType value = wasm_signature->GetParam(i);
arg_use_info[i] =
UseInfoForJSWasmCallArgument(input, value, params.feedback());
bool need_type_conversion =
arg_use_info[i].representation() == MachineRepresentation::kTagged;
// UseInfo should be AnyTagged
DCHECK(!need_type_conversion ||
(arg_use_info[i].truncation() == Truncation::Any() &&
arg_use_info[i].type_check() == TypeCheckKind::kNone));
js_wasm_call_data.set_arg_needs_conversion(i, need_type_conversion);
ProcessInput<T>(node, JSWasmCallNode::ArgumentIndex(i), arg_use_info[i]);
}
// Visit value, context and frame state inputs as tagged.
int first_effect_index = NodeProperties::FirstEffectIndex(node);
DCHECK(first_effect_index >
JSWasmCallNode::FirstArgumentIndex() + wasm_arg_count);
for (int i = JSWasmCallNode::FirstArgumentIndex() + wasm_arg_count;
i < first_effect_index; i++) {
ProcessInput<T>(node, i, UseInfo::AnyTagged());
}
// Effect and Control.
ProcessRemainingInputs<T>(node, NodeProperties::FirstEffectIndex(node));
if (wasm_signature->return_count() == 1) {
if (wasm_signature->GetReturn().kind() == wasm::ValueType::kI64) {
// Conversion between negative int64 and BigInt not supported yet.
// Do not bypass the type conversion when the result type is i64.
js_wasm_call_data.set_result_needs_conversion(true);
SetOutput<T>(node, MachineRepresentation::kTagged);
} else {
MachineType return_type =
MachineTypeForWasmReturnType(wasm_signature->GetReturn());
SetOutput<T>(
node, return_type.representation(),
JSWasmCallNode::TypeForWasmReturnType(wasm_signature->GetReturn()));
}
} else {
DCHECK_EQ(wasm_signature->return_count(), 0);
SetOutput<T>(node, MachineRepresentation::kTagged);
}
if (lower<T>()) {
LowerJSWasmCall(jsgraph_, node, js_wasm_call_data);
}
}
// Dispatching routine for visiting the node {node} with the usage {use}.
// Depending on the operator, propagate new usage info to the inputs.
template <Phase T>
@ -3848,8 +3732,7 @@ class RepresentationSelector {
case IrOpcode::kArgumentsLengthState:
case IrOpcode::kUnreachable:
case IrOpcode::kRuntimeAbort:
// All JavaScript operators except JSToNumber, JSToNumberConvertBigInt,
// kJSToNumeric and JSWasmCall have uniform handling.
// All JavaScript operators except JSToNumber have uniform handling.
#define OPCODE_CASE(name, ...) case IrOpcode::k##name:
JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
JS_OBJECT_OP_LIST(OPCODE_CASE)
@ -3865,9 +3748,6 @@ class RepresentationSelector {
case IrOpcode::kJSToObject:
case IrOpcode::kJSToString:
case IrOpcode::kJSParseInt:
if (node->opcode() == IrOpcode::kJSWasmCall) {
return VisitJSWasmCall<T>(node, lowering);
}
VisitInputs<T>(node);
// Assume the output is tagged.
return SetOutput<T>(node, MachineRepresentation::kTagged);
@ -3929,12 +3809,6 @@ class RepresentationSelector {
node->NullAllInputs(); // The {node} is now dead.
}
// Used for kJSWasmCall
void InlineWasmCall(Node* call, const wasm::FunctionSig* sig, Node* start,
Node* end);
void LowerJSWasmCall(JSGraph* jsgraph, Node* node,
const JSWasmCallData& js_wasm_call_data);
private:
JSGraph* jsgraph_;
Zone* zone_; // Temporary zone.
@ -3976,154 +3850,6 @@ class RepresentationSelector {
Linkage* linkage() { return linkage_; }
};
void RepresentationSelector::InlineWasmCall(Node* call,
const wasm::FunctionSig* sig,
Node* start, Node* end) {
DCHECK(FLAG_turbo_inline_js_wasm_calls);
DCHECK_NOT_NULL(start);
DCHECK_NOT_NULL(end);
Node* context = NodeProperties::GetContextInput(call);
Node* frame_state = NodeProperties::GetFrameStateInput(call);
// The scheduler is smart enough to place our code; we just ensure {control}
// becomes the control input of the start of the inlinee, and {effect} becomes
// the effect input of the start of the inlinee.
Node* control = NodeProperties::GetControlInput(call);
Node* effect = NodeProperties::GetEffectInput(call);
DCHECK_GE(start->op()->ValueOutputCount(), 3);
int const inlinee_new_target_index =
static_cast<int>(start->op()->ValueOutputCount()) - 3;
int const inlinee_arity_index =
static_cast<int>(start->op()->ValueOutputCount()) - 2;
int const inlinee_context_index =
static_cast<int>(start->op()->ValueOutputCount()) - 1;
// Counts the target, receiver/new_target, and arguments; but
// not feedback vector, context, effect, frame state or control.
DCHECK_EQ(static_cast<int>(sig->parameter_count()) +
JSCallOrConstructNode::kExtraInputCount -
JSCallOrConstructNode::kFeedbackVectorInputCount,
inlinee_new_target_index);
// Iterate over all uses of the start node.
for (Edge edge : start->use_edges()) {
Node* use = edge.from();
if (use->opcode() == IrOpcode::kParameter) {
int index = 1 + ParameterIndexOf(use->op());
DCHECK_LE(index, inlinee_context_index);
if (index < inlinee_new_target_index) {
// There is an input from the call, and the index is a value
// projection but not the context, so rewire the input.
DeferReplacement(use, call->InputAt(index));
} else if (index == inlinee_new_target_index) {
// The projection is requesting the new target value.
// This shouldn't happen, the call to a JSToWasm wrapper doesn't have
// a receiver or new_target.
UNREACHABLE();
} else if (index == inlinee_arity_index) {
// The projection is requesting the number of arguments.
// This should not happen in a JSToWasm subgraph
UNREACHABLE();
} else if (index == inlinee_context_index) {
// The projection is requesting the inlinee function context.
DeferReplacement(use, context);
} else {
// A JSWasmCall should have all the required arguments.
UNREACHABLE();
}
} else {
if (NodeProperties::IsEffectEdge(edge)) {
edge.UpdateTo(effect);
} else if (NodeProperties::IsControlEdge(edge)) {
edge.UpdateTo(control);
} else if (NodeProperties::IsFrameStateEdge(edge)) {
edge.UpdateTo(frame_state);
} else {
UNREACHABLE();
}
}
}
using NodeVector = ZoneVector<Node*>;
Zone* const local_zone = graph()->zone();
NodeVector values(local_zone);
NodeVector effects(local_zone);
NodeVector controls(local_zone);
for (Node* const input : end->inputs()) {
switch (input->opcode()) {
case IrOpcode::kReturn:
values.push_back(NodeProperties::GetValueInput(input, 1));
effects.push_back(NodeProperties::GetEffectInput(input));
controls.push_back(NodeProperties::GetControlInput(input));
break;
case IrOpcode::kDeoptimize:
case IrOpcode::kTerminate:
case IrOpcode::kThrow:
NodeProperties::MergeControlToEnd(graph(), common(), input);
break;
default:
UNREACHABLE();
break;
}
}
DCHECK_EQ(values.size(), effects.size());
DCHECK_EQ(values.size(), controls.size());
// The JSWasmCall always produces one value, Undefined if the Wasm function
// has no return value.
DCHECK_GT(values.size(), 0);
int const input_count = static_cast<int>(controls.size());
Node* control_output = graph()->NewNode(common()->Merge(input_count),
input_count, &controls.front());
values.push_back(control_output);
effects.push_back(control_output);
Node* value_output = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, input_count),
static_cast<int>(values.size()), &values.front());
Node* effect_output =
graph()->NewNode(common()->EffectPhi(input_count),
static_cast<int>(effects.size()), &effects.front());
ReplaceEffectControlUses(call, effect_output, control_output);
DeferReplacement(call, value_output);
}
void RepresentationSelector::LowerJSWasmCall(
JSGraph* jsgraph, Node* node, const JSWasmCallData& js_wasm_call_data) {
DCHECK(FLAG_turbo_inline_js_wasm_calls);
Graph* graph = this->graph();
JSWasmCallNode n(node);
const JSWasmCallParameters& wasm_call_params = n.Parameters();
// Create a nested frame state inside the frame state attached to the call;
// this will ensure that lazy deoptimizations at this point will still return
// the result of the Wasm function call.
Node* continuation_frame_state =
CreateJSWasmCallBuiltinContinuationFrameState(
jsgraph, n.context(), n.frame_state(), wasm_call_params.signature());
Node* start;
Node* end;
{
Graph::SubgraphScope scope(graph);
graph->SetEnd(nullptr);
BuildInlinedJSToWasmWrapper(
graph->zone(), jsgraph, wasm_call_params.signature(),
wasm_call_params.module(), source_positions_,
StubCallMode::kCallBuiltinPointer, wasm::WasmFeatures::FromFlags(),
&js_wasm_call_data, continuation_frame_state);
// Extract the inlinee start/end nodes.
start = graph->start();
end = graph->end();
}
InlineWasmCall(node, wasm_call_params.signature(), start, end);
}
// Template specializations
// Enqueue {use_node}'s {index} input if the {use_info} contains new information

View File

@ -992,15 +992,6 @@ Type Typer::Visitor::TypeCall(Node* node) { return Type::Any(); }
Type Typer::Visitor::TypeFastApiCall(Node* node) { return Type::Any(); }
Type Typer::Visitor::TypeJSWasmCall(Node* node) {
const JSWasmCallParameters& op_params = JSWasmCallParametersOf(node->op());
const wasm::FunctionSig* wasm_signature = op_params.signature();
if (wasm_signature->return_count() > 0) {
return JSWasmCallNode::TypeForWasmReturnType(wasm_signature->GetReturn());
}
return Type::Any();
}
Type Typer::Visitor::TypeProjection(Node* node) {
Type const type = Operand(node, 0);
if (type.Is(Type::None())) return Type::None();

View File

@ -1627,11 +1627,6 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckValueInputIs(node, 0, Type::ExternalPointer()); // callee
CheckValueInputIs(node, 1, Type::Any()); // receiver
break;
case IrOpcode::kJSWasmCall:
CHECK_GE(value_count, 3);
CheckTypeIs(node, Type::Any());
CheckValueInputIs(node, 0, Type::Any()); // callee
break;
// Machine operators
// -----------------------

View File

@ -164,17 +164,15 @@ bool ContainsInt64(const wasm::FunctionSig* sig) {
template <typename BuiltinDescriptor>
CallDescriptor* GetBuiltinCallDescriptor(WasmGraphBuilder* builder,
StubCallMode stub_mode,
bool needs_frame_state = false) {
StubCallMode stub_mode) {
BuiltinDescriptor interface_descriptor;
return Linkage::GetStubCallDescriptor(
builder->mcgraph()->zone(), // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
needs_frame_state ? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode); // stub call mode
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode); // stub call mode
}
} // namespace
@ -2803,17 +2801,15 @@ Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node* function,
Node* WasmGraphBuilder::BuildCallNode(const wasm::FunctionSig* sig,
Vector<Node*> args,
wasm::WasmCodePosition position,
Node* instance_node, const Operator* op,
Node* frame_state) {
Node* instance_node, const Operator* op) {
if (instance_node == nullptr) {
DCHECK_NOT_NULL(instance_node_);
instance_node = instance_node_.get();
}
needs_stack_check_ = true;
const size_t params = sig->parameter_count();
const size_t has_frame_state = frame_state != nullptr ? 1 : 0;
const size_t extra = 3; // instance_node, effect, and control.
const size_t count = 1 + params + extra + has_frame_state;
const size_t count = 1 + params + extra;
// Reallocate the buffer to make space for extra inputs.
base::SmallVector<Node*, 16 + extra> inputs(count);
@ -2825,9 +2821,8 @@ Node* WasmGraphBuilder::BuildCallNode(const wasm::FunctionSig* sig,
if (params > 0) base::Memcpy(&inputs[2], &args[1], params * sizeof(Node*));
// Add effect and control inputs.
if (has_frame_state != 0) inputs[params + 2] = frame_state;
inputs[params + has_frame_state + 2] = effect();
inputs[params + has_frame_state + 3] = control();
inputs[params + 2] = effect();
inputs[params + 3] = control();
Node* call = graph()->NewNode(op, static_cast<int>(count), inputs.begin());
// Return calls have no effect output. Other calls are the new effect node.
@ -2842,14 +2837,11 @@ Node* WasmGraphBuilder::BuildWasmCall(const wasm::FunctionSig* sig,
Vector<Node*> args, Vector<Node*> rets,
wasm::WasmCodePosition position,
Node* instance_node,
UseRetpoline use_retpoline,
Node* frame_state) {
UseRetpoline use_retpoline) {
CallDescriptor* call_descriptor =
GetWasmCallDescriptor(mcgraph()->zone(), sig, use_retpoline,
kWasmFunction, frame_state != nullptr);
GetWasmCallDescriptor(mcgraph()->zone(), sig, use_retpoline);
const Operator* op = mcgraph()->common()->Call(call_descriptor);
Node* call =
BuildCallNode(sig, args, position, instance_node, op, frame_state);
Node* call = BuildCallNode(sig, args, position, instance_node, op);
size_t ret_count = sig->return_count();
if (ret_count == 0) return call; // No return value.
@ -6067,11 +6059,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return i64_to_bigint_descriptor_;
}
CallDescriptor* GetBigIntToI64CallDescriptor(bool needs_frame_state) {
CallDescriptor* GetBigIntToI64CallDescriptor() {
if (bigint_to_i64_descriptor_) return bigint_to_i64_descriptor_;
bigint_to_i64_descriptor_ = GetBuiltinCallDescriptor<BigIntToI64Descriptor>(
this, stub_mode_, needs_frame_state);
bigint_to_i64_descriptor_ =
GetBuiltinCallDescriptor<BigIntToI64Descriptor>(this, stub_mode_);
AddInt64LoweringReplacement(
bigint_to_i64_descriptor_,
@ -6138,8 +6130,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return done.PhiAt(0);
}
Node* BuildChangeTaggedToInt32(Node* value, Node* context,
Node* frame_state) {
Node* BuildChangeTaggedToInt32(Node* value, Node* context) {
// We expect most integers at runtime to be Smis, so it is important for
// wrapper performance that Smi conversion be inlined.
auto builtin = gasm_->MakeDeferredLabel();
@ -6160,16 +6151,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
if (!tagged_non_smi_to_int32_operator_.is_set()) {
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), WasmTaggedNonSmiToInt32Descriptor(), 0,
frame_state ? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags,
Operator::kNoProperties, stub_mode_);
CallDescriptor::kNoFlags, Operator::kNoProperties, stub_mode_);
tagged_non_smi_to_int32_operator_.set(common->Call(call_descriptor));
}
Node* call = frame_state
? gasm_->Call(tagged_non_smi_to_int32_operator_.get(),
target, value, context, frame_state)
: gasm_->Call(tagged_non_smi_to_int32_operator_.get(),
target, value, context);
Node* call = gasm_->Call(tagged_non_smi_to_int32_operator_.get(), target,
value, context);
SetSourcePosition(call, 1);
gasm_->Goto(&done, call);
gasm_->Bind(&done);
@ -6202,25 +6188,18 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return gasm_->Call(float64_to_number_operator_.get(), target, value);
}
Node* BuildChangeTaggedToFloat64(Node* value, Node* context,
Node* frame_state) {
Node* BuildChangeTaggedToFloat64(Node* value, Node* context) {
CommonOperatorBuilder* common = mcgraph()->common();
Node* target = GetTargetForBuiltinCall(wasm::WasmCode::kWasmTaggedToFloat64,
Builtins::kWasmTaggedToFloat64);
bool needs_frame_state = frame_state != nullptr;
if (!tagged_to_float64_operator_.is_set()) {
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), WasmTaggedToFloat64Descriptor(), 0,
frame_state ? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags,
Operator::kNoProperties, stub_mode_);
CallDescriptor::kNoFlags, Operator::kNoProperties, stub_mode_);
tagged_to_float64_operator_.set(common->Call(call_descriptor));
}
Node* call = needs_frame_state
? gasm_->Call(tagged_to_float64_operator_.get(), target,
value, context, frame_state)
: gasm_->Call(tagged_to_float64_operator_.get(), target,
value, context);
Node* call =
gasm_->Call(tagged_to_float64_operator_.get(), target, value, context);
SetSourcePosition(call, 1);
return call;
}
@ -6343,10 +6322,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
graph()->NewNode(call, target, input, effect(), control()));
}
Node* BuildChangeBigIntToInt64(Node* input, Node* context,
Node* frame_state) {
const Operator* call = mcgraph()->common()->Call(
GetBigIntToI64CallDescriptor(frame_state != nullptr));
Node* BuildChangeBigIntToInt64(Node* input, Node* context) {
const Operator* call =
mcgraph()->common()->Call(GetBigIntToI64CallDescriptor());
Node* target;
if (mcgraph()->machine()->Is64()) {
@ -6361,9 +6339,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Builtins::kBigIntToI32Pair);
}
if (frame_state)
return SetEffectControl(graph()->NewNode(
call, target, input, context, frame_state, effect(), control()));
return SetEffectControl(
graph()->NewNode(call, target, input, context, effect(), control()));
}
@ -6391,8 +6366,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
type_check.merge);
}
Node* FromJS(Node* input, Node* js_context, wasm::ValueType type,
Node* frame_state = nullptr) {
Node* FromJS(Node* input, Node* js_context, wasm::ValueType type) {
switch (type.kind()) {
case wasm::ValueType::kRef:
case wasm::ValueType::kOptRef: {
@ -6428,18 +6402,18 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::ValueType::kF32:
return graph()->NewNode(
mcgraph()->machine()->TruncateFloat64ToFloat32(),
BuildChangeTaggedToFloat64(input, js_context, frame_state));
BuildChangeTaggedToFloat64(input, js_context));
case wasm::ValueType::kF64:
return BuildChangeTaggedToFloat64(input, js_context, frame_state);
return BuildChangeTaggedToFloat64(input, js_context);
case wasm::ValueType::kI32:
return BuildChangeTaggedToInt32(input, js_context, frame_state);
return BuildChangeTaggedToInt32(input, js_context);
case wasm::ValueType::kI64:
// i64 values can only come from BigInt.
DCHECK(enabled_features_.has_bigint());
return BuildChangeBigIntToInt64(input, js_context, frame_state);
return BuildChangeBigIntToInt64(input, js_context);
case wasm::ValueType::kRtt: // TODO(7748): Implement.
case wasm::ValueType::kS128:
@ -6508,8 +6482,14 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
}
}
void BuildModifyThreadInWasmFlagHelper(Node* thread_in_wasm_flag_address,
bool new_value) {
void BuildModifyThreadInWasmFlag(bool new_value) {
if (!trap_handler::IsTrapHandlerEnabled()) return;
Node* isolate_root = BuildLoadIsolateRoot();
Node* thread_in_wasm_flag_address =
gasm_->Load(MachineType::Pointer(), isolate_root,
Isolate::thread_in_wasm_flag_address_offset());
if (FLAG_debug_code) {
Node* flag_value = SetEffect(
graph()->NewNode(mcgraph()->machine()->Load(MachineType::Pointer()),
@ -6543,46 +6523,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
mcgraph()->Int32Constant(new_value ? 1 : 0), effect(), control()));
}
void BuildModifyThreadInWasmFlag(bool new_value) {
if (!trap_handler::IsTrapHandlerEnabled()) return;
Node* isolate_root = BuildLoadIsolateRoot();
Node* thread_in_wasm_flag_address =
gasm_->Load(MachineType::Pointer(), isolate_root,
Isolate::thread_in_wasm_flag_address_offset());
BuildModifyThreadInWasmFlagHelper(thread_in_wasm_flag_address, new_value);
}
class ModifyThreadInWasmFlagScope {
public:
ModifyThreadInWasmFlagScope(
WasmWrapperGraphBuilder* wasm_wrapper_graph_builder,
WasmGraphAssembler* gasm)
: wasm_wrapper_graph_builder_(wasm_wrapper_graph_builder) {
if (!trap_handler::IsTrapHandlerEnabled()) return;
Node* isolate_root = wasm_wrapper_graph_builder_->BuildLoadIsolateRoot();
thread_in_wasm_flag_address_ =
gasm->Load(MachineType::Pointer(), isolate_root,
Isolate::thread_in_wasm_flag_address_offset());
wasm_wrapper_graph_builder_->BuildModifyThreadInWasmFlagHelper(
thread_in_wasm_flag_address_, true);
}
~ModifyThreadInWasmFlagScope() {
if (!trap_handler::IsTrapHandlerEnabled()) return;
wasm_wrapper_graph_builder_->BuildModifyThreadInWasmFlagHelper(
thread_in_wasm_flag_address_, false);
}
private:
WasmWrapperGraphBuilder* wasm_wrapper_graph_builder_;
Node* thread_in_wasm_flag_address_;
};
Node* BuildMultiReturnFixedArrayFromIterable(const wasm::FunctionSig* sig,
Node* iterable, Node* context) {
Node* length = BuildChangeUint31ToSmi(
@ -6601,42 +6541,38 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* BuildCallAndReturn(bool is_import, Node* js_context,
Node* function_data,
base::SmallVector<Node*, 16> args,
const JSWasmCallData* js_wasm_call_data,
Node* frame_state) {
base::SmallVector<Node*, 16> args) {
// Set the ThreadInWasm flag before we do the actual call.
BuildModifyThreadInWasmFlag(true);
const int rets_count = static_cast<int>(sig_->return_count());
base::SmallVector<Node*, 1> rets(rets_count);
// Set the ThreadInWasm flag before we do the actual call.
{
ModifyThreadInWasmFlagScope modify_thread_in_wasm_flag_builder(
this, gasm_.get());
if (is_import) {
// Call to an imported function.
// Load function index from {WasmExportedFunctionData}.
Node* function_index = BuildChangeSmiToInt32(
gasm_->LoadExportedFunctionIndexAsSmi(function_data));
BuildImportCall(sig_, VectorOf(args), VectorOf(rets),
wasm::kNoCodePosition, function_index, kCallContinues);
} else {
// Call to a wasm function defined in this module.
// The call target is the jump table slot for that function.
Node* jump_table_start =
LOAD_INSTANCE_FIELD(JumpTableStart, MachineType::Pointer());
Node* jump_table_offset =
BuildLoadJumpTableOffsetFromExportedFunctionData(function_data);
Node* jump_table_slot = graph()->NewNode(
mcgraph()->machine()->IntAdd(), jump_table_start, jump_table_offset);
args[0] = jump_table_slot;
if (is_import) {
// Call to an imported function.
// Load function index from {WasmExportedFunctionData}.
Node* function_index = BuildChangeSmiToInt32(
gasm_->LoadExportedFunctionIndexAsSmi(function_data));
BuildImportCall(sig_, VectorOf(args), VectorOf(rets),
wasm::kNoCodePosition, function_index, kCallContinues);
} else {
// Call to a wasm function defined in this module.
// The call target is the jump table slot for that function.
Node* jump_table_start =
LOAD_INSTANCE_FIELD(JumpTableStart, MachineType::Pointer());
Node* jump_table_offset =
BuildLoadJumpTableOffsetFromExportedFunctionData(function_data);
Node* jump_table_slot =
graph()->NewNode(mcgraph()->machine()->IntAdd(), jump_table_start,
jump_table_offset);
args[0] = jump_table_slot;
BuildWasmCall(sig_, VectorOf(args), VectorOf(rets),
wasm::kNoCodePosition, nullptr, kNoRetpoline,
frame_state);
}
BuildWasmCall(sig_, VectorOf(args), VectorOf(rets), wasm::kNoCodePosition,
nullptr, kNoRetpoline);
}
// Clear the ThreadInWasm flag.
BuildModifyThreadInWasmFlag(false);
Node* jsval;
if (sig_->return_count() == 0) {
// We do not use {BuildLoadUndefinedValueFromInstance} here because it
@ -6648,9 +6584,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
mcgraph()->Int32Constant(
IsolateData::root_slot_offset(RootIndex::kUndefinedValue)));
} else if (sig_->return_count() == 1) {
jsval = js_wasm_call_data && !js_wasm_call_data->result_needs_conversion()
? rets[0]
: ToJS(rets[0], sig_->GetReturn());
jsval = ToJS(rets[0], sig_->GetReturn());
} else {
int32_t return_count = static_cast<int32_t>(sig_->return_count());
Node* size =
@ -6737,13 +6671,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
}
}
void BuildJSToWasmWrapper(bool is_import,
const JSWasmCallData* js_wasm_call_data = nullptr,
Node* frame_state = nullptr) {
const int wasm_param_count = static_cast<int>(sig_->parameter_count());
void BuildJSToWasmWrapper(bool is_import) {
const int wasm_count = static_cast<int>(sig_->parameter_count());
// Build the start and the JS parameter nodes.
SetEffectControl(Start(wasm_param_count + 5));
SetEffectControl(Start(wasm_count + 5));
// Create the js_closure and js_context parameters.
Node* js_closure =
@ -6752,8 +6684,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
graph()->start());
Node* js_context = graph()->NewNode(
mcgraph()->common()->Parameter(
Linkage::GetJSCallContextParamIndex(wasm_param_count + 1),
"%context"),
Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
graph()->start());
// Create the instance_node node to pass as parameter. It is loaded from
@ -6773,18 +6704,17 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return;
}
const int args_count = wasm_param_count + 1; // +1 for wasm_code.
const int args_count = wasm_count + 1; // +1 for wasm_code.
// Check whether the signature of the function allows for a fast
// transformation (if any params exist that need transformation).
// Create a fast transformation path, only if it does.
bool include_fast_path = !js_wasm_call_data && wasm_param_count > 0 &&
QualifiesForFastTransform(sig_);
bool include_fast_path = wasm_count && QualifiesForFastTransform(sig_);
// Prepare Param() nodes. Param() nodes can only be created once,
// so we need to use the same nodes along all possible transformation paths.
base::SmallVector<Node*, 16> params(args_count);
for (int i = 0; i < wasm_param_count; ++i) params[i + 1] = Param(i + 1);
for (int i = 0; i < wasm_count; ++i) params[i + 1] = Param(i + 1);
auto done = gasm_->MakeLabel(MachineRepresentation::kTagged);
if (include_fast_path) {
@ -6793,47 +6723,30 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
// using the fast transformation. When a param that cannot be transformed
// fast is encountered, skip checking the rest and fall back to the slow
// path.
for (int i = 0; i < wasm_param_count; ++i) {
for (int i = 0; i < wasm_count; ++i) {
CanTransformFast(params[i + 1], sig_->GetParam(i), &slow_path);
}
// Convert JS parameters to wasm numbers using the fast transformation
// and build the call.
base::SmallVector<Node*, 16> args(args_count);
for (int i = 0; i < wasm_param_count; ++i) {
for (int i = 0; i < wasm_count; ++i) {
Node* wasm_param = FromJSFast(params[i + 1], sig_->GetParam(i));
args[i + 1] = wasm_param;
}
Node* jsval = BuildCallAndReturn(is_import, js_context, function_data,
args, js_wasm_call_data, frame_state);
Node* jsval =
BuildCallAndReturn(is_import, js_context, function_data, args);
gasm_->Goto(&done, jsval);
gasm_->Bind(&slow_path);
}
// Convert JS parameters to wasm numbers using the default transformation
// and build the call.
base::SmallVector<Node*, 16> args(args_count);
for (int i = 0; i < wasm_param_count; ++i) {
bool do_conversion =
!js_wasm_call_data || js_wasm_call_data->arg_needs_conversion(i);
if (do_conversion) {
args[i + 1] =
FromJS(params[i + 1], js_context, sig_->GetParam(i), frame_state);
} else {
Node* wasm_param = params[i + 1];
// For Float32 parameters
// we set UseInfo::CheckedNumberOrOddballAsFloat64 in
// simplified-lowering and we need to add here a conversion from Float64
// to Float32.
if (sig_->GetParam(i).kind() == wasm::ValueType::kF32) {
wasm_param = graph()->NewNode(
mcgraph()->machine()->TruncateFloat64ToFloat32(), wasm_param);
}
args[i + 1] = wasm_param;
}
for (int i = 0; i < wasm_count; ++i) {
Node* wasm_param = FromJS(params[i + 1], js_context, sig_->GetParam(i));
args[i + 1] = wasm_param;
}
Node* jsval = BuildCallAndReturn(is_import, js_context, function_data, args,
js_wasm_call_data, frame_state);
Node* jsval =
BuildCallAndReturn(is_import, js_context, function_data, args);
// If both the default and a fast transformation paths are present,
// get the return value based on the path used.
if (include_fast_path) {
@ -7360,16 +7273,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
} // namespace
void BuildInlinedJSToWasmWrapper(
Zone* zone, MachineGraph* mcgraph, const wasm::FunctionSig* signature,
const wasm::WasmModule* module, compiler::SourcePositionTable* spt,
StubCallMode stub_mode, wasm::WasmFeatures features,
const JSWasmCallData* js_wasm_call_data, Node* frame_state) {
WasmWrapperGraphBuilder builder(zone, mcgraph, signature, module, spt,
stub_mode, features);
builder.BuildJSToWasmWrapper(false, js_wasm_call_data, frame_state);
}
std::unique_ptr<OptimizedCompilationJob> NewJSToWasmCompilationJob(
Isolate* isolate, wasm::WasmEngine* wasm_engine,
const wasm::FunctionSig* sig, const wasm::WasmModule* module,
@ -8088,8 +7991,7 @@ class LinkageLocationAllocator {
// General code uses the above configuration data.
CallDescriptor* GetWasmCallDescriptor(
Zone* zone, const wasm::FunctionSig* fsig,
WasmGraphBuilder::UseRetpoline use_retpoline, WasmCallKind call_kind,
bool need_frame_state) {
WasmGraphBuilder::UseRetpoline use_retpoline, WasmCallKind call_kind) {
// The extra here is to accomodate the instance object as first parameter
// and, when specified, the additional callable.
bool extra_callable_param =
@ -8166,9 +8068,7 @@ CallDescriptor* GetWasmCallDescriptor(
}
CallDescriptor::Flags flags =
use_retpoline ? CallDescriptor::kRetpoline
: need_frame_state ? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags;
use_retpoline ? CallDescriptor::kRetpoline : CallDescriptor::kNoFlags;
return zone->New<CallDescriptor>( // --
descriptor_kind, // kind
target_type, // target MachineType

View File

@ -148,28 +148,6 @@ enum CWasmEntryParameters {
V8_EXPORT_PRIVATE Handle<Code> CompileCWasmEntry(
Isolate*, const wasm::FunctionSig*, const wasm::WasmModule* module);
class JSWasmCallData {
public:
void set_arg_needs_conversion(size_t index, bool value) {
if (index >= arg_needs_conversion_.size())
arg_needs_conversion_.resize(index + 1);
arg_needs_conversion_[index] = value;
}
bool arg_needs_conversion(size_t index) const {
DCHECK_LT(index, arg_needs_conversion_.size());
return arg_needs_conversion_[index];
}
void set_result_needs_conversion(bool value) {
result_needs_conversion_ = value;
}
bool result_needs_conversion() const { return result_needs_conversion_; }
private:
bool result_needs_conversion_ = false;
std::vector<bool> arg_needs_conversion_;
};
// Values from the instance object are cached between Wasm-level function calls.
// This struct allows the SSA environment handling this cache to be defined
// and manipulated in wasm-compiler.{h,cc} instead of inside the Wasm decoder.
@ -509,7 +487,7 @@ class WasmGraphBuilder {
Node* BuildCCall(MachineSignature* sig, Node* function, Args... args);
Node* BuildCallNode(const wasm::FunctionSig* sig, Vector<Node*> args,
wasm::WasmCodePosition position, Node* instance_node,
const Operator* op, Node* frame_state = nullptr);
const Operator* op);
// Helper function for {BuildIndirectCall}.
void LoadIndirectFunctionTable(uint32_t table_index, Node** ift_size,
Node** ift_sig_ids, Node** ift_targets,
@ -520,8 +498,7 @@ class WasmGraphBuilder {
IsReturnCall continuation);
Node* BuildWasmCall(const wasm::FunctionSig* sig, Vector<Node*> args,
Vector<Node*> rets, wasm::WasmCodePosition position,
Node* instance_node, UseRetpoline use_retpoline,
Node* frame_state = nullptr);
Node* instance_node, UseRetpoline use_retpoline);
Node* BuildWasmReturnCall(const wasm::FunctionSig* sig, Vector<Node*> args,
wasm::WasmCodePosition position,
Node* instance_node, UseRetpoline use_retpoline);
@ -686,17 +663,11 @@ class WasmGraphBuilder {
enum WasmCallKind { kWasmFunction, kWasmImportWrapper, kWasmCapiFunction };
V8_EXPORT_PRIVATE void BuildInlinedJSToWasmWrapper(
Zone* zone, MachineGraph* mcgraph, const wasm::FunctionSig* signature,
const wasm::WasmModule* module, compiler::SourcePositionTable* spt,
StubCallMode stub_mode, wasm::WasmFeatures features,
const JSWasmCallData* js_wasm_call_data, Node* frame_state);
V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
Zone* zone, const wasm::FunctionSig* signature,
WasmGraphBuilder::UseRetpoline use_retpoline =
WasmGraphBuilder::kNoRetpoline,
WasmCallKind kind = kWasmFunction, bool need_frame_state = false);
WasmCallKind kind = kWasmFunction);
V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor(
Zone* zone, const CallDescriptor* call_descriptor);

View File

@ -29,7 +29,6 @@
#include "src/objects/smi.h"
#include "src/snapshot/embedded/embedded-data.h"
#include "src/tracing/trace-event.h"
#include "src/wasm/wasm-linkage.h"
// Has to be the last include (doesn't have include guards)
#include "src/objects/object-macros.h"
@ -485,24 +484,6 @@ uint16_t InternalFormalParameterCountWithReceiver(SharedFunctionInfo sfi) {
} // namespace
namespace {
// Encodes/decodes the return type of a Wasm function as the integer value of
// wasm::ValueType::Kind, or -1 if the function returns void.
int EncodeWasmReturnType(base::Optional<wasm::ValueType::Kind> return_type) {
return return_type ? static_cast<int>(return_type.value()) : -1;
}
base::Optional<wasm::ValueType::Kind> DecodeWasmReturnType(int code) {
if (code >= 0) {
return {static_cast<wasm::ValueType::Kind>(code)};
}
return {};
}
} // namespace
Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
DeoptimizeKind kind, unsigned bailout_id, Address from,
int fp_to_sp_delta)
@ -956,7 +937,6 @@ void Deoptimizer::DoComputeOutputFrames() {
DoComputeConstructStubFrame(translated_frame, frame_index);
break;
case TranslatedFrame::kBuiltinContinuation:
case TranslatedFrame::kJSToWasmBuiltinContinuation:
DoComputeBuiltinContinuation(translated_frame, frame_index,
BuiltinContinuationMode::STUB);
break;
@ -1676,36 +1656,6 @@ Builtins::Name Deoptimizer::TrampolineForBuiltinContinuation(
UNREACHABLE();
}
TranslatedValue Deoptimizer::TranslatedValueForWasmReturnType(
base::Optional<wasm::ValueType::Kind> wasm_call_return_type) {
if (wasm_call_return_type) {
switch (wasm_call_return_type.value()) {
case wasm::ValueType::kI32:
return TranslatedValue::NewInt32(
&translated_state_,
(int32_t)input_->GetRegister(kReturnRegister0.code()));
case wasm::ValueType::kI64:
return TranslatedValue::NewInt64ToBigInt(
&translated_state_,
(int64_t)input_->GetRegister(kReturnRegister0.code()));
case wasm::ValueType::kF32:
return TranslatedValue::NewFloat(
&translated_state_,
Float32(*reinterpret_cast<float*>(
input_->GetDoubleRegister(wasm::kFpReturnRegisters[0].code())
.get_bits_address())));
case wasm::ValueType::kF64:
return TranslatedValue::NewDouble(
&translated_state_,
input_->GetDoubleRegister(wasm::kFpReturnRegisters[0].code()));
default:
UNREACHABLE();
}
}
return TranslatedValue::NewTagged(&translated_state_,
ReadOnlyRoots(isolate()).undefined_value());
}
// BuiltinContinuationFrames capture the machine state that is expected as input
// to a builtin, including both input register values and stack parameters. When
// the frame is reactivated (i.e. the frame below it returns), a
@ -1767,21 +1717,6 @@ TranslatedValue Deoptimizer::TranslatedValueForWasmReturnType(
void Deoptimizer::DoComputeBuiltinContinuation(
TranslatedFrame* translated_frame, int frame_index,
BuiltinContinuationMode mode) {
TranslatedFrame::iterator result_iterator = translated_frame->end();
bool is_js_to_wasm_builtin_continuation =
translated_frame->kind() == TranslatedFrame::kJSToWasmBuiltinContinuation;
if (is_js_to_wasm_builtin_continuation) {
// For JSToWasmBuiltinContinuations, add a TranslatedValue with the result
// of the Wasm call, extracted from the input FrameDescription.
// This TranslatedValue will be written in the output frame in place of the
// hole and we'll use ContinueToCodeStubBuiltin in place of
// ContinueToCodeStubBuiltinWithResult.
TranslatedValue result = TranslatedValueForWasmReturnType(
translated_frame->wasm_call_return_type());
translated_frame->Add(result);
}
TranslatedFrame::iterator value_iterator = translated_frame->begin();
const BailoutId bailout_id = translated_frame->node_id();
@ -1865,15 +1800,9 @@ void Deoptimizer::DoComputeBuiltinContinuation(
frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
}
if (frame_info.frame_has_result_stack_slot()) {
if (is_js_to_wasm_builtin_continuation) {
frame_writer.PushTranslatedValue(result_iterator,
"return result on lazy deopt\n");
} else {
DCHECK_EQ(result_iterator, translated_frame->end());
frame_writer.PushRawObject(
roots.the_hole_value(),
"placeholder for return result on lazy deopt\n");
}
frame_writer.PushRawObject(
roots.the_hole_value(),
"placeholder for return result on lazy deopt\n");
}
} else {
// JavaScript builtin.
@ -1968,7 +1897,7 @@ void Deoptimizer::DoComputeBuiltinContinuation(
frame_writer.PushRawObject(Smi::FromInt(output_frame_size_above_fp),
"frame height at deoptimization\n");
// The context even if this is a stub continuation frame. We can't use the
// The context even if this is a stub contininuation frame. We can't use the
// usual context slot, because we must store the frame marker there.
frame_writer.PushTranslatedValue(context_register_value,
"builtin JavaScript context\n");
@ -2021,7 +1950,7 @@ void Deoptimizer::DoComputeBuiltinContinuation(
}
}
CHECK_EQ(result_iterator, value_iterator);
CHECK_EQ(translated_frame->end(), value_iterator);
CHECK_EQ(0u, frame_writer.top_offset());
// Clear the context register. The context might be a de-materialized object
@ -2037,13 +1966,10 @@ void Deoptimizer::DoComputeBuiltinContinuation(
// will build its own frame once we continue to it.
Register fp_reg = JavaScriptFrame::fp_register();
output_frame->SetRegister(fp_reg.code(), fp_value);
// For JSToWasmBuiltinContinuations use ContinueToCodeStubBuiltin, and not
// ContinueToCodeStubBuiltinWithResult because we don't want to overwrite the
// return value that we have already set.
Code continue_to_builtin =
isolate()->builtins()->builtin(TrampolineForBuiltinContinuation(
mode, frame_info.frame_has_result_stack_slot() &&
!is_js_to_wasm_builtin_continuation));
mode, frame_info.frame_has_result_stack_slot()));
if (is_topmost) {
// Only the pc of the topmost frame needs to be signed since it is
// authenticated at the end of the DeoptimizationEntry builtin.
@ -2230,16 +2156,6 @@ void Translation::BeginBuiltinContinuationFrame(BailoutId bailout_id,
buffer_->Add(height);
}
void Translation::BeginJSToWasmBuiltinContinuationFrame(
BailoutId bailout_id, int literal_id, unsigned height,
base::Optional<wasm::ValueType::Kind> return_type) {
buffer_->Add(JS_TO_WASM_BUILTIN_CONTINUATION_FRAME);
buffer_->Add(bailout_id.ToInt());
buffer_->Add(literal_id);
buffer_->Add(height);
buffer_->Add(EncodeWasmReturnType(return_type));
}
void Translation::BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
int literal_id,
unsigned height) {
@ -2416,7 +2332,6 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
case BEGIN:
case CONSTRUCT_STUB_FRAME:
case BUILTIN_CONTINUATION_FRAME:
case JS_TO_WASM_BUILTIN_CONTINUATION_FRAME:
case JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
case JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME:
return 3;
@ -2662,14 +2577,6 @@ TranslatedValue TranslatedValue::NewInt64(TranslatedState* container,
return slot;
}
// static
TranslatedValue TranslatedValue::NewInt64ToBigInt(TranslatedState* container,
int64_t value) {
TranslatedValue slot(container, kInt64ToBigInt);
slot.int64_value_ = value;
return slot;
}
// static
TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container,
uint32_t value) {
@ -2712,7 +2619,7 @@ int32_t TranslatedValue::int32_value() const {
}
int64_t TranslatedValue::int64_value() const {
DCHECK(kInt64 == kind() || kInt64ToBigInt == kind());
DCHECK_EQ(kInt64, kind());
return int64_value_;
}
@ -2774,10 +2681,6 @@ Object TranslatedValue::GetRawValue() const {
break;
}
case kInt64ToBigInt:
// Return the arguments marker.
break;
case kUInt32: {
bool is_smi = (uint32_value() <= static_cast<uintptr_t>(Smi::kMaxValue));
if (is_smi) {
@ -2867,37 +2770,28 @@ Handle<Object> TranslatedValue::GetValue() {
return container_->InitializeObjectAt(this);
}
double number = 0;
Handle<HeapObject> heap_object;
double number;
switch (kind()) {
case TranslatedValue::kInt32:
number = int32_value();
heap_object = isolate()->factory()->NewHeapNumber(number);
break;
case TranslatedValue::kInt64:
number = int64_value();
heap_object = isolate()->factory()->NewHeapNumber(number);
break;
case TranslatedValue::kInt64ToBigInt:
heap_object = BigInt::FromInt64(isolate(), int64_value());
break;
case TranslatedValue::kUInt32:
number = uint32_value();
heap_object = isolate()->factory()->NewHeapNumber(number);
break;
case TranslatedValue::kFloat:
number = float_value().get_scalar();
heap_object = isolate()->factory()->NewHeapNumber(number);
break;
case TranslatedValue::kDouble:
number = double_value().get_scalar();
heap_object = isolate()->factory()->NewHeapNumber(number);
break;
default:
UNREACHABLE();
}
DCHECK(!IsSmiDouble(number) || kind() == TranslatedValue::kInt64ToBigInt);
set_initialized_storage(heap_object);
DCHECK(!IsSmiDouble(number));
set_initialized_storage(isolate()->factory()->NewHeapNumber(number));
return storage_;
}
@ -2989,15 +2883,6 @@ TranslatedFrame TranslatedFrame::BuiltinContinuationFrame(
return frame;
}
TranslatedFrame TranslatedFrame::JSToWasmBuiltinContinuationFrame(
BailoutId bailout_id, SharedFunctionInfo shared_info, int height,
base::Optional<wasm::ValueType::Kind> return_type) {
TranslatedFrame frame(kJSToWasmBuiltinContinuation, shared_info, height);
frame.node_id_ = bailout_id;
frame.return_type_ = return_type;
return frame;
}
TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationFrame(
BailoutId bailout_id, SharedFunctionInfo shared_info, int height) {
TranslatedFrame frame(kJavaScriptBuiltinContinuation, shared_info, height);
@ -3033,7 +2918,6 @@ int TranslatedFrame::GetValueCount() {
case kConstructStub:
case kBuiltinContinuation:
case kJSToWasmBuiltinContinuation:
case kJavaScriptBuiltinContinuation:
case kJavaScriptBuiltinContinuationWithCatch: {
static constexpr int kTheContext = 1;
@ -3128,26 +3012,6 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
height);
}
case Translation::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME: {
BailoutId bailout_id = BailoutId(iterator->Next());
SharedFunctionInfo shared_info =
SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
int height = iterator->Next();
base::Optional<wasm::ValueType::Kind> return_type =
DecodeWasmReturnType(iterator->Next());
if (trace_file != nullptr) {
std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
PrintF(trace_file, " reading JS to Wasm builtin continuation frame %s",
name.get());
PrintF(trace_file,
" => bailout_id=%d, height=%d return_type=%d; inputs:\n",
bailout_id.ToInt(), height,
return_type.has_value() ? return_type.value() : -1);
}
return TranslatedFrame::JSToWasmBuiltinContinuationFrame(
bailout_id, shared_info, height, return_type);
}
case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME: {
BailoutId bailout_id = BailoutId(iterator->Next());
SharedFunctionInfo shared_info =
@ -3337,7 +3201,6 @@ int TranslatedState::CreateNextTranslatedValue(
case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME:
case Translation::BUILTIN_CONTINUATION_FRAME:
case Translation::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME:
case Translation::UPDATE_FEEDBACK:
// Peeled off before getting here.
break;

View File

@ -63,14 +63,12 @@ class TranslatedValue {
private:
friend class TranslatedState;
friend class TranslatedFrame;
friend class Deoptimizer;
enum Kind : uint8_t {
kInvalid,
kTagged,
kInt32,
kInt64,
kInt64ToBigInt,
kUInt32,
kBoolBit,
kFloat,
@ -107,8 +105,6 @@ class TranslatedValue {
static TranslatedValue NewDouble(TranslatedState* container, Float64 value);
static TranslatedValue NewInt32(TranslatedState* container, int32_t value);
static TranslatedValue NewInt64(TranslatedState* container, int64_t value);
static TranslatedValue NewInt64ToBigInt(TranslatedState* container,
int64_t value);
static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
static TranslatedValue NewTagged(TranslatedState* container, Object literal);
@ -176,7 +172,6 @@ class TranslatedFrame {
kArgumentsAdaptor,
kConstructStub,
kBuiltinContinuation,
kJSToWasmBuiltinContinuation,
kJavaScriptBuiltinContinuation,
kJavaScriptBuiltinContinuationWithCatch,
kInvalid
@ -251,15 +246,8 @@ class TranslatedFrame {
reference front() { return values_.front(); }
const_reference front() const { return values_.front(); }
// Only for Kind == kJSToWasmBuiltinContinuation
base::Optional<wasm::ValueType::Kind> wasm_call_return_type() const {
DCHECK_EQ(kind(), kJSToWasmBuiltinContinuation);
return return_type_;
}
private:
friend class TranslatedState;
friend class Deoptimizer;
// Constructor static methods.
static TranslatedFrame InterpretedFrame(BailoutId bytecode_offset,
@ -275,9 +263,6 @@ class TranslatedFrame {
int height);
static TranslatedFrame BuiltinContinuationFrame(
BailoutId bailout_id, SharedFunctionInfo shared_info, int height);
static TranslatedFrame JSToWasmBuiltinContinuationFrame(
BailoutId bailout_id, SharedFunctionInfo shared_info, int height,
base::Optional<wasm::ValueType::Kind> return_type);
static TranslatedFrame JavaScriptBuiltinContinuationFrame(
BailoutId bailout_id, SharedFunctionInfo shared_info, int height);
static TranslatedFrame JavaScriptBuiltinContinuationWithCatchFrame(
@ -314,9 +299,6 @@ class TranslatedFrame {
using ValuesContainer = std::deque<TranslatedValue>;
ValuesContainer values_;
// Only for Kind == kJSToWasmBuiltinContinuation
base::Optional<wasm::ValueType::Kind> return_type_;
};
// Auxiliary class for translating deoptimization values.
@ -596,9 +578,6 @@ class Deoptimizer : public Malloced {
static Builtins::Name TrampolineForBuiltinContinuation(
BuiltinContinuationMode mode, bool must_handle_result);
TranslatedValue TranslatedValueForWasmReturnType(
base::Optional<wasm::ValueType::Kind> wasm_call_return_type);
void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
int frame_index,
BuiltinContinuationMode mode);
@ -897,7 +876,6 @@ class TranslationIterator {
V(BEGIN) \
V(INTERPRETED_FRAME) \
V(BUILTIN_CONTINUATION_FRAME) \
V(JS_TO_WASM_BUILTIN_CONTINUATION_FRAME) \
V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME) \
V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME) \
V(CONSTRUCT_STUB_FRAME) \
@ -951,9 +929,6 @@ class Translation {
unsigned height);
void BeginBuiltinContinuationFrame(BailoutId bailout_id, int literal_id,
unsigned height);
void BeginJSToWasmBuiltinContinuationFrame(
BailoutId bailout_id, int literal_id, unsigned height,
base::Optional<wasm::ValueType::Kind> return_type);
void BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
int literal_id, unsigned height);
void BeginJavaScriptBuiltinContinuationWithCatchFrame(BailoutId bailout_id,

View File

@ -1088,8 +1088,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
isolate_root_bias());
}
THREAD_LOCAL_TOP_ADDRESS(Address, thread_in_wasm_flag_address)
MaterializedObjectStore* materialized_object_store() {
return materialized_object_store_;
}

View File

@ -424,7 +424,6 @@ DEFINE_BOOL(future, FUTURE_BOOL,
DEFINE_WEAK_IMPLICATION(future, write_protect_code_memory)
DEFINE_WEAK_IMPLICATION(future, finalize_streaming_on_background)
DEFINE_WEAK_IMPLICATION(future, super_ic)
DEFINE_WEAK_IMPLICATION(future, turbo_inline_js_wasm_calls)
// Flags for jitless
DEFINE_BOOL(jitless, V8_LITE_BOOL,
@ -736,7 +735,6 @@ DEFINE_INT(reuse_opt_code_count, 0,
DEFINE_BOOL(turbo_dynamic_map_checks, true,
"use dynamic map checks when generating code for property accesses "
"if all handlers in an IC are the same for turboprop and NCI")
DEFINE_BOOL(turbo_inline_js_wasm_calls, false, "inline JS->Wasm calls")
// Native context independent (NCI) code.
DEFINE_BOOL(turbo_nci, false,

View File

@ -526,19 +526,6 @@ void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) { // NOLINT
break;
}
case Translation::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME: {
int bailout_id = iterator.Next();
int shared_info_id = iterator.Next();
Object shared_info = LiteralArray().get(shared_info_id);
unsigned height = iterator.Next();
int wasm_return_type = iterator.Next();
os << "{bailout_id=" << bailout_id << ", function="
<< SharedFunctionInfo::cast(shared_info).DebugNameCStr().get()
<< ", height=" << height
<< ", wasm_return_type=" << wasm_return_type << "}";
break;
}
case Translation::ARGUMENTS_ADAPTOR_FRAME: {
int shared_info_id = iterator.Next();
Object shared_info = LiteralArray().get(shared_info_id);

View File

@ -15,7 +15,6 @@
#include "src/objects/scope-info.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/templates.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
// Has to be the last include (doesn't have include guards):
@ -657,22 +656,6 @@ bool SharedFunctionInfo::HasWasmJSFunctionData() const {
return function_data(kAcquireLoad).IsWasmJSFunctionData();
}
const wasm::WasmModule* SharedFunctionInfo::wasm_module() const {
if (!HasWasmExportedFunctionData()) return nullptr;
const WasmExportedFunctionData& function_data = wasm_exported_function_data();
const WasmInstanceObject& wasm_instance = function_data.instance();
const WasmModuleObject& wasm_module_object = wasm_instance.module_object();
return wasm_module_object.module();
}
const wasm::FunctionSig* SharedFunctionInfo::wasm_function_signature() const {
const wasm::WasmModule* module = wasm_module();
if (!module) return nullptr;
const WasmExportedFunctionData& function_data = wasm_exported_function_data();
DCHECK_LT(function_data.function_index(), module->functions.size());
return module->functions[function_data.function_index()].sig;
}
bool SharedFunctionInfo::HasWasmCapiFunctionData() const {
return function_data(kAcquireLoad).IsWasmCapiFunctionData();
}

View File

@ -18,7 +18,6 @@
#include "src/objects/smi.h"
#include "src/objects/struct.h"
#include "src/roots/roots.h"
#include "src/wasm/value-type.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "torque-generated/bit-fields.h"
#include "torque-generated/field-offsets.h"
@ -35,16 +34,10 @@ class BytecodeArray;
class CoverageInfo;
class DebugInfo;
class IsCompiledScope;
template <typename>
class Signature;
class WasmCapiFunctionData;
class WasmExportedFunctionData;
class WasmJSFunctionData;
namespace wasm {
struct WasmModule;
} // namespace wasm
#include "torque-generated/src/objects/shared-function-info-tq.inc"
// Data collected by the pre-parser storing information about scopes and inner
@ -324,9 +317,6 @@ class SharedFunctionInfo
inline bool HasWasmCapiFunctionData() const;
WasmCapiFunctionData wasm_capi_function_data() const;
inline const wasm::WasmModule* wasm_module() const;
inline const wasm::FunctionSig* wasm_function_signature() const;
// Clear out pre-parsed scope data from UncompiledDataWithPreparseData,
// turning it into UncompiledDataWithoutPreparseData.
inline void ClearPreparseData();

View File

@ -1,34 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/wasm/value-type.h"
#include "src/codegen/signature.h"
namespace v8 {
namespace internal {
namespace wasm {
base::Optional<wasm::ValueType::Kind> WasmReturnTypeFromSignature(
const FunctionSig* wasm_signature) {
if (wasm_signature->return_count() == 0) {
return {};
} else {
DCHECK_EQ(wasm_signature->return_count(), 1);
ValueType return_type = wasm_signature->GetReturn(0);
switch (return_type.kind()) {
case ValueType::kI32:
case ValueType::kI64:
case ValueType::kF32:
case ValueType::kF64:
return {return_type.kind()};
default:
UNREACHABLE();
}
}
}
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -6,7 +6,6 @@
#define V8_WASM_VALUE_TYPE_H_
#include "src/base/bit-field.h"
#include "src/base/optional.h"
#include "src/codegen/machine-type.h"
#include "src/wasm/wasm-constants.h"
@ -680,9 +679,6 @@ class StoreType {
};
};
base::Optional<wasm::ValueType::Kind> WasmReturnTypeFromSignature(
const FunctionSig* wasm_signature);
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -247,7 +247,6 @@ v8_source_set("cctest_sources") {
"test-inobject-slack-tracking.cc",
"test-inspector.cc",
"test-intl.cc",
"test-js-to-wasm.cc",
"test-js-weak-refs.cc",
"test-liveedit.cc",
"test-local-handles.cc",

View File

@ -365,10 +365,6 @@ static inline v8::Local<v8::Integer> v8_int(int32_t x) {
return v8::Integer::New(v8::Isolate::GetCurrent(), x);
}
static inline v8::Local<v8::BigInt> v8_bigint(int64_t x) {
return v8::BigInt::New(v8::Isolate::GetCurrent(), x);
}
static inline v8::Local<v8::String> v8_str(const char* x) {
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x).ToLocalChecked();
}

View File

@ -603,7 +603,6 @@
'test-api/TurboAsmDisablesDetach': [SKIP],
'test-cpu-profiler/TickLinesOptimized': [SKIP],
'test-heap/TestOptimizeAfterBytecodeFlushingCandidate': [SKIP],
'test-js-to-wasm/*': [SKIP],
'test-run-wasm-exceptions/RunWasmInterpreter_TryCatchCallDirect': [SKIP],
'test-run-wasm-exceptions/RunWasmInterpreter_TryCatchCallExternal': [SKIP],
'test-run-wasm-exceptions/RunWasmInterpreter_TryCatchCallIndirect': [SKIP],
@ -647,7 +646,6 @@
'test-cpu-profiler/DetailedSourcePositionAPI_Inlining': [SKIP],
'serializer-tester/BoundFunctionArguments': [SKIP],
'serializer-tester/BoundFunctionTarget': [SKIP],
'test-js-to-wasm/*': [SKIP],
}], # variant == turboprop
##############################################################################

View File

@ -27492,6 +27492,126 @@ UNINITIALIZED_TEST(NestedIsolates) {
#ifndef V8_LITE_MODE
namespace {
template <typename T>
struct ConvertJSValue {
static Maybe<T> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context);
};
template <>
struct ConvertJSValue<int32_t> {
static Maybe<int32_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return value->Int32Value(context);
}
};
template <>
struct ConvertJSValue<uint32_t> {
static Maybe<uint32_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return value->Uint32Value(context);
}
};
// NaNs and +/-Infinity should be 0, otherwise (modulo 2^64) - 2^63.
// Step 8 - 12 of https://heycam.github.io/webidl/#abstract-opdef-converttoint
// The int64_t and uint64_t implementations below are copied from Blink:
// https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h;l=249?q=doubletointeger&sq=&ss=chromium%2Fchromium%2Fsrc
template <>
struct ConvertJSValue<int64_t> {
static Maybe<int64_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
Maybe<double> double_value = value->NumberValue(context);
if (!double_value.IsJust()) {
return v8::Nothing<int64_t>();
}
double result = double_value.ToChecked();
if (std::isinf(result) || std::isnan(result)) {
return v8::Just(int64_t(0));
}
result = trunc(result);
constexpr uint64_t kMaxULL = std::numeric_limits<uint64_t>::max();
// -2^{64} < fmod_value < 2^{64}.
double fmod_value = fmod(result, kMaxULL + 1.0);
if (fmod_value >= 0) {
if (fmod_value < pow(2, 63)) {
// 0 <= fmod_value < 2^{63}.
// 0 <= value < 2^{63}. This cast causes no loss.
return v8::Just(static_cast<int64_t>(fmod_value));
} else {
// 2^{63} <= fmod_value < 2^{64}.
// 2^{63} <= value < 2^{64}. This cast causes no loss.
return v8::Just(static_cast<int64_t>(fmod_value - pow(2, 64)));
}
}
// -2^{64} < fmod_value < 0.
// 0 < fmod_value_uint64 < 2^{64}. This cast causes no loss.
uint64_t fmod_value_uint64 = static_cast<uint64_t>(-fmod_value);
// -1 < (kMaxULL - fmod_value_uint64) < 2^{64} - 1.
// 0 < value < 2^{64}.
return v8::Just(static_cast<int64_t>(kMaxULL - fmod_value_uint64 + 1));
}
};
template <>
struct ConvertJSValue<uint64_t> {
static Maybe<uint64_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
Maybe<double> double_value = value->NumberValue(context);
if (!double_value.IsJust()) {
return v8::Nothing<uint64_t>();
}
double result = double_value.ToChecked();
if (std::isinf(result) || std::isnan(result)) {
return v8::Just(uint64_t(0));
}
result = trunc(result);
constexpr uint64_t kMaxULL = std::numeric_limits<uint64_t>::max();
// -2^{64} < fmod_value < 2^{64}.
double fmod_value = fmod(result, kMaxULL + 1.0);
if (fmod_value >= 0) {
return v8::Just(static_cast<uint64_t>(fmod_value));
}
// -2^{64} < fmod_value < 0.
// 0 < fmod_value_uint64 < 2^{64}. This cast causes no loss.
uint64_t fmod_value_uint64 = static_cast<uint64_t>(-fmod_value);
// -1 < (kMaxULL - fmod_value_uint64) < 2^{64} - 1.
// 0 < value < 2^{64}.
return v8::Just(static_cast<uint64_t>(kMaxULL - fmod_value_uint64 + 1));
}
};
template <>
struct ConvertJSValue<float> {
static Maybe<float> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
Maybe<double> val = value->NumberValue(context);
if (val.IsNothing()) return v8::Nothing<float>();
return v8::Just(static_cast<float>(val.ToChecked()));
}
};
template <>
struct ConvertJSValue<double> {
static Maybe<double> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return value->NumberValue(context);
}
};
template <>
struct ConvertJSValue<bool> {
static Maybe<bool> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return v8::Just<bool>(value->BooleanValue(CcTest::isolate()));
}
};
template <typename Value, typename Impl>
struct BasicApiChecker {
static void FastCallback(v8::ApiObject receiver, Value argument,

View File

@ -52,135 +52,4 @@ static void CheckInternalFieldsAreZero(v8::Local<T> value) {
}
}
template <typename T>
struct ConvertJSValue {
static v8::Maybe<T> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context);
};
template <>
struct ConvertJSValue<int32_t> {
static v8::Maybe<int32_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return value->Int32Value(context);
}
};
template <>
struct ConvertJSValue<uint32_t> {
static v8::Maybe<uint32_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return value->Uint32Value(context);
}
};
// NaNs and +/-Infinity should be 0, otherwise (modulo 2^64) - 2^63.
// Step 8 - 12 of https://heycam.github.io/webidl/#abstract-opdef-converttoint
// The int64_t and uint64_t implementations below are copied from Blink:
// https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h;l=249?q=doubletointeger&sq=&ss=chromium%2Fchromium%2Fsrc
template <>
struct ConvertJSValue<int64_t> {
static v8::Maybe<int64_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
v8::Maybe<double> double_value = value->NumberValue(context);
if (!double_value.IsJust()) {
return v8::Nothing<int64_t>();
}
double result = double_value.ToChecked();
if (std::isinf(result) || std::isnan(result)) {
return v8::Just(int64_t(0));
}
result = trunc(result);
constexpr uint64_t kMaxULL = std::numeric_limits<uint64_t>::max();
// -2^{64} < fmod_value < 2^{64}.
double fmod_value = fmod(result, kMaxULL + 1.0);
if (fmod_value >= 0) {
if (fmod_value < pow(2, 63)) {
// 0 <= fmod_value < 2^{63}.
// 0 <= value < 2^{63}. This cast causes no loss.
return v8::Just(static_cast<int64_t>(fmod_value));
} else {
// 2^{63} <= fmod_value < 2^{64}.
// 2^{63} <= value < 2^{64}. This cast causes no loss.
return v8::Just(static_cast<int64_t>(fmod_value - pow(2, 64)));
}
}
// -2^{64} < fmod_value < 0.
// 0 < fmod_value_uint64 < 2^{64}. This cast causes no loss.
uint64_t fmod_value_uint64 = static_cast<uint64_t>(-fmod_value);
// -1 < (kMaxULL - fmod_value_uint64) < 2^{64} - 1.
// 0 < value < 2^{64}.
return v8::Just(static_cast<int64_t>(kMaxULL - fmod_value_uint64 + 1));
}
};
template <>
struct ConvertJSValue<uint64_t> {
static v8::Maybe<uint64_t> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
v8::Maybe<double> double_value = value->NumberValue(context);
if (!double_value.IsJust()) {
return v8::Nothing<uint64_t>();
}
double result = double_value.ToChecked();
if (std::isinf(result) || std::isnan(result)) {
return v8::Just(uint64_t(0));
}
result = trunc(result);
constexpr uint64_t kMaxULL = std::numeric_limits<uint64_t>::max();
// -2^{64} < fmod_value < 2^{64}.
double fmod_value = fmod(result, kMaxULL + 1.0);
if (fmod_value >= 0) {
return v8::Just(static_cast<uint64_t>(fmod_value));
}
// -2^{64} < fmod_value < 0.
// 0 < fmod_value_uint64 < 2^{64}. This cast causes no loss.
uint64_t fmod_value_uint64 = static_cast<uint64_t>(-fmod_value);
// -1 < (kMaxULL - fmod_value_uint64) < 2^{64} - 1.
// 0 < value < 2^{64}.
return v8::Just(static_cast<uint64_t>(kMaxULL - fmod_value_uint64 + 1));
}
};
template <>
struct ConvertJSValue<v8::BigInt> {
static v8::Maybe<v8::Local<v8::BigInt>> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
if (value->IsBigInt()) {
return v8::Just(value.As<v8::BigInt>());
}
return v8::Nothing<v8::Local<v8::BigInt>>();
}
};
template <>
struct ConvertJSValue<float> {
static v8::Maybe<float> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
v8::Maybe<double> val = value->NumberValue(context);
if (val.IsNothing()) return v8::Nothing<float>();
return v8::Just(static_cast<float>(val.ToChecked()));
}
};
template <>
struct ConvertJSValue<double> {
static v8::Maybe<double> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return value->NumberValue(context);
}
};
template <>
struct ConvertJSValue<bool> {
static v8::Maybe<bool> Get(v8::Local<v8::Value> value,
v8::Local<v8::Context> context) {
return v8::Just<bool>(value->BooleanValue(CcTest::isolate()));
}
};
#endif // V8_TEST_CCTEST_TEST_API_H_

View File

@ -1,845 +0,0 @@
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <iomanip>
#include "include/v8.h"
#include "src/api/api.h"
#include "src/wasm/wasm-module-builder.h"
#include "test/cctest/cctest.h"
#include "test/cctest/test-api.h"
#include "test/common/wasm/flag-utils.h"
#include "test/common/wasm/test-signatures.h"
#include "test/common/wasm/wasm-macro-gen.h"
namespace v8 {
namespace internal {
namespace wasm {
static const int kDeoptLoopCount = 1e4;
// Validates the type of the result returned by a test function.
template <typename T>
bool CheckType(v8::Local<v8::Value> result) {
return result->IsNumber();
}
template <>
bool CheckType<void>(v8::Local<v8::Value> result) {
return result->IsUndefined();
}
template <>
bool CheckType<int>(v8::Local<v8::Value> result) {
return result->IsInt32();
}
template <>
bool CheckType<int64_t>(v8::Local<v8::Value> result) {
return result->IsBigInt();
}
template <>
bool CheckType<v8::Local<v8::BigInt>>(v8::Local<v8::Value> result) {
return result->IsBigInt();
}
static TestSignatures sigs;
struct ExportedFunction {
std::string name;
FunctionSig* signature;
std::vector<ValueType> locals;
std::vector<uint8_t> code;
};
#define WASM_CODE(...) __VA_ARGS__
#define DECLARE_EXPORTED_FUNCTION(name, sig, code) \
static ExportedFunction k_##name = {#name, sig, {}, code};
#define DECLARE_EXPORTED_FUNCTION_WITH_LOCALS(name, sig, locals, code) \
static ExportedFunction k_##name = {#name, sig, locals, code};
DECLARE_EXPORTED_FUNCTION(nop, sigs.v_v(), WASM_CODE({WASM_NOP}))
DECLARE_EXPORTED_FUNCTION(i32_square, sigs.i_i(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(0),
kExprI32Mul}))
DECLARE_EXPORTED_FUNCTION(i64_square, sigs.l_l(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(0),
kExprI64Mul}))
DECLARE_EXPORTED_FUNCTION(f32_square, sigs.f_f(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(0),
kExprF32Mul}))
DECLARE_EXPORTED_FUNCTION(f64_square, sigs.d_d(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(0),
kExprF64Mul}))
DECLARE_EXPORTED_FUNCTION(void_square, sigs.v_i(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(0),
kExprI32Mul, kExprDrop}))
DECLARE_EXPORTED_FUNCTION(add, sigs.i_ii(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
kExprI32Add}))
DECLARE_EXPORTED_FUNCTION(i64_add, sigs.l_ll(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
kExprI64Add}))
DECLARE_EXPORTED_FUNCTION(sum3, sigs.i_iii(),
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
WASM_GET_LOCAL(2), kExprI32Add,
kExprI32Add}))
DECLARE_EXPORTED_FUNCTION(no_args, sigs.i_v(), WASM_CODE({WASM_I32V(42)}))
DECLARE_EXPORTED_FUNCTION(load, sigs.i_i(),
WASM_CODE({WASM_LOAD_MEM(MachineType::Int32(),
WASM_GET_LOCAL(0))}))
// int32_t test(int32_t v0, int32_t v1, int32_t v2, int32_t v3, int32_t v4,
// int32_t v5, int32_t v6, int32_t v7, int32_t v8, int32_t v9) {
// return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9;
// }
static const ValueType kIntTypes11[11] = {
kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32,
kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32};
static FunctionSig i_iiiiiiiiii(1, 10, kIntTypes11);
DECLARE_EXPORTED_FUNCTION(
sum10, &i_iiiiiiiiii,
WASM_CODE({WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2),
WASM_GET_LOCAL(3), WASM_GET_LOCAL(4), WASM_GET_LOCAL(5),
WASM_GET_LOCAL(6), WASM_GET_LOCAL(7), WASM_GET_LOCAL(8),
WASM_GET_LOCAL(9), kExprI32Add, kExprI32Add, kExprI32Add,
kExprI32Add, kExprI32Add, kExprI32Add, kExprI32Add, kExprI32Add,
kExprI32Add}))
// double test(int32_t i32, int64_t i64, float f32, double f64) {
// return i32 + i64 + f32 + f64;
// }
static const ValueType kMixedTypes5[5] = {kWasmF64, kWasmI32, kWasmI64,
kWasmF32, kWasmF64};
static FunctionSig d_ilfd(1, 4, kMixedTypes5);
DECLARE_EXPORTED_FUNCTION(
sum_mixed, &d_ilfd,
WASM_CODE({WASM_GET_LOCAL(2), kExprF64ConvertF32, WASM_GET_LOCAL(3),
kExprF64Add, WASM_GET_LOCAL(0), kExprF64UConvertI32, kExprF64Add,
WASM_GET_LOCAL(1), kExprF64UConvertI64, kExprF64Add}))
// float f32_square_deopt(float f32) {
// static int count = 0;
// if (++count == kDeoptLoopCount) {
// callback(f32);
// }
// return f32 * f32;
// }
DECLARE_EXPORTED_FUNCTION_WITH_LOCALS(
f32_square_deopt, sigs.f_f(), {kWasmI32},
WASM_CODE(
{WASM_STORE_MEM(
MachineType::Int32(), WASM_I32V(1024),
WASM_TEE_LOCAL(1, WASM_I32_ADD(WASM_LOAD_MEM(MachineType::Int32(),
WASM_I32V(1024)),
WASM_ONE))),
WASM_BLOCK(
WASM_BR_IF(0, WASM_I32_NE(WASM_GET_LOCAL(1),
WASM_I32V(kDeoptLoopCount))),
WASM_CALL_FUNCTION(0, WASM_F64_CONVERT_F32(WASM_GET_LOCAL(0)))),
WASM_F32_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))}))
// double f64_square_deopt(double f64) {
// static int count = 0;
// if (++count == kDeoptLoopCount) {
// callback(f64);
// }
// return f64 * f64;
// }
DECLARE_EXPORTED_FUNCTION_WITH_LOCALS(
f64_square_deopt, sigs.d_d(), {kWasmI32},
WASM_CODE(
{WASM_STORE_MEM(
MachineType::Int32(), WASM_I32V(1028),
WASM_TEE_LOCAL(1, WASM_I32_ADD(WASM_LOAD_MEM(MachineType::Int32(),
WASM_I32V(1028)),
WASM_ONE))),
WASM_BLOCK(WASM_BR_IF(0, WASM_I32_NE(WASM_GET_LOCAL(1),
WASM_I32V(kDeoptLoopCount))),
WASM_CALL_FUNCTION(0, WASM_GET_LOCAL(0))),
WASM_F64_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))}))
// int32_t i32_square_deopt(int32_t i32) {
// static int count = 0;
// if (++count == kDeoptLoopCount) {
// callback(i32);
// }
// return i32 * i32;
// }
DECLARE_EXPORTED_FUNCTION_WITH_LOCALS(
i32_square_deopt, sigs.i_i(), {kWasmI32},
WASM_CODE(
{WASM_STORE_MEM(
MachineType::Int32(), WASM_I32V(1032),
WASM_TEE_LOCAL(1, WASM_I32_ADD(WASM_LOAD_MEM(MachineType::Int32(),
WASM_I32V(1032)),
WASM_ONE))),
WASM_BLOCK(
WASM_BR_IF(0, WASM_I32_NE(WASM_GET_LOCAL(1),
WASM_I32V(kDeoptLoopCount))),
WASM_CALL_FUNCTION(0, WASM_F64_SCONVERT_I32(WASM_GET_LOCAL(0)))),
WASM_I32_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))}))
// int64_t i64_square_deopt(int64_t i64) {
// static int count = 0;
// if (++count == kDeoptLoopCount) {
// callback(i64);
// }
// return i64 * i64;
// }
DECLARE_EXPORTED_FUNCTION_WITH_LOCALS(
i64_square_deopt, sigs.l_l(), {kWasmI32},
WASM_CODE(
{WASM_STORE_MEM(
MachineType::Int32(), WASM_I32V(1036),
WASM_TEE_LOCAL(1, WASM_I32_ADD(WASM_LOAD_MEM(MachineType::Int32(),
WASM_I32V(1036)),
WASM_ONE))),
WASM_BLOCK(
WASM_BR_IF(0, WASM_I32_NE(WASM_GET_LOCAL(1),
WASM_I32V(kDeoptLoopCount))),
WASM_CALL_FUNCTION(0, WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(0)))),
WASM_I64_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))}))
// void void_square_deopt(int32_t i32) {
// static int count = 0;
// if (++count == kDeoptLoopCount) {
// callback(i32);
// }
// }
DECLARE_EXPORTED_FUNCTION_WITH_LOCALS(
void_square_deopt, sigs.v_i(), {kWasmI32},
WASM_CODE(
{WASM_STORE_MEM(
MachineType::Int32(), WASM_I32V(1040),
WASM_TEE_LOCAL(1, WASM_I32_ADD(WASM_LOAD_MEM(MachineType::Int32(),
WASM_I32V(1040)),
WASM_ONE))),
WASM_BLOCK(
WASM_BR_IF(0, WASM_I32_NE(WASM_GET_LOCAL(1),
WASM_I32V(kDeoptLoopCount))),
WASM_CALL_FUNCTION(0, WASM_F64_SCONVERT_I32(WASM_GET_LOCAL(0))))}))
class FastJSWasmCallTester {
public:
FastJSWasmCallTester()
: allow_natives_syntax_(&i::FLAG_allow_natives_syntax, true),
inline_js_wasm_calls_(&i::FLAG_turbo_inline_js_wasm_calls, true),
stress_background_compile_(&i::FLAG_stress_background_compile, false),
allocator_(),
zone_(&allocator_, ZONE_NAME),
builder_(zone_.New<WasmModuleBuilder>(&zone_)) {}
void DeclareCallback(const char* name, FunctionSig* signature,
const char* module) {
builder_->AddImport(CStrVector(name), signature, CStrVector(module));
}
void AddExportedFunction(const ExportedFunction& exported_func) {
WasmFunctionBuilder* func = builder_->AddFunction(exported_func.signature);
for (auto& wasm_type : exported_func.locals) func->AddLocal(wasm_type);
func->EmitCode(exported_func.code.data(),
static_cast<uint32_t>(exported_func.code.size()));
func->Emit(kExprEnd);
builder_->AddExport(CStrVector(exported_func.name.c_str()),
kExternalFunction, func->func_index());
}
// Executes a test function that returns a value of type T.
template <typename T>
void CallAndCheckWasmFunction(const std::string& exported_function_name,
const std::vector<v8::Local<v8::Value>>& args,
const T& expected_result,
bool test_lazy_deopt = false) {
LocalContext env;
v8::Local<v8::Value> result_value = DoCallAndCheckWasmFunction(
env, exported_function_name, args, test_lazy_deopt);
CHECK(CheckType<T>(result_value));
T result = ConvertJSValue<T>::Get(result_value, env.local()).ToChecked();
CHECK_EQ(result, expected_result);
}
// Executes a test function that returns NaN.
void CallAndCheckWasmFunctionNaN(
const std::string& exported_function_name,
const std::vector<v8::Local<v8::Value>>& args,
bool test_lazy_deopt = false) {
LocalContext env;
v8::Local<v8::Value> result_value = DoCallAndCheckWasmFunction(
env, exported_function_name, args, test_lazy_deopt);
CHECK(CheckType<double>(result_value));
double result =
ConvertJSValue<double>::Get(result_value, env.local()).ToChecked();
CHECK(std::isnan(result));
}
// Executes a test function that returns a BigInt.
void CallAndCheckWasmFunctionBigInt(
const std::string& exported_function_name,
const std::vector<v8::Local<v8::Value>>& args,
const v8::Local<v8::BigInt> expected_result,
bool test_lazy_deopt = false) {
LocalContext env;
v8::Local<v8::Value> result_value = DoCallAndCheckWasmFunction(
env, exported_function_name, args, test_lazy_deopt);
CHECK(CheckType<v8::Local<v8::BigInt>>(result_value));
auto result =
ConvertJSValue<v8::BigInt>::Get(result_value, env.local()).ToChecked();
CHECK_EQ(result->Int64Value(), expected_result->Int64Value());
}
// Executes a test function that returns void.
void CallAndCheckWasmFunction(const std::string& exported_function_name,
const std::vector<v8::Local<v8::Value>>& args,
bool test_lazy_deopt = false) {
LocalContext env;
v8::Local<v8::Value> result_value = DoCallAndCheckWasmFunction(
env, exported_function_name, args, test_lazy_deopt);
CHECK(test_lazy_deopt ? result_value->IsNumber() /* NaN */
: result_value->IsUndefined());
}
// Executes a test function that triggers eager deoptimization.
template <typename T>
T CallAndCheckWasmFunctionWithEagerDeopt(
const std::string& exported_function_name, const std::string& arg,
const T& expected_result, const std::string& deopt_arg) {
LocalContext env;
v8::Isolate* isolate = CcTest::isolate();
v8::TryCatch try_catch(isolate);
std::string js_code =
"const importObj = {"
" env: {"
" callback : function(num) {}"
" }"
"};"
"let buf = new Uint8Array(" +
WasmModuleAsJSArray() +
");"
"let module = new WebAssembly.Module(buf);"
"let instance = new WebAssembly.Instance(module, importObj);"
"function test(value) {"
" return instance.exports." +
exported_function_name +
"(value);"
"}"
"%PrepareFunctionForOptimization(test);"
"test(" +
arg +
");"
"%OptimizeFunctionOnNextCall(test);"
"test(" +
arg + ");";
v8::Local<v8::Value> result_value = CompileRun(js_code.c_str());
CHECK(CheckType<T>(result_value));
T result = ConvertJSValue<T>::Get(result_value, env.local()).ToChecked();
CHECK_EQ(result, expected_result);
std::string deopt_code = "test(" + deopt_arg + ");";
result_value = CompileRun(deopt_code.c_str());
CHECK(CheckType<T>(result_value));
return ConvertJSValue<T>::Get(result_value, env.local()).ToChecked();
}
// Executes a test function that throws an exception.
void CallAndCheckExceptionCaught(const std::string& exported_function_name,
const v8::Local<v8::Value> arg) {
LocalContext env;
CHECK((*env)->Global()->Set(env.local(), v8_str("arg"), arg).FromJust());
v8::Isolate* isolate = CcTest::isolate();
v8::TryCatch try_catch(isolate);
std::string js_code =
"const importObj = {"
" env: {"
" callback : function(num) {}"
" }"
"};"
"let buf = new Uint8Array(" +
WasmModuleAsJSArray() +
");"
"let module = new WebAssembly.Module(buf);"
"let instance = new WebAssembly.Instance(module, importObj);"
"let " +
exported_function_name + " = instance.exports." +
exported_function_name +
";"
"function test() {"
" return " +
exported_function_name +
"(arg);"
"}"
"%PrepareFunctionForOptimization(test);"
"test();";
CompileRun(js_code.c_str());
CHECK(try_catch.HasCaught());
try_catch.Reset();
CompileRun("%OptimizeFunctionOnNextCall(test); test();");
CHECK(try_catch.HasCaught());
}
// Executes a test function with a try/catch.
template <typename T>
void CallAndCheckWithTryCatch(const std::string& exported_function_name,
const v8::Local<v8::Value> arg) {
LocalContext env;
CHECK((*env)->Global()->Set(env.local(), v8_str("arg"), arg).FromJust());
std::string js_code =
"const importObj = {"
" env: {"
" callback : function(num) {}"
" }"
"};"
"let buf = new Uint8Array(" +
WasmModuleAsJSArray() +
");"
"let module = new WebAssembly.Module(buf);"
"let instance = new WebAssembly.Instance(module, importObj);"
"let " +
exported_function_name + " = instance.exports." +
exported_function_name +
";"
"function test() {"
" try {"
" return " +
exported_function_name +
"(arg);"
" } catch (e) {"
" return 0;"
" }"
"}"
"%PrepareFunctionForOptimization(test);"
"test();";
v8::Local<v8::Value> result_value_interpreted = CompileRun(js_code.c_str());
CHECK(CheckType<T>(result_value_interpreted));
T result_interpreted =
ConvertJSValue<T>::Get(result_value_interpreted, env.local())
.ToChecked();
v8::Local<v8::Value> result_value_compiled = CompileRun(
"%OptimizeFunctionOnNextCall(test);"
"test();");
CHECK(CheckType<T>(result_value_compiled));
T result_compiled =
ConvertJSValue<T>::Get(result_value_compiled, env.local()).ToChecked();
CHECK_EQ(result_interpreted, result_compiled);
}
private:
// Convert the code of a Wasm module into a string that represents the content
// of a JavaScript Uint8Array, that can be loaded with
// WebAssembly.Module(buf).
std::string WasmModuleAsJSArray() {
ZoneBuffer buffer(&zone_);
builder_->WriteTo(&buffer);
std::stringstream string_stream;
string_stream << "[";
auto it = buffer.begin();
if (it != buffer.end()) {
string_stream << "0x" << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<int>(*it++);
}
while (it != buffer.end()) {
string_stream << ", 0x" << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<int>(*it++);
}
string_stream << "]";
return string_stream.str();
}
v8::Local<v8::Value> DoCallAndCheckWasmFunction(
LocalContext& env, const std::string& exported_function_name,
const std::vector<v8::Local<v8::Value>>& args,
bool test_lazy_deopt = false) {
for (size_t i = 0; i < args.size(); i++) {
CHECK((*env)
->Global()
->Set(env.local(), v8_str(("arg" + std::to_string(i)).c_str()),
args[i])
.FromJust());
}
std::string js_code =
test_lazy_deopt
? GetJSTestCodeWithLazyDeopt(env, WasmModuleAsJSArray(),
exported_function_name, args.size())
: GetJSTestCode(WasmModuleAsJSArray(), exported_function_name,
args.size());
return CompileRun(js_code.c_str());
}
// Format the JS test code that loads and instantiates a Wasm module and
// calls a Wasm exported function, making sure that it is compiled by
// TurboFan:
//
// function test() {"
// let result = exported_func(arg0, arg1, ..., argN-1);
// return result;"
// }
std::string GetJSTestCode(const std::string& wasm_module,
const std::string& wasm_exported_function_name,
size_t arity) {
std::string js_args = ArgsToString(arity);
return "const importObj = {"
" env: { callback : function(num) {} }"
"};"
"let buf = new Uint8Array(" +
wasm_module +
");"
"let module = new WebAssembly.Module(buf);"
"let instance = new WebAssembly.Instance(module, importObj);"
"let " +
wasm_exported_function_name + " = instance.exports." +
wasm_exported_function_name +
";"
"function test() {"
" let result = " +
wasm_exported_function_name + "(" + js_args +
");"
" return result;"
"}"
"%PrepareFunctionForOptimization(test);"
"test(" +
js_args +
");"
"%OptimizeFunctionOnNextCall(test);"
"test(" +
js_args + ");";
}
// Format the JS test code that loads and instantiates a Wasm module and
// calls a Wasm exported function in a loop, and it's compiled with TurboFan:
//
// var b = 0;"
// var n = 0;"
// function test() {"
// let result = 0;
// for(var i = 0; i < 1e5; i++) {
// result = exported_func(arg0 + b) + n;
// }
// return result;"
// }
//
// Here the Wasm function calls back into a JavaScript function that modifies
// the values of 'b' and 'n', triggering the lazy deoptimization of the 'test'
// function.
std::string GetJSTestCodeWithLazyDeopt(
LocalContext& env, const std::string& wasm_module,
const std::string& wasm_exported_function_name, size_t arity) {
DCHECK_LE(arity, 1);
bool bigint_arg = false;
if (arity == 1) {
v8::Local<v8::Value> arg0 =
(*env)->Global()->Get(env.local(), v8_str("arg0")).ToLocalChecked();
bigint_arg = arg0->IsBigInt();
}
std::string js_args = ArgsToString(arity);
std::string code =
"const importObj = {"
" env: {"
" callback : function(num) {"
" n = 1; b = 1;"
" }"
" }"
"};"
"let buf = new Uint8Array(" +
wasm_module +
");"
"let module = new WebAssembly.Module(buf);"
"let instance = new WebAssembly.Instance(module, importObj);"
"let " +
wasm_exported_function_name + " = instance.exports." +
wasm_exported_function_name +
";"
"var b = 0;"
"var n = 0;"
"function test(" +
js_args +
") {"
" var result = 0;"
" for (let i = 0; i < " +
std::to_string(kDeoptLoopCount) + " + 5; i++) {";
code += bigint_arg ? " result = " + wasm_exported_function_name + "(" +
js_args + "+ BigInt(b)) + BigInt(n);"
: " result = " + wasm_exported_function_name + "(" +
js_args + "+ b) + n;";
code +=
" }"
" return result;"
"}"
"test(" +
js_args + ");";
return code;
}
// Format a string that represents the set of arguments passed to a test
// function, in the form 'arg0, arg1, ..., argN-1'.
// The value of these args is set by GetJSTestCodeWithLazyDeopt.
std::string ArgsToString(size_t arity) {
std::stringstream string_stream;
for (size_t i = 0; i < arity; i++) {
if (i > 0) string_stream << ", ";
string_stream << "arg" << i;
}
return string_stream.str();
}
i::FlagScope<bool> allow_natives_syntax_;
i::FlagScope<bool> inline_js_wasm_calls_;
i::FlagScope<bool> stress_background_compile_;
AccountingAllocator allocator_;
Zone zone_;
WasmModuleBuilder* builder_;
};
TEST(TestFastJSWasmCall_Nop) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_nop);
tester.CallAndCheckWasmFunction("nop", {});
}
TEST(TestFastJSWasmCall_I32Arg) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_i32_square);
tester.CallAndCheckWasmFunction<int32_t>("i32_square", {v8_num(42)}, 42 * 42);
}
TEST(TestFastJSWasmCall_I32ArgNotSmi) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_add);
tester.CallAndCheckWasmFunction<int32_t>(
"add", {v8_num(0x7fffffff), v8_int(1)}, 0x80000000);
}
TEST(TestFastJSWasmCall_F32Arg) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_f32_square);
tester.CallAndCheckWasmFunction<float>("f32_square", {v8_num(42.0)},
42.0 * 42.0);
}
TEST(TestFastJSWasmCall_F64Arg) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_f64_square);
tester.CallAndCheckWasmFunction<double>("f64_square", {v8_num(42.0)},
42.0 * 42.0);
}
TEST(TestFastJSWasmCall_I64Arg) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_i64_square);
tester.CallAndCheckWasmFunctionBigInt("i64_square", {v8_bigint(1234567890ll)},
v8_bigint(1234567890ll * 1234567890ll));
}
TEST(TestFastJSWasmCall_I64NegativeResult) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_i64_add);
tester.CallAndCheckWasmFunctionBigInt(
"i64_add", {v8_bigint(1ll), v8_bigint(-2ll)}, v8_bigint(-1ll));
}
TEST(TestFastJSWasmCall_MultipleArgs) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_sum10);
tester.CallAndCheckWasmFunction<int32_t>(
"sum10",
{v8_num(1), v8_num(2), v8_num(3), v8_num(4), v8_num(5), v8_num(6),
v8_num(7), v8_num(8), v8_num(9), v8_num(10)},
55);
}
TEST(TestFastJSWasmCall_MixedArgs) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_sum_mixed);
tester.CallAndCheckWasmFunction<double>(
"sum_mixed", {v8_num(1), v8_bigint(0x80000000), v8_num(42.0), v8_num(.5)},
1 + 0x80000000 + 42 + .5);
}
TEST(TestFastJSWasmCall_MistypedArgs) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_i32_square);
tester.CallAndCheckWasmFunction<int32_t>("i32_square", {v8_str("test")}, 0);
}
TEST(TestFastJSWasmCall_MixedMistypedArgs) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_sum_mixed);
tester.CallAndCheckWasmFunctionNaN(
"sum_mixed", {v8_str("alpha"), v8_bigint(0x80000000), v8_str("beta"),
v8_str("gamma")});
}
TEST(TestFastJSWasmCall_NoArgs) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_no_args);
tester.CallAndCheckWasmFunction<int32_t>("no_args", {}, 42);
}
TEST(TestFastJSWasmCall_NoReturnTypes) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_void_square);
tester.CallAndCheckWasmFunction("void_square", {v8_num(42)});
}
TEST(TestFastJSWasmCall_MismatchedArity) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_sum3);
tester.CallAndCheckWasmFunction<int32_t>("sum3", {v8_num(1), v8_num(2)}, 3);
tester.CallAndCheckWasmFunction<int32_t>(
"sum3",
{v8_num(1), v8_num(2), v8_num(3), v8_num(4), v8_num(5), v8_num(6)}, 6);
tester.CallAndCheckWasmFunction<int32_t>("sum3", {}, 0);
}
// Lazy deoptimization tests
TEST(TestFastJSWasmCall_LazyDeopt_I32Result) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.DeclareCallback("callback", sigs.v_d(), "env");
tester.AddExportedFunction(k_i32_square_deopt);
tester.CallAndCheckWasmFunction<int32_t>("i32_square_deopt", {v8_num(42)},
43 * 43 + 1, true);
}
TEST(TestFastJSWasmCall_LazyDeopt_I64Result) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.DeclareCallback("callback", sigs.v_d(), "env");
tester.AddExportedFunction(k_i64_square_deopt);
tester.CallAndCheckWasmFunctionBigInt("i64_square_deopt", {v8_bigint(42)},
v8_bigint(43 * 43 + 1), true);
// This test would fail if the result was converted into a HeapNumber through
// a double, losing precision.
tester.CallAndCheckWasmFunctionBigInt(
"i64_square_deopt", {v8_bigint(1234567890ll)},
v8_bigint(1524157877488187882ll), // (1234567890 + 1)*(1234567890 + 1)+1
true);
}
TEST(TestFastJSWasmCall_LazyDeopt_F32Result) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.DeclareCallback("callback", sigs.v_d(), "env");
tester.AddExportedFunction(k_f32_square_deopt);
tester.CallAndCheckWasmFunction<float>("f32_square_deopt", {v8_num(42.0)},
43 * 43 + 1, true);
}
TEST(TestFastJSWasmCall_LazyDeopt_F64Result) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.DeclareCallback("callback", sigs.v_d(), "env");
tester.AddExportedFunction(k_f64_square_deopt);
tester.CallAndCheckWasmFunction<float>("f64_square_deopt", {v8_num(42.0)},
43 * 43 + 1, true);
}
TEST(TestFastJSWasmCall_LazyDeopt_VoidResult) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.DeclareCallback("callback", sigs.v_d(), "env");
tester.AddExportedFunction(k_void_square_deopt);
tester.CallAndCheckWasmFunction("void_square_deopt", {v8_num(42.0)}, true);
}
// Eager deoptimization tests
TEST(TestFastJSWasmCall_EagerDeopt) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_f32_square);
float result_after_deopt =
tester.CallAndCheckWasmFunctionWithEagerDeopt<float>(
"f32_square", "42", 42.0 * 42.0, "{x:1,y:2}");
CHECK(std::isnan(result_after_deopt));
}
// Exception handling tests
TEST(TestFastJSWasmCall_Trap) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_load);
tester.CallAndCheckWithTryCatch<int>("load", {v8_int(0x7fffffff)});
}
TEST(TestFastJSWasmCall_I64ArgExpectsBigInt) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_i64_square);
tester.CallAndCheckExceptionCaught("i64_square", v8_int(42));
}
TEST(TestFastJSWasmCall_F32ArgDoesntExpectBigInt) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_f32_square);
tester.CallAndCheckExceptionCaught("f32_square", v8_bigint(42ll));
}
TEST(TestFastJSWasmCall_F64ArgDoesntExpectBigInt) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_f64_square);
tester.CallAndCheckExceptionCaught("f64_square", v8_bigint(42ll));
}
TEST(TestFastJSWasmCall_I32ArgDoesntExpectBigInt) {
v8::HandleScope scope(CcTest::isolate());
FastJSWasmCallTester tester;
tester.AddExportedFunction(k_i32_square);
tester.CallAndCheckExceptionCaught("i32_square", v8_bigint(42ll));
}
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -47,7 +47,6 @@ class TestSignatures {
sig_v_iii(0, 3, kIntTypes4),
sig_v_e(0, 1, kExternRefTypes4),
sig_v_c(0, 1, kFuncTypes4),
sig_v_d(0, 1, kDoubleTypes4),
sig_s_i(1, 1, kSimd128IntTypes4),
sig_s_s(1, 1, kSimd128Types4),
sig_s_ss(1, 2, kSimd128Types4),
@ -112,7 +111,6 @@ class TestSignatures {
FunctionSig* v_iii() { return &sig_v_iii; }
FunctionSig* v_e() { return &sig_v_e; }
FunctionSig* v_c() { return &sig_v_c; }
FunctionSig* v_d() { return &sig_v_d; }
FunctionSig* s_i() { return &sig_s_i; }
FunctionSig* s_s() { return &sig_s_s; }
FunctionSig* s_ss() { return &sig_s_ss; }
@ -180,7 +178,6 @@ class TestSignatures {
FunctionSig sig_v_iii;
FunctionSig sig_v_e;
FunctionSig sig_v_c;
FunctionSig sig_v_d;
FunctionSig sig_s_i;
FunctionSig sig_s_s;
FunctionSig sig_s_ss;