Commit 12c009de authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] 32-bit support WebAssembly's i64<>JavaScript's BigInt conversions

This CL was reviewed originally in https://crrev.com/c/1518181.

Bug: v8:7741
Change-Id: Iddb139a24c4b9aee6694e20cb5d04e9f9887160c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1752859
Auto-Submit: Sven Sauleau <sven@cloudflare.com>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63321}
parent 90cdb053
......@@ -17,6 +17,24 @@ TF_BUILTIN(BigIntToI64, CodeStubAssembler) {
return;
}
TNode<Object> value = CAST(Parameter(Descriptor::kArgument));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<BigInt> n = ToBigInt(context, value);
TVARIABLE(UintPtrT, var_low);
TVARIABLE(UintPtrT, var_high);
BigIntToRawBytes(n, &var_low, &var_high);
ReturnRaw(var_low.value());
}
// https://tc39.github.io/proposal-bigint/#sec-to-big-int64
TF_BUILTIN(BigIntToI32Pair, CodeStubAssembler) {
if (!Is32()) {
Unreachable();
return;
}
TNode<Object> value = CAST(Parameter(Descriptor::kArgument));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<BigInt> bigint = ToBigInt(context, value);
......@@ -24,10 +42,9 @@ TF_BUILTIN(BigIntToI64, CodeStubAssembler) {
TVARIABLE(UintPtrT, var_low);
TVARIABLE(UintPtrT, var_high);
// 2. Let int64bit be n modulo 2^64.
// 3. If int64bit ≥ 2^63, return int64bit - 2^64;
BigIntToRawBytes(bigint, &var_low, &var_high);
ReturnRaw(var_low.value());
Return(SloppyTNode<Object>(var_low.value()),
SloppyTNode<Object>(var_high.value()));
}
// https://tc39.github.io/proposal-bigint/#sec-bigint-constructor-number-value
......@@ -43,5 +60,18 @@ TF_BUILTIN(I64ToBigInt, CodeStubAssembler) {
Return(BigIntFromInt64(argument));
}
// https://tc39.github.io/proposal-bigint/#sec-bigint-constructor-number-value
TF_BUILTIN(I32PairToBigInt, CodeStubAssembler) {
if (!Is32()) {
Unreachable();
return;
}
TNode<IntPtrT> low = UncheckedCast<IntPtrT>(Parameter(Descriptor::kLow));
TNode<IntPtrT> high = UncheckedCast<IntPtrT>(Parameter(Descriptor::kHigh));
Return(BigIntFromInt32Pair(low, high));
}
} // namespace internal
} // namespace v8
......@@ -207,7 +207,9 @@ namespace internal {
TFC(Typeof, Typeof) \
TFC(GetSuperConstructor, Typeof) \
TFC(BigIntToI64, BigIntToI64) \
TFC(BigIntToI32Pair, BigIntToI32Pair) \
TFC(I64ToBigInt, I64ToBigInt) \
TFC(I32PairToBigInt, I32PairToBigInt) \
\
/* Type conversions continuations */ \
TFC(ToBooleanLazyDeoptContinuation, TypeConversionStackParameter) \
......@@ -1043,7 +1045,9 @@ namespace internal {
TFS(ThrowWasmTrapElemSegmentDropped) \
TFS(ThrowWasmTrapTableOutOfBounds) \
TFC(WasmI64ToBigInt, I64ToBigInt) \
TFC(WasmI32PairToBigInt, I32PairToBigInt) \
TFC(WasmBigIntToI64, BigIntToI64) \
TFC(WasmBigIntToI32Pair, BigIntToI32Pair) \
\
/* WeakMap */ \
TFJ(WeakMapConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
......@@ -1347,7 +1351,9 @@ namespace internal {
V(WasmRethrow) \
V(DoubleToI) \
V(WasmI64ToBigInt) \
V(WasmBigIntToI64)
V(WasmI32PairToBigInt) \
V(WasmBigIntToI64) \
V(WasmBigIntToI32Pair)
// The exception thrown in the following builtins are caught internally and will
// not be propagated further or re-thrown
......
......@@ -4,6 +4,7 @@
#include "src/builtins/builtins-utils-gen.h"
#include "src/codegen/code-stub-assembler.h"
#include "src/codegen/interface-descriptors.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes.h"
......@@ -297,6 +298,20 @@ TF_BUILTIN(WasmI64ToBigInt, WasmBuiltinsAssembler) {
TailCallStub(I64ToBigIntDescriptor(), target, NoContextConstant(), argument);
}
TF_BUILTIN(WasmI32PairToBigInt, WasmBuiltinsAssembler) {
if (!Is32()) {
Unreachable();
return;
}
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kI32PairToBigInt);
TNode<IntPtrT> low = UncheckedCast<IntPtrT>(Parameter(Descriptor::kLow));
TNode<IntPtrT> high = UncheckedCast<IntPtrT>(Parameter(Descriptor::kHigh));
TailCallStub(I32PairToBigIntDescriptor(), target, NoContextConstant(), low,
high);
}
TF_BUILTIN(WasmBigIntToI64, WasmBuiltinsAssembler) {
if (!Is64()) {
Unreachable();
......@@ -312,6 +327,21 @@ TF_BUILTIN(WasmBigIntToI64, WasmBuiltinsAssembler) {
TailCallStub(BigIntToI64Descriptor(), target, context, argument);
}
TF_BUILTIN(WasmBigIntToI32Pair, WasmBuiltinsAssembler) {
if (!Is32()) {
Unreachable();
return;
}
TNode<Object> context =
UncheckedCast<Object>(Parameter(Descriptor::kContext));
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kBigIntToI32Pair);
TNode<IntPtrT> argument =
UncheckedCast<IntPtrT>(Parameter(Descriptor::kArgument));
TailCallStub(BigIntToI32PairDescriptor(), target, context, argument);
}
#define DECLARE_ENUM(name) \
TF_BUILTIN(ThrowWasm##name, WasmBuiltinsAssembler) { \
TNode<Object> instance = LoadInstanceFromFrame(); \
......
......@@ -416,10 +416,20 @@ void I64ToBigIntDescriptor::InitializePlatformSpecific(
DefaultInitializePlatformSpecific(data, kParameterCount);
}
void I32PairToBigIntDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, kParameterCount);
}
void BigIntToI64Descriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, kParameterCount);
}
void BigIntToI32PairDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, kParameterCount);
}
} // namespace internal
} // namespace v8
......@@ -28,7 +28,9 @@ namespace internal {
V(ArraySingleArgumentConstructor) \
V(AsyncFunctionStackParameter) \
V(BigIntToI64) \
V(BigIntToI32Pair) \
V(I64ToBigInt) \
V(I32PairToBigInt) \
V(BinaryOp) \
V(CallForwardVarargs) \
V(CallFunctionTemplate) \
......@@ -1207,14 +1209,26 @@ class WasmThrowDescriptor final : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(WasmThrowDescriptor, CallInterfaceDescriptor)
};
class I64ToBigIntDescriptor final : public CallInterfaceDescriptor {
class V8_EXPORT_PRIVATE I64ToBigIntDescriptor final
: public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kArgument)
DEFINE_PARAMETER_TYPES(MachineType::Int64()) // kArgument
DECLARE_DESCRIPTOR(I64ToBigIntDescriptor, CallInterfaceDescriptor)
};
class BigIntToI64Descriptor final : public CallInterfaceDescriptor {
// 32 bits version of the I64ToBigIntDescriptor call interface descriptor
class V8_EXPORT_PRIVATE I32PairToBigIntDescriptor final
: public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kLow, kHigh)
DEFINE_PARAMETER_TYPES(MachineType::Uint32(), // kLow
MachineType::Uint32()) // kHigh
DECLARE_DESCRIPTOR(I32PairToBigIntDescriptor, CallInterfaceDescriptor)
};
class V8_EXPORT_PRIVATE BigIntToI64Descriptor final
: public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kArgument)
DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Int64(), // result 1
......@@ -1222,6 +1236,16 @@ class BigIntToI64Descriptor final : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(BigIntToI64Descriptor, CallInterfaceDescriptor)
};
class V8_EXPORT_PRIVATE BigIntToI32PairDescriptor final
: public CallInterfaceDescriptor {
public:
DEFINE_RESULT_AND_PARAMETERS(2, kArgument)
DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Uint32(), // result 1
MachineType::Uint32(), // result 2
MachineType::AnyTagged()) // kArgument
DECLARE_DESCRIPTOR(BigIntToI32PairDescriptor, CallInterfaceDescriptor)
};
class WasmAtomicNotifyDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kAddress, kCount)
......
......@@ -188,6 +188,7 @@ Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state,
}
bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
bool CodeAssembler::Is32() const { return raw_assembler()->machine()->Is32(); }
bool CodeAssembler::IsFloat64RoundUpSupported() const {
return raw_assembler()->machine()->Float64RoundUp().IsSupported();
......
......@@ -688,6 +688,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
const AssemblerOptions& options);
bool Is64() const;
bool Is32() const;
bool IsFloat64RoundUpSupported() const;
bool IsFloat64RoundDownSupported() const;
bool IsFloat64RoundTiesEvenSupported() const;
......
......@@ -21,9 +21,11 @@ namespace v8 {
namespace internal {
namespace compiler {
Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common, Zone* zone,
Signature<MachineRepresentation>* signature)
Int64Lowering::Int64Lowering(
Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common, Zone* zone,
Signature<MachineRepresentation>* signature,
std::unique_ptr<Int64LoweringSpecialCase> special_case)
: zone_(zone),
graph_(graph),
machine_(machine),
......@@ -32,8 +34,9 @@ Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
stack_(zone),
replacements_(nullptr),
signature_(signature),
placeholder_(graph->NewNode(common->Parameter(-2, "placeholder"),
graph->start())) {
placeholder_(
graph->NewNode(common->Parameter(-2, "placeholder"), graph->start())),
special_case_(std::move(special_case)) {
DCHECK_NOT_NULL(graph);
DCHECK_NOT_NULL(graph->end());
replacements_ = zone->NewArray<Replacement>(graph->NodeCount());
......@@ -77,7 +80,7 @@ void Int64Lowering::LowerGraph() {
namespace {
int GetReturnIndexAfterLowering(CallDescriptor* call_descriptor,
int GetReturnIndexAfterLowering(const CallDescriptor* call_descriptor,
int old_index) {
int result = old_index;
for (int i = 0; i < old_index; i++) {
......@@ -89,7 +92,7 @@ int GetReturnIndexAfterLowering(CallDescriptor* call_descriptor,
return result;
}
int GetReturnCountAfterLowering(CallDescriptor* call_descriptor) {
int GetReturnCountAfterLowering(const CallDescriptor* call_descriptor) {
return GetReturnIndexAfterLowering(
call_descriptor, static_cast<int>(call_descriptor->ReturnCount()));
}
......@@ -336,21 +339,21 @@ void Int64Lowering::LowerNode(Node* node) {
if (DefaultLowering(node) || returns_require_lowering) {
// Tail calls do not have return values, so adjusting the call
// descriptor is enough.
auto new_descriptor = GetI32WasmCallDescriptor(zone(), call_descriptor);
NodeProperties::ChangeOp(node, common()->TailCall(new_descriptor));
NodeProperties::ChangeOp(
node, common()->TailCall(LowerCallDescriptor(call_descriptor)));
}
break;
}
case IrOpcode::kCall: {
auto call_descriptor =
const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
auto call_descriptor = CallDescriptorOf(node->op());
bool returns_require_lowering =
GetReturnCountAfterLowering(call_descriptor) !=
static_cast<int>(call_descriptor->ReturnCount());
if (DefaultLowering(node) || returns_require_lowering) {
// We have to adjust the call descriptor.
NodeProperties::ChangeOp(node, common()->Call(GetI32WasmCallDescriptor(
zone(), call_descriptor)));
NodeProperties::ChangeOp(
node, common()->Call(LowerCallDescriptor(call_descriptor)));
}
if (returns_require_lowering) {
size_t return_arity = call_descriptor->ReturnCount();
......@@ -994,6 +997,19 @@ bool Int64Lowering::DefaultLowering(Node* node, bool low_word_only) {
return something_changed;
}
CallDescriptor* Int64Lowering::LowerCallDescriptor(
const CallDescriptor* call_descriptor) {
if (special_case_) {
if (call_descriptor == special_case_->bigint_to_i64_call_descriptor) {
return special_case_->bigint_to_i32_pair_call_descriptor;
}
if (call_descriptor == special_case_->i64_to_bigint_call_descriptor) {
return special_case_->i32_pair_to_bigint_call_descriptor;
}
}
return GetI32WasmCallDescriptor(zone(), call_descriptor);
}
void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
// if new_low == nullptr, then also new_high == nullptr.
DCHECK(new_low != nullptr || new_high == nullptr);
......
......@@ -20,11 +20,30 @@ class Signature;
namespace compiler {
// Struct for CallDescriptors that need special lowering.
struct V8_EXPORT_PRIVATE Int64LoweringSpecialCase {
Int64LoweringSpecialCase()
: bigint_to_i64_call_descriptor(nullptr),
i64_to_bigint_call_descriptor(nullptr),
bigint_to_i32_pair_call_descriptor(nullptr),
i32_pair_to_bigint_call_descriptor(nullptr) {}
// CallDescriptors that need special lowering.
CallDescriptor* bigint_to_i64_call_descriptor;
CallDescriptor* i64_to_bigint_call_descriptor;
// The replacement CallDescriptors.
CallDescriptor* bigint_to_i32_pair_call_descriptor;
CallDescriptor* i32_pair_to_bigint_call_descriptor;
};
class V8_EXPORT_PRIVATE Int64Lowering {
public:
Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common, Zone* zone,
Signature<MachineRepresentation>* signature);
Int64Lowering(
Graph* graph, MachineOperatorBuilder* machine,
CommonOperatorBuilder* common, Zone* zone,
Signature<MachineRepresentation>* signature,
std::unique_ptr<Int64LoweringSpecialCase> special_case = nullptr);
void LowerGraph();
......@@ -53,6 +72,8 @@ class V8_EXPORT_PRIVATE Int64Lowering {
void LowerWord64AtomicBinop(Node* node, const Operator* op);
void LowerWord64AtomicNarrowOp(Node* node, const Operator* op);
CallDescriptor* LowerCallDescriptor(const CallDescriptor* call_descriptor);
void ReplaceNode(Node* old, Node* new_low, Node* new_high);
bool HasReplacementLow(Node* node);
Node* GetReplacementLow(Node* node);
......@@ -77,6 +98,7 @@ class V8_EXPORT_PRIVATE Int64Lowering {
Replacement* replacements_;
Signature<MachineRepresentation>* signature_;
Node* placeholder_;
std::unique_ptr<Int64LoweringSpecialCase> special_case_;
};
} // namespace compiler
......
......@@ -3946,7 +3946,7 @@ Graph* WasmGraphBuilder::graph() { return mcgraph()->graph(); }
namespace {
Signature<MachineRepresentation>* CreateMachineSignature(
Zone* zone, wasm::FunctionSig* sig) {
Zone* zone, wasm::FunctionSig* sig, WasmGraphBuilder::CallOrigin origin) {
Signature<MachineRepresentation>::Builder builder(zone, sig->return_count(),
sig->parameter_count());
for (auto ret : sig->returns()) {
......@@ -3954,22 +3954,31 @@ Signature<MachineRepresentation>* CreateMachineSignature(
}
for (auto param : sig->parameters()) {
builder.AddParam(wasm::ValueTypes::MachineRepresentationFor(param));
if (origin == WasmGraphBuilder::kCalledFromWasm) {
builder.AddParam(wasm::ValueTypes::MachineRepresentationFor(param));
} else {
// Parameters coming from JavaScript are always tagged values. Especially
// when the signature says that it's an I64 value, then a BigInt object is
// provided by JavaScript, and not two 32-bit parameters.
builder.AddParam(MachineRepresentation::kTagged);
}
}
return builder.Build();
}
} // namespace
void WasmGraphBuilder::LowerInt64() {
void WasmGraphBuilder::LowerInt64(CallOrigin origin) {
if (mcgraph()->machine()->Is64()) return;
Int64Lowering r(mcgraph()->graph(), mcgraph()->machine(), mcgraph()->common(),
mcgraph()->zone(),
CreateMachineSignature(mcgraph()->zone(), sig_));
CreateMachineSignature(mcgraph()->zone(), sig_, origin),
std::move(lowering_special_case_));
r.LowerGraph();
}
void WasmGraphBuilder::SimdScalarLoweringForTesting() {
SimdScalarLowering(mcgraph(), CreateMachineSignature(mcgraph()->zone(), sig_))
SimdScalarLowering(mcgraph(), CreateMachineSignature(mcgraph()->zone(), sig_,
kCalledFromWasm))
.LowerGraph();
}
......@@ -5046,6 +5055,78 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
stub_mode_(stub_mode),
enabled_features_(features) {}
CallDescriptor* GetI32PairToBigIntCallDescriptor() {
I32PairToBigIntDescriptor interface_descriptor;
return Linkage::GetStubCallDescriptor(
mcgraph()->zone(), // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode_); // stub call mode
}
CallDescriptor* GetI64ToBigIntCallDescriptor() {
if (!lowering_special_case_) {
lowering_special_case_ = base::make_unique<Int64LoweringSpecialCase>();
}
if (lowering_special_case_->i64_to_bigint_call_descriptor) {
return lowering_special_case_->i64_to_bigint_call_descriptor;
}
I64ToBigIntDescriptor interface_descriptor;
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode_); // stub call mode
lowering_special_case_->i64_to_bigint_call_descriptor = call_descriptor;
lowering_special_case_->i32_pair_to_bigint_call_descriptor =
GetI32PairToBigIntCallDescriptor();
return call_descriptor;
}
CallDescriptor* GetBigIntToI32PairCallDescriptor() {
BigIntToI32PairDescriptor interface_descriptor;
return Linkage::GetStubCallDescriptor(
mcgraph()->zone(), // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode_); // stub call mode
}
CallDescriptor* GetBigIntToI64CallDescriptor() {
if (!lowering_special_case_) {
lowering_special_case_ = base::make_unique<Int64LoweringSpecialCase>();
}
if (lowering_special_case_->bigint_to_i64_call_descriptor) {
return lowering_special_case_->bigint_to_i64_call_descriptor;
}
BigIntToI64Descriptor interface_descriptor;
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode_); // stub call mode
lowering_special_case_->bigint_to_i64_call_descriptor = call_descriptor;
lowering_special_case_->bigint_to_i32_pair_call_descriptor =
GetBigIntToI32PairCallDescriptor();
return call_descriptor;
}
Node* BuildAllocateHeapNumberWithValue(Node* value, Node* control) {
MachineOperatorBuilder* machine = mcgraph()->machine();
CommonOperatorBuilder* common = mcgraph()->common();
......@@ -5343,47 +5424,59 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
}
Node* BuildChangeInt64ToBigInt(Node* input) {
I64ToBigIntDescriptor interface_descriptor;
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode_); // stub call mode
Node* target =
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmI64ToBigInt, RelocInfo::WASM_STUB_CALL)
: BuildLoadBuiltinFromIsolateRoot(Builtins::kI64ToBigInt);
const Operator* call =
mcgraph()->common()->Call(GetI64ToBigIntCallDescriptor());
Node* target;
if (mcgraph()->machine()->Is64()) {
target =
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmI64ToBigInt, RelocInfo::WASM_STUB_CALL)
: BuildLoadBuiltinFromIsolateRoot(Builtins::kI64ToBigInt);
} else {
DCHECK(mcgraph()->machine()->Is32());
// On 32-bit platforms we already set the target to the
// I32PairToBigInt builtin here, so that we don't have to replace the
// target in the int64-lowering.
target =
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmI32PairToBigInt,
RelocInfo::WASM_STUB_CALL)
: BuildLoadBuiltinFromIsolateRoot(Builtins::kI32PairToBigInt);
}
return SetEffect(
SetControl(graph()->NewNode(mcgraph()->common()->Call(call_descriptor),
target, input, Effect(), Control())));
SetControl(graph()->NewNode(call, target, input, Effect(), Control())));
}
Node* BuildChangeBigIntToInt64(Node* input, Node* context) {
BigIntToI64Descriptor interface_descriptor;
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
stub_mode_); // stub call mode
Node* target =
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmBigIntToI64, RelocInfo::WASM_STUB_CALL)
: BuildLoadBuiltinFromIsolateRoot(Builtins::kBigIntToI64);
const Operator* call =
mcgraph()->common()->Call(GetBigIntToI64CallDescriptor());
Node* target;
if (mcgraph()->machine()->Is64()) {
target =
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmBigIntToI64, RelocInfo::WASM_STUB_CALL)
: BuildLoadBuiltinFromIsolateRoot(Builtins::kBigIntToI64);
} else {
DCHECK(mcgraph()->machine()->Is32());
// On 32-bit platforms we already set the target to the
// BigIntToI32Pair builtin here, so that we don't have to replace the
// target in the int64-lowering.
target =
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmBigIntToI32Pair,
RelocInfo::WASM_STUB_CALL)
: BuildLoadBuiltinFromIsolateRoot(Builtins::kBigIntToI32Pair);
}
return SetEffect(SetControl(
graph()->NewNode(mcgraph()->common()->Call(call_descriptor), target,
input, context, Effect(), Control())));
graph()->NewNode(call, target, input, context, Effect(), Control())));
}
Node* FromJS(Node* node, Node* js_context, wasm::ValueType type) {
......@@ -5621,6 +5714,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
effect_, Control());
}
Return(jsval);
if (ContainsInt64(sig_)) LowerInt64(kCalledFromJS);
}
bool BuildWasmImportCallWrapper(WasmImportCallKind kind) {
......@@ -5811,6 +5905,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
BuildModifyThreadInWasmFlag(true);
Return(val);
if (ContainsInt64(sig_)) LowerInt64(kCalledFromWasm);
return true;
}
......@@ -5915,7 +6011,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Return(returns);
}
if (ContainsInt64(sig_)) LowerInt64();
if (ContainsInt64(sig_)) LowerInt64(kCalledFromWasm);
}
void BuildWasmInterpreterEntry(int func_index) {
......@@ -5987,7 +6083,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Return(returns);
}
if (ContainsInt64(sig_)) LowerInt64();
if (ContainsInt64(sig_)) LowerInt64(kCalledFromWasm);
}
void BuildJSToJSWrapper(Isolate* isolate) {
......@@ -6134,6 +6230,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Return(mcgraph()->IntPtrConstant(0));
if (mcgraph()->machine()->Is32() && ContainsInt64(sig_)) {
// No special lowering should be requested in the C entry.
DCHECK_NULL(lowering_special_case_);
MachineRepresentation sig_reps[] = {
MachineType::PointerRepresentation(), // return value
MachineType::PointerRepresentation(), // target
......@@ -6723,12 +6822,13 @@ bool BuildGraphForWasmFunction(AccountingAllocator* allocator,
return false;
}
builder.LowerInt64();
builder.LowerInt64(WasmWrapperGraphBuilder::kCalledFromWasm);
if (builder.has_simd() &&
(!CpuFeatures::SupportsWasmSimd128() || env->lower_simd)) {
SimdScalarLowering(mcgraph,
CreateMachineSignature(mcgraph->zone(), func_body.sig))
SimdScalarLowering(
mcgraph, CreateMachineSignature(mcgraph->zone(), func_body.sig,
WasmGraphBuilder::kCalledFromWasm))
.LowerGraph();
}
......@@ -6968,7 +7068,7 @@ CallDescriptor* GetWasmCallDescriptor(
namespace {
CallDescriptor* ReplaceTypeInCallDescriptorWith(
Zone* zone, CallDescriptor* call_descriptor, size_t num_replacements,
Zone* zone, const CallDescriptor* call_descriptor, size_t num_replacements,
MachineType input_type, MachineRepresentation output_type) {
size_t parameter_count = call_descriptor->ParameterCount();
size_t return_count = call_descriptor->ReturnCount();
......@@ -6984,7 +7084,7 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
}
if (parameter_count == call_descriptor->ParameterCount() &&
return_count == call_descriptor->ReturnCount()) {
return call_descriptor;
return const_cast<CallDescriptor*>(call_descriptor);
}
LocationSignature::Builder locations(zone, return_count, parameter_count);
......@@ -7032,8 +7132,8 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
}
} // namespace
CallDescriptor* GetI32WasmCallDescriptor(Zone* zone,
CallDescriptor* call_descriptor) {
CallDescriptor* GetI32WasmCallDescriptor(
Zone* zone, const CallDescriptor* call_descriptor) {
return ReplaceTypeInCallDescriptorWith(zone, call_descriptor, 2,
MachineType::Int64(),
MachineRepresentation::kWord32);
......
......@@ -34,6 +34,7 @@ class Operator;
class SourcePositionTable;
class WasmDecorator;
enum class TrapId : uint32_t;
struct Int64LoweringSpecialCase;
} // namespace compiler
namespace wasm {
......@@ -362,7 +363,9 @@ class WasmGraphBuilder {
wasm::FunctionSig* GetFunctionSignature() { return sig_; }
V8_EXPORT_PRIVATE void LowerInt64();
enum CallOrigin : bool { kCalledFromWasm, kCalledFromJS };
V8_EXPORT_PRIVATE void LowerInt64(CallOrigin origin);
V8_EXPORT_PRIVATE void SimdScalarLoweringForTesting();
......@@ -454,6 +457,8 @@ class WasmGraphBuilder {
compiler::SourcePositionTable* const source_position_table_ = nullptr;
std::unique_ptr<Int64LoweringSpecialCase> lowering_special_case_;
Node* NoContextConstant();
Node* BuildLoadIsolateRoot();
......@@ -626,7 +631,7 @@ V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
WasmCallKind kind = kWasmFunction);
V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor(
Zone* zone, CallDescriptor* call_descriptor);
Zone* zone, const CallDescriptor* call_descriptor);
V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptorForSimd(
Zone* zone, CallDescriptor* call_descriptor);
......
......@@ -365,7 +365,7 @@ void TestBuildingGraphWithBuilder(compiler::WasmGraphBuilder* builder,
FATAL("Verification failed; pc = +%x, msg = %s", result.error().offset(),
result.error().message().c_str());
}
builder->LowerInt64();
builder->LowerInt64(compiler::WasmGraphBuilder::kCalledFromWasm);
if (!CpuFeatures::SupportsWasmSimd128()) {
builder->SimdScalarLoweringForTesting();
}
......
......@@ -1082,7 +1082,6 @@
['arch in [arm, android_arm, android_ia32, ia32, ppc, s390, s390x, mipsel, mips]', {
# TODO(ssauleau): implement BigInt<>Wasm conversion for other arch -
# crbug.com/v8/7741
'wasm/bigint': [SKIP],
'wasm/bigint-i64-to-imported-js-func': [SKIP],
}], # arch in [arm, android_arm, android_ia32, ia32, ppc, s390, s390x, mipsel, mips]
......
......@@ -7,7 +7,7 @@
load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestWasmI64ToJSBigInt() {
var builder = new WasmModuleBuilder();
let builder = new WasmModuleBuilder();
builder
.addFunction("fn", kSig_l_v) // () -> i64
......@@ -16,22 +16,22 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
])
.exportFunc();
var module = builder.instantiate();
let module = builder.instantiate();
assertEquals(typeof module.exports.fn(), "bigint");
assertEquals(module.exports.fn(), 3n);
})();
(function TestJSBigIntToWasmI64Global() {
var builder = new WasmModuleBuilder();
let builder = new WasmModuleBuilder();
var a_global_index = builder
let a_global_index = builder
.addImportedGlobal("mod", "a", kWasmI64)
var b_global_index = builder
let b_global_index = builder
.addImportedGlobal("mod", "b", kWasmI64);
var c_global_index = builder
let c_global_index = builder
.addImportedGlobal("mod", "c", kWasmI64);
builder
......@@ -39,7 +39,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
.addExportOfKind('b', kExternalGlobal, b_global_index)
.addExportOfKind('c', kExternalGlobal, c_global_index);
var module = builder.instantiate({
let module = builder.instantiate({
mod: {
a: 1n,
b: 2n ** 63n,
......@@ -53,16 +53,16 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestJSBigIntToWasmI64MutableGlobal() {
var builder = new WasmModuleBuilder();
let builder = new WasmModuleBuilder();
var a_global_index = builder
let a_global_index = builder
.addImportedGlobal("mod", "a", kWasmI64, /* mutable = */ true)
builder
.addExportOfKind('a', kExternalGlobal, a_global_index);
// as non object
var fn = () => builder.instantiate({
let fn = () => builder.instantiate({
mod: {
a: 1n,
}
......@@ -71,7 +71,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertThrows(fn, WebAssembly.LinkError);
// as WebAssembly.Global object
var module = builder.instantiate({
let module = builder.instantiate({
mod: {
a: new WebAssembly.Global({ value: "i64", mutable: true }, 1n),
}
......@@ -81,20 +81,19 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestJSBigIntToWasmI64Identity() {
var builder = new WasmModuleBuilder();
let builder = new WasmModuleBuilder();
builder
.addFunction("f", kSig_l_l) // i64 -> i64
.addBody([
kExprGetLocal, 0x0,
kExprGetLocal, 0,
])
.exportFunc();
var module = builder.instantiate();
var f = module.exports.f;
let module = builder.instantiate();
let f = module.exports.f;
assertEquals(f(0n), 0n);
assertEquals(f(-0n), -0n);
assertEquals(f(123n), 123n);
assertEquals(f(-123n), -123n);
......@@ -103,9 +102,31 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertThrows(() => f(5), TypeError);
})();
(function TestJSBigIntToWasmI64Projection() {
let builder = new WasmModuleBuilder();
builder
.addFunction("f", kSig_l_ll) // i64 -> i64
.addBody([
kExprGetLocal, 1,
])
.exportFunc();
let module = builder.instantiate();
let f = module.exports.f;
assertEquals(f(1n, 0n), 0n);
assertEquals(f(1n, 123n), 123n);
assertEquals(f(1n, -123n), -123n);
assertEquals(f(1n, "5"), 5n);
assertThrows(() => f(1n, 5), TypeError);
})();
(function TestI64Global() {
var argument = { "value": "i64", "mutable": true };
var global = new WebAssembly.Global(argument);
let argument = { "value": "i64", "mutable": true };
let global = new WebAssembly.Global(argument);
assertEquals(global.value, 0n); // initial value
......@@ -117,10 +138,10 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestI64GlobalValueOf() {
var argument = { "value": "i64" };
let argument = { "value": "i64" };
// as literal
var global = new WebAssembly.Global(argument, {
let global = new WebAssembly.Global(argument, {
valueOf() {
return 123n;
}
......@@ -128,7 +149,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(global.value, 123n);
// as string
var global2 = new WebAssembly.Global(argument, {
let global2 = new WebAssembly.Global(argument, {
valueOf() {
return "321";
}
......@@ -137,7 +158,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestInvalidValtypeGlobalErrorMessage() {
var argument = { "value": "some string" };
let argument = { "value": "some string" };
assertThrows(() => new WebAssembly.Global(argument), TypeError);
try {
......@@ -149,26 +170,26 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestGlobalI64ValueWrongType() {
var argument = { "value": "i64" };
let argument = { "value": "i64" };
assertThrows(() => new WebAssembly.Global(argument, 666), TypeError);
})();
(function TestGlobalI64SetWrongType() {
var argument = { "value": "i64", "mutable": true };
var global = new WebAssembly.Global(argument);
let argument = { "value": "i64", "mutable": true };
let global = new WebAssembly.Global(argument);
assertThrows(() => global.value = 1, TypeError);
})();
(function TestFuncParamF64PassingBigInt() {
var builder = new WasmModuleBuilder();
let builder = new WasmModuleBuilder();
builder
.addFunction("f", kSig_v_d) // f64 -> ()
.addBody([])
.exportFunc();
var module = builder.instantiate();
let module = builder.instantiate();
assertThrows(() => module.exports.f(123n), TypeError);
})();
......@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "src/compiler/int64-lowering.h"
#include "src/codegen/interface-descriptors.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/signature.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/linkage.h"
......@@ -10,7 +13,6 @@
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/wasm-compiler.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/value-type.h"
#include "src/wasm/wasm-module.h"
#include "test/unittests/compiler/graph-unittest.h"
......@@ -48,6 +50,25 @@ class Int64LoweringTest : public GraphTest {
lowering.LowerGraph();
}
void LowerGraphWithSpecialCase(
Node* node, std::unique_ptr<Int64LoweringSpecialCase> special_case,
MachineRepresentation rep) {
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret = graph()->NewNode(common()->Return(), zero, node,
graph()->start(), graph()->start());
NodeProperties::MergeControlToEnd(graph(), common(), ret);
// Create a signature for the outer wasm<>js call; for these tests we focus
// on lowering the special cases rather than the wrapper node at the
// JavaScript boundaries.
Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 0);
sig_builder.AddReturn(rep);
Int64Lowering lowering(graph(), machine(), common(), zone(),
sig_builder.Build(), std::move(special_case));
lowering.LowerGraph();
}
void LowerGraph(Node* node, MachineRepresentation return_type,
MachineRepresentation rep = MachineRepresentation::kWord32,
int num_params = 0) {
......@@ -968,6 +989,100 @@ TEST_F(Int64LoweringTest, LoopCycle) {
LowerGraph(load, MachineRepresentation::kWord64);
}
TEST_F(Int64LoweringTest, WasmBigIntSpecialCaseBigIntToI64) {
Node* target = Int32Constant(1);
Node* context = Int32Constant(2);
Node* bigint = Int32Constant(4);
CallDescriptor* bigint_to_i64_call_descriptor =
Linkage::GetStubCallDescriptor(
zone(), // zone
BigIntToI64Descriptor(), // descriptor
BigIntToI64Descriptor()
.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
StubCallMode::kCallCodeObject); // stub call mode
CallDescriptor* bigint_to_i32_pair_call_descriptor =
Linkage::GetStubCallDescriptor(
zone(), // zone
BigIntToI32PairDescriptor(), // descriptor
BigIntToI32PairDescriptor()
.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
StubCallMode::kCallCodeObject); // stub call mode
auto lowering_special_case = base::make_unique<Int64LoweringSpecialCase>();
lowering_special_case->bigint_to_i64_call_descriptor =
bigint_to_i64_call_descriptor;
lowering_special_case->bigint_to_i32_pair_call_descriptor =
bigint_to_i32_pair_call_descriptor;
Node* call_node =
graph()->NewNode(common()->Call(bigint_to_i64_call_descriptor), target,
bigint, context, start(), start());
LowerGraphWithSpecialCase(call_node, std::move(lowering_special_case),
MachineRepresentation::kWord64);
Capture<Node*> call;
Matcher<Node*> call_matcher =
IsCall(bigint_to_i32_pair_call_descriptor, target, bigint, context,
start(), start());
EXPECT_THAT(graph()->end()->InputAt(1),
IsReturn2(IsProjection(0, AllOf(CaptureEq(&call), call_matcher)),
IsProjection(1, AllOf(CaptureEq(&call), call_matcher)),
start(), start()));
}
TEST_F(Int64LoweringTest, WasmBigIntSpecialCaseI64ToBigInt) {
Node* target = Int32Constant(1);
Node* i64 = Int64Constant(value(0));
CallDescriptor* i64_to_bigint_call_descriptor =
Linkage::GetStubCallDescriptor(
zone(), // zone
I64ToBigIntDescriptor(), // descriptor
I64ToBigIntDescriptor()
.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
StubCallMode::kCallCodeObject); // stub call mode
CallDescriptor* i32_pair_to_bigint_call_descriptor =
Linkage::GetStubCallDescriptor(
zone(), // zone
I32PairToBigIntDescriptor(), // descriptor
I32PairToBigIntDescriptor()
.GetStackParameterCount(), // stack parameter count
CallDescriptor::kNoFlags, // flags
Operator::kNoProperties, // properties
StubCallMode::kCallCodeObject); // stub call mode
auto lowering_special_case = base::make_unique<Int64LoweringSpecialCase>();
lowering_special_case->i64_to_bigint_call_descriptor =
i64_to_bigint_call_descriptor;
lowering_special_case->i32_pair_to_bigint_call_descriptor =
i32_pair_to_bigint_call_descriptor;
Node* call = graph()->NewNode(common()->Call(i64_to_bigint_call_descriptor),
target, i64, start(), start());
LowerGraphWithSpecialCase(call, std::move(lowering_special_case),
MachineRepresentation::kTaggedPointer);
EXPECT_THAT(
graph()->end()->InputAt(1),
IsReturn(IsCall(i32_pair_to_bigint_call_descriptor, target,
IsInt32Constant(low_word_value(0)),
IsInt32Constant(high_word_value(0)), start(), start()),
start(), start()));
}
} // namespace compiler
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment