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
void Foreign::ForeignPrint(std::ostream& os) { // NOLINT
os << "foreign address : " << reinterpret_cast<void*>(foreign_address());
os << "foreign address : " << foreign_address();
os << "\n";
}
......
......@@ -42,11 +42,6 @@ namespace base = v8::base;
instance->PrintInstancesChain(); \
} while (false)
#define TRACE_COMPILE(...) \
do { \
if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
} while (false)
namespace {
static const int kInvalidSigIndex = -1;
......@@ -325,7 +320,6 @@ class CompilationHelper {
std::queue<compiler::WasmCompilationUnit*> executed_units_;
base::Mutex result_mutex_;
base::AtomicNumber<size_t> next_unit_;
size_t num_background_tasks_ = 0;
// Run by each compilation task and by the main thread.
bool FetchAndExecuteCompilationUnit() {
......@@ -347,8 +341,9 @@ class CompilationHelper {
return true;
}
size_t InitializeParallelCompilation(
const std::vector<WasmFunction>& functions, ModuleBytesEnv& module_env) {
void InitializeParallelCompilation(const std::vector<WasmFunction>& functions,
ModuleBytesEnv& module_env,
ErrorThrower* thrower) {
uint32_t start = module_env.module_env.module->num_imported_functions +
FLAG_skip_compiling_wasm_funcs;
uint32_t num_funcs = static_cast<uint32_t>(functions.size());
......@@ -359,15 +354,14 @@ class CompilationHelper {
compilation_units_.push_back(
new compiler::WasmCompilationUnit(isolate_, &module_env, func));
}
return num_funcs;
}
uint32_t* StartCompilationTasks() {
num_background_tasks_ =
const size_t num_tasks =
Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
uint32_t* task_ids = new uint32_t[num_background_tasks_];
for (size_t i = 0; i < num_background_tasks_; ++i) {
uint32_t* task_ids = new uint32_t[num_tasks];
for (size_t i = 0; i < num_tasks; ++i) {
CompilationTask* task = new CompilationTask(this);
task_ids[i] = task->id();
V8::GetCurrentPlatform()->CallOnBackgroundThread(
......@@ -377,9 +371,13 @@ class CompilationHelper {
}
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
// for it to finish.
// for
// it to finish.
if (isolate_->cancelable_task_manager()->TryAbort(task_ids[i]) !=
CancelableTaskManager::kTaskAborted) {
module_->pending_tasks.get()->Wait();
......@@ -390,28 +388,21 @@ class CompilationHelper {
void FinishCompilationUnits(std::vector<Handle<Code>>& results,
ErrorThrower* thrower) {
while (true) {
int func_index = 0;
MaybeHandle<Code> result = FinishCompilationUnit(thrower, &func_index);
if (result.is_null()) break;
results[func_index] = result.ToHandleChecked();
compiler::WasmCompilationUnit* unit = nullptr;
{
base::LockGuard<base::Mutex> guard(&result_mutex_);
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,
std::vector<Handle<Code>>& results,
ErrorThrower* thrower) {
......@@ -440,7 +431,7 @@ class CompilationHelper {
// 1) The main thread allocates a compilation unit for each wasm function
// 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.
base::AtomicNumber<size_t> next_unit(
......@@ -1577,7 +1568,14 @@ class InstantiationHelper {
}
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,
WasmOpcodes::TypeName(global.type));
switch (global.type) {
......@@ -2604,19 +2602,21 @@ MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate(
namespace {
void RejectPromise(Isolate* isolate, Handle<Context> context,
ErrorThrower* thrower, Handle<JSPromise> promise) {
void RejectPromise(Isolate* isolate, ErrorThrower* thrower,
Handle<JSPromise> promise) {
v8::Local<v8::Promise::Resolver> resolver =
v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>();
Handle<Context> context(isolate->context(), isolate);
auto maybe = resolver->Reject(v8::Utils::ToLocal(context),
v8::Utils::ToLocal(thrower->Reify()));
CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception());
}
void ResolvePromise(Isolate* isolate, Handle<Context> context,
Handle<JSPromise> promise, Handle<Object> result) {
void ResolvePromise(Isolate* isolate, Handle<JSPromise> promise,
Handle<Object> result) {
v8::Local<v8::Promise::Resolver> resolver =
v8::Utils::PromiseToLocal(promise).As<v8::Promise::Resolver>();
Handle<Context> context(isolate->context(), isolate);
auto maybe = resolver->Resolve(v8::Utils::ToLocal(context),
v8::Utils::ToLocal(result));
CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception());
......@@ -2624,6 +2624,18 @@ void ResolvePromise(Isolate* isolate, Handle<Context> context,
} // 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,
Handle<WasmModuleObject> module_object,
MaybeHandle<JSReceiver> imports) {
......@@ -2631,11 +2643,10 @@ void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise,
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
RejectPromise(isolate, &thrower, promise);
return;
}
ResolvePromise(isolate, handle(isolate->context()), promise,
instance_object.ToHandleChecked());
ResolvePromise(isolate, promise, instance_object.ToHandleChecked());
}
void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
......@@ -2648,7 +2659,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
MaybeHandle<WasmModuleObject> module_object =
SyncCompile(isolate, &thrower, bytes);
if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
RejectPromise(isolate, &thrower, promise);
return;
}
Handle<WasmModuleObject> module = module_object.ToHandleChecked();
......@@ -2657,7 +2668,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
RejectPromise(isolate, &thrower, promise);
return;
}
......@@ -2673,388 +2684,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
JSObject::AddProperty(ret, instance_property_name,
instance_object.ToHandleChecked(), NONE);
ResolvePromise(isolate, handle(isolate->context()), 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();
ResolvePromise(isolate, promise, ret);
}
Handle<Code> wasm::CompileLazy(Isolate* isolate) {
......
......@@ -250,6 +250,7 @@ var failWithMessage;
failWithMessage = function failWithMessage(message) {
print("oh, we failed: " + 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 @@
// 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
// Flags: --expose-wasm
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
let kReturnValue = 17;
let buffer = (() => {
let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction('main', kSig_i_v)
.addBody([kExprI32Const, kReturnValue])
.exportFunc();
builder.addFunction("main", kSig_i_v)
.addBody([kExprI32Const, kReturnValue])
.exportFunc();
return builder.toBuffer();
})();
})()
function CheckInstance(instance) {
assertFalse(instance === undefined);
assertFalse(instance === null);
assertFalse(instance === 0);
assertEquals('object', typeof instance);
assertEquals("object", typeof instance);
// Check the exports object is frozen.
assertFalse(Object.isExtensible(instance.exports));
......@@ -34,14 +34,14 @@ function CheckInstance(instance) {
assertFalse(mem === undefined);
assertFalse(mem === null);
assertFalse(mem === 0);
assertEquals('object', typeof mem);
assertEquals("object", typeof mem);
assertTrue(mem instanceof WebAssembly.Memory);
var buf = mem.buffer;
assertTrue(buf instanceof ArrayBuffer);
assertEquals(65536, buf.byteLength);
for (var i = 0; i < 4; i++) {
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(buf, mem.buffer);
}
......@@ -51,26 +51,25 @@ function CheckInstance(instance) {
assertFalse(main === undefined);
assertFalse(main === null);
assertFalse(main === 0);
assertEquals('function', typeof main);
assertEquals("function", typeof main);
assertEquals(kReturnValue, main());
}
// Official API
(function BasicJSAPITest() {
print('sync module compile...');
print("sync module compile...");
let module = new WebAssembly.Module(buffer);
print('sync module instantiate...');
print("sync module instantiate...");
CheckInstance(new WebAssembly.Instance(module));
print('async module compile...');
print("async module compile...");
let promise = WebAssembly.compile(buffer);
assertPromiseResult(
promise, module => CheckInstance(new WebAssembly.Instance(module)));
promise.then(module => CheckInstance(new WebAssembly.Instance(module)));
print('async instantiate...');
print("async instantiate...");
let instance_promise = WebAssembly.instantiate(buffer);
assertPromiseResult(instance_promise, CheckInstance);
instance_promise.then(CheckInstance);
})();
// Check that validate works correctly for a module.
......@@ -79,34 +78,35 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
// Negative tests.
(function InvalidModules() {
print('InvalidModules...');
let invalid_cases = [undefined, 1, '', 'a', {some: 1, obj: 'b'}];
print("InvalidModules...");
let invalid_cases = [undefined, 1, "", "a", {some:1, obj: "b"}];
let len = invalid_cases.length;
for (var i = 0; i < len; ++i) {
try {
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) {
assertContains('Argument 0', e.toString());
assertContains("Argument 0", e.toString());
}
}
})();
// Compile async an invalid blob.
(function InvalidBinaryAsyncCompilation() {
print('InvalidBinaryAsyncCompilation...');
print("InvalidBinaryAsyncCompilation...");
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());
assertPromiseResult(
promise, compiled => assertUnreachable(
'should not be able to compile invalid blob.'),
e => assertInstanceof(e, WebAssembly.CompileError));
promise
.then(compiled =>
assertUnreachable("should not be able to compile invalid blob."))
.catch(e => assertContains("invalid signature index", e.toString()));
})();
// Multiple instances tests.
(function ManyInstances() {
print('ManyInstances...');
print("ManyInstances...");
let compiled_module = new WebAssembly.Module(buffer);
let instance_1 = 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)));
})();
(function ManyInstancesAsync() {
print('ManyInstancesAsync...');
print("ManyInstancesAsync...");
let promise = WebAssembly.compile(buffer);
assertPromiseResult(promise, compiled_module => {
promise.then(compiled_module => {
let instance_1 = new WebAssembly.Instance(compiled_module);
let instance_2 = new WebAssembly.Instance(compiled_module);
assertTrue(instance_1 != instance_2);
......@@ -124,29 +124,35 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
})();
(function InstancesAreIsolatedFromEachother() {
print('InstancesAreIsolatedFromEachother...');
print("InstancesAreIsolatedFromEachother...");
var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory', 1);
builder.addImportedMemory("", "memory", 1);
var kSig_v_i = makeSig([kWasmI32], []);
var signature = builder.addType(kSig_v_i);
builder.addImport('m', 'some_value', kSig_i_v);
builder.addImport('m', 'writer', signature);
builder.addFunction('main', kSig_i_i)
.addBody([
kExprGetLocal, 0, kExprI32LoadMem, 0, 0, kExprI32Const, 1,
kExprCallIndirect, signature, kTableZero, kExprGetLocal, 0,
kExprI32LoadMem, 0, 0, kExprCallFunction, 0, kExprI32Add
])
.exportFunc();
builder.addImport("m", "some_value", kSig_i_v);
builder.addImport("m", "writer", signature);
builder.addFunction("main", kSig_i_i)
.addBody([
kExprGetLocal, 0,
kExprI32LoadMem, 0, 0,
kExprI32Const, 1,
kExprCallIndirect, signature, kTableZero,
kExprGetLocal,0,
kExprI32LoadMem,0, 0,
kExprCallFunction, 0,
kExprI32Add
]).exportFunc();
// writer(mem[i]);
// return mem[i] + some_value();
builder.addFunction('_wrap_writer', signature).addBody([
kExprGetLocal, 0, kExprCallFunction, 1
]);
builder.addFunction("_wrap_writer", signature)
.addBody([
kExprGetLocal, 0,
kExprCallFunction, 1]);
builder.appendToTable([2, 3]);
var module = new WebAssembly.Module(builder.toBuffer());
var mem_1 = 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)));
var outval_1;
var outval_2;
var i1 = new WebAssembly.Instance(module, {
m: {some_value: () => 1, writer: (x) => outval_1 = x},
'': {memory: mem_1}
});
var i1 = new WebAssembly.Instance(module, {m: {some_value: () => 1,
writer: (x)=>outval_1 = x },
"": {memory: mem_1}});
var i2 = new WebAssembly.Instance(module, {
m: {some_value: () => 2, writer: (x) => outval_2 = x},
'': {memory: mem_2}
});
var i2 = new WebAssembly.Instance(module, {m: {some_value: () => 2,
writer: (x)=>outval_2 = x },
"": {memory: mem_2}});
assertEquals(43, i1.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)));
})();
(function GlobalsArePrivateToTheInstance() {
print('GlobalsArePrivateToTheInstance...');
var builder = new WasmModuleBuilder();
builder.addGlobal(kWasmI32, true);
builder.addFunction('read', kSig_i_v)
.addBody([kExprGetGlobal, 0])
.exportFunc();
builder.addFunction('write', kSig_v_i)
.addBody([kExprGetLocal, 0, kExprSetGlobal, 0])
.exportFunc();
var module = new WebAssembly.Module(builder.toBuffer());
var i1 = new WebAssembly.Instance(module);
var i2 = new WebAssembly.Instance(module);
i1.exports.write(1);
i2.exports.write(2);
assertEquals(1, i1.exports.read());
assertEquals(2, i2.exports.read());
print("GlobalsArePrivateToTheInstance...");
var builder = new WasmModuleBuilder();
builder.addGlobal(kWasmI32, true);
builder.addFunction("read", kSig_i_v)
.addBody([
kExprGetGlobal, 0])
.exportFunc();
builder.addFunction("write", kSig_v_i)
.addBody([
kExprGetLocal, 0,
kExprSetGlobal, 0])
.exportFunc();
var module = new WebAssembly.Module(builder.toBuffer());
var i1 = new WebAssembly.Instance(module);
var i2 = new WebAssembly.Instance(module);
i1.exports.write(1);
i2.exports.write(2);
assertEquals(1, i1.exports.read());
assertEquals(2, i2.exports.read());
})();
(function InstanceMemoryIsIsolated() {
print('InstanceMemoryIsIsolated...');
print("InstanceMemoryIsIsolated...");
var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory', 1);
builder.addImportedMemory("", "memory", 1);
builder.addFunction('f', kSig_i_v)
.addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0])
.exportFunc();
builder.addFunction("f", kSig_i_v)
.addBody([
kExprI32Const, 0,
kExprI32LoadMem, 0, 0
]).exportFunc();
var mem_1 = 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)));
view_2[0] = 1000;
var module = new WebAssembly.Module(builder.toBuffer());
var i1 = new WebAssembly.Instance(module, {'': {memory: mem_1}});
var i2 = new WebAssembly.Instance(module, {'': {memory: mem_2}});
var i1 = new WebAssembly.Instance(module, {"":{memory:mem_1}});
var i2 = new WebAssembly.Instance(module, {"":{memory:mem_2}});
assertEquals(1, i1.exports.f());
assertEquals(1000, i2.exports.f());
})();
(function MustBeMemory() {
print('MustBeMemory...');
print("MustBeMemory...");
var memory = new ArrayBuffer(65536);
let builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory');
builder.addImportedMemory("", "memory");
let module = new WebAssembly.Module(builder.toBuffer());
assertThrows(
() => new WebAssembly.Instance(module, {'': {memory: memory}}),
WebAssembly.LinkError);
assertThrows(() => new WebAssembly.Instance(module, {"":{memory:memory}}), WebAssembly.LinkError);
})();
(function TestNoMemoryToExport() {
......@@ -240,13 +249,13 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
})();
(function TestIterableExports() {
print('TestIterableExports...');
print("TestIterableExports...");
let builder = new WasmModuleBuilder;
builder.addExport('a', 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('d', builder.addFunction('', kSig_v_v).addBody([]));
builder.addExport('e', builder.addGlobal(kWasmI32, false));
builder.addExport("a", 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("d", builder.addFunction("", kSig_v_v).addBody([]));
builder.addExport("e", builder.addGlobal(kWasmI32, false));
let module = new WebAssembly.Module(builder.toBuffer());
let instance = new WebAssembly.Instance(module);
......
......@@ -4,16 +4,12 @@
// Flags: --expose-wasm --allow-natives-syntax
load('test/mjsunit/wasm/wasm-constants.js');
load('test/mjsunit/wasm/wasm-module-builder.js');
function unexpectedSuccess() {
% AbortJS('unexpected success');
if ((typeof drainJobQueue) != "function") {
drainJobQueue = () => { %RunMicrotasks() };
}
function unexpectedFail(error) {
% AbortJS('unexpected fail: ' + error);
}
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
function assertEq(val, expected) {
assertEquals(expected, val);
......@@ -27,10 +23,10 @@ function assertArrayBuffer(val, expected) {
}
}
function wasmIsSupported() {
return (typeof WebAssembly.Module) == 'function';
return (typeof WebAssembly.Module) == "function";
}
function assertErrorMessage(func, type, msg) {
// TODO assertThrows(func, type, msg);
//TODO assertThrows(func, type, msg);
assertThrows(func, type);
}
......@@ -41,103 +37,103 @@ let emptyModuleBinary = (() => {
let exportingModuleBinary = (() => {
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());
})();
let importingModuleBinary = (() => {
var builder = new WasmModuleBuilder();
builder.addImport('', 'f', kSig_i_v);
builder.addImport("", "f", kSig_i_v);
return new Int8Array(builder.toBuffer());
})();
let memoryImportingModuleBinary = (() => {
var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'my_memory');
builder.addImportedMemory("", "my_memory");
return new Int8Array(builder.toBuffer());
})();
let moduleBinaryImporting2Memories = (() => {
var builder = new WasmModuleBuilder();
builder.addImportedMemory('', 'memory1');
builder.addImportedMemory('', 'memory2');
builder.addImportedMemory("", "memory1");
builder.addImportedMemory("", "memory2");
return new Int8Array(builder.toBuffer());
})();
let moduleBinaryWithMemSectionAndMemImport = (() => {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, false);
builder.addImportedMemory('', 'memory1');
builder.addImportedMemory("", "memory1");
return new Int8Array(builder.toBuffer());
})();
// 'WebAssembly' data property on global object
let wasmDesc = Object.getOwnPropertyDescriptor(this, 'WebAssembly');
assertEq(typeof wasmDesc.value, 'object');
assertEq(typeof wasmDesc.value, "object");
assertTrue(wasmDesc.writable);
assertFalse(wasmDesc.enumerable);
assertTrue(wasmDesc.configurable);
// 'WebAssembly' object
assertEq(WebAssembly, wasmDesc.value);
assertEq(String(WebAssembly), '[object WebAssembly]');
assertEq(String(WebAssembly), "[object WebAssembly]");
// 'WebAssembly.CompileError'
let compileErrorDesc =
Object.getOwnPropertyDescriptor(WebAssembly, 'CompileError');
assertEq(typeof compileErrorDesc.value, 'function');
let compileErrorDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'CompileError');
assertEq(typeof compileErrorDesc.value, "function");
assertTrue(compileErrorDesc.writable);
assertFalse(compileErrorDesc.enumerable);
assertTrue(compileErrorDesc.configurable);
let CompileError = WebAssembly.CompileError;
assertEq(CompileError, compileErrorDesc.value);
assertEq(CompileError.length, 1);
assertEq(CompileError.name, 'CompileError');
assertEq(CompileError.name, "CompileError");
let compileError = new CompileError;
assertTrue(compileError instanceof CompileError);
assertTrue(compileError instanceof Error);
assertFalse(compileError instanceof TypeError);
assertEq(compileError.message, '');
assertEq(new CompileError('hi').message, 'hi');
assertEq(compileError.message, "");
assertEq(new CompileError("hi").message, "hi");
// 'WebAssembly.RuntimeError'
let runtimeErrorDesc =
Object.getOwnPropertyDescriptor(WebAssembly, 'RuntimeError');
assertEq(typeof runtimeErrorDesc.value, 'function');
let runtimeErrorDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'RuntimeError');
assertEq(typeof runtimeErrorDesc.value, "function");
assertTrue(runtimeErrorDesc.writable);
assertFalse(runtimeErrorDesc.enumerable);
assertTrue(runtimeErrorDesc.configurable);
let RuntimeError = WebAssembly.RuntimeError;
assertEq(RuntimeError, runtimeErrorDesc.value);
assertEq(RuntimeError.length, 1);
assertEq(RuntimeError.name, 'RuntimeError');
assertEq(RuntimeError.name, "RuntimeError");
let runtimeError = new RuntimeError;
assertTrue(runtimeError instanceof RuntimeError);
assertTrue(runtimeError instanceof Error);
assertFalse(runtimeError instanceof TypeError);
assertEq(runtimeError.message, '');
assertEq(new RuntimeError('hi').message, 'hi');
assertEq(runtimeError.message, "");
assertEq(new RuntimeError("hi").message, "hi");
// 'WebAssembly.LinkError'
let linkErrorDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'LinkError');
assertEq(typeof linkErrorDesc.value, 'function');
assertEq(typeof linkErrorDesc.value, "function");
assertTrue(linkErrorDesc.writable);
assertFalse(linkErrorDesc.enumerable);
assertTrue(linkErrorDesc.configurable);
let LinkError = WebAssembly.LinkError;
assertEq(LinkError, linkErrorDesc.value);
assertEq(LinkError.length, 1);
assertEq(LinkError.name, 'LinkError');
assertEq(LinkError.name, "LinkError");
let linkError = new LinkError;
assertTrue(linkError instanceof LinkError);
assertTrue(linkError instanceof Error);
assertFalse(linkError instanceof TypeError);
assertEq(linkError.message, '');
assertEq(new LinkError('hi').message, 'hi');
assertEq(linkError.message, "");
assertEq(new LinkError("hi").message, "hi");
// 'WebAssembly.Module' data property
let moduleDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Module');
assertEq(typeof moduleDesc.value, 'function');
assertEq(typeof moduleDesc.value, "function");
assertTrue(moduleDesc.writable);
assertFalse(moduleDesc.enumerable);
assertTrue(moduleDesc.configurable);
......@@ -146,32 +142,20 @@ assertTrue(moduleDesc.configurable);
let Module = WebAssembly.Module;
assertEq(Module, moduleDesc.value);
assertEq(Module.length, 1);
assertEq(Module.name, 'Module');
assertErrorMessage(
() => Module(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(
() => new Module(), TypeError, /requires more than 0 arguments/);
assertErrorMessage(
() => new Module(undefined), TypeError,
'first argument must be an ArrayBuffer or typed array object');
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/);
assertEq(Module.name, "Module");
assertErrorMessage(() => Module(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(() => new Module(), TypeError, /requires more than 0 arguments/);
assertErrorMessage(() => new Module(undefined), TypeError, "first argument must be an ArrayBuffer or typed array object");
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.buffer) instanceof Module);
// 'WebAssembly.Module.prototype' data property
let moduleProtoDesc = Object.getOwnPropertyDescriptor(Module, 'prototype');
assertEq(typeof moduleProtoDesc.value, 'object');
assertEq(typeof moduleProtoDesc.value, "object");
assertFalse(moduleProtoDesc.writable);
assertFalse(moduleProtoDesc.enumerable);
assertFalse(moduleProtoDesc.configurable);
......@@ -179,20 +163,20 @@ assertFalse(moduleProtoDesc.configurable);
// 'WebAssembly.Module.prototype' object
let moduleProto = Module.prototype;
assertEq(moduleProto, moduleProtoDesc.value);
assertEq(String(moduleProto), '[object WebAssembly.Module]');
assertEq(String(moduleProto), "[object WebAssembly.Module]");
assertEq(Object.getPrototypeOf(moduleProto), Object.prototype);
// 'WebAssembly.Module' instance objects
let emptyModule = new Module(emptyModuleBinary);
let importingModule = new Module(importingModuleBinary);
let exportingModule = new Module(exportingModuleBinary);
assertEq(typeof emptyModule, 'object');
assertEq(String(emptyModule), '[object WebAssembly.Module]');
assertEq(typeof emptyModule, "object");
assertEq(String(emptyModule), "[object WebAssembly.Module]");
assertEq(Object.getPrototypeOf(emptyModule), moduleProto);
// 'WebAssembly.Module.imports' data property
let moduleImportsDesc = Object.getOwnPropertyDescriptor(Module, 'imports');
assertEq(typeof moduleImportsDesc.value, 'function');
assertEq(typeof moduleImportsDesc.value, "function");
assertTrue(moduleImportsDesc.writable);
assertFalse(moduleImportsDesc.enumerable);
assertTrue(moduleImportsDesc.configurable);
......@@ -200,46 +184,40 @@ assertTrue(moduleImportsDesc.configurable);
// 'WebAssembly.Module.imports' method
let moduleImports = moduleImportsDesc.value;
assertEq(moduleImports.length, 1);
assertErrorMessage(
() => moduleImports(), TypeError, /requires more than 0 arguments/);
assertErrorMessage(
() => moduleImports(undefined), TypeError,
/first argument must be a WebAssembly.Module/);
assertErrorMessage(
() => moduleImports({}), TypeError,
/first argument must be a WebAssembly.Module/);
assertErrorMessage(() => moduleImports(), TypeError, /requires more than 0 arguments/);
assertErrorMessage(() => 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));
assertTrue(arr instanceof Array);
assertEq(arr.length, 0);
let importingModuleBinary2 = (() => {
var text =
'(module (func (import "a" "b")) (memory (import "c" "d") 1) (table (import "e" "f") 1 anyfunc) (global (import "g" "⚡") i32))'
var text = '(module (func (import "a" "b")) (memory (import "c" "d") 1) (table (import "e" "f") 1 anyfunc) (global (import "g" "⚡") i32))'
let builder = new WasmModuleBuilder();
builder.addImport('a', 'b', kSig_i_i);
builder.addImportedMemory('c', 'd');
builder.addImportedTable('e', 'f');
builder.addImportedGlobal('g', 'x', kWasmI32);
builder.addImport("a", "b", kSig_i_i);
builder.addImportedMemory("c", "d");
builder.addImportedTable("e", "f");
builder.addImportedGlobal("g", "x", kWasmI32);
return new Int8Array(builder.toBuffer());
})();
var arr = moduleImports(new Module(importingModuleBinary2));
assertTrue(arr instanceof Array);
assertEq(arr.length, 4);
assertEq(arr[0].kind, 'function');
assertEq(arr[0].module, 'a');
assertEq(arr[0].name, 'b');
assertEq(arr[1].kind, 'memory');
assertEq(arr[1].module, 'c');
assertEq(arr[1].name, 'd');
assertEq(arr[2].kind, 'table');
assertEq(arr[2].module, 'e');
assertEq(arr[2].name, 'f');
assertEq(arr[3].kind, 'global');
assertEq(arr[3].module, 'g');
assertEq(arr[3].name, 'x');
assertEq(arr[0].kind, "function");
assertEq(arr[0].module, "a");
assertEq(arr[0].name, "b");
assertEq(arr[1].kind, "memory");
assertEq(arr[1].module, "c");
assertEq(arr[1].name, "d");
assertEq(arr[2].kind, "table");
assertEq(arr[2].module, "e");
assertEq(arr[2].name, "f");
assertEq(arr[3].kind, "global");
assertEq(arr[3].module, "g");
assertEq(arr[3].name, "x");
// 'WebAssembly.Module.exports' data property
let moduleExportsDesc = Object.getOwnPropertyDescriptor(Module, 'exports');
assertEq(typeof moduleExportsDesc.value, 'function');
assertEq(typeof moduleExportsDesc.value, "function");
assertTrue(moduleExportsDesc.writable);
assertFalse(moduleExportsDesc.enumerable);
assertTrue(moduleExportsDesc.configurable);
......@@ -247,40 +225,38 @@ assertTrue(moduleExportsDesc.configurable);
// 'WebAssembly.Module.exports' method
let moduleExports = moduleExportsDesc.value;
assertEq(moduleExports.length, 1);
assertErrorMessage(
() => moduleExports(), TypeError, /requires more than 0 arguments/);
assertErrorMessage(
() => moduleExports(undefined), TypeError,
/first argument must be a WebAssembly.Module/);
assertErrorMessage(
() => moduleExports({}), TypeError,
/first argument must be a WebAssembly.Module/);
assertErrorMessage(() => moduleExports(), TypeError, /requires more than 0 arguments/);
assertErrorMessage(() => moduleExports(undefined), TypeError, /first argument must be a WebAssembly.Module/);
assertErrorMessage(() => moduleExports({}), TypeError, /first argument must be a WebAssembly.Module/);
var arr = moduleExports(emptyModule);
assertTrue(arr instanceof Array);
assertEq(arr.length, 0);
let exportingModuleBinary2 = (() => {
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();
builder.addFunction('foo', kSig_v_v).addBody([]).exportAs('a');
builder.addFunction("foo", kSig_v_v)
.addBody([])
.exportAs("a");
builder.addMemory(1, 1, false);
builder.exportMemoryAs('b');
builder.exportMemoryAs("b");
builder.setFunctionTableLength(1);
builder.addExportOfKind('c', kExternalTable, 0);
var o = builder.addGlobal(kWasmI32, false).exportAs('x');
builder.addExportOfKind("c", kExternalTable, 0);
var o = builder.addGlobal(kWasmI32, false)
.exportAs("x");
return new Int8Array(builder.toBuffer());
})();
var arr = moduleExports(new Module(exportingModuleBinary2));
assertTrue(arr instanceof Array);
assertEq(arr.length, 4);
assertEq(arr[0].kind, 'function');
assertEq(arr[0].name, 'a');
assertEq(arr[1].kind, 'memory');
assertEq(arr[1].name, 'b');
assertEq(arr[2].kind, 'table');
assertEq(arr[2].name, 'c');
assertEq(arr[3].kind, 'global');
assertEq(arr[3].name, 'x');
assertEq(arr[0].kind, "function");
assertEq(arr[0].name, "a");
assertEq(arr[1].kind, "memory");
assertEq(arr[1].name, "b");
assertEq(arr[2].kind, "table");
assertEq(arr[2].name, "c");
assertEq(arr[3].kind, "global");
assertEq(arr[3].name, "x");
// 'WebAssembly.Module.customSections' data property
let moduleCustomSectionsDesc =
......@@ -337,7 +313,7 @@ assertEq(arr.length, 0);
// 'WebAssembly.Instance' data property
let instanceDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Instance');
assertEq(typeof instanceDesc.value, 'function');
assertEq(typeof instanceDesc.value, "function");
assertTrue(instanceDesc.writable);
assertFalse(instanceDesc.enumerable);
assertTrue(instanceDesc.configurable);
......@@ -346,33 +322,23 @@ assertTrue(instanceDesc.configurable);
let Instance = WebAssembly.Instance;
assertEq(Instance, instanceDesc.value);
assertEq(Instance.length, 1);
assertEq(Instance.name, 'Instance');
assertEq(Instance.name, "Instance");
assertErrorMessage(
() => Instance(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(
() => new Instance(1), TypeError,
'first argument must be a WebAssembly.Module');
assertErrorMessage(
() => new Instance({}), TypeError,
'first argument must be a WebAssembly.Module');
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, '');
assertErrorMessage(() => Instance(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(() => new Instance(1), TypeError, "first argument must be a WebAssembly.Module");
assertErrorMessage(() => new Instance({}), TypeError, "first argument must be a WebAssembly.Module");
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);
// 'WebAssembly.Instance.prototype' data property
let instanceProtoDesc = Object.getOwnPropertyDescriptor(Instance, 'prototype');
assertEq(typeof instanceProtoDesc.value, 'object');
assertEq(typeof instanceProtoDesc.value, "object");
assertFalse(instanceProtoDesc.writable);
assertFalse(instanceProtoDesc.enumerable);
assertFalse(instanceProtoDesc.configurable);
......@@ -380,19 +346,18 @@ assertFalse(instanceProtoDesc.configurable);
// 'WebAssembly.Instance.prototype' object
let instanceProto = Instance.prototype;
assertEq(instanceProto, instanceProtoDesc.value);
assertEq(String(instanceProto), '[object WebAssembly.Instance]');
assertEq(String(instanceProto), "[object WebAssembly.Instance]");
assertEq(Object.getPrototypeOf(instanceProto), Object.prototype);
// 'WebAssembly.Instance' instance objects
let exportingInstance = new Instance(exportingModule);
assertEq(typeof exportingInstance, 'object');
assertEq(String(exportingInstance), '[object WebAssembly.Instance]');
assertEq(typeof exportingInstance, "object");
assertEq(String(exportingInstance), "[object WebAssembly.Instance]");
assertEq(Object.getPrototypeOf(exportingInstance), instanceProto);
// 'WebAssembly.Instance' 'exports' data property
let instanceExportsDesc =
Object.getOwnPropertyDescriptor(exportingInstance, 'exports');
assertEq(typeof instanceExportsDesc.value, 'object');
let instanceExportsDesc = Object.getOwnPropertyDescriptor(exportingInstance, 'exports');
assertEq(typeof instanceExportsDesc.value, "object");
assertTrue(instanceExportsDesc.writable);
assertTrue(instanceExportsDesc.enumerable);
assertTrue(instanceExportsDesc.configurable);
......@@ -413,7 +378,7 @@ assertErrorMessage(() => new f(), TypeError, /is not a constructor/);
// 'WebAssembly.Memory' data property
let memoryDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Memory');
assertEq(typeof memoryDesc.value, 'function');
assertEq(typeof memoryDesc.value, "function");
assertTrue(memoryDesc.writable);
assertFalse(memoryDesc.enumerable);
assertTrue(memoryDesc.configurable);
......@@ -422,34 +387,21 @@ assertTrue(memoryDesc.configurable);
let Memory = WebAssembly.Memory;
assertEq(Memory, memoryDesc.value);
assertEq(Memory.length, 1);
assertEq(Memory.name, 'Memory');
assertErrorMessage(
() => Memory(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(
() => new Memory(1), TypeError,
'first argument must be a memory descriptor');
assertErrorMessage(
() => new Memory({initial: {valueOf() { throw new Error('here') }}}), Error,
'here');
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/);
assertEq(Memory.name, "Memory");
assertErrorMessage(() => Memory(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(() => new Memory(1), TypeError, "first argument must be a memory descriptor");
assertErrorMessage(() => new Memory({initial:{valueOf() { throw new Error("here")}}}), Error, "here");
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);
assertEq(new Memory({initial: 1.5}).buffer.byteLength, kPageSize);
assertEq(new Memory({initial:1.5}).buffer.byteLength, kPageSize);
// 'WebAssembly.Memory.prototype' data property
let memoryProtoDesc = Object.getOwnPropertyDescriptor(Memory, 'prototype');
assertEq(typeof memoryProtoDesc.value, 'object');
assertEq(typeof memoryProtoDesc.value, "object");
assertFalse(memoryProtoDesc.writable);
assertFalse(memoryProtoDesc.enumerable);
assertFalse(memoryProtoDesc.configurable);
......@@ -457,34 +409,32 @@ assertFalse(memoryProtoDesc.configurable);
// 'WebAssembly.Memory.prototype' object
let memoryProto = Memory.prototype;
assertEq(memoryProto, memoryProtoDesc.value);
assertEq(String(memoryProto), '[object WebAssembly.Memory]');
assertEq(String(memoryProto), "[object WebAssembly.Memory]");
assertEq(Object.getPrototypeOf(memoryProto), Object.prototype);
// 'WebAssembly.Memory' instance objects
let mem1 = new Memory({initial: 1});
assertEq(typeof mem1, 'object');
assertEq(String(mem1), '[object WebAssembly.Memory]');
let mem1 = new Memory({initial:1});
assertEq(typeof mem1, "object");
assertEq(String(mem1), "[object WebAssembly.Memory]");
assertEq(Object.getPrototypeOf(mem1), memoryProto);
// 'WebAssembly.Memory.prototype.buffer' accessor property
let bufferDesc = Object.getOwnPropertyDescriptor(memoryProto, 'buffer');
assertEq(typeof bufferDesc.get, 'function');
assertEq(typeof bufferDesc.get, "function");
assertEq(bufferDesc.set, undefined);
assertFalse(bufferDesc.enumerable);
assertTrue(bufferDesc.configurable);
// 'WebAssembly.Memory.prototype.buffer' getter
let bufferGetter = bufferDesc.get;
assertErrorMessage(
() => bufferGetter.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(
() => bufferGetter.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(() => bufferGetter.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(() => bufferGetter.call({}), TypeError, /called on incompatible Object/);
assertTrue(bufferGetter.call(mem1) instanceof ArrayBuffer);
assertEq(bufferGetter.call(mem1).byteLength, kPageSize);
// 'WebAssembly.Memory.prototype.grow' data property
let memGrowDesc = Object.getOwnPropertyDescriptor(memoryProto, 'grow');
assertEq(typeof memGrowDesc.value, 'function');
assertEq(typeof memGrowDesc.value, "function");
assertFalse(memGrowDesc.enumerable);
assertTrue(memGrowDesc.configurable);
......@@ -492,16 +442,15 @@ assertTrue(memGrowDesc.configurable);
let memGrow = memGrowDesc.value;
assertEq(memGrow.length, 1);
assertErrorMessage(
() => memGrow.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(
() => memGrow.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(
() => memGrow.call(mem1, -1), RangeError, /bad Memory grow delta/);
assertErrorMessage(
() => memGrow.call(mem1, Math.pow(2, 32)), RangeError,
assertErrorMessage(() => memGrow.call(), TypeError,
/called on incompatible undefined/);
assertErrorMessage(() => memGrow.call({}), TypeError,
/called on incompatible Object/);
assertErrorMessage(() => memGrow.call(mem1, -1), RangeError,
/bad Memory grow delta/);
assertErrorMessage(() => memGrow.call(mem1, Math.pow(2,32)), RangeError,
/bad Memory grow delta/);
var mem = new Memory({initial: 1, maximum: 2});
var mem = new Memory({initial:1, maximum:2});
var buf = mem.buffer;
assertEq(buf.byteLength, kPageSize);
assertEq(mem.grow(0), 1);
......@@ -519,7 +468,7 @@ assertEq(buf, mem.buffer);
// 'WebAssembly.Table' data property
let tableDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Table');
assertEq(typeof tableDesc.value, 'function');
assertEq(typeof tableDesc.value, "function");
assertTrue(tableDesc.writable);
assertFalse(tableDesc.enumerable);
assertTrue(tableDesc.configurable);
......@@ -528,35 +477,17 @@ assertTrue(tableDesc.configurable);
let Table = WebAssembly.Table;
assertEq(Table, tableDesc.value);
assertEq(Table.length, 1);
assertEq(Table.name, 'Table');
assertErrorMessage(
() => Table(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(
() => new Table(1), TypeError, 'first argument must be a table descriptor');
assertErrorMessage(
() => new Table({initial: 1, element: 1}), TypeError, /must be "anyfunc"/);
assertErrorMessage(
() => new Table({initial: 1, element: 'any'}), TypeError,
/must be "anyfunc"/);
assertErrorMessage(
() => 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/);
assertEq(Table.name, "Table");
assertErrorMessage(() => Table(), TypeError, /constructor without new is forbidden/);
assertErrorMessage(() => new Table(1), TypeError, "first argument must be a table descriptor");
assertErrorMessage(() => new Table({initial:1, element:1}), TypeError, /must be "anyfunc"/);
assertErrorMessage(() => new Table({initial:1, element:"any"}), TypeError, /must be "anyfunc"/);
assertErrorMessage(() => 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.5, element: 'anyfunc'}) instanceof Table);
assertTrue(
......@@ -566,7 +497,7 @@ assertTrue(
// 'WebAssembly.Table.prototype' data property
let tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype');
assertEq(typeof tableProtoDesc.value, 'object');
assertEq(typeof tableProtoDesc.value, "object");
assertFalse(tableProtoDesc.writable);
assertFalse(tableProtoDesc.enumerable);
assertFalse(tableProtoDesc.configurable);
......@@ -574,18 +505,18 @@ assertFalse(tableProtoDesc.configurable);
// 'WebAssembly.Table.prototype' object
let tableProto = Table.prototype;
assertEq(tableProto, tableProtoDesc.value);
assertEq(String(tableProto), '[object WebAssembly.Table]');
assertEq(String(tableProto), "[object WebAssembly.Table]");
assertEq(Object.getPrototypeOf(tableProto), Object.prototype);
// 'WebAssembly.Table' instance objects
let tbl1 = new Table({initial: 2, element: 'anyfunc'});
assertEq(typeof tbl1, 'object');
assertEq(String(tbl1), '[object WebAssembly.Table]');
let tbl1 = new Table({initial:2, element:"anyfunc"});
assertEq(typeof tbl1, "object");
assertEq(String(tbl1), "[object WebAssembly.Table]");
assertEq(Object.getPrototypeOf(tbl1), tableProto);
// 'WebAssembly.Table.prototype.length' accessor data property
let lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length');
assertEq(typeof lengthDesc.get, 'function');
assertEq(typeof lengthDesc.get, "function");
assertEq(lengthDesc.set, undefined);
assertFalse(lengthDesc.enumerable);
assertTrue(lengthDesc.configurable);
......@@ -593,95 +524,68 @@ assertTrue(lengthDesc.configurable);
// 'WebAssembly.Table.prototype.length' getter
let lengthGetter = lengthDesc.get;
assertEq(lengthGetter.length, 0);
assertErrorMessage(
() => lengthGetter.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(
() => lengthGetter.call({}), TypeError, /called on incompatible Object/);
assertEq(typeof lengthGetter.call(tbl1), 'number');
assertErrorMessage(() => lengthGetter.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(() => lengthGetter.call({}), TypeError, /called on incompatible Object/);
assertEq(typeof lengthGetter.call(tbl1), "number");
assertEq(lengthGetter.call(tbl1), 2);
// 'WebAssembly.Table.prototype.get' data property
let getDesc = Object.getOwnPropertyDescriptor(tableProto, 'get');
assertEq(typeof getDesc.value, 'function');
assertEq(typeof getDesc.value, "function");
assertFalse(getDesc.enumerable);
assertTrue(getDesc.configurable);
// 'WebAssembly.Table.prototype.get' method
let get = getDesc.value;
assertEq(get.length, 1);
assertErrorMessage(
() => get.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(
() => get.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(() => get.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(() => get.call({}), TypeError, /called on incompatible Object/);
assertEq(get.call(tbl1, 0), null);
assertEq(get.call(tbl1, 1), null);
assertEq(get.call(tbl1, 1.5), null);
assertErrorMessage(() => get.call(tbl1, 2), RangeError, /bad Table get index/);
assertErrorMessage(
() => get.call(tbl1, 2.5), RangeError, /bad Table get index/);
assertErrorMessage(() => get.call(tbl1, 2.5), 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,
// /bad Table get index/);
assertErrorMessage(
() => get.call(tbl1, {valueOf() { throw new Error('hi') }}), Error, 'hi');
//TODO assertErrorMessage(() => get.call(tbl1, Math.pow(2,33)), RangeError, /bad Table get index/);
assertErrorMessage(() => get.call(tbl1, {valueOf() { throw new Error("hi") }}), Error, "hi");
// 'WebAssembly.Table.prototype.set' data property
let setDesc = Object.getOwnPropertyDescriptor(tableProto, 'set');
assertEq(typeof setDesc.value, 'function');
assertEq(typeof setDesc.value, "function");
assertFalse(setDesc.enumerable);
assertTrue(setDesc.configurable);
// 'WebAssembly.Table.prototype.set' method
let set = setDesc.value;
assertEq(set.length, 2);
assertErrorMessage(
() => set.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(
() => set.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(
() => set.call(tbl1, 0), TypeError, /requires more than 1 argument/);
assertErrorMessage(
() => set.call(tbl1, 2, null), RangeError, /bad Table set index/);
assertErrorMessage(
() => set.call(tbl1, -1, null), RangeError, /bad Table set index/);
// TODO assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null),
// 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');
assertErrorMessage(() => set.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(() => set.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(() => set.call(tbl1, 0), TypeError, /requires more than 1 argument/);
assertErrorMessage(() => set.call(tbl1, 2, null), RangeError, /bad Table set index/);
assertErrorMessage(() => set.call(tbl1, -1, null), RangeError, /bad Table set index/);
//TODO assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), 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, 1, null), undefined);
// 'WebAssembly.Table.prototype.grow' data property
let tblGrowDesc = Object.getOwnPropertyDescriptor(tableProto, 'grow');
assertEq(typeof tblGrowDesc.value, 'function');
assertEq(typeof tblGrowDesc.value, "function");
assertFalse(tblGrowDesc.enumerable);
assertTrue(tblGrowDesc.configurable);
// 'WebAssembly.Table.prototype.grow' method
let tblGrow = tblGrowDesc.value;
assertEq(tblGrow.length, 1);
assertErrorMessage(
() => tblGrow.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(
() => tblGrow.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(
() => 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});
assertErrorMessage(() => tblGrow.call(), TypeError, /called on incompatible undefined/);
assertErrorMessage(() => tblGrow.call({}), TypeError, /called on incompatible Object/);
assertErrorMessage(() => 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.grow(0), 1);
assertEq(tbl.length, 1);
......@@ -691,7 +595,7 @@ assertErrorMessage(() => tbl.grow(1), Error, /failed to grow table/);
// 'WebAssembly.validate' function
assertErrorMessage(() => WebAssembly.validate(), TypeError);
assertErrorMessage(() => WebAssembly.validate('hi'), TypeError);
assertErrorMessage(() => WebAssembly.validate("hi"), TypeError);
assertTrue(WebAssembly.validate(emptyModuleBinary));
// TODO: other ways for validate to return false.
assertFalse(WebAssembly.validate(moduleBinaryImporting2Memories));
......@@ -699,7 +603,7 @@ assertFalse(WebAssembly.validate(moduleBinaryWithMemSectionAndMemImport));
// 'WebAssembly.compile' data property
let compileDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'compile');
assertEq(typeof compileDesc.value, 'function');
assertEq(typeof compileDesc.value, "function");
assertTrue(compileDesc.writable);
assertFalse(compileDesc.enumerable);
assertTrue(compileDesc.configurable);
......@@ -708,45 +612,36 @@ assertTrue(compileDesc.configurable);
let compile = WebAssembly.compile;
assertEq(compile, compileDesc.value);
assertEq(compile.length, 1);
assertEq(compile.name, 'compile');
assertEq(compile.name, "compile");
function assertCompileError(args, err, msg) {
var error = null;
assertPromiseResult(compile(...args), unexpectedSuccess, error => {
assertTrue(error instanceof err);
assertTrue(Boolean(error.stack.match('js-api.js')));
// TODO assertTrue(Boolean(error.message.match(msg)));
});
compile(...args).catch(e => error = e);
drainJobQueue();
assertTrue(error instanceof err);
assertTrue(Boolean(error.stack.match('js-api.js')));
// TODO assertTrue(Boolean(error.message.match(msg)));
}
assertCompileError([], TypeError, /requires more than 0 arguments/);
assertCompileError(
[undefined], TypeError,
/first argument must be an ArrayBuffer or typed array object/);
assertCompileError(
[1], TypeError,
/first argument must be an ArrayBuffer or typed array object/);
assertCompileError(
[{}], 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/);
assertCompileError([undefined], TypeError, /first argument must be an ArrayBuffer or typed array object/);
assertCompileError([1], TypeError, /first argument must be an ArrayBuffer or typed array object/);
assertCompileError([{}], 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) {
var module = null;
assertPromiseResult(compile(bytes), m => assertTrue(m instanceof Module));
var module = null;
compile(bytes).then(m => module = m);
drainJobQueue();
assertTrue(module instanceof Module);
}
assertCompileSuccess(emptyModuleBinary);
assertCompileSuccess(emptyModuleBinary.buffer);
// 'WebAssembly.instantiate' data property
let instantiateDesc =
Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
assertEq(typeof instantiateDesc.value, 'function');
let instantiateDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
assertEq(typeof instantiateDesc.value, "function");
assertTrue(instantiateDesc.writable);
assertFalse(instantiateDesc.enumerable);
assertTrue(instantiateDesc.configurable);
......@@ -755,81 +650,56 @@ assertTrue(instantiateDesc.configurable);
let instantiate = WebAssembly.instantiate;
assertEq(instantiate, instantiateDesc.value);
assertEq(instantiate.length, 1);
assertEq(instantiate.name, 'instantiate');
assertEq(instantiate.name, "instantiate");
function assertInstantiateError(args, err, msg) {
var error = null;
assertPromiseResult(instantiate(...args), unexpectedSuccess, error => {
assertTrue(error instanceof err);
assertTrue(Boolean(error.stack.match('js-api.js')));
// TODO assertTrue(Boolean(error.message.match(msg)));
});
instantiate(...args).catch(e => error = e);
drainJobQueue();
assertTrue(error instanceof err);
assertTrue(Boolean(error.stack.match('js-api.js')));
// TODO assertTrue(Boolean(error.message.match(msg)));
}
var scratch_memory = new WebAssembly.Memory(new ArrayBuffer(10));
assertInstantiateError([], TypeError, /requires more than 0 arguments/);
assertInstantiateError(
[undefined], TypeError, /first argument must be a BufferSource/);
assertInstantiateError([undefined], TypeError, /first argument must be a BufferSource/);
assertInstantiateError([1], TypeError, /first argument must be a BufferSource/);
assertInstantiateError(
[{}], TypeError, /first argument must be a BufferSource/);
assertInstantiateError(
[new Uint8Array()], CompileError, /failed to match magic number/);
assertInstantiateError(
[new ArrayBuffer()], CompileError, /failed to match magic number/);
assertInstantiateError(
[new Uint8Array('hi!')], CompileError, /failed to match magic number/);
assertInstantiateError(
[new ArrayBuffer('hi!')], CompileError, /failed to match magic number/);
assertInstantiateError(
[importingModule], TypeError, /second argument must be an object/);
assertInstantiateError(
[importingModule, null], TypeError, /second argument must be an object/);
assertInstantiateError(
[importingModuleBinary, null], TypeError,
/second argument must be an object/);
assertInstantiateError(
[emptyModule, null], TypeError, /first argument must be a BufferSource/);
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?/);
assertInstantiateError([{}], TypeError, /first argument must be a BufferSource/);
assertInstantiateError([new Uint8Array()], CompileError, /failed to match magic number/);
assertInstantiateError([new ArrayBuffer()], CompileError, /failed to match magic number/);
assertInstantiateError([new Uint8Array("hi!")], CompileError, /failed to match magic number/);
assertInstantiateError([new ArrayBuffer("hi!")], CompileError, /failed to match magic number/);
assertInstantiateError([importingModule], TypeError, /second argument must be an object/);
assertInstantiateError([importingModule, null], TypeError, /second argument must be an object/);
assertInstantiateError([importingModuleBinary, null], TypeError, /second argument must be an object/);
assertInstantiateError([emptyModule, null], TypeError, /first argument must be a BufferSource/);
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) {
var result = null;
assertPromiseResult(instantiate(module_or_bytes, imports), result => {
if (module_or_bytes instanceof Module) {
assertTrue(result instanceof Instance);
} else {
assertTrue(result.module instanceof Module);
assertTrue(result.instance instanceof Instance);
}
});
instantiate(module_or_bytes, imports)
.then(r => result = r)
.catch(e => print(e));
drainJobQueue();
if (module_or_bytes instanceof Module) {
assertTrue(result instanceof Instance);
} else {
assertTrue(result.module instanceof Module);
assertTrue(result.instance instanceof Instance);
}
}
assertInstantiateSuccess(emptyModule);
assertInstantiateSuccess(emptyModuleBinary);
assertInstantiateSuccess(emptyModuleBinary.buffer);
assertInstantiateSuccess(importingModule, {'': {f: () => {}}});
assertInstantiateSuccess(importingModuleBinary, {'': {f: () => {}}});
assertInstantiateSuccess(importingModuleBinary.buffer, {'': {f: () => {}}});
assertInstantiateSuccess(
memoryImportingModuleBinary, {'': {'my_memory': scratch_memory}});
assertInstantiateSuccess(importingModuleBinary, {"":{f:()=>{}}});
assertInstantiateSuccess(importingModuleBinary.buffer, {"":{f:()=>{}}});
assertInstantiateSuccess(memoryImportingModuleBinary, {"": {"my_memory": scratch_memory}});
// 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.
//
// TODO(eholk): Once we have stable test IDs, use those as the key instead.
// See https://github.com/WebAssembly/spec/issues/415
//
// Flags: --expose-wasm --allow-natives-syntax
const known_failures = {
"'WebAssembly.Module.customSections' method":
'https://bugs.chromium.org/p/v8/issues/detail?id=5815',
......@@ -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/js-api/jsapi.js");
assertPromiseResult(last_promise, _ => {
last_promise.then(_ => {
if (failures.length > 0) {
let unexpected = false;
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