[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}
This commit is contained in:
parent
a472eccd53
commit
7a6e6bb1e2
@ -1189,7 +1189,7 @@ void Code::CodePrint(std::ostream& os) { // NOLINT
|
||||
|
||||
|
||||
void Foreign::ForeignPrint(std::ostream& os) { // NOLINT
|
||||
os << "foreign address : " << foreign_address();
|
||||
os << "foreign address : " << reinterpret_cast<void*>(foreign_address());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,11 @@ 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;
|
||||
@ -320,6 +325,7 @@ 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() {
|
||||
@ -341,9 +347,8 @@ class CompilationHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitializeParallelCompilation(const std::vector<WasmFunction>& functions,
|
||||
ModuleBytesEnv& module_env,
|
||||
ErrorThrower* thrower) {
|
||||
size_t InitializeParallelCompilation(
|
||||
const std::vector<WasmFunction>& functions, ModuleBytesEnv& module_env) {
|
||||
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());
|
||||
@ -354,14 +359,15 @@ class CompilationHelper {
|
||||
compilation_units_.push_back(
|
||||
new compiler::WasmCompilationUnit(isolate_, &module_env, func));
|
||||
}
|
||||
return num_funcs;
|
||||
}
|
||||
|
||||
uint32_t* StartCompilationTasks() {
|
||||
const size_t num_tasks =
|
||||
num_background_tasks_ =
|
||||
Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
|
||||
V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
|
||||
uint32_t* task_ids = new uint32_t[num_tasks];
|
||||
for (size_t i = 0; i < num_tasks; ++i) {
|
||||
uint32_t* task_ids = new uint32_t[num_background_tasks_];
|
||||
for (size_t i = 0; i < num_background_tasks_; ++i) {
|
||||
CompilationTask* task = new CompilationTask(this);
|
||||
task_ids[i] = task->id();
|
||||
V8::GetCurrentPlatform()->CallOnBackgroundThread(
|
||||
@ -371,13 +377,9 @@ class CompilationHelper {
|
||||
}
|
||||
|
||||
void WaitForCompilationTasks(uint32_t* task_ids) {
|
||||
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) {
|
||||
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.
|
||||
// for it to finish.
|
||||
if (isolate_->cancelable_task_manager()->TryAbort(task_ids[i]) !=
|
||||
CancelableTaskManager::kTaskAborted) {
|
||||
module_->pending_tasks.get()->Wait();
|
||||
@ -388,21 +390,28 @@ class CompilationHelper {
|
||||
void FinishCompilationUnits(std::vector<Handle<Code>>& results,
|
||||
ErrorThrower* thrower) {
|
||||
while (true) {
|
||||
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;
|
||||
int func_index = 0;
|
||||
MaybeHandle<Code> result = FinishCompilationUnit(thrower, &func_index);
|
||||
if (result.is_null()) break;
|
||||
results[func_index] = result.ToHandleChecked();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -431,7 +440,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, thrower);
|
||||
InitializeParallelCompilation(module->functions, *module_env);
|
||||
|
||||
// Objects for the synchronization with the background threads.
|
||||
base::AtomicNumber<size_t> next_unit(
|
||||
@ -1568,14 +1577,7 @@ class InstantiationHelper {
|
||||
}
|
||||
|
||||
void WriteGlobalValue(WasmGlobal& global, Handle<Object> value) {
|
||||
double num = 0;
|
||||
if (value->IsSmi()) {
|
||||
num = Smi::cast(*value)->value();
|
||||
} else if (value->IsHeapNumber()) {
|
||||
num = HeapNumber::cast(*value)->value();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
double num = value->Number();
|
||||
TRACE("init [globals+%u] = %lf, type = %s\n", global.offset, num,
|
||||
WasmOpcodes::TypeName(global.type));
|
||||
switch (global.type) {
|
||||
@ -2602,21 +2604,19 @@ MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate(
|
||||
|
||||
namespace {
|
||||
|
||||
void RejectPromise(Isolate* isolate, ErrorThrower* thrower,
|
||||
Handle<JSPromise> promise) {
|
||||
void RejectPromise(Isolate* isolate, Handle<Context> context,
|
||||
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<JSPromise> promise,
|
||||
Handle<Object> result) {
|
||||
void ResolvePromise(Isolate* isolate, Handle<Context> context,
|
||||
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,18 +2624,6 @@ void ResolvePromise(Isolate* isolate, Handle<JSPromise> promise,
|
||||
|
||||
} // 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) {
|
||||
@ -2643,10 +2631,11 @@ 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, &thrower, promise);
|
||||
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
|
||||
return;
|
||||
}
|
||||
ResolvePromise(isolate, promise, instance_object.ToHandleChecked());
|
||||
ResolvePromise(isolate, handle(isolate->context()), promise,
|
||||
instance_object.ToHandleChecked());
|
||||
}
|
||||
|
||||
void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
|
||||
@ -2659,7 +2648,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
|
||||
MaybeHandle<WasmModuleObject> module_object =
|
||||
SyncCompile(isolate, &thrower, bytes);
|
||||
if (thrower.error()) {
|
||||
RejectPromise(isolate, &thrower, promise);
|
||||
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
|
||||
return;
|
||||
}
|
||||
Handle<WasmModuleObject> module = module_object.ToHandleChecked();
|
||||
@ -2668,7 +2657,7 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
|
||||
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
|
||||
isolate, &thrower, module, imports, Handle<JSArrayBuffer>::null());
|
||||
if (thrower.error()) {
|
||||
RejectPromise(isolate, &thrower, promise);
|
||||
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2684,7 +2673,388 @@ void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
|
||||
JSObject::AddProperty(ret, instance_property_name,
|
||||
instance_object.ToHandleChecked(), NONE);
|
||||
|
||||
ResolvePromise(isolate, promise, ret);
|
||||
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();
|
||||
}
|
||||
|
||||
Handle<Code> wasm::CompileLazy(Isolate* isolate) {
|
||||
|
@ -250,7 +250,6 @@ var failWithMessage;
|
||||
|
||||
|
||||
failWithMessage = function failWithMessage(message) {
|
||||
print("oh, we failed: " + message);
|
||||
throw new MjsUnitAssertionError(message);
|
||||
}
|
||||
|
||||
|
49
test/mjsunit/wasm/async-compile.js
Normal file
49
test/mjsunit/wasm/async-compile.js
Normal file
@ -0,0 +1,49 @@
|
||||
// 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);
|
||||
}
|
22
test/mjsunit/wasm/compilation-limits-asm.js
Normal file
22
test/mjsunit/wasm/compilation-limits-asm.js
Normal file
@ -0,0 +1,22 @@
|
||||
// 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));
|
113
test/mjsunit/wasm/compilation-limits.js
Normal file
113
test/mjsunit/wasm/compilation-limits.js
Normal file
@ -0,0 +1,113 @@
|
||||
// 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
|
||||
// Flags: --expose-wasm --allow-natives-syntax
|
||||
|
||||
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,25 +51,26 @@ 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);
|
||||
promise.then(module => CheckInstance(new WebAssembly.Instance(module)));
|
||||
assertPromiseResult(
|
||||
promise, module => CheckInstance(new WebAssembly.Instance(module)));
|
||||
|
||||
print("async instantiate...");
|
||||
print('async instantiate...');
|
||||
let instance_promise = WebAssembly.instantiate(buffer);
|
||||
instance_promise.then(CheckInstance);
|
||||
assertPromiseResult(instance_promise, CheckInstance);
|
||||
})();
|
||||
|
||||
// Check that validate works correctly for a module.
|
||||
@ -78,35 +79,34 @@ 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());
|
||||
promise
|
||||
.then(compiled =>
|
||||
assertUnreachable("should not be able to compile invalid blob."))
|
||||
.catch(e => assertContains("invalid signature index", e.toString()));
|
||||
assertPromiseResult(
|
||||
promise, compiled => assertUnreachable(
|
||||
'should not be able to compile invalid blob.'),
|
||||
e => assertInstanceof(e, WebAssembly.CompileError));
|
||||
})();
|
||||
|
||||
// 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);
|
||||
promise.then(compiled_module => {
|
||||
assertPromiseResult(promise, compiled_module => {
|
||||
let instance_1 = new WebAssembly.Instance(compiled_module);
|
||||
let instance_2 = new WebAssembly.Instance(compiled_module);
|
||||
assertTrue(instance_1 != instance_2);
|
||||
@ -124,35 +124,29 @@ 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.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.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});
|
||||
@ -164,13 +158,15 @@ 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));
|
||||
@ -180,40 +176,34 @@ 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();
|
||||
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();
|
||||
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());
|
||||
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});
|
||||
@ -223,23 +213,24 @@ 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() {
|
||||
@ -249,13 +240,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,12 +4,16 @@
|
||||
|
||||
// Flags: --expose-wasm --allow-natives-syntax
|
||||
|
||||
if ((typeof drainJobQueue) != "function") {
|
||||
drainJobQueue = () => { %RunMicrotasks() };
|
||||
load('test/mjsunit/wasm/wasm-constants.js');
|
||||
load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
|
||||
function unexpectedSuccess() {
|
||||
% AbortJS('unexpected success');
|
||||
}
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
function unexpectedFail(error) {
|
||||
% AbortJS('unexpected fail: ' + error);
|
||||
}
|
||||
|
||||
function assertEq(val, expected) {
|
||||
assertEquals(expected, val);
|
||||
@ -23,10 +27,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);
|
||||
}
|
||||
|
||||
@ -37,103 +41,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);
|
||||
@ -142,20 +146,32 @@ 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);
|
||||
@ -163,20 +179,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);
|
||||
@ -184,40 +200,46 @@ 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);
|
||||
@ -225,38 +247,40 @@ 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 =
|
||||
@ -313,7 +337,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);
|
||||
@ -322,23 +346,33 @@ 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);
|
||||
@ -346,18 +380,19 @@ 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);
|
||||
@ -378,7 +413,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);
|
||||
@ -387,21 +422,34 @@ 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);
|
||||
@ -409,32 +457,34 @@ 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);
|
||||
|
||||
@ -442,15 +492,16 @@ 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,
|
||||
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/);
|
||||
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);
|
||||
@ -468,7 +519,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);
|
||||
@ -477,17 +528,35 @@ 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(
|
||||
@ -497,7 +566,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);
|
||||
@ -505,18 +574,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);
|
||||
@ -524,68 +593,95 @@ 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);
|
||||
@ -595,7 +691,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));
|
||||
@ -603,7 +699,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);
|
||||
@ -612,36 +708,45 @@ 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;
|
||||
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)));
|
||||
assertPromiseResult(compile(...args), unexpectedSuccess, error => {
|
||||
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;
|
||||
compile(bytes).then(m => module = m);
|
||||
drainJobQueue();
|
||||
assertTrue(module instanceof Module);
|
||||
var module = null;
|
||||
assertPromiseResult(compile(bytes), m => assertTrue(m 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);
|
||||
@ -650,56 +755,81 @@ 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;
|
||||
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)));
|
||||
assertPromiseResult(instantiate(...args), unexpectedSuccess, error => {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
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}});
|
||||
|
@ -1,9 +1,12 @@
|
||||
// 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',
|
||||
@ -78,7 +81,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");
|
||||
|
||||
last_promise.then(_ => {
|
||||
assertPromiseResult(last_promise, _ => {
|
||||
if (failures.length > 0) {
|
||||
let unexpected = false;
|
||||
print("Some tests FAILED:");
|
||||
|
@ -1,118 +0,0 @@
|
||||
// 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);
|
Loading…
Reference in New Issue
Block a user