[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:
Sven Sauleau 2018-12-07 20:50:26 +01:00 committed by Commit Bot
parent 3f3e2993ec
commit 2b92afd054
17 changed files with 471 additions and 31 deletions

View File

@ -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",

View 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

View File

@ -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

View File

@ -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(); \

View File

@ -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

View File

@ -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*,

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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_

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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) \

View File

@ -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);

View File

@ -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
View 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);
})();