| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "test/common/wasm/wasm-module-runner.h" | 5 #include "test/common/wasm/wasm-module-runner.h" |
| 6 | 6 |
| 7 #include "src/handles.h" | 7 #include "src/handles.h" |
| 8 #include "src/isolate.h" | 8 #include "src/isolate.h" |
| 9 #include "src/objects.h" | 9 #include "src/objects.h" |
| 10 #include "src/property-descriptor.h" | 10 #include "src/property-descriptor.h" |
| 11 #include "src/wasm/module-decoder.h" | 11 #include "src/wasm/module-decoder.h" |
| 12 #include "src/wasm/wasm-interpreter.h" | 12 #include "src/wasm/wasm-interpreter.h" |
| 13 #include "src/wasm/wasm-module.h" | 13 #include "src/wasm/wasm-module.h" |
| 14 #include "src/wasm/wasm-result.h" | 14 #include "src/wasm/wasm-result.h" |
| 15 #include "src/zone.h" | 15 #include "src/zone.h" |
| 16 | 16 |
| 17 namespace v8 { | 17 namespace v8 { |
| 18 namespace internal { | 18 namespace internal { |
| 19 namespace wasm { | 19 namespace wasm { |
| 20 namespace testing { | 20 namespace testing { |
| 21 | 21 |
| 22 uint32_t GetMinModuleMemSize(const WasmModule* module) { | 22 uint32_t GetMinModuleMemSize(const WasmModule* module) { |
| 23 return WasmModule::kPageSize * module->min_mem_pages; | 23 return WasmModule::kPageSize * module->min_mem_pages; |
| 24 } | 24 } |
| 25 | 25 |
| 26 const WasmModule* DecodeWasmModuleForTesting(Isolate* isolate, Zone* zone, | 26 const WasmModule* DecodeWasmModuleForTesting(Isolate* isolate, Zone* zone, |
| 27 ErrorThrower& thrower, | 27 ErrorThrower* thrower, |
| 28 const byte* module_start, | 28 const byte* module_start, |
| 29 const byte* module_end, | 29 const byte* module_end, |
| 30 ModuleOrigin origin) { | 30 ModuleOrigin origin) { |
| 31 // Decode the module, but don't verify function bodies, since we'll | 31 // Decode the module, but don't verify function bodies, since we'll |
| 32 // be compiling them anyway. | 32 // be compiling them anyway. |
| 33 ModuleResult decoding_result = | 33 ModuleResult decoding_result = |
| 34 DecodeWasmModule(isolate, zone, module_start, module_end, false, origin); | 34 DecodeWasmModule(isolate, zone, module_start, module_end, false, origin); |
| 35 | 35 |
| 36 std::unique_ptr<const WasmModule> module(decoding_result.val); | 36 std::unique_ptr<const WasmModule> module(decoding_result.val); |
| 37 if (decoding_result.failed()) { | 37 if (decoding_result.failed()) { |
| 38 // Module verification failed. throw. | 38 // Module verification failed. throw. |
| 39 thrower.Error("WASM.compileRun() failed: %s", | 39 thrower->Error("WASM.compileRun() failed: %s", |
| 40 decoding_result.error_msg.get()); | 40 decoding_result.error_msg.get()); |
| 41 return nullptr; | 41 return nullptr; |
| 42 } | 42 } |
| 43 | 43 |
| 44 if (thrower.error()) return nullptr; | 44 if (thrower->error()) return nullptr; |
| 45 return module.release(); | 45 return module.release(); |
| 46 } | 46 } |
| 47 | 47 |
| 48 const Handle<JSObject> InstantiateModuleForTesting(Isolate* isolate, | 48 const Handle<JSObject> InstantiateModuleForTesting(Isolate* isolate, |
| 49 ErrorThrower& thrower, | 49 ErrorThrower* thrower, |
| 50 const WasmModule* module) { | 50 const WasmModule* module) { |
| 51 CHECK(module != nullptr); | 51 CHECK(module != nullptr); |
| 52 | 52 |
| 53 if (module->import_table.size() > 0) { | 53 if (module->import_table.size() > 0) { |
| 54 thrower.Error("Not supported: module has imports."); | 54 thrower->Error("Not supported: module has imports."); |
| 55 } | 55 } |
| 56 if (module->export_table.size() == 0) { | 56 if (module->export_table.size() == 0) { |
| 57 thrower.Error("Not supported: module has no exports."); | 57 thrower->Error("Not supported: module has no exports."); |
| 58 } | 58 } |
| 59 | 59 |
| 60 if (thrower.error()) return Handle<JSObject>::null(); | 60 if (thrower->error()) return Handle<JSObject>::null(); |
| 61 | 61 |
| 62 // Although we decoded the module for some pre-validation, run the bytes | 62 // Although we decoded the module for some pre-validation, run the bytes |
| 63 // again through the normal pipeline. | 63 // again through the normal pipeline. |
| 64 MaybeHandle<JSObject> module_object = CreateModuleObjectFromBytes( | 64 MaybeHandle<JSObject> module_object = CreateModuleObjectFromBytes( |
| 65 isolate, module->module_start, module->module_end, &thrower, | 65 isolate, module->module_start, module->module_end, thrower, |
| 66 ModuleOrigin::kWasmOrigin); | 66 ModuleOrigin::kWasmOrigin); |
| 67 if (module_object.is_null()) return Handle<JSObject>::null(); | 67 if (module_object.is_null()) return Handle<JSObject>::null(); |
| 68 return WasmModule::Instantiate(isolate, module_object.ToHandleChecked(), | 68 return WasmModule::Instantiate(isolate, module_object.ToHandleChecked(), |
| 69 Handle<JSReceiver>::null(), | 69 Handle<JSReceiver>::null(), |
| 70 Handle<JSArrayBuffer>::null()) | 70 Handle<JSArrayBuffer>::null()) |
| 71 .ToHandleChecked(); | 71 .ToHandleChecked(); |
| 72 } | 72 } |
| 73 | 73 |
| 74 int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, | 74 int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, |
| 75 const byte* module_end, ModuleOrigin origin) { | 75 const byte* module_end, ModuleOrigin origin) { |
| 76 HandleScope scope(isolate); | 76 HandleScope scope(isolate); |
| 77 Zone zone(isolate->allocator()); | 77 Zone zone(isolate->allocator()); |
| 78 | 78 |
| 79 ErrorThrower thrower(isolate, "CompileAndRunWasmModule"); | 79 ErrorThrower thrower(isolate, "CompileAndRunWasmModule"); |
| 80 std::unique_ptr<const WasmModule> module(DecodeWasmModuleForTesting( | 80 std::unique_ptr<const WasmModule> module(DecodeWasmModuleForTesting( |
| 81 isolate, &zone, thrower, module_start, module_end, origin)); | 81 isolate, &zone, &thrower, module_start, module_end, origin)); |
| 82 | 82 |
| 83 if (module == nullptr) { | 83 if (module == nullptr) { |
| 84 return -1; | 84 return -1; |
| 85 } | 85 } |
| 86 Handle<JSObject> instance = | 86 Handle<JSObject> instance = |
| 87 InstantiateModuleForTesting(isolate, thrower, module.get()); | 87 InstantiateModuleForTesting(isolate, &thrower, module.get()); |
| 88 if (instance.is_null()) { | 88 if (instance.is_null()) { |
| 89 return -1; | 89 return -1; |
| 90 } | 90 } |
| 91 const char* f_name = origin == ModuleOrigin::kAsmJsOrigin ? "caller" : "main"; | 91 const char* f_name = origin == ModuleOrigin::kAsmJsOrigin ? "caller" : "main"; |
| 92 return CallWasmFunctionForTesting(isolate, instance, thrower, f_name, 0, | 92 return CallWasmFunctionForTesting(isolate, instance, &thrower, f_name, 0, |
| 93 nullptr, origin); | 93 nullptr, origin); |
| 94 } | 94 } |
| 95 | 95 |
| 96 int32_t InterpretWasmModule(Isolate* isolate, ErrorThrower& thrower, | 96 int32_t InterpretWasmModule(Isolate* isolate, ErrorThrower* thrower, |
| 97 const WasmModule* module, int function_index, | 97 const WasmModule* module, int function_index, |
| 98 WasmVal* args) { | 98 WasmVal* args) { |
| 99 CHECK(module != nullptr); | 99 CHECK(module != nullptr); |
| 100 | 100 |
| 101 Zone zone(isolate->allocator()); | 101 Zone zone(isolate->allocator()); |
| 102 v8::internal::HandleScope scope(isolate); | 102 v8::internal::HandleScope scope(isolate); |
| 103 | 103 |
| 104 if (module->import_table.size() > 0) { | 104 if (module->import_table.size() > 0) { |
| 105 thrower.Error("Not supported: module has imports."); | 105 thrower->Error("Not supported: module has imports."); |
| 106 } | 106 } |
| 107 if (module->export_table.size() == 0) { | 107 if (module->export_table.size() == 0) { |
| 108 thrower.Error("Not supported: module has no exports."); | 108 thrower->Error("Not supported: module has no exports."); |
| 109 } | 109 } |
| 110 | 110 |
| 111 if (thrower.error()) return -1; | 111 if (thrower->error()) return -1; |
| 112 | 112 |
| 113 ModuleEnv module_env; | 113 ModuleEnv module_env; |
| 114 module_env.module = module; | 114 module_env.module = module; |
| 115 module_env.origin = module->origin; | 115 module_env.origin = module->origin; |
| 116 | 116 |
| 117 for (size_t i = 0; i < module->functions.size(); i++) { | 117 for (size_t i = 0; i < module->functions.size(); i++) { |
| 118 FunctionBody body = { | 118 FunctionBody body = { |
| 119 &module_env, module->functions[i].sig, module->module_start, | 119 &module_env, module->functions[i].sig, module->module_start, |
| 120 module->module_start + module->functions[i].code_start_offset, | 120 module->module_start + module->functions[i].code_start_offset, |
| 121 module->module_start + module->functions[i].code_end_offset}; | 121 module->module_start + module->functions[i].code_end_offset}; |
| 122 DecodeResult result = VerifyWasmCode(isolate->allocator(), body); | 122 DecodeResult result = VerifyWasmCode(isolate->allocator(), body); |
| 123 if (result.failed()) { | 123 if (result.failed()) { |
| 124 thrower.Error("Function did not verify"); | 124 thrower->Error("Function did not verify"); |
| 125 return -1; | 125 return -1; |
| 126 } | 126 } |
| 127 } | 127 } |
| 128 | 128 |
| 129 // The code verifies, we create an instance to run it in the interpreter. | 129 // The code verifies, we create an instance to run it in the interpreter. |
| 130 WasmModuleInstance instance(module); | 130 WasmModuleInstance instance(module); |
| 131 instance.context = isolate->native_context(); | 131 instance.context = isolate->native_context(); |
| 132 instance.mem_size = GetMinModuleMemSize(module); | 132 instance.mem_size = GetMinModuleMemSize(module); |
| 133 // TODO(ahaas): Move memory allocation to wasm-module.cc for better | 133 // TODO(ahaas): Move memory allocation to wasm-module.cc for better |
| 134 // encapsulation. | 134 // encapsulation. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 145 WasmInterpreter::State interpreter_result = thread->Run(); | 145 WasmInterpreter::State interpreter_result = thread->Run(); |
| 146 if (instance.mem_start) { | 146 if (instance.mem_start) { |
| 147 free(instance.mem_start); | 147 free(instance.mem_start); |
| 148 } | 148 } |
| 149 if (interpreter_result == WasmInterpreter::FINISHED) { | 149 if (interpreter_result == WasmInterpreter::FINISHED) { |
| 150 WasmVal val = thread->GetReturnValue(); | 150 WasmVal val = thread->GetReturnValue(); |
| 151 return val.to<int32_t>(); | 151 return val.to<int32_t>(); |
| 152 } else if (thread->state() == WasmInterpreter::TRAPPED) { | 152 } else if (thread->state() == WasmInterpreter::TRAPPED) { |
| 153 return 0xdeadbeef; | 153 return 0xdeadbeef; |
| 154 } else { | 154 } else { |
| 155 thrower.Error("Interpreter did not finish execution within its step bound"); | 155 thrower->Error( |
| 156 "Interpreter did not finish execution within its step bound"); |
| 156 return -1; | 157 return -1; |
| 157 } | 158 } |
| 158 } | 159 } |
| 159 | 160 |
| 160 int32_t CallWasmFunctionForTesting(Isolate* isolate, Handle<JSObject> instance, | 161 int32_t CallWasmFunctionForTesting(Isolate* isolate, Handle<JSObject> instance, |
| 161 ErrorThrower& thrower, const char* name, | 162 ErrorThrower* thrower, const char* name, |
| 162 int argc, Handle<Object> argv[], | 163 int argc, Handle<Object> argv[], |
| 163 ModuleOrigin origin) { | 164 ModuleOrigin origin) { |
| 164 Handle<JSObject> exports_object; | 165 Handle<JSObject> exports_object; |
| 165 if (origin == ModuleOrigin::kAsmJsOrigin) { | 166 if (origin == ModuleOrigin::kAsmJsOrigin) { |
| 166 exports_object = instance; | 167 exports_object = instance; |
| 167 } else { | 168 } else { |
| 168 Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports"); | 169 Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports"); |
| 169 exports_object = Handle<JSObject>::cast( | 170 exports_object = Handle<JSObject>::cast( |
| 170 JSObject::GetProperty(instance, exports).ToHandleChecked()); | 171 JSObject::GetProperty(instance, exports).ToHandleChecked()); |
| 171 } | 172 } |
| 172 Handle<Name> main_name = isolate->factory()->NewStringFromAsciiChecked(name); | 173 Handle<Name> main_name = isolate->factory()->NewStringFromAsciiChecked(name); |
| 173 PropertyDescriptor desc; | 174 PropertyDescriptor desc; |
| 174 Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor( | 175 Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor( |
| 175 isolate, exports_object, main_name, &desc); | 176 isolate, exports_object, main_name, &desc); |
| 176 if (!property_found.FromMaybe(false)) return -1; | 177 if (!property_found.FromMaybe(false)) return -1; |
| 177 | 178 |
| 178 Handle<JSFunction> main_export = Handle<JSFunction>::cast(desc.value()); | 179 Handle<JSFunction> main_export = Handle<JSFunction>::cast(desc.value()); |
| 179 | 180 |
| 180 // Call the JS function. | 181 // Call the JS function. |
| 181 Handle<Object> undefined = isolate->factory()->undefined_value(); | 182 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 182 MaybeHandle<Object> retval = | 183 MaybeHandle<Object> retval = |
| 183 Execution::Call(isolate, main_export, undefined, argc, argv); | 184 Execution::Call(isolate, main_export, undefined, argc, argv); |
| 184 | 185 |
| 185 // The result should be a number. | 186 // The result should be a number. |
| 186 if (retval.is_null()) { | 187 if (retval.is_null()) { |
| 187 thrower.Error("WASM.compileRun() failed: Invocation was null"); | 188 thrower->Error("WASM.compileRun() failed: Invocation was null"); |
| 188 return -1; | 189 return -1; |
| 189 } | 190 } |
| 190 Handle<Object> result = retval.ToHandleChecked(); | 191 Handle<Object> result = retval.ToHandleChecked(); |
| 191 if (result->IsSmi()) { | 192 if (result->IsSmi()) { |
| 192 return Smi::cast(*result)->value(); | 193 return Smi::cast(*result)->value(); |
| 193 } | 194 } |
| 194 if (result->IsHeapNumber()) { | 195 if (result->IsHeapNumber()) { |
| 195 return static_cast<int32_t>(HeapNumber::cast(*result)->value()); | 196 return static_cast<int32_t>(HeapNumber::cast(*result)->value()); |
| 196 } | 197 } |
| 197 thrower.Error("WASM.compileRun() failed: Return value should be number"); | 198 thrower->Error("WASM.compileRun() failed: Return value should be number"); |
| 198 return -1; | 199 return -1; |
| 199 } | 200 } |
| 200 | 201 |
| 201 } // namespace testing | 202 } // namespace testing |
| 202 } // namespace wasm | 203 } // namespace wasm |
| 203 } // namespace internal | 204 } // namespace internal |
| 204 } // namespace v8 | 205 } // namespace v8 |
| OLD | NEW |