Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "test/common/wasm/wasm-module-runner.h"
6 :
7 : #include "src/handles.h"
8 : #include "src/isolate.h"
9 : #include "src/objects-inl.h"
10 : #include "src/objects.h"
11 : #include "src/property-descriptor.h"
12 : #include "src/wasm/module-compiler.h"
13 : #include "src/wasm/module-decoder.h"
14 : #include "src/wasm/wasm-interpreter.h"
15 : #include "src/wasm/wasm-js.h"
16 : #include "src/wasm/wasm-module.h"
17 : #include "src/wasm/wasm-objects.h"
18 : #include "src/wasm/wasm-result.h"
19 :
20 : namespace v8 {
21 : namespace internal {
22 : namespace wasm {
23 : namespace testing {
24 :
25 0 : uint32_t GetInitialMemSize(const WasmModule* module) {
26 0 : return WasmModule::kPageSize * module->initial_pages;
27 : }
28 :
29 7 : std::unique_ptr<WasmModule> DecodeWasmModuleForTesting(
30 : Isolate* isolate, ErrorThrower* thrower, const byte* module_start,
31 : const byte* module_end, ModuleOrigin origin, bool verify_functions) {
32 : // Decode the module, but don't verify function bodies, since we'll
33 : // be compiling them anyway.
34 : ModuleResult decoding_result = SyncDecodeWasmModule(
35 14 : isolate, module_start, module_end, verify_functions, origin);
36 :
37 7 : if (decoding_result.failed()) {
38 : // Module verification failed. throw.
39 : thrower->CompileError("DecodeWasmModule failed: %s",
40 0 : decoding_result.error_msg().c_str());
41 : }
42 :
43 7 : return std::move(decoding_result.val);
44 : }
45 :
46 2 : bool InterpretWasmModuleForTesting(Isolate* isolate,
47 : Handle<WasmInstanceObject> instance,
48 : const char* name, size_t argc,
49 : WasmValue* args) {
50 : MaybeHandle<WasmExportedFunction> maybe_function =
51 1 : GetExportedFunction(isolate, instance, "main");
52 : Handle<WasmExportedFunction> function;
53 1 : if (!maybe_function.ToHandle(&function)) {
54 : return false;
55 : }
56 : int function_index = function->function_index();
57 3 : FunctionSig* signature = instance->module()->functions[function_index].sig;
58 1 : size_t param_count = signature->parameter_count();
59 1 : std::unique_ptr<WasmValue[]> arguments(new WasmValue[param_count]);
60 :
61 1 : memcpy(arguments.get(), args, std::min(param_count, argc));
62 :
63 : // Fill the parameters up with default values.
64 1 : for (size_t i = argc; i < param_count; ++i) {
65 0 : switch (signature->GetParam(i)) {
66 : case MachineRepresentation::kWord32:
67 0 : arguments[i] = WasmValue(int32_t{0});
68 0 : break;
69 : case MachineRepresentation::kWord64:
70 0 : arguments[i] = WasmValue(int64_t{0});
71 0 : break;
72 : case MachineRepresentation::kFloat32:
73 0 : arguments[i] = WasmValue(0.0f);
74 0 : break;
75 : case MachineRepresentation::kFloat64:
76 0 : arguments[i] = WasmValue(0.0);
77 0 : break;
78 : default:
79 0 : UNREACHABLE();
80 : }
81 : }
82 :
83 : // Don't execute more than 16k steps.
84 : constexpr int kMaxNumSteps = 16 * 1024;
85 :
86 1 : Zone zone(isolate->allocator(), ZONE_NAME);
87 :
88 1 : WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
89 2 : WasmInterpreter::HeapObjectsScope heap_objects_scope(interpreter, instance);
90 1 : WasmInterpreter::Thread* thread = interpreter->GetThread(0);
91 1 : thread->Reset();
92 1 : thread->InitFrame(&instance->module()->functions[function_index],
93 1 : arguments.get());
94 1 : WasmInterpreter::State interpreter_result = thread->Run(kMaxNumSteps);
95 :
96 2 : return interpreter_result != WasmInterpreter::PAUSED;
97 : }
98 :
99 348 : int32_t RunWasmModuleForTesting(Isolate* isolate,
100 : Handle<WasmInstanceObject> instance, int argc,
101 : Handle<Object> argv[]) {
102 : ErrorThrower thrower(isolate, "RunWasmModule");
103 : return CallWasmFunctionForTesting(isolate, instance, &thrower, "main", argc,
104 348 : argv);
105 : }
106 :
107 252 : int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
108 : const byte* module_end) {
109 : HandleScope scope(isolate);
110 252 : ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
111 : MaybeHandle<WasmInstanceObject> instance = SyncCompileAndInstantiate(
112 252 : isolate, &thrower, ModuleWireBytes(module_start, module_end), {}, {});
113 252 : if (instance.is_null()) {
114 : return -1;
115 : }
116 : return RunWasmModuleForTesting(isolate, instance.ToHandleChecked(), 0,
117 252 : nullptr);
118 : }
119 :
120 0 : int32_t CompileAndRunAsmWasmModule(Isolate* isolate, const byte* module_start,
121 : const byte* module_end) {
122 : HandleScope scope(isolate);
123 0 : ErrorThrower thrower(isolate, "CompileAndRunAsmWasmModule");
124 : MaybeHandle<WasmModuleObject> module = wasm::SyncCompileTranslatedAsmJs(
125 : isolate, &thrower, ModuleWireBytes(module_start, module_end),
126 0 : Handle<Script>::null(), Vector<const byte>());
127 : DCHECK_EQ(thrower.error(), module.is_null());
128 0 : if (module.is_null()) return -1;
129 :
130 : MaybeHandle<WasmInstanceObject> instance = wasm::SyncInstantiate(
131 : isolate, &thrower, module.ToHandleChecked(), Handle<JSReceiver>::null(),
132 0 : Handle<JSArrayBuffer>::null());
133 : DCHECK_EQ(thrower.error(), instance.is_null());
134 0 : if (instance.is_null()) return -1;
135 :
136 : return RunWasmModuleForTesting(isolate, instance.ToHandleChecked(), 0,
137 0 : nullptr);
138 : }
139 1 : int32_t InterpretWasmModule(Isolate* isolate,
140 : Handle<WasmInstanceObject> instance,
141 : ErrorThrower* thrower, int32_t function_index,
142 : WasmValue* args, bool* possible_nondeterminism) {
143 : // Don't execute more than 16k steps.
144 : constexpr int kMaxNumSteps = 16 * 1024;
145 :
146 1 : Zone zone(isolate->allocator(), ZONE_NAME);
147 : v8::internal::HandleScope scope(isolate);
148 :
149 1 : WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
150 2 : WasmInterpreter::HeapObjectsScope heap_objects_scope(interpreter, instance);
151 1 : WasmInterpreter::Thread* thread = interpreter->GetThread(0);
152 1 : thread->Reset();
153 3 : thread->InitFrame(&(instance->module()->functions[function_index]), args);
154 1 : WasmInterpreter::State interpreter_result = thread->Run(kMaxNumSteps);
155 :
156 1 : *possible_nondeterminism = thread->PossibleNondeterminism();
157 1 : if (interpreter_result == WasmInterpreter::FINISHED) {
158 1 : WasmValue val = thread->GetReturnValue();
159 : return val.to<int32_t>();
160 0 : } else if (thread->state() == WasmInterpreter::TRAPPED) {
161 : return 0xdeadbeef;
162 : } else {
163 : thrower->RangeError(
164 0 : "Interpreter did not finish execution within its step bound");
165 0 : return -1;
166 1 : }
167 : }
168 :
169 374 : MaybeHandle<WasmExportedFunction> GetExportedFunction(
170 : Isolate* isolate, Handle<WasmInstanceObject> instance, const char* name) {
171 : Handle<JSObject> exports_object;
172 374 : Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports");
173 : exports_object = Handle<JSObject>::cast(
174 748 : JSObject::GetProperty(instance, exports).ToHandleChecked());
175 :
176 374 : Handle<Name> main_name = isolate->factory()->NewStringFromAsciiChecked(name);
177 : PropertyDescriptor desc;
178 : Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor(
179 374 : isolate, exports_object, main_name, &desc);
180 374 : if (!property_found.FromMaybe(false)) return {};
181 374 : if (!desc.value()->IsJSFunction()) return {};
182 :
183 374 : return Handle<WasmExportedFunction>::cast(desc.value());
184 : }
185 :
186 373 : int32_t CallWasmFunctionForTesting(Isolate* isolate,
187 : Handle<WasmInstanceObject> instance,
188 : ErrorThrower* thrower, const char* name,
189 : int argc, Handle<Object> argv[]) {
190 : MaybeHandle<WasmExportedFunction> maybe_export =
191 373 : GetExportedFunction(isolate, instance, name);
192 : Handle<WasmExportedFunction> main_export;
193 373 : if (!maybe_export.ToHandle(&main_export)) {
194 : return -1;
195 : }
196 :
197 : // Call the JS function.
198 : Handle<Object> undefined = isolate->factory()->undefined_value();
199 : MaybeHandle<Object> retval =
200 373 : Execution::Call(isolate, main_export, undefined, argc, argv);
201 :
202 : // The result should be a number.
203 373 : if (retval.is_null()) {
204 : DCHECK(isolate->has_pending_exception());
205 : isolate->clear_pending_exception();
206 60 : thrower->RuntimeError("Calling exported wasm function failed.");
207 60 : return -1;
208 : }
209 : Handle<Object> result = retval.ToHandleChecked();
210 313 : if (result->IsSmi()) {
211 193 : return Smi::ToInt(*result);
212 : }
213 120 : if (result->IsHeapNumber()) {
214 120 : return static_cast<int32_t>(HeapNumber::cast(*result)->value());
215 : }
216 : thrower->RuntimeError(
217 0 : "Calling exported wasm function failed: Return value should be number");
218 0 : return -1;
219 : }
220 :
221 390 : void SetupIsolateForWasmModule(Isolate* isolate) {
222 390 : WasmJs::Install(isolate, true);
223 390 : }
224 :
225 : } // namespace testing
226 : } // namespace wasm
227 : } // namespace internal
228 : } // namespace v8
|