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:
parent
860fcb1bd2
commit
de50785ed5
1
BUILD.gn
1
BUILD.gn
@ -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",
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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, \
|
||||
|
@ -293,7 +293,7 @@ void TypeConversionNoContextDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
void SingleParameterOnStackDescriptor::InitializePlatformSpecific(
|
||||
void TypeConversionStackParameterDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
data->InitializePlatformSpecific(0, nullptr);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -196,8 +196,7 @@
|
||||
V(JSCall) \
|
||||
V(JSCallForwardVarargs) \
|
||||
V(JSCallWithArrayLike) \
|
||||
V(JSCallWithSpread) \
|
||||
V(JSWasmCall)
|
||||
V(JSCallWithSpread)
|
||||
|
||||
#define JS_CONSTRUCT_OP_LIST(V) \
|
||||
V(JSConstructForwardVarargs) \
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
// -----------------------
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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_;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
##############################################################################
|
||||
|
@ -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,
|
||||
|
@ -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_
|
||||
|
@ -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
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user