// 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/execution/isolate.h" #include "src/handles/handles.h" #include "src/objects/heap-number-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/property-descriptor.h" #include "src/wasm/module-decoder.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-interpreter.h" #include "src/wasm/wasm-js.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects.h" #include "src/wasm/wasm-result.h" namespace v8 { namespace internal { namespace wasm { namespace testing { uint32_t GetInitialMemSize(const WasmModule* module) { return kWasmPageSize * module->initial_pages; } MaybeHandle CompileForTesting(Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) { auto enabled_features = WasmFeaturesFromIsolate(isolate); MaybeHandle module = isolate->wasm_engine()->SyncCompile( isolate, enabled_features, thrower, bytes); DCHECK_EQ(thrower->error(), module.is_null()); return module; } MaybeHandle CompileAndInstantiateForTesting( Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) { MaybeHandle module = CompileForTesting(isolate, thrower, bytes); if (module.is_null()) return {}; return isolate->wasm_engine()->SyncInstantiate( isolate, thrower, module.ToHandleChecked(), {}, {}); } std::shared_ptr DecodeWasmModuleForTesting( Isolate* isolate, ErrorThrower* thrower, const byte* module_start, const byte* module_end, ModuleOrigin origin, bool verify_functions) { // Decode the module, but don't verify function bodies, since we'll // be compiling them anyway. auto enabled_features = WasmFeaturesFromIsolate(isolate); ModuleResult decoding_result = DecodeWasmModule( enabled_features, module_start, module_end, verify_functions, origin, isolate->counters(), isolate->wasm_engine()->allocator()); if (decoding_result.failed()) { // Module verification failed. throw. thrower->CompileError("DecodeWasmModule failed: %s", decoding_result.error().message().c_str()); } return std::move(decoding_result).value(); } bool InterpretWasmModuleForTesting(Isolate* isolate, Handle instance, const char* name, size_t argc, WasmValue* args) { HandleScope handle_scope(isolate); // Avoid leaking handles. WasmCodeRefScope code_ref_scope; MaybeHandle maybe_function = GetExportedFunction(isolate, instance, "main"); Handle function; if (!maybe_function.ToHandle(&function)) { return false; } int function_index = function->function_index(); FunctionSig* signature = instance->module()->functions[function_index].sig; size_t param_count = signature->parameter_count(); std::unique_ptr arguments(new WasmValue[param_count]); size_t arg_count = std::min(param_count, argc); if (arg_count > 0) { memcpy(arguments.get(), args, arg_count); } // Fill the parameters up with default values. for (size_t i = argc; i < param_count; ++i) { switch (signature->GetParam(i)) { case kWasmI32: arguments[i] = WasmValue(int32_t{0}); break; case kWasmI64: arguments[i] = WasmValue(int64_t{0}); break; case kWasmF32: arguments[i] = WasmValue(0.0f); break; case kWasmF64: arguments[i] = WasmValue(0.0); break; default: UNREACHABLE(); } } // Don't execute more than 16k steps. constexpr int kMaxNumSteps = 16 * 1024; Zone zone(isolate->allocator(), ZONE_NAME); WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance); WasmInterpreter::Thread* thread = interpreter->GetThread(0); thread->Reset(); // Start an activation so that we can deal with stack overflows. We do not // finish the activation. An activation is just part of the state of the // interpreter, and we do not reuse the interpreter anyways. In addition, // finishing the activation is not correct in all cases, e.g. when the // execution of the interpreter did not finish after kMaxNumSteps. thread->StartActivation(); thread->InitFrame(&instance->module()->functions[function_index], arguments.get()); WasmInterpreter::State interpreter_result = thread->Run(kMaxNumSteps); if (isolate->has_pending_exception()) { // Stack overflow during interpretation. isolate->clear_pending_exception(); return false; } return interpreter_result != WasmInterpreter::PAUSED; } int32_t RunWasmModuleForTesting(Isolate* isolate, Handle instance, int argc, Handle argv[]) { ErrorThrower thrower(isolate, "RunWasmModule"); return CallWasmFunctionForTesting(isolate, instance, &thrower, "main", argc, argv); } int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, const byte* module_end) { HandleScope scope(isolate); ErrorThrower thrower(isolate, "CompileAndRunWasmModule"); MaybeHandle instance = CompileAndInstantiateForTesting( isolate, &thrower, ModuleWireBytes(module_start, module_end)); if (instance.is_null()) { return -1; } return RunWasmModuleForTesting(isolate, instance.ToHandleChecked(), 0, nullptr); } int32_t CompileAndRunAsmWasmModule(Isolate* isolate, const byte* module_start, const byte* module_end) { HandleScope scope(isolate); ErrorThrower thrower(isolate, "CompileAndRunAsmWasmModule"); MaybeHandle data = isolate->wasm_engine()->SyncCompileTranslatedAsmJs( isolate, &thrower, ModuleWireBytes(module_start, module_end), Vector(), Handle()); DCHECK_EQ(thrower.error(), data.is_null()); if (data.is_null()) return -1; MaybeHandle module = isolate->wasm_engine()->FinalizeTranslatedAsmJs( isolate, data.ToHandleChecked(), Handle