Commit 668dcf3b authored by Michael Achenbach's avatar Michael Achenbach Committed by Commit Bot

Revert "[wasm] Make WebAssembly.compile() asynchronous"

This reverts commit 7a6e6bb1.

Reason for revert: breaks layout tests:
https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/14688

See:
https://github.com/v8/v8/wiki/Blink-layout-tests

Original change's description:
> [wasm] Make WebAssembly.compile() asynchronous
> 
> titzer@ originally created this
> CL (https://codereview.chromium.org/2757903002). I fixed crashing tests
> and adressed some comments of the reviewers.
> 
> R=​bradnelson@chromium.org, clemensh@chromium.org, mtrofin@chromium.org
> BUG=v8:6003
> 
> Change-Id: I4ab6d503909402d24043657a896200032e6d1023
> Reviewed-on: https://chromium-review.googlesource.com/464887
> Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
> Reviewed-by: Mircea Trofin <mtrofin@chromium.org>
> Commit-Queue: Andreas Haas <ahaas@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#44333}

TBR=bradnelson@chromium.org,mtrofin@chromium.org,ahaas@chromium.org,clemensh@chromium.org,titzer@chromium.org,v8-reviews@googlegroups.com
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:6003

Change-Id: I87dbdbba0be4624828b6b0a94e02b6681593e335
Reviewed-on: https://chromium-review.googlesource.com/465813Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44342}
parent f4f58e31
...@@ -1189,7 +1189,7 @@ void Code::CodePrint(std::ostream& os) { // NOLINT ...@@ -1189,7 +1189,7 @@ void Code::CodePrint(std::ostream& os) { // NOLINT
void Foreign::ForeignPrint(std::ostream& os) { // NOLINT void Foreign::ForeignPrint(std::ostream& os) { // NOLINT
os << "foreign address : " << reinterpret_cast<void*>(foreign_address()); os << "foreign address : " << foreign_address();
os << "\n"; os << "\n";
} }
......
...@@ -42,11 +42,6 @@ namespace base = v8::base; ...@@ -42,11 +42,6 @@ namespace base = v8::base;
instance->PrintInstancesChain(); \ instance->PrintInstancesChain(); \
} while (false) } while (false)
#define TRACE_COMPILE(...) \
do { \
if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
} while (false)
namespace { namespace {
static const int kInvalidSigIndex = -1; static const int kInvalidSigIndex = -1;
...@@ -325,7 +320,6 @@ class CompilationHelper { ...@@ -325,7 +320,6 @@ class CompilationHelper {
std::queue<compiler::WasmCompilationUnit*> executed_units_; std::queue<compiler::WasmCompilationUnit*> executed_units_;
base::Mutex result_mutex_; base::Mutex result_mutex_;
base::AtomicNumber<size_t> next_unit_; base::AtomicNumber<size_t> next_unit_;
size_t num_background_tasks_ = 0;
// Run by each compilation task and by the main thread. // Run by each compilation task and by the main thread.
bool FetchAndExecuteCompilationUnit() { bool FetchAndExecuteCompilationUnit() {
...@@ -347,8 +341,9 @@ class CompilationHelper { ...@@ -347,8 +341,9 @@ class CompilationHelper {
return true; return true;
} }
size_t InitializeParallelCompilation( void InitializeParallelCompilation(const std::vector<WasmFunction>& functions,
const std::vector<WasmFunction>& functions, ModuleBytesEnv& module_env) { ModuleBytesEnv& module_env,
ErrorThrower* thrower) {
uint32_t start = module_env.module_env.module->num_imported_functions + uint32_t start = module_env.module_env.module->num_imported_functions +
FLAG_skip_compiling_wasm_funcs; FLAG_skip_compiling_wasm_funcs;
uint32_t num_funcs = static_cast<uint32_t>(functions.size()); uint32_t num_funcs = static_cast<uint32_t>(functions.size());
...@@ -359,15 +354,14 @@ class CompilationHelper { ...@@ -359,15 +354,14 @@ class CompilationHelper {
compilation_units_.push_back( compilation_units_.push_back(
new compiler::WasmCompilationUnit(isolate_, &module_env, func)); new compiler::WasmCompilationUnit(isolate_, &module_env, func));
} }
return num_funcs;
} }
uint32_t* StartCompilationTasks() { uint32_t* StartCompilationTasks() {
num_background_tasks_ = const size_t num_tasks =
Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks), Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads()); V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
uint32_t* task_ids = new uint32_t[num_background_tasks_]; uint32_t* task_ids = new uint32_t[num_tasks];
for (size_t i = 0; i < num_background_tasks_; ++i) { for (size_t i = 0; i < num_tasks; ++i) {
CompilationTask* task = new CompilationTask(this); CompilationTask* task = new CompilationTask(this);
task_ids[i] = task->id(); task_ids[i] = task->id();
V8::GetCurrentPlatform()->CallOnBackgroundThread( V8::GetCurrentPlatform()->CallOnBackgroundThread(
...@@ -377,9 +371,13 @@ class CompilationHelper { ...@@ -377,9 +371,13 @@ class CompilationHelper {
} }
void WaitForCompilationTasks(uint32_t* task_ids) { void WaitForCompilationTasks(uint32_t* task_ids) {
for (size_t i = 0; i < num_background_tasks_; ++i) { const size_t num_tasks =
Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
for (size_t i = 0; i < num_tasks; ++i) {
// If the task has not started yet, then we abort it. Otherwise we wait // If the task has not started yet, then we abort it. Otherwise we wait
// for it to finish. // for
// it to finish.
if (isolate_->cancelable_task_manager()->TryAbort(task_ids[i]) != if (isolate_->cancelable_task_manager()->TryAbort(task_ids[i]) !=
CancelableTaskManager::kTaskAborted) { CancelableTaskManager::kTaskAborted) {
module_->pending_tasks.get()->Wait(); module_->pending_tasks.get()->Wait();
...@@ -390,28 +388,21 @@ class CompilationHelper { ...@@ -390,28 +388,21 @@ class CompilationHelper {
void FinishCompilationUnits(std::vector<Handle<Code>>& results, void FinishCompilationUnits(std::vector<Handle<Code>>& results,
ErrorThrower* thrower) { ErrorThrower* thrower) {
while (true) { while (true) {
int func_index = 0; compiler::WasmCompilationUnit* unit = nullptr;
MaybeHandle<Code> result = FinishCompilationUnit(thrower, &func_index); {
if (result.is_null()) break; base::LockGuard<base::Mutex> guard(&result_mutex_);
results[func_index] = result.ToHandleChecked(); if (executed_units_.empty()) {
break;
}
unit = executed_units_.front();
executed_units_.pop();
}
int j = unit->func_index();
results[j] = unit->FinishCompilation(thrower);
delete unit;
} }
} }
MaybeHandle<Code> FinishCompilationUnit(ErrorThrower* thrower,
int* func_index) {
compiler::WasmCompilationUnit* unit = nullptr;
{
base::LockGuard<base::Mutex> guard(&result_mutex_);
if (executed_units_.empty()) return {};
unit = executed_units_.front();
executed_units_.pop();
}
*func_index = unit->func_index();
Handle<Code> result = unit->FinishCompilation(thrower);
delete unit;
return result;
}
void CompileInParallel(ModuleBytesEnv* module_env, void CompileInParallel(ModuleBytesEnv* module_env,
std::vector<Handle<Code>>& results, std::vector<Handle<Code>>& results,
ErrorThrower* thrower) { ErrorThrower* thrower) {
...@@ -440,7 +431,7 @@ class CompilationHelper { ...@@ -440,7 +431,7 @@ class CompilationHelper {
// 1) The main thread allocates a compilation unit for each wasm function // 1) The main thread allocates a compilation unit for each wasm function
// and stores them in the vector {compilation_units}. // and stores them in the vector {compilation_units}.
InitializeParallelCompilation(module->functions, *module_env); InitializeParallelCompilation(module->functions, *module_env, thrower);
// Objects for the synchronization with the background threads. // Objects for the synchronization with the background threads.
base::AtomicNumber<size_t> next_unit( base::AtomicNumber<size_t> next_unit(
...@@ -1577,7 +1568,14 @@ class InstantiationHelper { ...@@ -1577,7 +1568,14 @@ class InstantiationHelper {
} }
void WriteGlobalValue(WasmGlobal& global, Handle<Object> value) { void WriteGlobalValue(WasmGlobal& global, Handle<Object> value) {
double num = value->Number(); double num = 0;
if (value->IsSmi()) {
num = Smi::cast(*value)->value();
} else if (value->IsHeapNumber()) {
num = HeapNumber::cast(*value)->value();
} else {
UNREACHABLE();
}
TRACE("init [globals+%u] = %lf, type = %s\n", global.offset, num, TRACE("init [globals+%u] = %lf, type = %s\n", global.offset, num,
WasmOpcodes::TypeName(global.type)); WasmOpcodes::TypeName(global.type));
switch (global.type) { switch (global.type) {
...@@ -2604,19 +2602,21 @@ MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate( ...@@ -2604,19 +2602,21 @@ MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate(
namespace { namespace {
void RejectPromise(Isolate* isolate, Handle<Context> context, void RejectPromise(Isolate* isolate, ErrorThrower* thrower,
ErrorThrower* thrower, Handle<JSPromise> promise) { Handle<JSPromise> promise) {
v8::Local<v8::Promise::Resolver> resolver = v8::Local<v8::Promise::Resolver> resolver =
v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>(); v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>();
Handle<Context> context(isolate->context(), isolate);
auto maybe = resolver->Reject(v8::Utils::ToLocal(context), auto maybe = resolver->Reject(v8::Utils::ToLocal(context),
v8::Utils::ToLocal(thrower->Reify())); v8::Utils::ToLocal(thrower->Reify()));
CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception()); CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception());
} }
void ResolvePromise(Isolate* isolate, Handle<Context> context, void ResolvePromise(Isolate* isolate, Handle<JSPromise> promise,
Handle<JSPromise> promise, Handle<Object> result) { Handle<Object> result) {
v8::Local<v8::Promise::Resolver> resolver = v8::Local<v8::Promise::Resolver> resolver =
v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>(); v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>();
Handle<Context> context(isolate->context(), isolate);
auto maybe = resolver->Resolve(v8::Utils::ToLocal(context), auto maybe = resolver->Resolve(v8::Utils::ToLocal(context),
v8::Utils::ToLocal(result)); v8::Utils::ToLocal(result));
CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception()); CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception());
...@@ -2624,6 +2624,18 @@ void ResolvePromise(Isolate* isolate, Handle<Context> context, ...@@ -2624,6 +2624,18 @@ void ResolvePromise(Isolate* isolate, Handle<Context> context,
} // namespace } // namespace
void wasm::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise,
const ModuleWireBytes& bytes) {
ErrorThrower thrower(isolate, nullptr);
MaybeHandle<WasmModuleObject> module_object =
SyncCompile(isolate, &thrower, bytes);
if (thrower.error()) {
RejectPromise(isolate, &thrower, promise);
return;
}
ResolvePromise(isolate, promise, module_object.ToHandleChecked());
}
void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise, void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise,
Handle<WasmModuleObject> module_object, Handle<WasmModuleObject> module_object,
MaybeHandle<JSReceiver> imports) { MaybeHandle<JSReceiver> imports) {
...@@ -2631,11 +2643,10 @@ void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise, ...@@ -2631,11 +2643,10 @@ void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise,
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate( MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null()); isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) { if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise); RejectPromise(isolate, &thrower, promise);
return; return;
} }
ResolvePromise(isolate, handle(isolate->context()), promise, ResolvePromise(isolate, promise, instance_object.ToHandleChecked());
instance_object.ToHandleChecked());
} }
void wasm::AsyncCompileAndInstantiate(Isolate* isolate, void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
...@@ -2648,7 +2659,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate, ...@@ -2648,7 +2659,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
MaybeHandle<WasmModuleObject> module_object = MaybeHandle<WasmModuleObject> module_object =
SyncCompile(isolate, &thrower, bytes); SyncCompile(isolate, &thrower, bytes);
if (thrower.error()) { if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise); RejectPromise(isolate, &thrower, promise);
return; return;
} }
Handle<WasmModuleObject> module = module_object.ToHandleChecked(); Handle<WasmModuleObject> module = module_object.ToHandleChecked();
...@@ -2657,7 +2668,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate, ...@@ -2657,7 +2668,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate( MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module, imports, Handle<JSArrayBuffer>::null()); isolate, &thrower, module, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) { if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise); RejectPromise(isolate, &thrower, promise);
return; return;
} }
...@@ -2673,388 +2684,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate, ...@@ -2673,388 +2684,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
JSObject::AddProperty(ret, instance_property_name, JSObject::AddProperty(ret, instance_property_name,
instance_object.ToHandleChecked(), NONE); instance_object.ToHandleChecked(), NONE);
ResolvePromise(isolate, handle(isolate->context()), promise, ret); ResolvePromise(isolate, promise, ret);
}
// Encapsulates all the state and steps of an asynchronous compilation.
// An asynchronous compile job consists of a number of tasks that are executed
// as foreground and background tasks. Any phase that touches the V8 heap or
// allocates on the V8 heap (e.g. creating the module object) must be a
// foreground task. All other tasks (e.g. decoding and validating, the majority
// of the work of compilation) can be background tasks.
// TODO(wasm): factor out common parts of this with the synchronous pipeline.
class AsyncCompileJob {
public:
explicit AsyncCompileJob(Isolate* isolate, std::unique_ptr<byte[]> bytes_copy,
int length, Handle<Context> context,
Handle<JSPromise> promise)
: isolate_(isolate),
bytes_copy_(std::move(bytes_copy)),
wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length) {
// The handles for the context and promise must be deferred.
DeferredHandleScope deferred(isolate);
context_ = Handle<Context>(*context);
module_promise_ = Handle<JSPromise>(*promise);
deferred_handles_.push_back(deferred.Detach());
}
bool Start() {
return DoAsync(&AsyncCompileJob::DecodeModule); // --
}
~AsyncCompileJob() {
for (auto d : deferred_handles_) delete d;
}
private:
Isolate* isolate_;
std::unique_ptr<byte[]> bytes_copy_;
ModuleWireBytes wire_bytes_;
Handle<Context> context_;
Handle<JSPromise> module_promise_;
WasmModule* module_ = nullptr;
ModuleResult result_;
std::unique_ptr<CompilationHelper> helper_ = nullptr;
std::unique_ptr<ModuleBytesEnv> module_bytes_env_ = nullptr;
volatile bool failed_ = false;
std::vector<DeferredHandles*> deferred_handles_;
Handle<WasmModuleWrapper> module_wrapper_;
Handle<WasmModuleObject> module_object_;
Handle<FixedArray> function_tables_;
Handle<FixedArray> signature_tables_;
Handle<WasmCompiledModule> compiled_module_;
Handle<FixedArray> code_table_;
std::unique_ptr<WasmInstance> temp_instance_ = nullptr;
std::unique_ptr<uint32_t[]> task_ids_ = nullptr;
size_t outstanding_units_ = 0;
size_t num_background_tasks_ = 0;
//==========================================================================
// Step 1: (async) Decode the module.
//==========================================================================
bool DecodeModule() {
DisallowHandleAllocation no_handle;
DisallowHeapAllocation no_allocation;
// Decode the module bytes.
TRACE_COMPILE("(1) Decoding module...\n");
result_ = DecodeWasmModule(isolate_, wire_bytes_.start(), wire_bytes_.end(),
true, kWasmOrigin);
if (result_.failed()) {
// Decoding failure; reject the promise and clean up.
if (result_.val) delete result_.val;
return DoSync(&AsyncCompileJob::DecodeFail);
} else {
// Decode passed.
module_ = const_cast<WasmModule*>(result_.val);
return DoSync(&AsyncCompileJob::PrepareAndStartCompile);
}
}
//==========================================================================
// Step 1b: (sync) Fail decoding the module.
//==========================================================================
bool DecodeFail() {
HandleScope scope(isolate_);
ErrorThrower thrower(isolate_, nullptr);
thrower.CompileFailed("Wasm decoding failed", result_);
RejectPromise(isolate_, context_, &thrower, module_promise_);
return false;
}
//==========================================================================
// Step 2 (sync): Create heap-allocated data and start compile.
//==========================================================================
bool PrepareAndStartCompile() {
TRACE_COMPILE("(2) Prepare and start compile...\n");
DeferredHandleScope deferred(isolate_);
Factory* factory = isolate_->factory();
// The {module_wrapper} will take ownership of the {WasmModule} object,
// and it will be destroyed when the GC reclaims the wrapper object.
module_wrapper_ = WasmModuleWrapper::New(isolate_, module_);
temp_instance_ = std::unique_ptr<WasmInstance>(new WasmInstance(module_));
temp_instance_->context = isolate_->native_context();
temp_instance_->mem_size = WasmModule::kPageSize * module_->min_mem_pages;
temp_instance_->mem_start = nullptr;
temp_instance_->globals_start = nullptr;
// Initialize the indirect tables with placeholders.
int function_table_count =
static_cast<int>(module_->function_tables.size());
function_tables_ = factory->NewFixedArray(function_table_count, TENURED);
signature_tables_ = factory->NewFixedArray(function_table_count, TENURED);
for (int i = 0; i < function_table_count; ++i) {
temp_instance_->function_tables[i] = factory->NewFixedArray(1, TENURED);
temp_instance_->signature_tables[i] = factory->NewFixedArray(1, TENURED);
function_tables_->set(i, *temp_instance_->function_tables[i]);
signature_tables_->set(i, *temp_instance_->signature_tables[i]);
}
// The {code_table} array contains import wrappers and functions (which
// are both included in {functions.size()}, and export wrappers.
// The results of compilation will be written into it.
int code_table_size = static_cast<int>(module_->functions.size() +
module_->num_exported_functions);
code_table_ = factory->NewFixedArray(code_table_size, TENURED);
// Initialize {code_table_} with the illegal builtin. All call sites
// will be patched at instantiation.
Handle<Code> illegal_builtin = isolate_->builtins()->Illegal();
// TODO(wasm): Fix this for lazy compilation.
for (uint32_t i = 0; i < module_->functions.size(); ++i) {
code_table_->set(static_cast<int>(i), *illegal_builtin);
temp_instance_->function_code[i] = illegal_builtin;
}
isolate_->counters()->wasm_functions_per_wasm_module()->AddSample(
static_cast<int>(module_->functions.size()));
helper_ = std::unique_ptr<CompilationHelper>(
new CompilationHelper(isolate_, module_));
DCHECK_LE(module_->num_imported_functions, module_->functions.size());
size_t num_functions =
module_->functions.size() - module_->num_imported_functions;
if (num_functions == 0) {
// Degenerate case of an empty module.
deferred_handles_.push_back(deferred.Detach());
return DoSync(&AsyncCompileJob::FinishCompile);
}
// Start asynchronous compilation tasks.
num_background_tasks_ =
Max(static_cast<size_t>(1),
Min(num_functions,
Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
V8::GetCurrentPlatform()
->NumberOfAvailableBackgroundThreads())));
module_bytes_env_ = std::unique_ptr<ModuleBytesEnv>(
new ModuleBytesEnv(module_, temp_instance_.get(), wire_bytes_));
outstanding_units_ = helper_->InitializeParallelCompilation(
module_->functions, *module_bytes_env_);
task_ids_ =
std::unique_ptr<uint32_t[]>(new uint32_t[num_background_tasks_]);
for (size_t i = 0; i < num_background_tasks_; ++i) {
DoAsync(&AsyncCompileJob::ExecuteCompilationUnits, &(task_ids_.get())[i]);
}
deferred_handles_.push_back(deferred.Detach());
return true;
}
//==========================================================================
// Step 3 (async x K tasks): Execute compilation units.
//==========================================================================
bool ExecuteCompilationUnits() {
DisallowHandleAllocation no_handle;
DisallowHeapAllocation no_allocation;
TRACE_COMPILE("(3) Compiling...\n");
while (!failed_ && helper_->FetchAndExecuteCompilationUnit()) {
// TODO(ahaas): Create one FinishCompilationUnit job for all compilation
// units.
DoSync(&AsyncCompileJob::FinishCompilationUnit);
// TODO(ahaas): Limit the number of outstanding compilation units to be
// finished to reduce memory overhead.
}
helper_->module_->pending_tasks.get()->Signal();
return true;
}
//==========================================================================
// Step 4 (sync x each function): Finish a single compilation unit.
//==========================================================================
bool FinishCompilationUnit() {
TRACE_COMPILE("(4a) Finishing compilation unit...\n");
HandleScope scope(isolate_);
if (failed_) return true; // already failed
int func_index = 0;
ErrorThrower thrower(isolate_, nullptr);
MaybeHandle<Code> result =
helper_->FinishCompilationUnit(&thrower, &func_index);
if (thrower.error()) {
RejectPromise(isolate_, context_, &thrower, module_promise_);
failed_ = true;
} else {
code_table_->set(func_index + module_->num_imported_functions,
*(result.ToHandleChecked()));
}
if (failed_ || --outstanding_units_ == 0) {
// All compilation units are done. We still need to wait for the
// background tasks to shut down and only then is it safe to finish the
// compile and delete this job. We can wait for that to happen also
// in a background task.
DoAsync(&AsyncCompileJob::WaitForBackgroundTasks);
}
return true;
}
//==========================================================================
// Step 4b (async): Wait for all background tasks to finish.
//==========================================================================
bool WaitForBackgroundTasks() {
DisallowHandleAllocation no_handle;
DisallowHeapAllocation no_allocation;
TRACE_COMPILE("(4b) Waiting for background tasks...\n");
for (size_t i = 0; i < num_background_tasks_; ++i) {
// If the task has not started yet, then we abort it. Otherwise we wait
// for it to finish.
if (isolate_->cancelable_task_manager()->TryAbort(task_ids_.get()[i]) !=
CancelableTaskManager::kTaskAborted) {
module_->pending_tasks.get()->Wait();
}
}
if (failed_) {
// If {failed_}, we've already rejected the promise and there
// is nothing more to do.
return false;
} else {
// Otherwise, post a synchronous task to finish the compile.
DoSync(&AsyncCompileJob::FinishCompile);
return true;
}
}
//==========================================================================
// Step 5 (sync): Finish heap-allocated data structures.
//==========================================================================
bool FinishCompile() {
TRACE_COMPILE("(5) Finish compile...\n");
HandleScope scope(isolate_);
// At this point, compilation has completed. Update the code table.
for (size_t i = FLAG_skip_compiling_wasm_funcs;
i < temp_instance_->function_code.size(); ++i) {
Code* code = Code::cast(code_table_->get(static_cast<int>(i)));
RecordStats(isolate_, code);
}
// Create heap objects for script and module bytes to be stored in the
// shared module data. Asm.js is not compiled asynchronously.
Handle<Script> script = CreateWasmScript(isolate_, wire_bytes_);
Handle<ByteArray> asm_js_offset_table;
// TODO(wasm): Improve efficiency of storing module wire bytes.
// 1. Only store relevant sections, not function bodies
// 2. Don't make a second copy of the bytes here; reuse the copy made
// for asynchronous compilation and store it as an external one
// byte string for serialization/deserialization.
Handle<String> module_bytes =
isolate_->factory()
->NewStringFromOneByte({wire_bytes_.start(), wire_bytes_.length()},
TENURED)
.ToHandleChecked();
DCHECK(module_bytes->IsSeqOneByteString());
// Create the shared module data.
// TODO(clemensh): For the same module (same bytes / same hash), we should
// only have one WasmSharedModuleData. Otherwise, we might only set
// breakpoints on a (potentially empty) subset of the instances.
Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
isolate_, module_wrapper_, Handle<SeqOneByteString>::cast(module_bytes),
script, asm_js_offset_table);
DeferredHandleScope deferred(isolate_);
// Create the compiled module object and populate with compiled functions
// and information needed at instantiation time. This object needs to be
// serializable. Instantiation may occur off a deserialized version of this
// object.
compiled_module_ = WasmCompiledModule::New(isolate_, shared);
compiled_module_->set_num_imported_functions(
module_->num_imported_functions);
compiled_module_->set_code_table(code_table_);
compiled_module_->set_min_mem_pages(module_->min_mem_pages);
compiled_module_->set_max_mem_pages(module_->max_mem_pages);
if (!module_->function_tables.empty()) {
compiled_module_->set_function_tables(function_tables_);
compiled_module_->set_signature_tables(signature_tables_);
compiled_module_->set_empty_function_tables(function_tables_);
}
// Finish the WASM script now and make it public to the debugger.
script->set_wasm_compiled_module(*compiled_module_);
isolate_->debug()->OnAfterCompile(script);
deferred_handles_.push_back(deferred.Detach());
// TODO(wasm): compiling wrappers should be made async as well.
return DoSync(&AsyncCompileJob::CompileWrappers);
}
//==========================================================================
// Step 6 (sync): Compile JS->WASM wrappers.
//==========================================================================
bool CompileWrappers() {
TRACE_COMPILE("(6) Compile wrappers...\n");
// Compile JS->WASM wrappers for exported functions.
HandleScope scope(isolate_);
JSToWasmWrapperCache js_to_wasm_cache;
int func_index = 0;
for (auto exp : module_->export_table) {
if (exp.kind != kExternalFunction) continue;
Handle<Code> wasm_code(Code::cast(code_table_->get(exp.index)), isolate_);
Handle<Code> wrapper_code =
js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(isolate_, module_,
wasm_code, exp.index);
int export_index =
static_cast<int>(module_->functions.size() + func_index);
code_table_->set(export_index, *wrapper_code);
RecordStats(isolate_, *wrapper_code);
func_index++;
}
return DoSync(&AsyncCompileJob::FinishModule);
}
//==========================================================================
// Step 7 (sync): Finish the module and resolve the promise.
//==========================================================================
bool FinishModule() {
TRACE_COMPILE("(7) Finish module...\n");
HandleScope scope(isolate_);
Handle<WasmModuleObject> result =
WasmModuleObject::New(isolate_, compiled_module_);
ResolvePromise(isolate_, context_, module_promise_, result);
return false; // no more work to do.
}
// Run the given member method as an asynchronous task.
bool DoAsync(bool (AsyncCompileJob::*func)(), uint32_t* task_id = nullptr) {
auto task = new Task(this, func);
if (task_id) *task_id = task->id();
V8::GetCurrentPlatform()->CallOnBackgroundThread(
task, v8::Platform::kShortRunningTask);
return true; // more work to do.
}
// Run the given member method as a synchronous task.
bool DoSync(bool (AsyncCompileJob::*func)()) {
V8::GetCurrentPlatform()->CallOnForegroundThread(
reinterpret_cast<v8::Isolate*>(isolate_), new Task(this, func));
return true; // more work to do.
}
// A helper closure to run a particular member method as a task.
class Task : public CancelableTask {
public:
AsyncCompileJob* job_;
bool (AsyncCompileJob::*func_)();
explicit Task(AsyncCompileJob* job, bool (AsyncCompileJob::*func)())
: CancelableTask(job->isolate_), job_(job), func_(func) {}
void RunInternal() override {
bool more = (job_->*func_)(); // run the task.
if (!more) delete job_; // if no more work, then this job is done.
}
};
};
void wasm::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise,
const ModuleWireBytes& bytes) {
// Make a copy of the wire bytes in case the user program changes them
// during asynchronous compilation.
std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
memcpy(copy.get(), bytes.start(), bytes.length());
auto job = new AsyncCompileJob(isolate, std::move(copy), bytes.length(),
handle(isolate->context()), promise);
job->Start();
} }
Handle<Code> wasm::CompileLazy(Isolate* isolate) { Handle<Code> wasm::CompileLazy(Isolate* isolate) {
......
...@@ -250,6 +250,7 @@ var failWithMessage; ...@@ -250,6 +250,7 @@ var failWithMessage;
failWithMessage = function failWithMessage(message) { failWithMessage = function failWithMessage(message) {
print("oh, we failed: " + message);
throw new MjsUnitAssertionError(message); throw new MjsUnitAssertionError(message);
} }
......
// 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.
// Flags: --expose-wasm --allow-natives-syntax
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
let ok_buffer = (() => {
var builder = new WasmModuleBuilder();
builder.addFunction("f", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportAs("f");
return builder.toBuffer();
})();
// The OK buffer validates and can be made into a module.
assertTrue(WebAssembly.validate(ok_buffer));
let ok_module = new WebAssembly.Module(ok_buffer);
assertTrue(ok_module instanceof WebAssembly.Module);
// The bad buffer does not validate and cannot be made into a module.
let bad_buffer = new ArrayBuffer(0);
assertFalse(WebAssembly.validate(bad_buffer));
assertThrows(() => new WebAssembly.Module(bad_buffer), WebAssembly.CompileError);
function checkModule(module) {
assertTrue(module instanceof WebAssembly.Module);
}
function checkCompileError(ex) {
assertTrue(ex instanceof WebAssembly.CompileError);
}
let kNumCompiles = 3;
// Three compilations of the OK module should succeed.
for (var i = 0; i < kNumCompiles; i++) {
assertPromiseResult(WebAssembly.compile(ok_buffer), checkModule,
(ex) => assertUnreachable);
}
// Three compilations of the bad module should fail.
for (var i = 0; i < kNumCompiles; i++) {
assertPromiseResult(WebAssembly.compile(bad_buffer),
(module) => assertUnreachable,
checkCompileError);
}
// 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.
// Flags: --allow-natives-syntax --validate-asm
// Compilation limits for WASM are not enforced for asm->wasm.
%SetWasmCompileControls(0, false);
function AsmModule() {
"use asm";
function xxx() { return 43; }
function yyy() { return 43; }
function zzz() { return 43; }
function main() { return 43; }
return {main: main};
}
assertEquals(43, AsmModule(
undefined, undefined, new ArrayBuffer(1024)).main());
assertTrue(%IsAsmWasmCode(AsmModule));
// 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.
// Flags: --allow-natives-syntax
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
%SetWasmCompileControls(100000, true);
%SetWasmCompileControls(100000, false);
let buffer = (() => {
let builder = new WasmModuleBuilder();
builder.addFunction("f", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportAs("f");
return builder.toBuffer();
})();
let ok_module = new WebAssembly.Module(buffer);
assertTrue(ok_module instanceof WebAssembly.Module);
assertEquals(42, new WebAssembly.Instance(ok_module).exports.f());
failWithMessage = msg => %AbortJS(msg);
async function SuccessfulTest() {
print("SuccessfulTest...");
%SetWasmCompileControls(buffer.byteLength, true);
%SetWasmInstantiateControls();
let m = new WebAssembly.Module(buffer);
let i = new WebAssembly.Instance(m);
assertEquals(i.exports.f(), 42);
}
async function FailSyncCompile() {
print("FailSyncCompile...");
%SetWasmCompileControls(buffer.byteLength - 1, true);
assertThrows(() => new WebAssembly.Module(buffer), RangeError);
print(" wait");
try {
let m = await WebAssembly.compile(buffer);
print(" cont");
assertTrue(m instanceof WebAssembly.Module);
} catch (e) {
print(" catch");
assertUnreachable();
}
}
async function FailSyncInstantiate() {
print("FailSyncInstantiate...");
%SetWasmCompileControls(buffer.byteLength - 1, true);
assertThrows(() => new WebAssembly.Instance(ok_module), RangeError);
print(" wait");
try {
let i = await WebAssembly.instantiate(ok_module);
print(" cont");
assertTrue(i instanceof WebAssembly.Instance);
} catch (e) {
print(" catch: " + e);
assertUnreachable();
}
}
async function FailAsyncCompile() {
print("FailAsyncCompile...");
%SetWasmCompileControls(buffer.byteLength - 1, false);
assertThrows(() => new WebAssembly.Module(buffer), RangeError);
print(" wait");
try {
let m = await WebAssembly.compile(buffer);
print(" cont");
assertUnreachable();
} catch (e) {
print(" catch: " + e);
assertTrue(e instanceof RangeError);
}
}
async function FailAsyncInstantiate() {
print("FailAsyncInstantiate...");
%SetWasmCompileControls(buffer.byteLength - 1, false);
assertThrows(() => new WebAssembly.Instance(buffer), RangeError);
print(" wait");
try {
let m = await WebAssembly.instantiate(buffer);
print(" cont");
assertUnreachable();
} catch (e) {
print(" catch: " + e);
assertTrue(e instanceof RangeError);
}
}
async function TestAll() {
await SuccessfulTest();
await FailSyncCompile();
await FailSyncInstantiate();
await FailAsyncCompile();
await FailAsyncInstantiate();
}
%IncrementWaitCount();
TestAll().then(
() => { %DecrementWaitCount(); },
() => { %DecrementWaitCount(); }
);
...@@ -2,28 +2,28 @@ ...@@ -2,28 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --expose-wasm --allow-natives-syntax // Flags: --expose-wasm
load('test/mjsunit/wasm/wasm-constants.js'); load("test/mjsunit/wasm/wasm-constants.js");
load('test/mjsunit/wasm/wasm-module-builder.js'); load("test/mjsunit/wasm/wasm-module-builder.js");
let kReturnValue = 17; let kReturnValue = 17;
let buffer = (() => { let buffer = (() => {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true); builder.addMemory(1, 1, true);
builder.addFunction('main', kSig_i_v) builder.addFunction("main", kSig_i_v)
.addBody([kExprI32Const, kReturnValue]) .addBody([kExprI32Const, kReturnValue])
.exportFunc(); .exportFunc();
return builder.toBuffer(); return builder.toBuffer();
})(); })()
function CheckInstance(instance) { function CheckInstance(instance) {
assertFalse(instance === undefined); assertFalse(instance === undefined);
assertFalse(instance === null); assertFalse(instance === null);
assertFalse(instance === 0); assertFalse(instance === 0);
assertEquals('object', typeof instance); assertEquals("object", typeof instance);
// Check the exports object is frozen. // Check the exports object is frozen.
assertFalse(Object.isExtensible(instance.exports)); assertFalse(Object.isExtensible(instance.exports));
...@@ -34,14 +34,14 @@ function CheckInstance(instance) { ...@@ -34,14 +34,14 @@ function CheckInstance(instance) {
assertFalse(mem === undefined); assertFalse(mem === undefined);
assertFalse(mem === null); assertFalse(mem === null);
assertFalse(mem === 0); assertFalse(mem === 0);
assertEquals('object', typeof mem); assertEquals("object", typeof mem);
assertTrue(mem instanceof WebAssembly.Memory); assertTrue(mem instanceof WebAssembly.Memory);
var buf = mem.buffer; var buf = mem.buffer;
assertTrue(buf instanceof ArrayBuffer); assertTrue(buf instanceof ArrayBuffer);
assertEquals(65536, buf.byteLength); assertEquals(65536, buf.byteLength);
for (var i = 0; i < 4; i++) { for (var i = 0; i < 4; i++) {
instance.exports.memory = 0; // should be ignored instance.exports.memory = 0; // should be ignored
mem.buffer = 0; // should be ignored mem.buffer = 0; // should be ignored
assertSame(mem, instance.exports.memory); assertSame(mem, instance.exports.memory);
assertSame(buf, mem.buffer); assertSame(buf, mem.buffer);
} }
...@@ -51,26 +51,25 @@ function CheckInstance(instance) { ...@@ -51,26 +51,25 @@ function CheckInstance(instance) {
assertFalse(main === undefined); assertFalse(main === undefined);
assertFalse(main === null); assertFalse(main === null);
assertFalse(main === 0); assertFalse(main === 0);
assertEquals('function', typeof main); assertEquals("function", typeof main);
assertEquals(kReturnValue, main()); assertEquals(kReturnValue, main());
} }
// Official API // Official API
(function BasicJSAPITest() { (function BasicJSAPITest() {
print('sync module compile...'); print("sync module compile...");
let module = new WebAssembly.Module(buffer); let module = new WebAssembly.Module(buffer);
print('sync module instantiate...'); print("sync module instantiate...");
CheckInstance(new WebAssembly.Instance(module)); CheckInstance(new WebAssembly.Instance(module));
print('async module compile...'); print("async module compile...");
let promise = WebAssembly.compile(buffer); let promise = WebAssembly.compile(buffer);
assertPromiseResult( promise.then(module => CheckInstance(new WebAssembly.Instance(module)));
promise, module => CheckInstance(new WebAssembly.Instance(module)));
print('async instantiate...'); print("async instantiate...");
let instance_promise = WebAssembly.instantiate(buffer); let instance_promise = WebAssembly.instantiate(buffer);
assertPromiseResult(instance_promise, CheckInstance); instance_promise.then(CheckInstance);
})(); })();
// Check that validate works correctly for a module. // Check that validate works correctly for a module.
...@@ -79,34 +78,35 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -79,34 +78,35 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
// Negative tests. // Negative tests.
(function InvalidModules() { (function InvalidModules() {
print('InvalidModules...'); print("InvalidModules...");
let invalid_cases = [undefined, 1, '', 'a', {some: 1, obj: 'b'}]; let invalid_cases = [undefined, 1, "", "a", {some:1, obj: "b"}];
let len = invalid_cases.length; let len = invalid_cases.length;
for (var i = 0; i < len; ++i) { for (var i = 0; i < len; ++i) {
try { try {
let instance = new WebAssembly.Instance(invalid_cases[i]); let instance = new WebAssembly.Instance(invalid_cases[i]);
assertUnreachable('should not be able to instantiate invalid modules.'); assertUnreachable("should not be able to instantiate invalid modules.");
} catch (e) { } catch (e) {
assertContains('Argument 0', e.toString()); assertContains("Argument 0", e.toString());
} }
} }
})(); })();
// Compile async an invalid blob. // Compile async an invalid blob.
(function InvalidBinaryAsyncCompilation() { (function InvalidBinaryAsyncCompilation() {
print('InvalidBinaryAsyncCompilation...'); print("InvalidBinaryAsyncCompilation...");
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addFunction('f', kSig_i_i).addBody([kExprCallFunction, 0]); builder.addFunction("f", kSig_i_i)
.addBody([kExprCallFunction, 0]);
let promise = WebAssembly.compile(builder.toBuffer()); let promise = WebAssembly.compile(builder.toBuffer());
assertPromiseResult( promise
promise, compiled => assertUnreachable( .then(compiled =>
'should not be able to compile invalid blob.'), assertUnreachable("should not be able to compile invalid blob."))
e => assertInstanceof(e, WebAssembly.CompileError)); .catch(e => assertContains("invalid signature index", e.toString()));
})(); })();
// Multiple instances tests. // Multiple instances tests.
(function ManyInstances() { (function ManyInstances() {
print('ManyInstances...'); print("ManyInstances...");
let compiled_module = new WebAssembly.Module(buffer); let compiled_module = new WebAssembly.Module(buffer);
let instance_1 = new WebAssembly.Instance(compiled_module); let instance_1 = new WebAssembly.Instance(compiled_module);
let instance_2 = new WebAssembly.Instance(compiled_module); let instance_2 = new WebAssembly.Instance(compiled_module);
...@@ -114,9 +114,9 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -114,9 +114,9 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
})(); })();
(function ManyInstancesAsync() { (function ManyInstancesAsync() {
print('ManyInstancesAsync...'); print("ManyInstancesAsync...");
let promise = WebAssembly.compile(buffer); let promise = WebAssembly.compile(buffer);
assertPromiseResult(promise, compiled_module => { promise.then(compiled_module => {
let instance_1 = new WebAssembly.Instance(compiled_module); let instance_1 = new WebAssembly.Instance(compiled_module);
let instance_2 = new WebAssembly.Instance(compiled_module); let instance_2 = new WebAssembly.Instance(compiled_module);
assertTrue(instance_1 != instance_2); assertTrue(instance_1 != instance_2);
...@@ -124,29 +124,35 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -124,29 +124,35 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
})(); })();
(function InstancesAreIsolatedFromEachother() { (function InstancesAreIsolatedFromEachother() {
print('InstancesAreIsolatedFromEachother...'); print("InstancesAreIsolatedFromEachother...");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory', 1); builder.addImportedMemory("", "memory", 1);
var kSig_v_i = makeSig([kWasmI32], []); var kSig_v_i = makeSig([kWasmI32], []);
var signature = builder.addType(kSig_v_i); var signature = builder.addType(kSig_v_i);
builder.addImport('m', 'some_value', kSig_i_v); builder.addImport("m", "some_value", kSig_i_v);
builder.addImport('m', 'writer', signature); builder.addImport("m", "writer", signature);
builder.addFunction('main', kSig_i_i) builder.addFunction("main", kSig_i_i)
.addBody([ .addBody([
kExprGetLocal, 0, kExprI32LoadMem, 0, 0, kExprI32Const, 1, kExprGetLocal, 0,
kExprCallIndirect, signature, kTableZero, kExprGetLocal, 0, kExprI32LoadMem, 0, 0,
kExprI32LoadMem, 0, 0, kExprCallFunction, 0, kExprI32Add kExprI32Const, 1,
]) kExprCallIndirect, signature, kTableZero,
.exportFunc(); kExprGetLocal,0,
kExprI32LoadMem,0, 0,
kExprCallFunction, 0,
kExprI32Add
]).exportFunc();
// writer(mem[i]); // writer(mem[i]);
// return mem[i] + some_value(); // return mem[i] + some_value();
builder.addFunction('_wrap_writer', signature).addBody([ builder.addFunction("_wrap_writer", signature)
kExprGetLocal, 0, kExprCallFunction, 1 .addBody([
]); kExprGetLocal, 0,
kExprCallFunction, 1]);
builder.appendToTable([2, 3]); builder.appendToTable([2, 3]);
var module = new WebAssembly.Module(builder.toBuffer()); var module = new WebAssembly.Module(builder.toBuffer());
var mem_1 = new WebAssembly.Memory({initial: 1}); var mem_1 = new WebAssembly.Memory({initial: 1});
var mem_2 = new WebAssembly.Memory({initial: 1}); var mem_2 = new WebAssembly.Memory({initial: 1});
...@@ -158,15 +164,13 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -158,15 +164,13 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
var outval_1; var outval_1;
var outval_2; var outval_2;
var i1 = new WebAssembly.Instance(module, { var i1 = new WebAssembly.Instance(module, {m: {some_value: () => 1,
m: {some_value: () => 1, writer: (x) => outval_1 = x}, writer: (x)=>outval_1 = x },
'': {memory: mem_1} "": {memory: mem_1}});
});
var i2 = new WebAssembly.Instance(module, { var i2 = new WebAssembly.Instance(module, {m: {some_value: () => 2,
m: {some_value: () => 2, writer: (x) => outval_2 = x}, writer: (x)=>outval_2 = x },
'': {memory: mem_2} "": {memory: mem_2}});
});
assertEquals(43, i1.exports.main(0)); assertEquals(43, i1.exports.main(0));
assertEquals(1002, i2.exports.main(0)); assertEquals(1002, i2.exports.main(0));
...@@ -176,34 +180,40 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -176,34 +180,40 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
})(); })();
(function GlobalsArePrivateToTheInstance() { (function GlobalsArePrivateToTheInstance() {
print('GlobalsArePrivateToTheInstance...'); print("GlobalsArePrivateToTheInstance...");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addGlobal(kWasmI32, true); builder.addGlobal(kWasmI32, true);
builder.addFunction('read', kSig_i_v) builder.addFunction("read", kSig_i_v)
.addBody([kExprGetGlobal, 0]) .addBody([
.exportFunc(); kExprGetGlobal, 0])
.exportFunc();
builder.addFunction('write', kSig_v_i)
.addBody([kExprGetLocal, 0, kExprSetGlobal, 0]) builder.addFunction("write", kSig_v_i)
.exportFunc(); .addBody([
kExprGetLocal, 0,
var module = new WebAssembly.Module(builder.toBuffer()); kExprSetGlobal, 0])
var i1 = new WebAssembly.Instance(module); .exportFunc();
var i2 = new WebAssembly.Instance(module);
i1.exports.write(1); var module = new WebAssembly.Module(builder.toBuffer());
i2.exports.write(2); var i1 = new WebAssembly.Instance(module);
assertEquals(1, i1.exports.read()); var i2 = new WebAssembly.Instance(module);
assertEquals(2, i2.exports.read()); i1.exports.write(1);
i2.exports.write(2);
assertEquals(1, i1.exports.read());
assertEquals(2, i2.exports.read());
})(); })();
(function InstanceMemoryIsIsolated() { (function InstanceMemoryIsIsolated() {
print('InstanceMemoryIsIsolated...'); print("InstanceMemoryIsIsolated...");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory', 1); builder.addImportedMemory("", "memory", 1);
builder.addFunction('f', kSig_i_v) builder.addFunction("f", kSig_i_v)
.addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0]) .addBody([
.exportFunc(); kExprI32Const, 0,
kExprI32LoadMem, 0, 0
]).exportFunc();
var mem_1 = new WebAssembly.Memory({initial: 1}); var mem_1 = new WebAssembly.Memory({initial: 1});
var mem_2 = new WebAssembly.Memory({initial: 1}); var mem_2 = new WebAssembly.Memory({initial: 1});
...@@ -213,24 +223,23 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -213,24 +223,23 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
view_2[0] = 1000; view_2[0] = 1000;
var module = new WebAssembly.Module(builder.toBuffer()); var module = new WebAssembly.Module(builder.toBuffer());
var i1 = new WebAssembly.Instance(module, {'': {memory: mem_1}}); var i1 = new WebAssembly.Instance(module, {"":{memory:mem_1}});
var i2 = new WebAssembly.Instance(module, {'': {memory: mem_2}}); var i2 = new WebAssembly.Instance(module, {"":{memory:mem_2}});
assertEquals(1, i1.exports.f()); assertEquals(1, i1.exports.f());
assertEquals(1000, i2.exports.f()); assertEquals(1000, i2.exports.f());
})(); })();
(function MustBeMemory() { (function MustBeMemory() {
print('MustBeMemory...'); print("MustBeMemory...");
var memory = new ArrayBuffer(65536); var memory = new ArrayBuffer(65536);
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory'); builder.addImportedMemory("", "memory");
let module = new WebAssembly.Module(builder.toBuffer()); let module = new WebAssembly.Module(builder.toBuffer());
assertThrows(
() => new WebAssembly.Instance(module, {'': {memory: memory}}), assertThrows(() => new WebAssembly.Instance(module, {"":{memory:memory}}), WebAssembly.LinkError);
WebAssembly.LinkError);
})(); })();
(function TestNoMemoryToExport() { (function TestNoMemoryToExport() {
...@@ -240,13 +249,13 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -240,13 +249,13 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
})(); })();
(function TestIterableExports() { (function TestIterableExports() {
print('TestIterableExports...'); print("TestIterableExports...");
let builder = new WasmModuleBuilder; let builder = new WasmModuleBuilder;
builder.addExport('a', builder.addFunction('', kSig_v_v).addBody([])); builder.addExport("a", builder.addFunction("", kSig_v_v).addBody([]));
builder.addExport('b', builder.addFunction('', kSig_v_v).addBody([])); builder.addExport("b", builder.addFunction("", kSig_v_v).addBody([]));
builder.addExport('c', builder.addFunction('', kSig_v_v).addBody([])); builder.addExport("c", builder.addFunction("", kSig_v_v).addBody([]));
builder.addExport('d', builder.addFunction('', kSig_v_v).addBody([])); builder.addExport("d", builder.addFunction("", kSig_v_v).addBody([]));
builder.addExport('e', builder.addGlobal(kWasmI32, false)); builder.addExport("e", builder.addGlobal(kWasmI32, false));
let module = new WebAssembly.Module(builder.toBuffer()); let module = new WebAssembly.Module(builder.toBuffer());
let instance = new WebAssembly.Instance(module); let instance = new WebAssembly.Instance(module);
......
...@@ -4,16 +4,12 @@ ...@@ -4,16 +4,12 @@
// Flags: --expose-wasm --allow-natives-syntax // Flags: --expose-wasm --allow-natives-syntax
load('test/mjsunit/wasm/wasm-constants.js'); if ((typeof drainJobQueue) != "function") {
load('test/mjsunit/wasm/wasm-module-builder.js'); drainJobQueue = () => { %RunMicrotasks() };
function unexpectedSuccess() {
% AbortJS('unexpected success');
} }
function unexpectedFail(error) { load("test/mjsunit/wasm/wasm-constants.js");
% AbortJS('unexpected fail: ' + error); load("test/mjsunit/wasm/wasm-module-builder.js");
}
function assertEq(val, expected) { function assertEq(val, expected) {
assertEquals(expected, val); assertEquals(expected, val);
...@@ -27,10 +23,10 @@ function assertArrayBuffer(val, expected) { ...@@ -27,10 +23,10 @@ function assertArrayBuffer(val, expected) {
} }
} }
function wasmIsSupported() { function wasmIsSupported() {
return (typeof WebAssembly.Module) == 'function'; return (typeof WebAssembly.Module) == "function";
} }
function assertErrorMessage(func, type, msg) { function assertErrorMessage(func, type, msg) {
// TODO assertThrows(func, type, msg); //TODO assertThrows(func, type, msg);
assertThrows(func, type); assertThrows(func, type);
} }
...@@ -41,103 +37,103 @@ let emptyModuleBinary = (() => { ...@@ -41,103 +37,103 @@ let emptyModuleBinary = (() => {
let exportingModuleBinary = (() => { let exportingModuleBinary = (() => {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addFunction('f', kSig_i_v).addBody([kExprI32Const, 42]).exportAs('f'); builder.addFunction("f", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportAs("f");
return new Int8Array(builder.toBuffer()); return new Int8Array(builder.toBuffer());
})(); })();
let importingModuleBinary = (() => { let importingModuleBinary = (() => {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImport('', 'f', kSig_i_v); builder.addImport("", "f", kSig_i_v);
return new Int8Array(builder.toBuffer()); return new Int8Array(builder.toBuffer());
})(); })();
let memoryImportingModuleBinary = (() => { let memoryImportingModuleBinary = (() => {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'my_memory'); builder.addImportedMemory("", "my_memory");
return new Int8Array(builder.toBuffer()); return new Int8Array(builder.toBuffer());
})(); })();
let moduleBinaryImporting2Memories = (() => { let moduleBinaryImporting2Memories = (() => {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory1'); builder.addImportedMemory("", "memory1");
builder.addImportedMemory('', 'memory2'); builder.addImportedMemory("", "memory2");
return new Int8Array(builder.toBuffer()); return new Int8Array(builder.toBuffer());
})(); })();
let moduleBinaryWithMemSectionAndMemImport = (() => { let moduleBinaryWithMemSectionAndMemImport = (() => {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, false); builder.addMemory(1, 1, false);
builder.addImportedMemory('', 'memory1'); builder.addImportedMemory("", "memory1");
return new Int8Array(builder.toBuffer()); return new Int8Array(builder.toBuffer());
})(); })();
// 'WebAssembly' data property on global object // 'WebAssembly' data property on global object
let wasmDesc = Object.getOwnPropertyDescriptor(this, 'WebAssembly'); let wasmDesc = Object.getOwnPropertyDescriptor(this, 'WebAssembly');
assertEq(typeof wasmDesc.value, 'object'); assertEq(typeof wasmDesc.value, "object");
assertTrue(wasmDesc.writable); assertTrue(wasmDesc.writable);
assertFalse(wasmDesc.enumerable); assertFalse(wasmDesc.enumerable);
assertTrue(wasmDesc.configurable); assertTrue(wasmDesc.configurable);
// 'WebAssembly' object // 'WebAssembly' object
assertEq(WebAssembly, wasmDesc.value); assertEq(WebAssembly, wasmDesc.value);
assertEq(String(WebAssembly), '[object WebAssembly]'); assertEq(String(WebAssembly), "[object WebAssembly]");
// 'WebAssembly.CompileError' // 'WebAssembly.CompileError'
let compileErrorDesc = let compileErrorDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'CompileError');
Object.getOwnPropertyDescriptor(WebAssembly, 'CompileError'); assertEq(typeof compileErrorDesc.value, "function");
assertEq(typeof compileErrorDesc.value, 'function');
assertTrue(compileErrorDesc.writable); assertTrue(compileErrorDesc.writable);
assertFalse(compileErrorDesc.enumerable); assertFalse(compileErrorDesc.enumerable);
assertTrue(compileErrorDesc.configurable); assertTrue(compileErrorDesc.configurable);
let CompileError = WebAssembly.CompileError; let CompileError = WebAssembly.CompileError;
assertEq(CompileError, compileErrorDesc.value); assertEq(CompileError, compileErrorDesc.value);
assertEq(CompileError.length, 1); assertEq(CompileError.length, 1);
assertEq(CompileError.name, 'CompileError'); assertEq(CompileError.name, "CompileError");
let compileError = new CompileError; let compileError = new CompileError;
assertTrue(compileError instanceof CompileError); assertTrue(compileError instanceof CompileError);
assertTrue(compileError instanceof Error); assertTrue(compileError instanceof Error);
assertFalse(compileError instanceof TypeError); assertFalse(compileError instanceof TypeError);
assertEq(compileError.message, ''); assertEq(compileError.message, "");
assertEq(new CompileError('hi').message, 'hi'); assertEq(new CompileError("hi").message, "hi");
// 'WebAssembly.RuntimeError' // 'WebAssembly.RuntimeError'
let runtimeErrorDesc = let runtimeErrorDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'RuntimeError');
Object.getOwnPropertyDescriptor(WebAssembly, 'RuntimeError'); assertEq(typeof runtimeErrorDesc.value, "function");
assertEq(typeof runtimeErrorDesc.value, 'function');
assertTrue(runtimeErrorDesc.writable); assertTrue(runtimeErrorDesc.writable);
assertFalse(runtimeErrorDesc.enumerable); assertFalse(runtimeErrorDesc.enumerable);
assertTrue(runtimeErrorDesc.configurable); assertTrue(runtimeErrorDesc.configurable);
let RuntimeError = WebAssembly.RuntimeError; let RuntimeError = WebAssembly.RuntimeError;
assertEq(RuntimeError, runtimeErrorDesc.value); assertEq(RuntimeError, runtimeErrorDesc.value);
assertEq(RuntimeError.length, 1); assertEq(RuntimeError.length, 1);
assertEq(RuntimeError.name, 'RuntimeError'); assertEq(RuntimeError.name, "RuntimeError");
let runtimeError = new RuntimeError; let runtimeError = new RuntimeError;
assertTrue(runtimeError instanceof RuntimeError); assertTrue(runtimeError instanceof RuntimeError);
assertTrue(runtimeError instanceof Error); assertTrue(runtimeError instanceof Error);
assertFalse(runtimeError instanceof TypeError); assertFalse(runtimeError instanceof TypeError);
assertEq(runtimeError.message, ''); assertEq(runtimeError.message, "");
assertEq(new RuntimeError('hi').message, 'hi'); assertEq(new RuntimeError("hi").message, "hi");
// 'WebAssembly.LinkError' // 'WebAssembly.LinkError'
let linkErrorDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'LinkError'); let linkErrorDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'LinkError');
assertEq(typeof linkErrorDesc.value, 'function'); assertEq(typeof linkErrorDesc.value, "function");
assertTrue(linkErrorDesc.writable); assertTrue(linkErrorDesc.writable);
assertFalse(linkErrorDesc.enumerable); assertFalse(linkErrorDesc.enumerable);
assertTrue(linkErrorDesc.configurable); assertTrue(linkErrorDesc.configurable);
let LinkError = WebAssembly.LinkError; let LinkError = WebAssembly.LinkError;
assertEq(LinkError, linkErrorDesc.value); assertEq(LinkError, linkErrorDesc.value);
assertEq(LinkError.length, 1); assertEq(LinkError.length, 1);
assertEq(LinkError.name, 'LinkError'); assertEq(LinkError.name, "LinkError");
let linkError = new LinkError; let linkError = new LinkError;
assertTrue(linkError instanceof LinkError); assertTrue(linkError instanceof LinkError);
assertTrue(linkError instanceof Error); assertTrue(linkError instanceof Error);
assertFalse(linkError instanceof TypeError); assertFalse(linkError instanceof TypeError);
assertEq(linkError.message, ''); assertEq(linkError.message, "");
assertEq(new LinkError('hi').message, 'hi'); assertEq(new LinkError("hi").message, "hi");
// 'WebAssembly.Module' data property // 'WebAssembly.Module' data property
let moduleDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Module'); let moduleDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Module');
assertEq(typeof moduleDesc.value, 'function'); assertEq(typeof moduleDesc.value, "function");
assertTrue(moduleDesc.writable); assertTrue(moduleDesc.writable);
assertFalse(moduleDesc.enumerable); assertFalse(moduleDesc.enumerable);
assertTrue(moduleDesc.configurable); assertTrue(moduleDesc.configurable);
...@@ -146,32 +142,20 @@ assertTrue(moduleDesc.configurable); ...@@ -146,32 +142,20 @@ assertTrue(moduleDesc.configurable);
let Module = WebAssembly.Module; let Module = WebAssembly.Module;
assertEq(Module, moduleDesc.value); assertEq(Module, moduleDesc.value);
assertEq(Module.length, 1); assertEq(Module.length, 1);
assertEq(Module.name, 'Module'); assertEq(Module.name, "Module");
assertErrorMessage( assertErrorMessage(() => Module(), TypeError, /constructor without new is forbidden/);
() => Module(), TypeError, /constructor without new is forbidden/); assertErrorMessage(() => new Module(), TypeError, /requires more than 0 arguments/);
assertErrorMessage( assertErrorMessage(() => new Module(undefined), TypeError, "first argument must be an ArrayBuffer or typed array object");
() => new Module(), TypeError, /requires more than 0 arguments/); assertErrorMessage(() => new Module(1), TypeError, "first argument must be an ArrayBuffer or typed array object");
assertErrorMessage( assertErrorMessage(() => new Module({}), TypeError, "first argument must be an ArrayBuffer or typed array object");
() => new Module(undefined), TypeError, assertErrorMessage(() => new Module(new Uint8Array()), CompileError, /failed to match magic number/);
'first argument must be an ArrayBuffer or typed array object'); assertErrorMessage(() => new Module(new ArrayBuffer()), CompileError, /failed to match magic number/);
assertErrorMessage(
() => new Module(1), TypeError,
'first argument must be an ArrayBuffer or typed array object');
assertErrorMessage(
() => new Module({}), TypeError,
'first argument must be an ArrayBuffer or typed array object');
assertErrorMessage(
() => new Module(new Uint8Array()), CompileError,
/failed to match magic number/);
assertErrorMessage(
() => new Module(new ArrayBuffer()), CompileError,
/failed to match magic number/);
assertTrue(new Module(emptyModuleBinary) instanceof Module); assertTrue(new Module(emptyModuleBinary) instanceof Module);
assertTrue(new Module(emptyModuleBinary.buffer) instanceof Module); assertTrue(new Module(emptyModuleBinary.buffer) instanceof Module);
// 'WebAssembly.Module.prototype' data property // 'WebAssembly.Module.prototype' data property
let moduleProtoDesc = Object.getOwnPropertyDescriptor(Module, 'prototype'); let moduleProtoDesc = Object.getOwnPropertyDescriptor(Module, 'prototype');
assertEq(typeof moduleProtoDesc.value, 'object'); assertEq(typeof moduleProtoDesc.value, "object");
assertFalse(moduleProtoDesc.writable); assertFalse(moduleProtoDesc.writable);
assertFalse(moduleProtoDesc.enumerable); assertFalse(moduleProtoDesc.enumerable);
assertFalse(moduleProtoDesc.configurable); assertFalse(moduleProtoDesc.configurable);
...@@ -179,20 +163,20 @@ assertFalse(moduleProtoDesc.configurable); ...@@ -179,20 +163,20 @@ assertFalse(moduleProtoDesc.configurable);
// 'WebAssembly.Module.prototype' object // 'WebAssembly.Module.prototype' object
let moduleProto = Module.prototype; let moduleProto = Module.prototype;
assertEq(moduleProto, moduleProtoDesc.value); assertEq(moduleProto, moduleProtoDesc.value);
assertEq(String(moduleProto), '[object WebAssembly.Module]'); assertEq(String(moduleProto), "[object WebAssembly.Module]");
assertEq(Object.getPrototypeOf(moduleProto), Object.prototype); assertEq(Object.getPrototypeOf(moduleProto), Object.prototype);
// 'WebAssembly.Module' instance objects // 'WebAssembly.Module' instance objects
let emptyModule = new Module(emptyModuleBinary); let emptyModule = new Module(emptyModuleBinary);
let importingModule = new Module(importingModuleBinary); let importingModule = new Module(importingModuleBinary);
let exportingModule = new Module(exportingModuleBinary); let exportingModule = new Module(exportingModuleBinary);
assertEq(typeof emptyModule, 'object'); assertEq(typeof emptyModule, "object");
assertEq(String(emptyModule), '[object WebAssembly.Module]'); assertEq(String(emptyModule), "[object WebAssembly.Module]");
assertEq(Object.getPrototypeOf(emptyModule), moduleProto); assertEq(Object.getPrototypeOf(emptyModule), moduleProto);
// 'WebAssembly.Module.imports' data property // 'WebAssembly.Module.imports' data property
let moduleImportsDesc = Object.getOwnPropertyDescriptor(Module, 'imports'); let moduleImportsDesc = Object.getOwnPropertyDescriptor(Module, 'imports');
assertEq(typeof moduleImportsDesc.value, 'function'); assertEq(typeof moduleImportsDesc.value, "function");
assertTrue(moduleImportsDesc.writable); assertTrue(moduleImportsDesc.writable);
assertFalse(moduleImportsDesc.enumerable); assertFalse(moduleImportsDesc.enumerable);
assertTrue(moduleImportsDesc.configurable); assertTrue(moduleImportsDesc.configurable);
...@@ -200,46 +184,40 @@ assertTrue(moduleImportsDesc.configurable); ...@@ -200,46 +184,40 @@ assertTrue(moduleImportsDesc.configurable);
// 'WebAssembly.Module.imports' method // 'WebAssembly.Module.imports' method
let moduleImports = moduleImportsDesc.value; let moduleImports = moduleImportsDesc.value;
assertEq(moduleImports.length, 1); assertEq(moduleImports.length, 1);
assertErrorMessage( assertErrorMessage(() => moduleImports(), TypeError, /requires more than 0 arguments/);
() => moduleImports(), TypeError, /requires more than 0 arguments/); assertErrorMessage(() => moduleImports(undefined), TypeError, /first argument must be a WebAssembly.Module/);
assertErrorMessage( assertErrorMessage(() => moduleImports({}), TypeError, /first argument must be a WebAssembly.Module/);
() => moduleImports(undefined), TypeError,
/first argument must be a WebAssembly.Module/);
assertErrorMessage(
() => moduleImports({}), TypeError,
/first argument must be a WebAssembly.Module/);
var arr = moduleImports(new Module(emptyModuleBinary)); var arr = moduleImports(new Module(emptyModuleBinary));
assertTrue(arr instanceof Array); assertTrue(arr instanceof Array);
assertEq(arr.length, 0); assertEq(arr.length, 0);
let importingModuleBinary2 = (() => { let importingModuleBinary2 = (() => {
var text = var text = '(module (func (import "a" "b")) (memory (import "c" "d") 1) (table (import "e" "f") 1 anyfunc) (global (import "g" "⚡") i32))'
'(module (func (import "a" "b")) (memory (import "c" "d") 1) (table (import "e" "f") 1 anyfunc) (global (import "g" "⚡") i32))'
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addImport('a', 'b', kSig_i_i); builder.addImport("a", "b", kSig_i_i);
builder.addImportedMemory('c', 'd'); builder.addImportedMemory("c", "d");
builder.addImportedTable('e', 'f'); builder.addImportedTable("e", "f");
builder.addImportedGlobal('g', 'x', kWasmI32); builder.addImportedGlobal("g", "x", kWasmI32);
return new Int8Array(builder.toBuffer()); return new Int8Array(builder.toBuffer());
})(); })();
var arr = moduleImports(new Module(importingModuleBinary2)); var arr = moduleImports(new Module(importingModuleBinary2));
assertTrue(arr instanceof Array); assertTrue(arr instanceof Array);
assertEq(arr.length, 4); assertEq(arr.length, 4);
assertEq(arr[0].kind, 'function'); assertEq(arr[0].kind, "function");
assertEq(arr[0].module, 'a'); assertEq(arr[0].module, "a");
assertEq(arr[0].name, 'b'); assertEq(arr[0].name, "b");
assertEq(arr[1].kind, 'memory'); assertEq(arr[1].kind, "memory");
assertEq(arr[1].module, 'c'); assertEq(arr[1].module, "c");
assertEq(arr[1].name, 'd'); assertEq(arr[1].name, "d");
assertEq(arr[2].kind, 'table'); assertEq(arr[2].kind, "table");
assertEq(arr[2].module, 'e'); assertEq(arr[2].module, "e");
assertEq(arr[2].name, 'f'); assertEq(arr[2].name, "f");
assertEq(arr[3].kind, 'global'); assertEq(arr[3].kind, "global");
assertEq(arr[3].module, 'g'); assertEq(arr[3].module, "g");
assertEq(arr[3].name, 'x'); assertEq(arr[3].name, "x");
// 'WebAssembly.Module.exports' data property // 'WebAssembly.Module.exports' data property
let moduleExportsDesc = Object.getOwnPropertyDescriptor(Module, 'exports'); let moduleExportsDesc = Object.getOwnPropertyDescriptor(Module, 'exports');
assertEq(typeof moduleExportsDesc.value, 'function'); assertEq(typeof moduleExportsDesc.value, "function");
assertTrue(moduleExportsDesc.writable); assertTrue(moduleExportsDesc.writable);
assertFalse(moduleExportsDesc.enumerable); assertFalse(moduleExportsDesc.enumerable);
assertTrue(moduleExportsDesc.configurable); assertTrue(moduleExportsDesc.configurable);
...@@ -247,40 +225,38 @@ assertTrue(moduleExportsDesc.configurable); ...@@ -247,40 +225,38 @@ assertTrue(moduleExportsDesc.configurable);
// 'WebAssembly.Module.exports' method // 'WebAssembly.Module.exports' method
let moduleExports = moduleExportsDesc.value; let moduleExports = moduleExportsDesc.value;
assertEq(moduleExports.length, 1); assertEq(moduleExports.length, 1);
assertErrorMessage( assertErrorMessage(() => moduleExports(), TypeError, /requires more than 0 arguments/);
() => moduleExports(), TypeError, /requires more than 0 arguments/); assertErrorMessage(() => moduleExports(undefined), TypeError, /first argument must be a WebAssembly.Module/);
assertErrorMessage( assertErrorMessage(() => moduleExports({}), TypeError, /first argument must be a WebAssembly.Module/);
() => moduleExports(undefined), TypeError,
/first argument must be a WebAssembly.Module/);
assertErrorMessage(
() => moduleExports({}), TypeError,
/first argument must be a WebAssembly.Module/);
var arr = moduleExports(emptyModule); var arr = moduleExports(emptyModule);
assertTrue(arr instanceof Array); assertTrue(arr instanceof Array);
assertEq(arr.length, 0); assertEq(arr.length, 0);
let exportingModuleBinary2 = (() => { let exportingModuleBinary2 = (() => {
var text = var text =
'(module (func (export "a")) (memory (export "b") 1) (table (export "c") 1 anyfunc) (global (export "⚡") i32 (i32.const 0)))'; '(module (func (export "a")) (memory (export "b") 1) (table (export "c") 1 anyfunc) (global (export "⚡") i32 (i32.const 0)))';
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addFunction('foo', kSig_v_v).addBody([]).exportAs('a'); builder.addFunction("foo", kSig_v_v)
.addBody([])
.exportAs("a");
builder.addMemory(1, 1, false); builder.addMemory(1, 1, false);
builder.exportMemoryAs('b'); builder.exportMemoryAs("b");
builder.setFunctionTableLength(1); builder.setFunctionTableLength(1);
builder.addExportOfKind('c', kExternalTable, 0); builder.addExportOfKind("c", kExternalTable, 0);
var o = builder.addGlobal(kWasmI32, false).exportAs('x'); var o = builder.addGlobal(kWasmI32, false)
.exportAs("x");
return new Int8Array(builder.toBuffer()); return new Int8Array(builder.toBuffer());
})(); })();
var arr = moduleExports(new Module(exportingModuleBinary2)); var arr = moduleExports(new Module(exportingModuleBinary2));
assertTrue(arr instanceof Array); assertTrue(arr instanceof Array);
assertEq(arr.length, 4); assertEq(arr.length, 4);
assertEq(arr[0].kind, 'function'); assertEq(arr[0].kind, "function");
assertEq(arr[0].name, 'a'); assertEq(arr[0].name, "a");
assertEq(arr[1].kind, 'memory'); assertEq(arr[1].kind, "memory");
assertEq(arr[1].name, 'b'); assertEq(arr[1].name, "b");
assertEq(arr[2].kind, 'table'); assertEq(arr[2].kind, "table");
assertEq(arr[2].name, 'c'); assertEq(arr[2].name, "c");
assertEq(arr[3].kind, 'global'); assertEq(arr[3].kind, "global");
assertEq(arr[3].name, 'x'); assertEq(arr[3].name, "x");
// 'WebAssembly.Module.customSections' data property // 'WebAssembly.Module.customSections' data property
let moduleCustomSectionsDesc = let moduleCustomSectionsDesc =
...@@ -337,7 +313,7 @@ assertEq(arr.length, 0); ...@@ -337,7 +313,7 @@ assertEq(arr.length, 0);
// 'WebAssembly.Instance' data property // 'WebAssembly.Instance' data property
let instanceDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Instance'); let instanceDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Instance');
assertEq(typeof instanceDesc.value, 'function'); assertEq(typeof instanceDesc.value, "function");
assertTrue(instanceDesc.writable); assertTrue(instanceDesc.writable);
assertFalse(instanceDesc.enumerable); assertFalse(instanceDesc.enumerable);
assertTrue(instanceDesc.configurable); assertTrue(instanceDesc.configurable);
...@@ -346,33 +322,23 @@ assertTrue(instanceDesc.configurable); ...@@ -346,33 +322,23 @@ assertTrue(instanceDesc.configurable);
let Instance = WebAssembly.Instance; let Instance = WebAssembly.Instance;
assertEq(Instance, instanceDesc.value); assertEq(Instance, instanceDesc.value);
assertEq(Instance.length, 1); assertEq(Instance.length, 1);
assertEq(Instance.name, 'Instance'); assertEq(Instance.name, "Instance");
assertErrorMessage( assertErrorMessage(() => Instance(), TypeError, /constructor without new is forbidden/);
() => Instance(), TypeError, /constructor without new is forbidden/); assertErrorMessage(() => new Instance(1), TypeError, "first argument must be a WebAssembly.Module");
assertErrorMessage( assertErrorMessage(() => new Instance({}), TypeError, "first argument must be a WebAssembly.Module");
() => new Instance(1), TypeError, assertErrorMessage(() => new Instance(emptyModule, null), TypeError, "second argument must be an object");
'first argument must be a WebAssembly.Module'); assertErrorMessage(() => new Instance(importingModule, null), TypeError, "");
assertErrorMessage( assertErrorMessage(() => new Instance(importingModule, undefined), TypeError, "");
() => new Instance({}), TypeError, assertErrorMessage(() => new Instance(importingModule, {"":{g:()=>{}}}), LinkError, "");
'first argument must be a WebAssembly.Module'); assertErrorMessage(() => new Instance(importingModule, {t:{f:()=>{}}}), LinkError, "");
assertErrorMessage(
() => new Instance(emptyModule, null), TypeError,
'second argument must be an object');
assertErrorMessage(() => new Instance(importingModule, null), TypeError, '');
assertErrorMessage(
() => new Instance(importingModule, undefined), TypeError, '');
assertErrorMessage(
() => new Instance(importingModule, {'': {g: () => {}}}), LinkError, '');
assertErrorMessage(
() => new Instance(importingModule, {t: {f: () => {}}}), LinkError, '');
assertTrue(new Instance(emptyModule) instanceof Instance); assertTrue(new Instance(emptyModule) instanceof Instance);
assertTrue(new Instance(emptyModule, {}) instanceof Instance); assertTrue(new Instance(emptyModule, {}) instanceof Instance);
// 'WebAssembly.Instance.prototype' data property // 'WebAssembly.Instance.prototype' data property
let instanceProtoDesc = Object.getOwnPropertyDescriptor(Instance, 'prototype'); let instanceProtoDesc = Object.getOwnPropertyDescriptor(Instance, 'prototype');
assertEq(typeof instanceProtoDesc.value, 'object'); assertEq(typeof instanceProtoDesc.value, "object");
assertFalse(instanceProtoDesc.writable); assertFalse(instanceProtoDesc.writable);
assertFalse(instanceProtoDesc.enumerable); assertFalse(instanceProtoDesc.enumerable);
assertFalse(instanceProtoDesc.configurable); assertFalse(instanceProtoDesc.configurable);
...@@ -380,19 +346,18 @@ assertFalse(instanceProtoDesc.configurable); ...@@ -380,19 +346,18 @@ assertFalse(instanceProtoDesc.configurable);
// 'WebAssembly.Instance.prototype' object // 'WebAssembly.Instance.prototype' object
let instanceProto = Instance.prototype; let instanceProto = Instance.prototype;
assertEq(instanceProto, instanceProtoDesc.value); assertEq(instanceProto, instanceProtoDesc.value);
assertEq(String(instanceProto), '[object WebAssembly.Instance]'); assertEq(String(instanceProto), "[object WebAssembly.Instance]");
assertEq(Object.getPrototypeOf(instanceProto), Object.prototype); assertEq(Object.getPrototypeOf(instanceProto), Object.prototype);
// 'WebAssembly.Instance' instance objects // 'WebAssembly.Instance' instance objects
let exportingInstance = new Instance(exportingModule); let exportingInstance = new Instance(exportingModule);
assertEq(typeof exportingInstance, 'object'); assertEq(typeof exportingInstance, "object");
assertEq(String(exportingInstance), '[object WebAssembly.Instance]'); assertEq(String(exportingInstance), "[object WebAssembly.Instance]");
assertEq(Object.getPrototypeOf(exportingInstance), instanceProto); assertEq(Object.getPrototypeOf(exportingInstance), instanceProto);
// 'WebAssembly.Instance' 'exports' data property // 'WebAssembly.Instance' 'exports' data property
let instanceExportsDesc = let instanceExportsDesc = Object.getOwnPropertyDescriptor(exportingInstance, 'exports');
Object.getOwnPropertyDescriptor(exportingInstance, 'exports'); assertEq(typeof instanceExportsDesc.value, "object");
assertEq(typeof instanceExportsDesc.value, 'object');
assertTrue(instanceExportsDesc.writable); assertTrue(instanceExportsDesc.writable);
assertTrue(instanceExportsDesc.enumerable); assertTrue(instanceExportsDesc.enumerable);
assertTrue(instanceExportsDesc.configurable); assertTrue(instanceExportsDesc.configurable);
...@@ -413,7 +378,7 @@ assertErrorMessage(() => new f(), TypeError, /is not a constructor/); ...@@ -413,7 +378,7 @@ assertErrorMessage(() => new f(), TypeError, /is not a constructor/);
// 'WebAssembly.Memory' data property // 'WebAssembly.Memory' data property
let memoryDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Memory'); let memoryDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Memory');
assertEq(typeof memoryDesc.value, 'function'); assertEq(typeof memoryDesc.value, "function");
assertTrue(memoryDesc.writable); assertTrue(memoryDesc.writable);
assertFalse(memoryDesc.enumerable); assertFalse(memoryDesc.enumerable);
assertTrue(memoryDesc.configurable); assertTrue(memoryDesc.configurable);
...@@ -422,34 +387,21 @@ assertTrue(memoryDesc.configurable); ...@@ -422,34 +387,21 @@ assertTrue(memoryDesc.configurable);
let Memory = WebAssembly.Memory; let Memory = WebAssembly.Memory;
assertEq(Memory, memoryDesc.value); assertEq(Memory, memoryDesc.value);
assertEq(Memory.length, 1); assertEq(Memory.length, 1);
assertEq(Memory.name, 'Memory'); assertEq(Memory.name, "Memory");
assertErrorMessage( assertErrorMessage(() => Memory(), TypeError, /constructor without new is forbidden/);
() => Memory(), TypeError, /constructor without new is forbidden/); assertErrorMessage(() => new Memory(1), TypeError, "first argument must be a memory descriptor");
assertErrorMessage( assertErrorMessage(() => new Memory({initial:{valueOf() { throw new Error("here")}}}), Error, "here");
() => new Memory(1), TypeError, assertErrorMessage(() => new Memory({initial:-1}), RangeError, /bad Memory initial size/);
'first argument must be a memory descriptor'); assertErrorMessage(() => new Memory({initial:Math.pow(2,32)}), RangeError, /bad Memory initial size/);
assertErrorMessage( assertErrorMessage(() => new Memory({initial:1, maximum: Math.pow(2,32)/Math.pow(2,14) }), RangeError, /bad Memory maximum size/);
() => new Memory({initial: {valueOf() { throw new Error('here') }}}), Error, assertErrorMessage(() => new Memory({initial:2, maximum:1 }), RangeError, /bad Memory maximum size/);
'here'); assertErrorMessage(() => new Memory({maximum: -1 }), RangeError, /bad Memory maximum size/);
assertErrorMessage(
() => new Memory({initial: -1}), RangeError, /bad Memory initial size/);
assertErrorMessage(
() => new Memory({initial: Math.pow(2, 32)}), RangeError,
/bad Memory initial size/);
assertErrorMessage(
() => new Memory({initial: 1, maximum: Math.pow(2, 32) / Math.pow(2, 14)}),
RangeError, /bad Memory maximum size/);
assertErrorMessage(
() => new Memory({initial: 2, maximum: 1}), RangeError,
/bad Memory maximum size/);
assertErrorMessage(
() => new Memory({maximum: -1}), RangeError, /bad Memory maximum size/);
assertTrue(new Memory({initial: 1}) instanceof Memory); assertTrue(new Memory({initial: 1}) instanceof Memory);
assertEq(new Memory({initial: 1.5}).buffer.byteLength, kPageSize); assertEq(new Memory({initial:1.5}).buffer.byteLength, kPageSize);
// 'WebAssembly.Memory.prototype' data property // 'WebAssembly.Memory.prototype' data property
let memoryProtoDesc = Object.getOwnPropertyDescriptor(Memory, 'prototype'); let memoryProtoDesc = Object.getOwnPropertyDescriptor(Memory, 'prototype');
assertEq(typeof memoryProtoDesc.value, 'object'); assertEq(typeof memoryProtoDesc.value, "object");
assertFalse(memoryProtoDesc.writable); assertFalse(memoryProtoDesc.writable);
assertFalse(memoryProtoDesc.enumerable); assertFalse(memoryProtoDesc.enumerable);
assertFalse(memoryProtoDesc.configurable); assertFalse(memoryProtoDesc.configurable);
...@@ -457,34 +409,32 @@ assertFalse(memoryProtoDesc.configurable); ...@@ -457,34 +409,32 @@ assertFalse(memoryProtoDesc.configurable);
// 'WebAssembly.Memory.prototype' object // 'WebAssembly.Memory.prototype' object
let memoryProto = Memory.prototype; let memoryProto = Memory.prototype;
assertEq(memoryProto, memoryProtoDesc.value); assertEq(memoryProto, memoryProtoDesc.value);
assertEq(String(memoryProto), '[object WebAssembly.Memory]'); assertEq(String(memoryProto), "[object WebAssembly.Memory]");
assertEq(Object.getPrototypeOf(memoryProto), Object.prototype); assertEq(Object.getPrototypeOf(memoryProto), Object.prototype);
// 'WebAssembly.Memory' instance objects // 'WebAssembly.Memory' instance objects
let mem1 = new Memory({initial: 1}); let mem1 = new Memory({initial:1});
assertEq(typeof mem1, 'object'); assertEq(typeof mem1, "object");
assertEq(String(mem1), '[object WebAssembly.Memory]'); assertEq(String(mem1), "[object WebAssembly.Memory]");
assertEq(Object.getPrototypeOf(mem1), memoryProto); assertEq(Object.getPrototypeOf(mem1), memoryProto);
// 'WebAssembly.Memory.prototype.buffer' accessor property // 'WebAssembly.Memory.prototype.buffer' accessor property
let bufferDesc = Object.getOwnPropertyDescriptor(memoryProto, 'buffer'); let bufferDesc = Object.getOwnPropertyDescriptor(memoryProto, 'buffer');
assertEq(typeof bufferDesc.get, 'function'); assertEq(typeof bufferDesc.get, "function");
assertEq(bufferDesc.set, undefined); assertEq(bufferDesc.set, undefined);
assertFalse(bufferDesc.enumerable); assertFalse(bufferDesc.enumerable);
assertTrue(bufferDesc.configurable); assertTrue(bufferDesc.configurable);
// 'WebAssembly.Memory.prototype.buffer' getter // 'WebAssembly.Memory.prototype.buffer' getter
let bufferGetter = bufferDesc.get; let bufferGetter = bufferDesc.get;
assertErrorMessage( assertErrorMessage(() => bufferGetter.call(), TypeError, /called on incompatible undefined/);
() => bufferGetter.call(), TypeError, /called on incompatible undefined/); assertErrorMessage(() => bufferGetter.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(
() => bufferGetter.call({}), TypeError, /called on incompatible Object/);
assertTrue(bufferGetter.call(mem1) instanceof ArrayBuffer); assertTrue(bufferGetter.call(mem1) instanceof ArrayBuffer);
assertEq(bufferGetter.call(mem1).byteLength, kPageSize); assertEq(bufferGetter.call(mem1).byteLength, kPageSize);
// 'WebAssembly.Memory.prototype.grow' data property // 'WebAssembly.Memory.prototype.grow' data property
let memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow'); let memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
assertEq(typeof memGrowDesc.value, 'function'); assertEq(typeof memGrowDesc.value, "function");
assertFalse(memGrowDesc.enumerable); assertFalse(memGrowDesc.enumerable);
assertTrue(memGrowDesc.configurable); assertTrue(memGrowDesc.configurable);
...@@ -492,16 +442,15 @@ assertTrue(memGrowDesc.configurable); ...@@ -492,16 +442,15 @@ assertTrue(memGrowDesc.configurable);
let memGrow = memGrowDesc.value; let memGrow = memGrowDesc.value;
assertEq(memGrow.length, 1); assertEq(memGrow.length, 1);
assertErrorMessage( assertErrorMessage(() => memGrow.call(), TypeError,
() => memGrow.call(), TypeError, /called on incompatible undefined/); /called on incompatible undefined/);
assertErrorMessage( assertErrorMessage(() => memGrow.call({}), TypeError,
() => memGrow.call({}), TypeError, /called on incompatible Object/); /called on incompatible Object/);
assertErrorMessage( assertErrorMessage(() => memGrow.call(mem1, -1), RangeError,
() => memGrow.call(mem1, -1), RangeError, /bad Memory grow delta/); /bad Memory grow delta/);
assertErrorMessage( assertErrorMessage(() => memGrow.call(mem1, Math.pow(2,32)), RangeError,
() => memGrow.call(mem1, Math.pow(2, 32)), RangeError,
/bad Memory grow delta/); /bad Memory grow delta/);
var mem = new Memory({initial: 1, maximum: 2}); var mem = new Memory({initial:1, maximum:2});
var buf = mem.buffer; var buf = mem.buffer;
assertEq(buf.byteLength, kPageSize); assertEq(buf.byteLength, kPageSize);
assertEq(mem.grow(0), 1); assertEq(mem.grow(0), 1);
...@@ -519,7 +468,7 @@ assertEq(buf, mem.buffer); ...@@ -519,7 +468,7 @@ assertEq(buf, mem.buffer);
// 'WebAssembly.Table' data property // 'WebAssembly.Table' data property
let tableDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Table'); let tableDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Table');
assertEq(typeof tableDesc.value, 'function'); assertEq(typeof tableDesc.value, "function");
assertTrue(tableDesc.writable); assertTrue(tableDesc.writable);
assertFalse(tableDesc.enumerable); assertFalse(tableDesc.enumerable);
assertTrue(tableDesc.configurable); assertTrue(tableDesc.configurable);
...@@ -528,35 +477,17 @@ assertTrue(tableDesc.configurable); ...@@ -528,35 +477,17 @@ assertTrue(tableDesc.configurable);
let Table = WebAssembly.Table; let Table = WebAssembly.Table;
assertEq(Table, tableDesc.value); assertEq(Table, tableDesc.value);
assertEq(Table.length, 1); assertEq(Table.length, 1);
assertEq(Table.name, 'Table'); assertEq(Table.name, "Table");
assertErrorMessage( assertErrorMessage(() => Table(), TypeError, /constructor without new is forbidden/);
() => Table(), TypeError, /constructor without new is forbidden/); assertErrorMessage(() => new Table(1), TypeError, "first argument must be a table descriptor");
assertErrorMessage( assertErrorMessage(() => new Table({initial:1, element:1}), TypeError, /must be "anyfunc"/);
() => new Table(1), TypeError, 'first argument must be a table descriptor'); assertErrorMessage(() => new Table({initial:1, element:"any"}), TypeError, /must be "anyfunc"/);
assertErrorMessage( assertErrorMessage(() => new Table({initial:1, element:{valueOf() { return "anyfunc" }}}), TypeError, /must be "anyfunc"/);
() => new Table({initial: 1, element: 1}), TypeError, /must be "anyfunc"/); assertErrorMessage(() => new Table({initial:{valueOf() { throw new Error("here")}}, element:"anyfunc"}), Error, "here");
assertErrorMessage( assertErrorMessage(() => new Table({initial:-1, element:"anyfunc"}), RangeError, /bad Table initial size/);
() => new Table({initial: 1, element: 'any'}), TypeError, assertErrorMessage(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), RangeError, /bad Table initial size/);
/must be "anyfunc"/); assertErrorMessage(() => new Table({initial:2, maximum:1, element:"anyfunc"}), RangeError, /bad Table maximum size/);
assertErrorMessage( assertErrorMessage(() => new Table({initial:2, maximum:Math.pow(2,32), element:"anyfunc"}), RangeError, /bad Table maximum size/);
() => new Table({initial: 1, element: {valueOf() { return 'anyfunc' }}}),
TypeError, /must be "anyfunc"/);
assertErrorMessage(
() => new Table(
{initial: {valueOf() { throw new Error('here') }}, element: 'anyfunc'}),
Error, 'here');
assertErrorMessage(
() => new Table({initial: -1, element: 'anyfunc'}), RangeError,
/bad Table initial size/);
assertErrorMessage(
() => new Table({initial: Math.pow(2, 32), element: 'anyfunc'}), RangeError,
/bad Table initial size/);
assertErrorMessage(
() => new Table({initial: 2, maximum: 1, element: 'anyfunc'}), RangeError,
/bad Table maximum size/);
assertErrorMessage(
() => new Table({initial: 2, maximum: Math.pow(2, 32), element: 'anyfunc'}),
RangeError, /bad Table maximum size/);
assertTrue(new Table({initial: 1, element: 'anyfunc'}) instanceof Table); assertTrue(new Table({initial: 1, element: 'anyfunc'}) instanceof Table);
assertTrue(new Table({initial: 1.5, element: 'anyfunc'}) instanceof Table); assertTrue(new Table({initial: 1.5, element: 'anyfunc'}) instanceof Table);
assertTrue( assertTrue(
...@@ -566,7 +497,7 @@ assertTrue( ...@@ -566,7 +497,7 @@ assertTrue(
// 'WebAssembly.Table.prototype' data property // 'WebAssembly.Table.prototype' data property
let tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype'); let tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype');
assertEq(typeof tableProtoDesc.value, 'object'); assertEq(typeof tableProtoDesc.value, "object");
assertFalse(tableProtoDesc.writable); assertFalse(tableProtoDesc.writable);
assertFalse(tableProtoDesc.enumerable); assertFalse(tableProtoDesc.enumerable);
assertFalse(tableProtoDesc.configurable); assertFalse(tableProtoDesc.configurable);
...@@ -574,18 +505,18 @@ assertFalse(tableProtoDesc.configurable); ...@@ -574,18 +505,18 @@ assertFalse(tableProtoDesc.configurable);
// 'WebAssembly.Table.prototype' object // 'WebAssembly.Table.prototype' object
let tableProto = Table.prototype; let tableProto = Table.prototype;
assertEq(tableProto, tableProtoDesc.value); assertEq(tableProto, tableProtoDesc.value);
assertEq(String(tableProto), '[object WebAssembly.Table]'); assertEq(String(tableProto), "[object WebAssembly.Table]");
assertEq(Object.getPrototypeOf(tableProto), Object.prototype); assertEq(Object.getPrototypeOf(tableProto), Object.prototype);
// 'WebAssembly.Table' instance objects // 'WebAssembly.Table' instance objects
let tbl1 = new Table({initial: 2, element: 'anyfunc'}); let tbl1 = new Table({initial:2, element:"anyfunc"});
assertEq(typeof tbl1, 'object'); assertEq(typeof tbl1, "object");
assertEq(String(tbl1), '[object WebAssembly.Table]'); assertEq(String(tbl1), "[object WebAssembly.Table]");
assertEq(Object.getPrototypeOf(tbl1), tableProto); assertEq(Object.getPrototypeOf(tbl1), tableProto);
// 'WebAssembly.Table.prototype.length' accessor data property // 'WebAssembly.Table.prototype.length' accessor data property
let lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length'); let lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length');
assertEq(typeof lengthDesc.get, 'function'); assertEq(typeof lengthDesc.get, "function");
assertEq(lengthDesc.set, undefined); assertEq(lengthDesc.set, undefined);
assertFalse(lengthDesc.enumerable); assertFalse(lengthDesc.enumerable);
assertTrue(lengthDesc.configurable); assertTrue(lengthDesc.configurable);
...@@ -593,95 +524,68 @@ assertTrue(lengthDesc.configurable); ...@@ -593,95 +524,68 @@ assertTrue(lengthDesc.configurable);
// 'WebAssembly.Table.prototype.length' getter // 'WebAssembly.Table.prototype.length' getter
let lengthGetter = lengthDesc.get; let lengthGetter = lengthDesc.get;
assertEq(lengthGetter.length, 0); assertEq(lengthGetter.length, 0);
assertErrorMessage( assertErrorMessage(() => lengthGetter.call(), TypeError, /called on incompatible undefined/);
() => lengthGetter.call(), TypeError, /called on incompatible undefined/); assertErrorMessage(() => lengthGetter.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage( assertEq(typeof lengthGetter.call(tbl1), "number");
() => lengthGetter.call({}), TypeError, /called on incompatible Object/);
assertEq(typeof lengthGetter.call(tbl1), 'number');
assertEq(lengthGetter.call(tbl1), 2); assertEq(lengthGetter.call(tbl1), 2);
// 'WebAssembly.Table.prototype.get' data property // 'WebAssembly.Table.prototype.get' data property
let getDesc = Object.getOwnPropertyDescriptor(tableProto, 'get'); let getDesc = Object.getOwnPropertyDescriptor(tableProto, 'get');
assertEq(typeof getDesc.value, 'function'); assertEq(typeof getDesc.value, "function");
assertFalse(getDesc.enumerable); assertFalse(getDesc.enumerable);
assertTrue(getDesc.configurable); assertTrue(getDesc.configurable);
// 'WebAssembly.Table.prototype.get' method // 'WebAssembly.Table.prototype.get' method
let get = getDesc.value; let get = getDesc.value;
assertEq(get.length, 1); assertEq(get.length, 1);
assertErrorMessage( assertErrorMessage(() => get.call(), TypeError, /called on incompatible undefined/);
() => get.call(), TypeError, /called on incompatible undefined/); assertErrorMessage(() => get.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(
() => get.call({}), TypeError, /called on incompatible Object/);
assertEq(get.call(tbl1, 0), null); assertEq(get.call(tbl1, 0), null);
assertEq(get.call(tbl1, 1), null); assertEq(get.call(tbl1, 1), null);
assertEq(get.call(tbl1, 1.5), null); assertEq(get.call(tbl1, 1.5), null);
assertErrorMessage(() => get.call(tbl1, 2), RangeError, /bad Table get index/); assertErrorMessage(() => get.call(tbl1, 2), RangeError, /bad Table get index/);
assertErrorMessage( assertErrorMessage(() => get.call(tbl1, 2.5), RangeError, /bad Table get index/);
() => get.call(tbl1, 2.5), RangeError, /bad Table get index/);
assertErrorMessage(() => get.call(tbl1, -1), RangeError, /bad Table get index/); assertErrorMessage(() => get.call(tbl1, -1), RangeError, /bad Table get index/);
// TODO assertErrorMessage(() => get.call(tbl1, Math.pow(2,33)), RangeError, //TODO assertErrorMessage(() => get.call(tbl1, Math.pow(2,33)), RangeError, /bad Table get index/);
// /bad Table get index/); assertErrorMessage(() => get.call(tbl1, {valueOf() { throw new Error("hi") }}), Error, "hi");
assertErrorMessage(
() => get.call(tbl1, {valueOf() { throw new Error('hi') }}), Error, 'hi');
// 'WebAssembly.Table.prototype.set' data property // 'WebAssembly.Table.prototype.set' data property
let setDesc = Object.getOwnPropertyDescriptor(tableProto, 'set'); let setDesc = Object.getOwnPropertyDescriptor(tableProto, 'set');
assertEq(typeof setDesc.value, 'function'); assertEq(typeof setDesc.value, "function");
assertFalse(setDesc.enumerable); assertFalse(setDesc.enumerable);
assertTrue(setDesc.configurable); assertTrue(setDesc.configurable);
// 'WebAssembly.Table.prototype.set' method // 'WebAssembly.Table.prototype.set' method
let set = setDesc.value; let set = setDesc.value;
assertEq(set.length, 2); assertEq(set.length, 2);
assertErrorMessage( assertErrorMessage(() => set.call(), TypeError, /called on incompatible undefined/);
() => set.call(), TypeError, /called on incompatible undefined/); assertErrorMessage(() => set.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage( assertErrorMessage(() => set.call(tbl1, 0), TypeError, /requires more than 1 argument/);
() => set.call({}), TypeError, /called on incompatible Object/); assertErrorMessage(() => set.call(tbl1, 2, null), RangeError, /bad Table set index/);
assertErrorMessage( assertErrorMessage(() => set.call(tbl1, -1, null), RangeError, /bad Table set index/);
() => set.call(tbl1, 0), TypeError, /requires more than 1 argument/); //TODO assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), RangeError, /bad Table set index/);
assertErrorMessage( assertErrorMessage(() => set.call(tbl1, 0, undefined), TypeError, /can only assign WebAssembly exported functions to Table/);
() => set.call(tbl1, 2, null), RangeError, /bad Table set index/); assertErrorMessage(() => set.call(tbl1, 0, {}), TypeError, /can only assign WebAssembly exported functions to Table/);
assertErrorMessage( assertErrorMessage(() => set.call(tbl1, 0, function() {}), TypeError, /can only assign WebAssembly exported functions to Table/);
() => set.call(tbl1, -1, null), RangeError, /bad Table set index/); assertErrorMessage(() => set.call(tbl1, 0, Math.sin), TypeError, /can only assign WebAssembly exported functions to Table/);
// TODO assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), assertErrorMessage(() => set.call(tbl1, {valueOf() { throw Error("hai") }}, null), Error, "hai");
// RangeError, /bad Table set index/);
assertErrorMessage(
() => set.call(tbl1, 0, undefined), TypeError,
/can only assign WebAssembly exported functions to Table/);
assertErrorMessage(
() => set.call(tbl1, 0, {}), TypeError,
/can only assign WebAssembly exported functions to Table/);
assertErrorMessage(() => set.call(tbl1, 0, function() {
}), TypeError, /can only assign WebAssembly exported functions to Table/);
assertErrorMessage(
() => set.call(tbl1, 0, Math.sin), TypeError,
/can only assign WebAssembly exported functions to Table/);
assertErrorMessage(
() => set.call(tbl1, {valueOf() { throw Error('hai') }}, null), Error,
'hai');
assertEq(set.call(tbl1, 0, null), undefined); assertEq(set.call(tbl1, 0, null), undefined);
assertEq(set.call(tbl1, 1, null), undefined); assertEq(set.call(tbl1, 1, null), undefined);
// 'WebAssembly.Table.prototype.grow' data property // 'WebAssembly.Table.prototype.grow' data property
let tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow'); let tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow');
assertEq(typeof tblGrowDesc.value, 'function'); assertEq(typeof tblGrowDesc.value, "function");
assertFalse(tblGrowDesc.enumerable); assertFalse(tblGrowDesc.enumerable);
assertTrue(tblGrowDesc.configurable); assertTrue(tblGrowDesc.configurable);
// 'WebAssembly.Table.prototype.grow' method // 'WebAssembly.Table.prototype.grow' method
let tblGrow = tblGrowDesc.value; let tblGrow = tblGrowDesc.value;
assertEq(tblGrow.length, 1); assertEq(tblGrow.length, 1);
assertErrorMessage( assertErrorMessage(() => tblGrow.call(), TypeError, /called on incompatible undefined/);
() => tblGrow.call(), TypeError, /called on incompatible undefined/); assertErrorMessage(() => tblGrow.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage( assertErrorMessage(() => tblGrow.call(tbl1, -1), RangeError, /bad Table grow delta/);
() => tblGrow.call({}), TypeError, /called on incompatible Object/); assertErrorMessage(() => tblGrow.call(tbl1, Math.pow(2,32)), RangeError, /bad Table grow delta/);
assertErrorMessage( var tbl = new Table({element:"anyfunc", initial:1, maximum:2});
() => tblGrow.call(tbl1, -1), RangeError, /bad Table grow delta/);
assertErrorMessage(
() => tblGrow.call(tbl1, Math.pow(2, 32)), RangeError,
/bad Table grow delta/);
var tbl = new Table({element: 'anyfunc', initial: 1, maximum: 2});
assertEq(tbl.length, 1); assertEq(tbl.length, 1);
assertEq(tbl.grow(0), 1); assertEq(tbl.grow(0), 1);
assertEq(tbl.length, 1); assertEq(tbl.length, 1);
...@@ -691,7 +595,7 @@ assertErrorMessage(() => tbl.grow(1), Error, /failed to grow table/); ...@@ -691,7 +595,7 @@ assertErrorMessage(() => tbl.grow(1), Error, /failed to grow table/);
// 'WebAssembly.validate' function // 'WebAssembly.validate' function
assertErrorMessage(() => WebAssembly.validate(), TypeError); assertErrorMessage(() => WebAssembly.validate(), TypeError);
assertErrorMessage(() => WebAssembly.validate('hi'), TypeError); assertErrorMessage(() => WebAssembly.validate("hi"), TypeError);
assertTrue(WebAssembly.validate(emptyModuleBinary)); assertTrue(WebAssembly.validate(emptyModuleBinary));
// TODO: other ways for validate to return false. // TODO: other ways for validate to return false.
assertFalse(WebAssembly.validate(moduleBinaryImporting2Memories)); assertFalse(WebAssembly.validate(moduleBinaryImporting2Memories));
...@@ -699,7 +603,7 @@ assertFalse(WebAssembly.validate(moduleBinaryWithMemSectionAndMemImport)); ...@@ -699,7 +603,7 @@ assertFalse(WebAssembly.validate(moduleBinaryWithMemSectionAndMemImport));
// 'WebAssembly.compile' data property // 'WebAssembly.compile' data property
let compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile'); let compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile');
assertEq(typeof compileDesc.value, 'function'); assertEq(typeof compileDesc.value, "function");
assertTrue(compileDesc.writable); assertTrue(compileDesc.writable);
assertFalse(compileDesc.enumerable); assertFalse(compileDesc.enumerable);
assertTrue(compileDesc.configurable); assertTrue(compileDesc.configurable);
...@@ -708,45 +612,36 @@ assertTrue(compileDesc.configurable); ...@@ -708,45 +612,36 @@ assertTrue(compileDesc.configurable);
let compile = WebAssembly.compile; let compile = WebAssembly.compile;
assertEq(compile, compileDesc.value); assertEq(compile, compileDesc.value);
assertEq(compile.length, 1); assertEq(compile.length, 1);
assertEq(compile.name, 'compile'); assertEq(compile.name, "compile");
function assertCompileError(args, err, msg) { function assertCompileError(args, err, msg) {
var error = null; var error = null;
assertPromiseResult(compile(...args), unexpectedSuccess, error => { compile(...args).catch(e => error = e);
assertTrue(error instanceof err); drainJobQueue();
assertTrue(Boolean(error.stack.match('js-api.js'))); assertTrue(error instanceof err);
// TODO assertTrue(Boolean(error.message.match(msg))); assertTrue(Boolean(error.stack.match('js-api.js')));
}); // TODO assertTrue(Boolean(error.message.match(msg)));
} }
assertCompileError([], TypeError, /requires more than 0 arguments/); assertCompileError([], TypeError, /requires more than 0 arguments/);
assertCompileError( assertCompileError([undefined], TypeError, /first argument must be an ArrayBuffer or typed array object/);
[undefined], TypeError, assertCompileError([1], TypeError, /first argument must be an ArrayBuffer or typed array object/);
/first argument must be an ArrayBuffer or typed array object/); assertCompileError([{}], TypeError, /first argument must be an ArrayBuffer or typed array object/);
assertCompileError( assertCompileError([new Uint8Array()], CompileError, /BufferSource argument is empty/);
[1], TypeError, assertCompileError([new ArrayBuffer()], CompileError, /BufferSource argument is empty/);
/first argument must be an ArrayBuffer or typed array object/); assertCompileError([new Uint8Array("hi!")], CompileError, /failed to match magic number/);
assertCompileError( assertCompileError([new ArrayBuffer("hi!")], CompileError, /failed to match magic number/);
[{}], TypeError,
/first argument must be an ArrayBuffer or typed array object/);
assertCompileError(
[new Uint8Array()], CompileError, /BufferSource argument is empty/);
assertCompileError(
[new ArrayBuffer()], CompileError, /BufferSource argument is empty/);
assertCompileError(
[new Uint8Array('hi!')], CompileError, /failed to match magic number/);
assertCompileError(
[new ArrayBuffer('hi!')], CompileError, /failed to match magic number/);
function assertCompileSuccess(bytes) { function assertCompileSuccess(bytes) {
var module = null; var module = null;
assertPromiseResult(compile(bytes), m => assertTrue(m instanceof Module)); compile(bytes).then(m => module = m);
drainJobQueue();
assertTrue(module instanceof Module);
} }
assertCompileSuccess(emptyModuleBinary); assertCompileSuccess(emptyModuleBinary);
assertCompileSuccess(emptyModuleBinary.buffer); assertCompileSuccess(emptyModuleBinary.buffer);
// 'WebAssembly.instantiate' data property // 'WebAssembly.instantiate' data property
let instantiateDesc = let instantiateDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate'); assertEq(typeof instantiateDesc.value, "function");
assertEq(typeof instantiateDesc.value, 'function');
assertTrue(instantiateDesc.writable); assertTrue(instantiateDesc.writable);
assertFalse(instantiateDesc.enumerable); assertFalse(instantiateDesc.enumerable);
assertTrue(instantiateDesc.configurable); assertTrue(instantiateDesc.configurable);
...@@ -755,81 +650,56 @@ assertTrue(instantiateDesc.configurable); ...@@ -755,81 +650,56 @@ assertTrue(instantiateDesc.configurable);
let instantiate = WebAssembly.instantiate; let instantiate = WebAssembly.instantiate;
assertEq(instantiate, instantiateDesc.value); assertEq(instantiate, instantiateDesc.value);
assertEq(instantiate.length, 1); assertEq(instantiate.length, 1);
assertEq(instantiate.name, 'instantiate'); assertEq(instantiate.name, "instantiate");
function assertInstantiateError(args, err, msg) { function assertInstantiateError(args, err, msg) {
var error = null; var error = null;
assertPromiseResult(instantiate(...args), unexpectedSuccess, error => { instantiate(...args).catch(e => error = e);
assertTrue(error instanceof err); drainJobQueue();
assertTrue(Boolean(error.stack.match('js-api.js'))); assertTrue(error instanceof err);
// TODO assertTrue(Boolean(error.message.match(msg))); assertTrue(Boolean(error.stack.match('js-api.js')));
}); // TODO assertTrue(Boolean(error.message.match(msg)));
} }
var scratch_memory = new WebAssembly.Memory(new ArrayBuffer(10)); var scratch_memory = new WebAssembly.Memory(new ArrayBuffer(10));
assertInstantiateError([], TypeError, /requires more than 0 arguments/); assertInstantiateError([], TypeError, /requires more than 0 arguments/);
assertInstantiateError( assertInstantiateError([undefined], TypeError, /first argument must be a BufferSource/);
[undefined], TypeError, /first argument must be a BufferSource/);
assertInstantiateError([1], TypeError, /first argument must be a BufferSource/); assertInstantiateError([1], TypeError, /first argument must be a BufferSource/);
assertInstantiateError( assertInstantiateError([{}], TypeError, /first argument must be a BufferSource/);
[{}], TypeError, /first argument must be a BufferSource/); assertInstantiateError([new Uint8Array()], CompileError, /failed to match magic number/);
assertInstantiateError( assertInstantiateError([new ArrayBuffer()], CompileError, /failed to match magic number/);
[new Uint8Array()], CompileError, /failed to match magic number/); assertInstantiateError([new Uint8Array("hi!")], CompileError, /failed to match magic number/);
assertInstantiateError( assertInstantiateError([new ArrayBuffer("hi!")], CompileError, /failed to match magic number/);
[new ArrayBuffer()], CompileError, /failed to match magic number/); assertInstantiateError([importingModule], TypeError, /second argument must be an object/);
assertInstantiateError( assertInstantiateError([importingModule, null], TypeError, /second argument must be an object/);
[new Uint8Array('hi!')], CompileError, /failed to match magic number/); assertInstantiateError([importingModuleBinary, null], TypeError, /second argument must be an object/);
assertInstantiateError( assertInstantiateError([emptyModule, null], TypeError, /first argument must be a BufferSource/);
[new ArrayBuffer('hi!')], CompileError, /failed to match magic number/); assertInstantiateError([importingModuleBinary, null], TypeError, /TODO: error messages?/);
assertInstantiateError( assertInstantiateError([importingModuleBinary, undefined], TypeError, /TODO: error messages?/);
[importingModule], TypeError, /second argument must be an object/); assertInstantiateError([importingModuleBinary, {}], LinkError, /TODO: error messages?/);
assertInstantiateError( assertInstantiateError([importingModuleBinary, {"":{g:()=>{}}}], LinkError, /TODO: error messages?/);
[importingModule, null], TypeError, /second argument must be an object/); assertInstantiateError([importingModuleBinary, {t:{f:()=>{}}}], LinkError, /TODO: error messages?/);
assertInstantiateError( assertInstantiateError([memoryImportingModuleBinary, null], TypeError, /TODO: error messages?/);
[importingModuleBinary, null], TypeError, assertInstantiateError([memoryImportingModuleBinary, undefined], TypeError, /TODO: error messages?/);
/second argument must be an object/); assertInstantiateError([memoryImportingModuleBinary, {}], LinkError, /TODO: error messages?/);
assertInstantiateError( assertInstantiateError([memoryImportingModuleBinary, {"mod": {"my_memory": scratch_memory}}], LinkError, /TODO: error messages?/);
[emptyModule, null], TypeError, /first argument must be a BufferSource/); assertInstantiateError([memoryImportingModuleBinary, {"": {"memory": scratch_memory}}], LinkError, /TODO: error messages?/);
assertInstantiateError(
[importingModuleBinary, null], TypeError, /TODO: error messages?/);
assertInstantiateError(
[importingModuleBinary, undefined], TypeError, /TODO: error messages?/);
assertInstantiateError(
[importingModuleBinary, {}], LinkError, /TODO: error messages?/);
assertInstantiateError(
[importingModuleBinary, {'': {g: () => {}}}], LinkError,
/TODO: error messages?/);
assertInstantiateError(
[importingModuleBinary, {t: {f: () => {}}}], LinkError,
/TODO: error messages?/);
assertInstantiateError(
[memoryImportingModuleBinary, null], TypeError, /TODO: error messages?/);
assertInstantiateError(
[memoryImportingModuleBinary, undefined], TypeError,
/TODO: error messages?/);
assertInstantiateError(
[memoryImportingModuleBinary, {}], LinkError, /TODO: error messages?/);
assertInstantiateError(
[memoryImportingModuleBinary, {'mod': {'my_memory': scratch_memory}}],
LinkError, /TODO: error messages?/);
assertInstantiateError(
[memoryImportingModuleBinary, {'': {'memory': scratch_memory}}], LinkError,
/TODO: error messages?/);
function assertInstantiateSuccess(module_or_bytes, imports) { function assertInstantiateSuccess(module_or_bytes, imports) {
var result = null; var result = null;
assertPromiseResult(instantiate(module_or_bytes, imports), result => { instantiate(module_or_bytes, imports)
if (module_or_bytes instanceof Module) { .then(r => result = r)
assertTrue(result instanceof Instance); .catch(e => print(e));
} else { drainJobQueue();
assertTrue(result.module instanceof Module); if (module_or_bytes instanceof Module) {
assertTrue(result.instance instanceof Instance); assertTrue(result instanceof Instance);
} } else {
}); assertTrue(result.module instanceof Module);
assertTrue(result.instance instanceof Instance);
}
} }
assertInstantiateSuccess(emptyModule); assertInstantiateSuccess(emptyModule);
assertInstantiateSuccess(emptyModuleBinary); assertInstantiateSuccess(emptyModuleBinary);
assertInstantiateSuccess(emptyModuleBinary.buffer); assertInstantiateSuccess(emptyModuleBinary.buffer);
assertInstantiateSuccess(importingModule, {'': {f: () => {}}}); assertInstantiateSuccess(importingModule, {'': {f: () => {}}});
assertInstantiateSuccess(importingModuleBinary, {'': {f: () => {}}}); assertInstantiateSuccess(importingModuleBinary, {"":{f:()=>{}}});
assertInstantiateSuccess(importingModuleBinary.buffer, {'': {f: () => {}}}); assertInstantiateSuccess(importingModuleBinary.buffer, {"":{f:()=>{}}});
assertInstantiateSuccess( assertInstantiateSuccess(memoryImportingModuleBinary, {"": {"my_memory": scratch_memory}});
memoryImportingModuleBinary, {'': {'my_memory': scratch_memory}});
// Copyright 2017 the V8 project authors. All rights reserved. // Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
//
// TODO(eholk): Once we have stable test IDs, use those as the key instead. // TODO(eholk): Once we have stable test IDs, use those as the key instead.
// See https://github.com/WebAssembly/spec/issues/415 // See https://github.com/WebAssembly/spec/issues/415
//
// Flags: --expose-wasm --allow-natives-syntax
const known_failures = { const known_failures = {
"'WebAssembly.Module.customSections' method": "'WebAssembly.Module.customSections' method":
'https://bugs.chromium.org/p/v8/issues/detail?id=5815', 'https://bugs.chromium.org/p/v8/issues/detail?id=5815',
...@@ -81,7 +78,7 @@ load("test/wasm-js/test/harness/wasm-constants.js"); ...@@ -81,7 +78,7 @@ load("test/wasm-js/test/harness/wasm-constants.js");
load("test/wasm-js/test/harness/wasm-module-builder.js"); load("test/wasm-js/test/harness/wasm-module-builder.js");
load("test/wasm-js/test/js-api/jsapi.js"); load("test/wasm-js/test/js-api/jsapi.js");
assertPromiseResult(last_promise, _ => { last_promise.then(_ => {
if (failures.length > 0) { if (failures.length > 0) {
let unexpected = false; let unexpected = false;
print("Some tests FAILED:"); print("Some tests FAILED:");
......
// 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.
// Flags: --allow-natives-syntax --validate-asm
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
let buffer = (() => {
var builder = new WasmModuleBuilder();
builder.addFunction("f", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportAs("f");
return builder.toBuffer();
})();
// allow up to the buffer size
%SetWasmCompileControls(buffer.byteLength, true);
%SetWasmInstantiateControls();
var m = new WebAssembly.Module(buffer);
var i = new WebAssembly.Instance(m);
assertEquals(i.exports.f(), 42);
// the buffer can't compile synchronously, but we allow async compile
%SetWasmCompileControls(buffer.byteLength - 1, true);
// test first that we can't sync-instantiate this module anymore
try {
i = new WebAssembly.Instance(m);
} catch (e) {
assertTrue(e instanceof RangeError);
}
//...but we can async-instantiate it
WebAssembly.instantiate(m)
.then(instance => i = instance,
assertUnreachable);
%RunMicrotasks();
assertTrue(i instanceof WebAssembly.Instance);
try {
m = new WebAssembly.Module(buffer);
assertUnreachable();
} catch (e) {
assertTrue(e instanceof RangeError);
}
WebAssembly.compile(buffer)
.then(res => m = res,
m = null);
%RunMicrotasks();
assertTrue(m instanceof WebAssembly.Module)
WebAssembly.instantiate(buffer)
.then(res => m = res.module,
m = null);
%RunMicrotasks();
assertTrue(m instanceof WebAssembly.Module);
// Async compile works, but using the sync instantiate doesn't
i = undefined;
m = undefined;
var ex = undefined;
WebAssembly.compile(buffer)
.then(mod => {
m = mod;
try {
i = new WebAssembly.Instance(m);
} catch (e) {
ex = e;
}
},
e => ex = e);
%RunMicrotasks();
assertTrue(ex instanceof RangeError);
assertEquals(i, undefined);
assertTrue(m instanceof WebAssembly.Module);
// Now block async compile works.
%SetWasmCompileControls(buffer.byteLength - 1, false);
WebAssembly.compile(buffer)
.then(ex = null,
e => ex = e);
%RunMicrotasks();
assertTrue(ex instanceof RangeError);
WebAssembly.instantiate(buffer)
.then(ex = null,
e => ex = e);
%RunMicrotasks();
assertTrue(ex instanceof RangeError);
// Verify that, for asm-wasm, these controls are ignored.
%SetWasmCompileControls(0, false);
function assertValidAsm(func) {
assertTrue(%IsAsmWasmCode(func));
}
function assertWasm(expected, func) {
assertEquals(
expected, func(undefined, undefined, new ArrayBuffer(1024)).caller());
assertValidAsm(func);
}
function TestAsmWasmIsUnaffected() {
"use asm";
function caller() {
return 43;
}
return {caller: caller};
}
assertWasm(43, TestAsmWasmIsUnaffected);
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