LCOV - code coverage report
Current view: top level - test/common/wasm - wasm-module-runner.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 72 102 70.6 %
Date: 2019-04-18 Functions: 10 13 76.9 %

          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/heap-number-inl.h"
      11             : #include "src/property-descriptor.h"
      12             : #include "src/wasm/module-decoder.h"
      13             : #include "src/wasm/wasm-engine.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 kWasmPageSize * module->initial_pages;
      27             : }
      28             : 
      29         237 : MaybeHandle<WasmModuleObject> CompileForTesting(Isolate* isolate,
      30             :                                                 ErrorThrower* thrower,
      31             :                                                 const ModuleWireBytes& bytes) {
      32         237 :   auto enabled_features = WasmFeaturesFromIsolate(isolate);
      33             :   MaybeHandle<WasmModuleObject> module = isolate->wasm_engine()->SyncCompile(
      34         237 :       isolate, enabled_features, thrower, bytes);
      35             :   DCHECK_EQ(thrower->error(), module.is_null());
      36         237 :   return module;
      37             : }
      38             : 
      39         228 : MaybeHandle<WasmInstanceObject> CompileAndInstantiateForTesting(
      40             :     Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) {
      41             :   MaybeHandle<WasmModuleObject> module =
      42         228 :       CompileForTesting(isolate, thrower, bytes);
      43         228 :   if (module.is_null()) return {};
      44             :   return isolate->wasm_engine()->SyncInstantiate(
      45         456 :       isolate, thrower, module.ToHandleChecked(), {}, {});
      46             : }
      47             : 
      48           0 : std::shared_ptr<WasmModule> DecodeWasmModuleForTesting(
      49             :     Isolate* isolate, ErrorThrower* thrower, const byte* module_start,
      50             :     const byte* module_end, ModuleOrigin origin, bool verify_functions) {
      51             :   // Decode the module, but don't verify function bodies, since we'll
      52             :   // be compiling them anyway.
      53           0 :   auto enabled_features = WasmFeaturesFromIsolate(isolate);
      54           0 :   ModuleResult decoding_result = DecodeWasmModule(
      55             :       enabled_features, module_start, module_end, verify_functions, origin,
      56           0 :       isolate->counters(), isolate->wasm_engine()->allocator());
      57             : 
      58           0 :   if (decoding_result.failed()) {
      59             :     // Module verification failed. throw.
      60             :     thrower->CompileError("DecodeWasmModule failed: %s",
      61           0 :                           decoding_result.error().message().c_str());
      62             :   }
      63             : 
      64           0 :   return std::move(decoding_result).value();
      65             : }
      66             : 
      67           1 : bool InterpretWasmModuleForTesting(Isolate* isolate,
      68             :                                    Handle<WasmInstanceObject> instance,
      69             :                                    const char* name, size_t argc,
      70             :                                    WasmValue* args) {
      71             :   HandleScope handle_scope(isolate);  // Avoid leaking handles.
      72           2 :   WasmCodeRefScope code_ref_scope;
      73             :   MaybeHandle<WasmExportedFunction> maybe_function =
      74           1 :       GetExportedFunction(isolate, instance, "main");
      75             :   Handle<WasmExportedFunction> function;
      76           1 :   if (!maybe_function.ToHandle(&function)) {
      77             :     return false;
      78             :   }
      79           1 :   int function_index = function->function_index();
      80           3 :   FunctionSig* signature = instance->module()->functions[function_index].sig;
      81           1 :   size_t param_count = signature->parameter_count();
      82           1 :   std::unique_ptr<WasmValue[]> arguments(new WasmValue[param_count]);
      83             : 
      84           1 :   size_t arg_count = std::min(param_count, argc);
      85           1 :   if (arg_count > 0) {
      86             :     memcpy(arguments.get(), args, arg_count);
      87             :   }
      88             : 
      89             :   // Fill the parameters up with default values.
      90           1 :   for (size_t i = argc; i < param_count; ++i) {
      91           0 :     switch (signature->GetParam(i)) {
      92             :       case kWasmI32:
      93           0 :         arguments[i] = WasmValue(int32_t{0});
      94           0 :         break;
      95             :       case kWasmI64:
      96           0 :         arguments[i] = WasmValue(int64_t{0});
      97           0 :         break;
      98             :       case kWasmF32:
      99           0 :         arguments[i] = WasmValue(0.0f);
     100           0 :         break;
     101             :       case kWasmF64:
     102           0 :         arguments[i] = WasmValue(0.0);
     103           0 :         break;
     104             :       default:
     105           0 :         UNREACHABLE();
     106             :     }
     107             :   }
     108             : 
     109             :   // Don't execute more than 16k steps.
     110             :   constexpr int kMaxNumSteps = 16 * 1024;
     111             : 
     112           2 :   Zone zone(isolate->allocator(), ZONE_NAME);
     113             : 
     114           1 :   WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
     115           1 :   WasmInterpreter::Thread* thread = interpreter->GetThread(0);
     116           1 :   thread->Reset();
     117             : 
     118             :   // Start an activation so that we can deal with stack overflows. We do not
     119             :   // finish the activation. An activation is just part of the state of the
     120             :   // interpreter, and we do not reuse the interpreter anyways. In addition,
     121             :   // finishing the activation is not correct in all cases, e.g. when the
     122             :   // execution of the interpreter did not finish after kMaxNumSteps.
     123           1 :   thread->StartActivation();
     124           2 :   thread->InitFrame(&instance->module()->functions[function_index],
     125           1 :                     arguments.get());
     126           1 :   WasmInterpreter::State interpreter_result = thread->Run(kMaxNumSteps);
     127             : 
     128             :   isolate->clear_pending_exception();
     129             : 
     130           1 :   return interpreter_result != WasmInterpreter::PAUSED;
     131             : }
     132             : 
     133        2279 : int32_t RunWasmModuleForTesting(Isolate* isolate,
     134             :                                 Handle<WasmInstanceObject> instance, int argc,
     135             :                                 Handle<Object> argv[]) {
     136        2279 :   ErrorThrower thrower(isolate, "RunWasmModule");
     137             :   return CallWasmFunctionForTesting(isolate, instance, &thrower, "main", argc,
     138        4558 :                                     argv);
     139             : }
     140             : 
     141         168 : int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
     142             :                                 const byte* module_end) {
     143             :   HandleScope scope(isolate);
     144         168 :   ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
     145             :   MaybeHandle<WasmInstanceObject> instance = CompileAndInstantiateForTesting(
     146         168 :       isolate, &thrower, ModuleWireBytes(module_start, module_end));
     147         168 :   if (instance.is_null()) {
     148             :     return -1;
     149             :   }
     150             :   return RunWasmModuleForTesting(isolate, instance.ToHandleChecked(), 0,
     151         168 :                                  nullptr);
     152             : }
     153             : 
     154           0 : int32_t CompileAndRunAsmWasmModule(Isolate* isolate, const byte* module_start,
     155             :                                    const byte* module_end) {
     156             :   HandleScope scope(isolate);
     157           0 :   ErrorThrower thrower(isolate, "CompileAndRunAsmWasmModule");
     158             :   MaybeHandle<AsmWasmData> data =
     159             :       isolate->wasm_engine()->SyncCompileTranslatedAsmJs(
     160             :           isolate, &thrower, ModuleWireBytes(module_start, module_end),
     161           0 :           Vector<const byte>(), Handle<HeapNumber>());
     162             :   DCHECK_EQ(thrower.error(), data.is_null());
     163           0 :   if (data.is_null()) return -1;
     164             : 
     165             :   MaybeHandle<WasmModuleObject> module =
     166             :       isolate->wasm_engine()->FinalizeTranslatedAsmJs(
     167           0 :           isolate, data.ToHandleChecked(), Handle<Script>::null());
     168             : 
     169             :   MaybeHandle<WasmInstanceObject> instance =
     170             :       isolate->wasm_engine()->SyncInstantiate(
     171             :           isolate, &thrower, module.ToHandleChecked(),
     172           0 :           Handle<JSReceiver>::null(), Handle<JSArrayBuffer>::null());
     173             :   DCHECK_EQ(thrower.error(), instance.is_null());
     174           0 :   if (instance.is_null()) return -1;
     175             : 
     176             :   return RunWasmModuleForTesting(isolate, instance.ToHandleChecked(), 0,
     177           0 :                                  nullptr);
     178             : }
     179           1 : WasmInterpretationResult InterpretWasmModule(
     180             :     Isolate* isolate, Handle<WasmInstanceObject> instance,
     181             :     int32_t function_index, WasmValue* args) {
     182             :   // Don't execute more than 16k steps.
     183             :   constexpr int kMaxNumSteps = 16 * 1024;
     184             : 
     185           2 :   Zone zone(isolate->allocator(), ZONE_NAME);
     186             :   v8::internal::HandleScope scope(isolate);
     187             : 
     188           1 :   WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
     189           1 :   WasmInterpreter::Thread* thread = interpreter->GetThread(0);
     190           1 :   thread->Reset();
     191             : 
     192             :   // Start an activation so that we can deal with stack overflows. We do not
     193             :   // finish the activation. An activation is just part of the state of the
     194             :   // interpreter, and we do not reuse the interpreter anyways. In addition,
     195             :   // finishing the activation is not correct in all cases, e.g. when the
     196             :   // execution of the interpreter did not finish after kMaxNumSteps.
     197           1 :   thread->StartActivation();
     198           3 :   thread->InitFrame(&(instance->module()->functions[function_index]), args);
     199           1 :   WasmInterpreter::State interpreter_result = thread->Run(kMaxNumSteps);
     200             : 
     201             :   bool stack_overflow = isolate->has_pending_exception();
     202             :   isolate->clear_pending_exception();
     203             : 
     204           1 :   if (stack_overflow) return WasmInterpretationResult::Stopped();
     205             : 
     206           1 :   if (thread->state() == WasmInterpreter::TRAPPED) {
     207           0 :     return WasmInterpretationResult::Trapped(thread->PossibleNondeterminism());
     208             :   }
     209             : 
     210           1 :   if (interpreter_result == WasmInterpreter::FINISHED) {
     211             :     return WasmInterpretationResult::Finished(
     212           2 :         thread->GetReturnValue().to<int32_t>(),
     213           1 :         thread->PossibleNondeterminism());
     214             :   }
     215             : 
     216             :   return WasmInterpretationResult::Stopped();
     217             : }
     218             : 
     219        2297 : MaybeHandle<WasmExportedFunction> GetExportedFunction(
     220             :     Isolate* isolate, Handle<WasmInstanceObject> instance, const char* name) {
     221             :   Handle<JSObject> exports_object;
     222        2297 :   Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports");
     223             :   exports_object = Handle<JSObject>::cast(
     224        4594 :       JSObject::GetProperty(isolate, instance, exports).ToHandleChecked());
     225             : 
     226        2297 :   Handle<Name> main_name = isolate->factory()->NewStringFromAsciiChecked(name);
     227             :   PropertyDescriptor desc;
     228             :   Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor(
     229        2297 :       isolate, exports_object, main_name, &desc);
     230        2297 :   if (!property_found.FromMaybe(false)) return {};
     231        2297 :   if (!desc.value()->IsJSFunction()) return {};
     232             : 
     233        2297 :   return Handle<WasmExportedFunction>::cast(desc.value());
     234             : }
     235             : 
     236        2296 : int32_t CallWasmFunctionForTesting(Isolate* isolate,
     237             :                                    Handle<WasmInstanceObject> instance,
     238             :                                    ErrorThrower* thrower, const char* name,
     239             :                                    int argc, Handle<Object> argv[]) {
     240             :   MaybeHandle<WasmExportedFunction> maybe_export =
     241        2296 :       GetExportedFunction(isolate, instance, name);
     242             :   Handle<WasmExportedFunction> main_export;
     243        2296 :   if (!maybe_export.ToHandle(&main_export)) {
     244             :     return -1;
     245             :   }
     246             : 
     247             :   // Call the JS function.
     248             :   Handle<Object> undefined = isolate->factory()->undefined_value();
     249             :   MaybeHandle<Object> retval =
     250        2296 :       Execution::Call(isolate, main_export, undefined, argc, argv);
     251             : 
     252             :   // The result should be a number.
     253        2296 :   if (retval.is_null()) {
     254             :     DCHECK(isolate->has_pending_exception());
     255             :     isolate->clear_pending_exception();
     256          40 :     thrower->RuntimeError("Calling exported wasm function failed.");
     257          40 :     return -1;
     258             :   }
     259             :   Handle<Object> result = retval.ToHandleChecked();
     260        2256 :   if (result->IsSmi()) {
     261        2176 :     return Smi::ToInt(*result);
     262             :   }
     263          80 :   if (result->IsHeapNumber()) {
     264          80 :     return static_cast<int32_t>(HeapNumber::cast(*result)->value());
     265             :   }
     266             :   thrower->RuntimeError(
     267           0 :       "Calling exported wasm function failed: Return value should be number");
     268           0 :   return -1;
     269             : }
     270             : 
     271         363 : void SetupIsolateForWasmModule(Isolate* isolate) {
     272         363 :   WasmJs::Install(isolate, true);
     273         363 : }
     274             : 
     275             : }  // namespace testing
     276             : }  // namespace wasm
     277             : }  // namespace internal
     278       53324 : }  // namespace v8

Generated by: LCOV version 1.10