[wasm] Add WebAssembly's i64<>JavaScript's BigInt conversions - 64 bits
Uses the JavaScript BigInt Object to represent Wasm's 64bits integers. Attention, 32 bits architectures are not supported yet. Bug: v8:7741 Change-Id: I28b718fa567bca5103b2f38a879049cd20a46f12 Reviewed-on: https://chromium-review.googlesource.com/c/1355144 Commit-Queue: Andreas Haas <ahaas@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#58152}
This commit is contained in:
parent
3f3e2993ec
commit
2b92afd054
1
BUILD.gn
1
BUILD.gn
@ -1420,6 +1420,7 @@ v8_source_set("v8_initializers") {
|
||||
"src/builtins/builtins-async-gen.h",
|
||||
"src/builtins/builtins-async-generator-gen.cc",
|
||||
"src/builtins/builtins-async-iterator-gen.cc",
|
||||
"src/builtins/builtins-bigint-gen.cc",
|
||||
"src/builtins/builtins-boolean-gen.cc",
|
||||
"src/builtins/builtins-call-gen.cc",
|
||||
"src/builtins/builtins-call-gen.h",
|
||||
|
46
src/builtins/builtins-bigint-gen.cc
Normal file
46
src/builtins/builtins-bigint-gen.cc
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2017 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/builtins/builtins-utils-gen.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/code-stub-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// https://tc39.github.io/proposal-bigint/#sec-to-big-int64
|
||||
TF_BUILTIN(BigIntToI64, CodeStubAssembler) {
|
||||
if (!Is64()) {
|
||||
Unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
TNode<Object> value = CAST(Parameter(Descriptor::kArgument));
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<BigInt> bigint = ToBigInt(context, value);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-bigint/#sec-bigint-constructor-number-value
|
||||
TF_BUILTIN(I64ToBigInt, CodeStubAssembler) {
|
||||
if (!Is64()) {
|
||||
Unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
TNode<IntPtrT> argument =
|
||||
UncheckedCast<IntPtrT>(Parameter(Descriptor::kArgument));
|
||||
|
||||
Return(BigIntFromInt64(argument));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -201,6 +201,8 @@ namespace internal {
|
||||
TFC(ToLength, TypeConversion, 1) \
|
||||
TFC(Typeof, Typeof, 1) \
|
||||
TFC(GetSuperConstructor, Typeof, 1) \
|
||||
TFC(BigIntToI64, BigIntToI64, 1) \
|
||||
TFC(I64ToBigInt, BigIntToWasmI64, 1) \
|
||||
\
|
||||
/* Type conversions continuations */ \
|
||||
TFC(ToBooleanLazyDeoptContinuation, TypeConversionStackParameter, 1) \
|
||||
@ -1260,6 +1262,7 @@ namespace internal {
|
||||
TFS(ThrowWasmTrapFloatUnrepresentable) \
|
||||
TFS(ThrowWasmTrapFuncInvalid) \
|
||||
TFS(ThrowWasmTrapFuncSigMismatch) \
|
||||
TFC(BigIntToWasmI64, BigIntToWasmI64, 1) \
|
||||
\
|
||||
/* WeakMap */ \
|
||||
TFJ(WeakMapConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
@ -1550,7 +1553,8 @@ namespace internal {
|
||||
V(WasmStackGuard) \
|
||||
V(WasmToNumber) \
|
||||
V(WasmThrow) \
|
||||
V(DoubleToI)
|
||||
V(DoubleToI) \
|
||||
V(BigIntToWasmI64)
|
||||
|
||||
// The exception thrown in the following builtins are caught internally and will
|
||||
// not be propagated further or re-thrown
|
||||
|
@ -219,6 +219,20 @@ TF_BUILTIN(WasmMemoryGrow, WasmBuiltinsAssembler) {
|
||||
ReturnRaw(Int32Constant(-1));
|
||||
}
|
||||
|
||||
TF_BUILTIN(BigIntToWasmI64, WasmBuiltinsAssembler) {
|
||||
if (!Is64()) {
|
||||
Unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kI64ToBigInt);
|
||||
TNode<IntPtrT> argument =
|
||||
UncheckedCast<IntPtrT>(Parameter(Descriptor::kArgument));
|
||||
|
||||
TailCallStub(BigIntToWasmI64Descriptor(), target, NoContextConstant(),
|
||||
argument);
|
||||
}
|
||||
|
||||
#define DECLARE_ENUM(name) \
|
||||
TF_BUILTIN(ThrowWasm##name, WasmBuiltinsAssembler) { \
|
||||
TNode<Object> instance = LoadInstanceFromFrame(); \
|
||||
|
@ -4315,7 +4315,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
: WasmGraphBuilder(nullptr, zone, jsgraph, sig, spt),
|
||||
isolate_(jsgraph->isolate()),
|
||||
jsgraph_(jsgraph),
|
||||
stub_mode_(stub_mode) {}
|
||||
stub_mode_(stub_mode),
|
||||
enabled_features_(wasm::WasmFeaturesFromIsolate(isolate_)) {}
|
||||
|
||||
Node* BuildAllocateHeapNumberWithValue(Node* value, Node* control) {
|
||||
MachineOperatorBuilder* machine = mcgraph()->machine();
|
||||
@ -4567,8 +4568,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
case wasm::kWasmI32:
|
||||
return BuildChangeInt32ToTagged(node);
|
||||
case wasm::kWasmS128:
|
||||
case wasm::kWasmI64:
|
||||
UNREACHABLE();
|
||||
case wasm::kWasmI64: {
|
||||
DCHECK(enabled_features_.bigint);
|
||||
return BuildChangeInt64ToBigInt(node);
|
||||
}
|
||||
case wasm::kWasmF32:
|
||||
node = graph()->NewNode(mcgraph()->machine()->ChangeFloat32ToFloat64(),
|
||||
node);
|
||||
@ -4582,6 +4586,48 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
Node* BuildChangeInt64ToBigInt(Node* input) {
|
||||
BigIntToWasmI64Descriptor 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::kBigIntToWasmI64, RelocInfo::WASM_STUB_CALL)
|
||||
: jsgraph()->HeapConstant(BUILTIN_CODE(isolate_, I64ToBigInt));
|
||||
|
||||
return SetEffect(
|
||||
SetControl(graph()->NewNode(mcgraph()->common()->Call(call_descriptor),
|
||||
target, input, Effect(), Control())));
|
||||
}
|
||||
|
||||
Node* BuildChangeBigIntToInt64(Node* input, Node* context) {
|
||||
DCHECK_EQ(stub_mode_, StubCallMode::kCallOnHeapBuiltin);
|
||||
|
||||
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
|
||||
StubCallMode::kCallOnHeapBuiltin); // stub call mode
|
||||
|
||||
Node* target = jsgraph()->HeapConstant(BUILTIN_CODE(isolate_, BigIntToI64));
|
||||
|
||||
return SetEffect(SetControl(
|
||||
graph()->NewNode(mcgraph()->common()->Call(call_descriptor), target,
|
||||
input, context, Effect(), Control())));
|
||||
}
|
||||
|
||||
Node* FromJS(Node* node, Node* js_context, wasm::ValueType type) {
|
||||
DCHECK_NE(wasm::kWasmStmt, type);
|
||||
|
||||
@ -4590,11 +4636,15 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
return node;
|
||||
}
|
||||
|
||||
// Do a JavaScript ToNumber.
|
||||
Node* num = BuildJavaScriptToNumber(node, js_context);
|
||||
Node* num = nullptr;
|
||||
|
||||
// Change representation.
|
||||
num = BuildChangeTaggedToFloat64(num);
|
||||
if (type != wasm::kWasmI64) {
|
||||
// Do a JavaScript ToNumber.
|
||||
num = BuildJavaScriptToNumber(node, js_context);
|
||||
|
||||
// Change representation.
|
||||
num = BuildChangeTaggedToFloat64(num);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case wasm::kWasmI32: {
|
||||
@ -4602,18 +4652,24 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
num);
|
||||
break;
|
||||
}
|
||||
case wasm::kWasmS128:
|
||||
case wasm::kWasmI64:
|
||||
UNREACHABLE();
|
||||
case wasm::kWasmI64: {
|
||||
DCHECK(enabled_features_.bigint);
|
||||
num = BuildChangeBigIntToInt64(node, js_context);
|
||||
break;
|
||||
}
|
||||
case wasm::kWasmF32:
|
||||
num = graph()->NewNode(mcgraph()->machine()->TruncateFloat64ToFloat32(),
|
||||
num);
|
||||
break;
|
||||
case wasm::kWasmF64:
|
||||
break;
|
||||
case wasm::kWasmS128:
|
||||
UNREACHABLE();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
DCHECK_NOT_NULL(num);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
@ -4724,7 +4780,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
instance_node_.set(
|
||||
BuildLoadInstanceFromExportedFunctionData(function_data));
|
||||
|
||||
if (!wasm::IsJSCompatibleSignature(sig_)) {
|
||||
if (!wasm::IsJSCompatibleSignature(sig_, enabled_features_.bigint)) {
|
||||
// Throw a TypeError. Use the js_context of the calling javascript
|
||||
// function (passed as a parameter), such that the generated code is
|
||||
// js_context independent.
|
||||
@ -5113,6 +5169,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
JSGraph* jsgraph_;
|
||||
StubCallMode stub_mode_;
|
||||
SetOncePointer<const Operator> allocate_heap_number_operator_;
|
||||
wasm::WasmFeatures enabled_features_;
|
||||
};
|
||||
|
||||
void AppendSignature(char* buffer, size_t max_name_len,
|
||||
@ -5195,7 +5252,8 @@ MaybeHandle<Code> CompileJSToWasmWrapper(Isolate* isolate,
|
||||
}
|
||||
|
||||
WasmImportCallKind GetWasmImportCallKind(Handle<JSReceiver> target,
|
||||
wasm::FunctionSig* expected_sig) {
|
||||
wasm::FunctionSig* expected_sig,
|
||||
bool has_bigint_feature) {
|
||||
if (WasmExportedFunction::IsWasmExportedFunction(*target)) {
|
||||
auto imported_function = WasmExportedFunction::cast(*target);
|
||||
wasm::FunctionSig* imported_sig =
|
||||
@ -5209,7 +5267,7 @@ WasmImportCallKind GetWasmImportCallKind(Handle<JSReceiver> target,
|
||||
return WasmImportCallKind::kWasmToWasm;
|
||||
}
|
||||
// Assuming we are calling to JS, check whether this would be a runtime error.
|
||||
if (!wasm::IsJSCompatibleSignature(expected_sig)) {
|
||||
if (!wasm::IsJSCompatibleSignature(expected_sig, has_bigint_feature)) {
|
||||
return WasmImportCallKind::kRuntimeTypeError;
|
||||
}
|
||||
// For JavaScript calls, determine whether the target has an arity match
|
||||
|
@ -108,7 +108,8 @@ enum class WasmImportCallKind : uint8_t {
|
||||
};
|
||||
|
||||
WasmImportCallKind GetWasmImportCallKind(Handle<JSReceiver> callable,
|
||||
wasm::FunctionSig* sig);
|
||||
wasm::FunctionSig* sig,
|
||||
bool has_bigint_feature);
|
||||
|
||||
// Compiles an import call wrapper, which allows WASM to call imports.
|
||||
wasm::WasmCode* CompileWasmImportCallWrapper(Isolate*, wasm::NativeModule*,
|
||||
|
@ -379,5 +379,15 @@ void CloneObjectWithVectorDescriptor::InitializePlatformSpecific(
|
||||
DefaultInitializePlatformSpecific(data, kParameterCount);
|
||||
}
|
||||
|
||||
void BigIntToWasmI64Descriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
DefaultInitializePlatformSpecific(data, kParameterCount);
|
||||
}
|
||||
|
||||
void BigIntToI64Descriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
DefaultInitializePlatformSpecific(data, kParameterCount);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -79,6 +79,8 @@ namespace internal {
|
||||
V(WasmI32AtomicWait) \
|
||||
V(WasmI64AtomicWait) \
|
||||
V(CloneObjectWithVector) \
|
||||
V(BigIntToWasmI64) \
|
||||
V(BigIntToI64) \
|
||||
BUILTIN_LIST_TFS(V)
|
||||
|
||||
class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
|
||||
@ -1103,6 +1105,21 @@ class WasmThrowDescriptor final : public CallInterfaceDescriptor {
|
||||
DECLARE_DESCRIPTOR(WasmThrowDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class BigIntToWasmI64Descriptor final : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS_NO_CONTEXT(kArgument)
|
||||
DEFINE_PARAMETER_TYPES(MachineType::Int64()) // kArgument
|
||||
DECLARE_DESCRIPTOR(BigIntToWasmI64Descriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class BigIntToI64Descriptor final : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kArgument)
|
||||
DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Int64(), // result 1
|
||||
MachineType::AnyTagged()) // kArgument
|
||||
DECLARE_DESCRIPTOR(BigIntToI64Descriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class WasmAtomicWakeDescriptor final : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS_NO_CONTEXT(kAddress, kCount)
|
||||
|
@ -1444,8 +1444,8 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) {
|
||||
static_cast<int32_t>(num));
|
||||
break;
|
||||
case kWasmI64:
|
||||
// TODO(titzer): initialization of imported i64 globals.
|
||||
UNREACHABLE();
|
||||
WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global),
|
||||
static_cast<int64_t>(num));
|
||||
break;
|
||||
case kWasmF32:
|
||||
WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
|
||||
@ -1562,6 +1562,8 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
|
||||
int num_imported_tables = 0;
|
||||
int num_imported_mutable_globals = 0;
|
||||
|
||||
WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate_);
|
||||
|
||||
DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
|
||||
int num_imports = static_cast<int>(module_->import_table.size());
|
||||
NativeModule* native_module = instance->module_object()->native_module();
|
||||
@ -1584,7 +1586,8 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
|
||||
DCHECK_EQ(num_imported_functions, func_index);
|
||||
auto js_receiver = Handle<JSReceiver>::cast(value);
|
||||
FunctionSig* expected_sig = module_->functions[func_index].sig;
|
||||
auto kind = compiler::GetWasmImportCallKind(js_receiver, expected_sig);
|
||||
auto kind = compiler::GetWasmImportCallKind(js_receiver, expected_sig,
|
||||
enabled_features.bigint);
|
||||
switch (kind) {
|
||||
case compiler::WasmImportCallKind::kLinkError:
|
||||
ReportLinkError(
|
||||
@ -1757,7 +1760,10 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
|
||||
|
||||
// The mutable-global proposal allows importing i64 values, but only if
|
||||
// they are passed as a WebAssembly.Global object.
|
||||
if (global.type == kWasmI64 &&
|
||||
//
|
||||
// However, the bigint proposal allows importing constant i64 values,
|
||||
// as non WebAssembly.Global object.
|
||||
if (global.type == kWasmI64 && !enabled_.bigint &&
|
||||
!(enabled_.mut_global && value->IsWasmGlobalObject())) {
|
||||
ReportLinkError("global import cannot have type i64", index,
|
||||
module_name, import_name);
|
||||
@ -1816,6 +1822,19 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
|
||||
return -1;
|
||||
}
|
||||
WriteGlobalValue(global, value->Number());
|
||||
} else if (enabled_.bigint && global.type == kWasmI64) {
|
||||
if (global.mutability) {
|
||||
ReportLinkError(
|
||||
"imported mutable global must be a WebAssembly.Global object",
|
||||
index, module_name, import_name);
|
||||
return -1;
|
||||
}
|
||||
Handle<BigInt> bigint;
|
||||
|
||||
if (!BigInt::FromObject(isolate_, value).ToHandle(&bigint)) {
|
||||
return -1;
|
||||
}
|
||||
WriteGlobalValue(global, bigint->AsInt64());
|
||||
} else {
|
||||
ReportLinkError(
|
||||
"global import must be a number or WebAssembly.Global object",
|
||||
@ -1825,6 +1844,13 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
|
||||
} else {
|
||||
if (value->IsNumber()) {
|
||||
WriteGlobalValue(global, value->Number());
|
||||
} else if (enabled_.bigint && global.type == kWasmI64) {
|
||||
Handle<BigInt> bigint;
|
||||
|
||||
if (!BigInt::FromObject(isolate_, value).ToHandle(&bigint)) {
|
||||
return -1;
|
||||
}
|
||||
WriteGlobalValue(global, bigint->AsInt64());
|
||||
} else {
|
||||
ReportLinkError("global import must be a number", index,
|
||||
module_name, import_name);
|
||||
|
@ -23,6 +23,8 @@
|
||||
SEPARATOR \
|
||||
V(mut_global, "import/export mutable global support", true) \
|
||||
SEPARATOR \
|
||||
V(bigint, "JS BigInt support", false) \
|
||||
SEPARATOR \
|
||||
V(bulk_memory, "bulk memory opcodes", false)
|
||||
|
||||
#endif // V8_WASM_WASM_FEATURE_FLAGS_H_
|
||||
|
@ -2714,8 +2714,11 @@ class ThreadImpl {
|
||||
Handle<Object> object_ref,
|
||||
const WasmCode* code,
|
||||
FunctionSig* sig) {
|
||||
wasm::WasmFeatures enabled_features =
|
||||
wasm::WasmFeaturesFromIsolate(isolate);
|
||||
|
||||
if (code->kind() == WasmCode::kWasmToJsWrapper &&
|
||||
!IsJSCompatibleSignature(sig)) {
|
||||
!IsJSCompatibleSignature(sig, enabled_features.bigint)) {
|
||||
isolate->Throw(*isolate->factory()->NewTypeError(
|
||||
MessageTemplate::kWasmTrapTypeError));
|
||||
return TryHandleException(isolate);
|
||||
|
@ -1102,6 +1102,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
}
|
||||
}
|
||||
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||
|
||||
// The descriptor's type, called 'value'. It is called 'value' because this
|
||||
// descriptor is planned to be re-used as the global's type for reflection,
|
||||
// so calling it 'type' is redundant.
|
||||
@ -1118,11 +1120,20 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
type = i::wasm::kWasmI32;
|
||||
} else if (string->StringEquals(v8_str(isolate, "f32"))) {
|
||||
type = i::wasm::kWasmF32;
|
||||
} else if (enabled_features.bigint &&
|
||||
string->StringEquals(v8_str(isolate, "i64"))) {
|
||||
type = i::wasm::kWasmI64;
|
||||
} else if (string->StringEquals(v8_str(isolate, "f64"))) {
|
||||
type = i::wasm::kWasmF64;
|
||||
} else {
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'value' must be 'i32', 'f32', or 'f64'");
|
||||
if (enabled_features.bigint) {
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'value' must be 'i32', 'i64', 'f32' or 'f64'");
|
||||
} else {
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'value' must be 'i32', 'f32' or 'f64'");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1151,6 +1162,18 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
global_obj->SetI32(i32_value);
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmI64: {
|
||||
DCHECK(enabled_features.bigint);
|
||||
|
||||
int64_t i64_value = 0;
|
||||
if (!value->IsUndefined()) {
|
||||
v8::Local<v8::BigInt> bigint_value;
|
||||
if (!value->ToBigInt(context).ToLocal(&bigint_value)) return;
|
||||
i64_value = bigint_value->Int64Value();
|
||||
}
|
||||
global_obj->SetI64(i64_value);
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmF32: {
|
||||
float f32_value = 0;
|
||||
if (!value->IsUndefined()) {
|
||||
@ -1403,9 +1426,17 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
case i::wasm::kWasmI32:
|
||||
return_value.Set(receiver->GetI32());
|
||||
break;
|
||||
case i::wasm::kWasmI64:
|
||||
thrower.TypeError("Can't get the value of i64 WebAssembly.Global");
|
||||
case i::wasm::kWasmI64: {
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||
if (enabled_features.bigint) {
|
||||
Local<BigInt> value = BigInt::New(isolate, receiver->GetI64());
|
||||
|
||||
return_value.Set(value);
|
||||
} else {
|
||||
thrower.TypeError("Can't get the value of i64 WebAssembly.Global");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmF32:
|
||||
return_value.Set(receiver->GetF32());
|
||||
break;
|
||||
@ -1450,9 +1481,17 @@ void WebAssemblyGlobalSetValue(
|
||||
receiver->SetI32(i32_value);
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmI64:
|
||||
thrower.TypeError("Can't set the value of i64 WebAssembly.Global");
|
||||
case i::wasm::kWasmI64: {
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||
if (enabled_features.bigint) {
|
||||
v8::Local<v8::BigInt> bigint_value;
|
||||
if (!args[0]->ToBigInt(context).ToLocal(&bigint_value)) return;
|
||||
receiver->SetI64(bigint_value->Int64Value());
|
||||
} else {
|
||||
thrower.TypeError("Can't set the value of i64 WebAssembly.Global");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case i::wasm::kWasmF32: {
|
||||
double f64_value = 0;
|
||||
if (!args[0]->NumberValue(context).To(&f64_value)) return;
|
||||
|
@ -381,11 +381,18 @@ std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
|
||||
return os;
|
||||
}
|
||||
|
||||
bool IsJSCompatibleSignature(const FunctionSig* sig) {
|
||||
for (auto type : sig->all()) {
|
||||
if (type == kWasmI64 || type == kWasmS128) return false;
|
||||
bool IsJSCompatibleSignature(const FunctionSig* sig, bool has_bigint_feature) {
|
||||
if (sig->return_count() > 1) {
|
||||
return false;
|
||||
}
|
||||
return sig->return_count() <= 1;
|
||||
for (auto type : sig->all()) {
|
||||
if (!has_bigint_feature && type == kWasmI64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == kWasmS128) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -16,7 +16,7 @@ namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const FunctionSig& function);
|
||||
bool IsJSCompatibleSignature(const FunctionSig* sig);
|
||||
bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
|
||||
|
||||
// Control expressions and blocks.
|
||||
#define FOREACH_CONTROL_OPCODE(V) \
|
||||
|
@ -44,7 +44,7 @@ TestingModuleBuilder::TestingModuleBuilder(
|
||||
// Manually compile an import wrapper and insert it into the instance.
|
||||
CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
|
||||
auto kind = compiler::GetWasmImportCallKind(maybe_import->js_function,
|
||||
maybe_import->sig);
|
||||
maybe_import->sig, false);
|
||||
auto import_wrapper = native_module_->import_wrapper_cache()->GetOrCompile(
|
||||
isolate_, kind, maybe_import->sig);
|
||||
|
||||
|
@ -929,4 +929,10 @@
|
||||
'wasm/asm-wasm-f64': [SKIP],
|
||||
}], # arch == x64
|
||||
|
||||
##############################################################################
|
||||
['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],
|
||||
}], # arch in [arm, android_arm, android_ia32, ia32, ppc, s390, s390x, mipsel, mips]
|
||||
]
|
||||
|
206
test/mjsunit/wasm/bigint.js
Normal file
206
test/mjsunit/wasm/bigint.js
Normal file
@ -0,0 +1,206 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Flags: --experimental-wasm-bigint
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function TestWasmI64ToJSBigInt() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
|
||||
builder
|
||||
.addFunction("fn", kSig_l_v) // () -> i64
|
||||
.addBody([
|
||||
kExprI64Const, 0x3,
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
var module = builder.instantiate();
|
||||
|
||||
assertEquals(typeof module.exports.fn(), "bigint");
|
||||
assertEquals(module.exports.fn(), 3n);
|
||||
})();
|
||||
|
||||
(function TestWasmI64ToJSBigIntImportedFunc() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
|
||||
var a_index = builder
|
||||
.addImport("a", "a", kSig_v_l) // i64 -> ()
|
||||
|
||||
builder
|
||||
.addFunction("fn", kSig_v_v) // () -> ()
|
||||
.addBody([
|
||||
kExprI64Const, 0x1,
|
||||
kExprCallFunction, a_index
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
a_was_called = false;
|
||||
|
||||
var module = builder.instantiate({
|
||||
a: {
|
||||
a(param) {
|
||||
assertEquals(typeof param, "bigint");
|
||||
assertEquals(param, 1n);
|
||||
a_was_called = true;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
module.exports.fn();
|
||||
|
||||
assertTrue(a_was_called);
|
||||
})();
|
||||
|
||||
(function TestJSBigIntToWasmI64Global() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
|
||||
var a_global_index = builder
|
||||
.addImportedGlobal("mod", "a", kWasmI64)
|
||||
|
||||
var b_global_index = builder
|
||||
.addImportedGlobal("mod", "b", kWasmI64);
|
||||
|
||||
var c_global_index = builder
|
||||
.addImportedGlobal("mod", "c", kWasmI64);
|
||||
|
||||
builder
|
||||
.addExportOfKind('a', kExternalGlobal, a_global_index)
|
||||
.addExportOfKind('b', kExternalGlobal, b_global_index)
|
||||
.addExportOfKind('c', kExternalGlobal, c_global_index);
|
||||
|
||||
var module = builder.instantiate({
|
||||
mod: {
|
||||
a: 1n,
|
||||
b: 2n ** 63n,
|
||||
c: "123",
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals(module.exports.a.value, 1n);
|
||||
assertEquals(module.exports.b.value, - (2n ** 63n));
|
||||
assertEquals(module.exports.c.value, 123n);
|
||||
})();
|
||||
|
||||
(function TestJSBigIntToWasmI64MutableGlobal() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
|
||||
var a_global_index = builder
|
||||
.addImportedGlobal("mod", "a", kWasmI64, /* mutable = */ true)
|
||||
|
||||
builder
|
||||
.addExportOfKind('a', kExternalGlobal, a_global_index);
|
||||
|
||||
// as non object
|
||||
var fn = () => builder.instantiate({
|
||||
mod: {
|
||||
a: 1n,
|
||||
}
|
||||
});
|
||||
|
||||
assertThrows(fn, WebAssembly.LinkError);
|
||||
|
||||
// as WebAssembly.Global object
|
||||
var module = builder.instantiate({
|
||||
mod: {
|
||||
a: new WebAssembly.Global({ value: "i64", mutable: true }, 1n),
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals(module.exports.a.value, 1n);
|
||||
})();
|
||||
|
||||
(function TestJSBigIntToWasmI64Identity() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
|
||||
builder
|
||||
.addFunction("f", kSig_l_l) // i64 -> i64
|
||||
.addBody([
|
||||
kExprGetLocal, 0x0,
|
||||
])
|
||||
.exportFunc();
|
||||
|
||||
var module = builder.instantiate();
|
||||
var f = module.exports.f;
|
||||
|
||||
assertEquals(f(0n), 0n);
|
||||
assertEquals(f(-0n), -0n);
|
||||
assertEquals(f(123n), 123n);
|
||||
assertEquals(f(-123n), -123n);
|
||||
|
||||
assertEquals(f("5"), 5n);
|
||||
|
||||
assertThrows(() => f(5), TypeError);
|
||||
})();
|
||||
|
||||
(function TestI64Global() {
|
||||
var argument = { "value": "i64", "mutable": true };
|
||||
var global = new WebAssembly.Global(argument);
|
||||
|
||||
assertEquals(global.value, 0n); // initial value
|
||||
|
||||
global.value = 123n;
|
||||
assertEquals(global.valueOf(), 123n);
|
||||
|
||||
global.value = 2n ** 63n;
|
||||
assertEquals(global.valueOf(), - (2n ** 63n));
|
||||
})();
|
||||
|
||||
(function TestI64GlobalValueOf() {
|
||||
var argument = { "value": "i64" };
|
||||
|
||||
// as literal
|
||||
var global = new WebAssembly.Global(argument, {
|
||||
valueOf() {
|
||||
return 123n;
|
||||
}
|
||||
});
|
||||
assertEquals(global.value, 123n);
|
||||
|
||||
// as string
|
||||
var global2 = new WebAssembly.Global(argument, {
|
||||
valueOf() {
|
||||
return "321";
|
||||
}
|
||||
});
|
||||
assertEquals(global2.value, 321n);
|
||||
})();
|
||||
|
||||
(function TestInvalidValtypeGlobalErrorMessage() {
|
||||
var argument = { "value": "some string" };
|
||||
assertThrows(() => new WebAssembly.Global(argument), TypeError);
|
||||
|
||||
try {
|
||||
new WebAssembly.Global(argument);
|
||||
} catch (e) {
|
||||
assertContains("'value' must be", e.message);
|
||||
assertContains("i64", e.message);
|
||||
}
|
||||
})();
|
||||
|
||||
(function TestGlobalI64ValueWrongType() {
|
||||
var argument = { "value": "i64" };
|
||||
assertThrows(() => new WebAssembly.Global(argument, 666), TypeError);
|
||||
})();
|
||||
|
||||
(function TestGlobalI64SetWrongType() {
|
||||
var argument = { "value": "i64", "mutable": true };
|
||||
var global = new WebAssembly.Global(argument);
|
||||
|
||||
assertThrows(() => global.value = 1, TypeError);
|
||||
})();
|
||||
|
||||
(function TestFuncParamF64PassingBigInt() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
|
||||
builder
|
||||
.addFunction("f", kSig_v_d) // f64 -> ()
|
||||
.addBody([])
|
||||
.exportFunc();
|
||||
|
||||
var module = builder.instantiate();
|
||||
|
||||
assertThrows(() => module.exports.f(123n), TypeError);
|
||||
})();
|
Loading…
Reference in New Issue
Block a user