e1eee748dd
Reason for revert: Main suspect for tsan: https://build.chromium.org/p/client.v8/builders/V8%20Linux64%20TSAN/builds/11893 Also changes layout tests: https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/10036 +mips builder: https://build.chromium.org/p/client.v8.ports/builders/V8%20Mips%20-%20builder/builds/4032 Original issue's description: > [wasm] Master CL for Binary 0xC changes. > > [0xC] Convert to stack machine semantics. > [0xC] Use section codes instead of names. > [0xC] Add elements section decoding. > [0xC] Decoding of globals section. > [0xC] Decoding of memory section. > [0xC] Decoding of imports section. > [0xC] Decoding of exports section. > [0xC] Decoding of data section. > [0xC] Remove CallImport bytecode. > [0xC] Function bodies have an implicit block. > [0xC] Remove the bottom label from loops. > [0xC] Add signatures to blocks. > [0xC] Remove arities from branches. > Add tests for init expression decoding. > Rework compilation of import wrappers and how they are patched. > Rework function indices in debugging. > Fix ASM->WASM builder for stack machine. > Reorganize asm.js foreign functions due to import indices change. > > R=ahaas@chromium.org,rossberg@chromium.org,bradnelson@chromium.org > BUG=chromium:575167 > LOG=Y > > Committed: https://crrev.com/76eb976a67273b8c03c744f64ad850b0432554b9 > Cr-Commit-Position: refs/heads/master@{#39678} TBR=ahaas@chromium.org,bradnelson@chromium.org,mtrofin@chromium.org,rossberg@chromium.org,bradnelson@google.com,titzer@chromium.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=chromium:575167 Review-Url: https://codereview.chromium.org/2361053004 Cr-Commit-Position: refs/heads/master@{#39685}
217 lines
7.7 KiB
C++
217 lines
7.7 KiB
C++
// Copyright 2016 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "test/common/wasm/wasm-module-runner.h"
|
|
|
|
#include "src/handles.h"
|
|
#include "src/isolate.h"
|
|
#include "src/objects.h"
|
|
#include "src/property-descriptor.h"
|
|
#include "src/wasm/module-decoder.h"
|
|
#include "src/wasm/wasm-interpreter.h"
|
|
#include "src/wasm/wasm-js.h"
|
|
#include "src/wasm/wasm-module.h"
|
|
#include "src/wasm/wasm-result.h"
|
|
#include "src/zone/zone.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace wasm {
|
|
namespace testing {
|
|
|
|
uint32_t GetMinModuleMemSize(const WasmModule* module) {
|
|
return WasmModule::kPageSize * module->min_mem_pages;
|
|
}
|
|
|
|
const WasmModule* DecodeWasmModuleForTesting(Isolate* isolate, Zone* zone,
|
|
ErrorThrower* thrower,
|
|
const byte* module_start,
|
|
const byte* module_end,
|
|
ModuleOrigin origin) {
|
|
// Decode the module, but don't verify function bodies, since we'll
|
|
// be compiling them anyway.
|
|
ModuleResult decoding_result =
|
|
DecodeWasmModule(isolate, zone, module_start, module_end, false, origin);
|
|
|
|
std::unique_ptr<const WasmModule> module(decoding_result.val);
|
|
if (decoding_result.failed()) {
|
|
// Module verification failed. throw.
|
|
thrower->Error("WASM.compileRun() failed: %s",
|
|
decoding_result.error_msg.get());
|
|
return nullptr;
|
|
}
|
|
|
|
if (thrower->error()) return nullptr;
|
|
return module.release();
|
|
}
|
|
|
|
const Handle<JSObject> InstantiateModuleForTesting(Isolate* isolate,
|
|
ErrorThrower* thrower,
|
|
const WasmModule* module) {
|
|
CHECK(module != nullptr);
|
|
|
|
if (module->import_table.size() > 0) {
|
|
thrower->Error("Not supported: module has imports.");
|
|
}
|
|
if (module->export_table.size() == 0) {
|
|
thrower->Error("Not supported: module has no exports.");
|
|
}
|
|
|
|
if (thrower->error()) return Handle<JSObject>::null();
|
|
|
|
// Although we decoded the module for some pre-validation, run the bytes
|
|
// again through the normal pipeline.
|
|
MaybeHandle<JSObject> module_object = CreateModuleObjectFromBytes(
|
|
isolate, module->module_start, module->module_end, thrower,
|
|
ModuleOrigin::kWasmOrigin);
|
|
if (module_object.is_null()) return Handle<JSObject>::null();
|
|
MaybeHandle<JSObject> maybe_instance = WasmModule::Instantiate(
|
|
isolate, module_object.ToHandleChecked(), Handle<JSReceiver>::null(),
|
|
Handle<JSArrayBuffer>::null());
|
|
Handle<JSObject> instance;
|
|
if (!maybe_instance.ToHandle(&instance)) {
|
|
return Handle<JSObject>::null();
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
|
|
const byte* module_end, ModuleOrigin origin) {
|
|
HandleScope scope(isolate);
|
|
Zone zone(isolate->allocator());
|
|
|
|
ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
|
|
std::unique_ptr<const WasmModule> module(DecodeWasmModuleForTesting(
|
|
isolate, &zone, &thrower, module_start, module_end, origin));
|
|
|
|
if (module == nullptr) {
|
|
return -1;
|
|
}
|
|
Handle<JSObject> instance =
|
|
InstantiateModuleForTesting(isolate, &thrower, module.get());
|
|
if (instance.is_null()) {
|
|
return -1;
|
|
}
|
|
const char* f_name = origin == ModuleOrigin::kAsmJsOrigin ? "caller" : "main";
|
|
return CallWasmFunctionForTesting(isolate, instance, &thrower, f_name, 0,
|
|
nullptr, origin);
|
|
}
|
|
|
|
int32_t InterpretWasmModule(Isolate* isolate, ErrorThrower* thrower,
|
|
const WasmModule* module, int function_index,
|
|
WasmVal* args) {
|
|
CHECK(module != nullptr);
|
|
|
|
Zone zone(isolate->allocator());
|
|
v8::internal::HandleScope scope(isolate);
|
|
|
|
if (module->import_table.size() > 0) {
|
|
thrower->Error("Not supported: module has imports.");
|
|
}
|
|
if (module->export_table.size() == 0) {
|
|
thrower->Error("Not supported: module has no exports.");
|
|
}
|
|
|
|
if (thrower->error()) return -1;
|
|
|
|
ModuleEnv module_env;
|
|
module_env.module = module;
|
|
module_env.origin = module->origin;
|
|
|
|
for (size_t i = 0; i < module->functions.size(); i++) {
|
|
FunctionBody body = {
|
|
&module_env, module->functions[i].sig, module->module_start,
|
|
module->module_start + module->functions[i].code_start_offset,
|
|
module->module_start + module->functions[i].code_end_offset};
|
|
DecodeResult result = VerifyWasmCode(isolate->allocator(), body);
|
|
if (result.failed()) {
|
|
thrower->Error("Function did not verify");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// The code verifies, we create an instance to run it in the interpreter.
|
|
WasmModuleInstance instance(module);
|
|
instance.context = isolate->native_context();
|
|
instance.mem_size = GetMinModuleMemSize(module);
|
|
// TODO(ahaas): Move memory allocation to wasm-module.cc for better
|
|
// encapsulation.
|
|
instance.mem_start =
|
|
static_cast<byte*>(calloc(GetMinModuleMemSize(module), 1));
|
|
instance.globals_start = nullptr;
|
|
module_env.instance = &instance;
|
|
|
|
WasmInterpreter interpreter(&instance, isolate->allocator());
|
|
|
|
WasmInterpreter::Thread* thread = interpreter.GetThread(0);
|
|
thread->Reset();
|
|
thread->PushFrame(&(module->functions[function_index]), args);
|
|
WasmInterpreter::State interpreter_result = thread->Run();
|
|
if (instance.mem_start) {
|
|
free(instance.mem_start);
|
|
}
|
|
if (interpreter_result == WasmInterpreter::FINISHED) {
|
|
WasmVal val = thread->GetReturnValue();
|
|
return val.to<int32_t>();
|
|
} else if (thread->state() == WasmInterpreter::TRAPPED) {
|
|
return 0xdeadbeef;
|
|
} else {
|
|
thrower->Error(
|
|
"Interpreter did not finish execution within its step bound");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int32_t CallWasmFunctionForTesting(Isolate* isolate, Handle<JSObject> instance,
|
|
ErrorThrower* thrower, const char* name,
|
|
int argc, Handle<Object> argv[],
|
|
ModuleOrigin origin) {
|
|
Handle<JSObject> exports_object;
|
|
if (origin == ModuleOrigin::kAsmJsOrigin) {
|
|
exports_object = instance;
|
|
} else {
|
|
Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports");
|
|
exports_object = Handle<JSObject>::cast(
|
|
JSObject::GetProperty(instance, exports).ToHandleChecked());
|
|
}
|
|
Handle<Name> main_name = isolate->factory()->NewStringFromAsciiChecked(name);
|
|
PropertyDescriptor desc;
|
|
Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor(
|
|
isolate, exports_object, main_name, &desc);
|
|
if (!property_found.FromMaybe(false)) return -1;
|
|
|
|
Handle<JSFunction> main_export = Handle<JSFunction>::cast(desc.value());
|
|
|
|
// Call the JS function.
|
|
Handle<Object> undefined = isolate->factory()->undefined_value();
|
|
MaybeHandle<Object> retval =
|
|
Execution::Call(isolate, main_export, undefined, argc, argv);
|
|
|
|
// The result should be a number.
|
|
if (retval.is_null()) {
|
|
thrower->Error("WASM.compileRun() failed: Invocation was null");
|
|
return -1;
|
|
}
|
|
Handle<Object> result = retval.ToHandleChecked();
|
|
if (result->IsSmi()) {
|
|
return Smi::cast(*result)->value();
|
|
}
|
|
if (result->IsHeapNumber()) {
|
|
return static_cast<int32_t>(HeapNumber::cast(*result)->value());
|
|
}
|
|
thrower->Error("WASM.compileRun() failed: Return value should be number");
|
|
return -1;
|
|
}
|
|
|
|
void SetupIsolateForWasmModule(Isolate* isolate) {
|
|
WasmJs::InstallWasmMapsIfNeeded(isolate, isolate->native_context());
|
|
WasmJs::InstallWasmModuleSymbolIfNeeded(isolate, isolate->global_object(),
|
|
isolate->native_context());
|
|
}
|
|
|
|
} // namespace testing
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|