LCOV - code coverage report
Current view: top level - src/runtime - runtime-wasm.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 145 162 89.5 %
Date: 2019-01-20 Functions: 23 40 57.5 %

          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 "src/arguments-inl.h"
       6             : #include "src/compiler/wasm-compiler.h"
       7             : #include "src/conversions.h"
       8             : #include "src/counters.h"
       9             : #include "src/debug/debug.h"
      10             : #include "src/frame-constants.h"
      11             : #include "src/heap/factory.h"
      12             : #include "src/message-template.h"
      13             : #include "src/objects-inl.h"
      14             : #include "src/objects/frame-array-inl.h"
      15             : #include "src/runtime/runtime-utils.h"
      16             : #include "src/trap-handler/trap-handler.h"
      17             : #include "src/v8memory.h"
      18             : #include "src/wasm/module-compiler.h"
      19             : #include "src/wasm/wasm-code-manager.h"
      20             : #include "src/wasm/wasm-constants.h"
      21             : #include "src/wasm/wasm-engine.h"
      22             : #include "src/wasm/wasm-objects.h"
      23             : 
      24             : namespace v8 {
      25             : namespace internal {
      26             : 
      27             : namespace {
      28             : 
      29        4105 : WasmInstanceObject GetWasmInstanceOnStackTop(Isolate* isolate) {
      30        4105 :   StackFrameIterator it(isolate, isolate->thread_local_top());
      31             :   // On top: C entry stub.
      32             :   DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
      33        4105 :   it.Advance();
      34             :   // Next: the wasm compiled frame.
      35             :   DCHECK(it.frame()->is_wasm_compiled());
      36        4105 :   WasmCompiledFrame* frame = WasmCompiledFrame::cast(it.frame());
      37        8210 :   return frame->wasm_instance();
      38             : }
      39             : 
      40        2413 : Context GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) {
      41        2413 :   return GetWasmInstanceOnStackTop(isolate)->native_context();
      42             : }
      43             : 
      44             : class ClearThreadInWasmScope {
      45             :  public:
      46      218462 :   ClearThreadInWasmScope() {
      47             :     DCHECK_EQ(trap_handler::IsTrapHandlerEnabled(),
      48             :               trap_handler::IsThreadInWasm());
      49             :     trap_handler::ClearThreadInWasm();
      50      218462 :   }
      51      218462 :   ~ClearThreadInWasmScope() {
      52             :     DCHECK(!trap_handler::IsThreadInWasm());
      53             :     trap_handler::SetThreadInWasm();
      54      218462 :   }
      55             : };
      56             : 
      57             : }  // namespace
      58             : 
      59          36 : RUNTIME_FUNCTION(Runtime_WasmIsValidAnyFuncValue) {
      60          36 :   HandleScope scope(isolate);
      61             :   DCHECK_EQ(1, args.length());
      62          36 :   CONVERT_ARG_HANDLE_CHECKED(Object, function, 0);
      63             : 
      64          72 :   if (function->IsNull(isolate)) {
      65           0 :     return Smi::FromInt(true);
      66             :   }
      67          36 :   if (WasmExportedFunction::IsWasmExportedFunction(*function)) {
      68          18 :     return Smi::FromInt(true);
      69             :   }
      70          18 :   return Smi::FromInt(false);
      71             : }
      72             : 
      73        2196 : RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) {
      74        2196 :   HandleScope scope(isolate);
      75             :   DCHECK_EQ(2, args.length());
      76        4392 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
      77             :   // {delta_pages} is checked to be a positive smi in the WasmMemoryGrow builtin
      78             :   // which calls this runtime function.
      79        4392 :   CONVERT_UINT32_ARG_CHECKED(delta_pages, 1);
      80             : 
      81             :   // This runtime function is always being called from wasm code.
      82        4392 :   ClearThreadInWasmScope flag_scope;
      83             : 
      84             :   int ret = WasmMemoryObject::Grow(
      85        6588 :       isolate, handle(instance->memory_object(), isolate), delta_pages);
      86             :   // The WasmMemoryGrow builtin which calls this runtime function expects us to
      87             :   // always return a Smi.
      88        4392 :   return Smi::FromInt(ret);
      89             : }
      90             : 
      91      167114 : RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
      92             :   DCHECK_EQ(1, args.length());
      93      334228 :   CONVERT_SMI_ARG_CHECKED(message_id, 0);
      94      167114 :   ClearThreadInWasmScope clear_wasm_flag;
      95             : 
      96      334228 :   HandleScope scope(isolate);
      97             :   Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
      98      167114 :       MessageTemplateFromInt(message_id));
      99      334228 :   return isolate->Throw(*error_obj);
     100             : }
     101             : 
     102          10 : RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
     103             :   SealHandleScope shs(isolate);
     104             :   DCHECK_LE(0, args.length());
     105             :   DCHECK(isolate->context().is_null());
     106          10 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     107          10 :   return isolate->StackOverflow();
     108             : }
     109             : 
     110         126 : RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
     111         126 :   HandleScope scope(isolate);
     112             :   DCHECK_EQ(0, args.length());
     113         252 :   THROW_NEW_ERROR_RETURN_FAILURE(
     114         126 :       isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
     115             : }
     116             : 
     117         738 : RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
     118             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     119         738 :   HandleScope scope(isolate);
     120             :   DCHECK_EQ(2, args.length());
     121             :   DCHECK(isolate->context().is_null());
     122         738 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     123        1476 :   CONVERT_ARG_CHECKED(HeapObject, tag_raw, 0);
     124        1476 :   CONVERT_SMI_ARG_CHECKED(size, 1);
     125             :   // TODO(mstarzinger): Manually box because parameters are not visited yet.
     126             :   Handle<Object> tag(tag_raw, isolate);
     127             :   Handle<Object> exception = isolate->factory()->NewWasmRuntimeError(
     128         738 :       MessageTemplate::kWasmExceptionError);
     129        1476 :   CHECK(!Object::SetProperty(isolate, exception,
     130             :                              isolate->factory()->wasm_exception_tag_symbol(),
     131             :                              tag, LanguageMode::kStrict)
     132             :              .is_null());
     133         738 :   Handle<FixedArray> values = isolate->factory()->NewFixedArray(size);
     134        1476 :   CHECK(!Object::SetProperty(isolate, exception,
     135             :                              isolate->factory()->wasm_exception_values_symbol(),
     136             :                              values, LanguageMode::kStrict)
     137             :              .is_null());
     138         738 :   return *exception;
     139             : }
     140             : 
     141         540 : RUNTIME_FUNCTION(Runtime_WasmExceptionGetTag) {
     142             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     143         540 :   HandleScope scope(isolate);
     144             :   DCHECK_EQ(1, args.length());
     145             :   DCHECK(isolate->context().is_null());
     146         540 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     147         540 :   CONVERT_ARG_CHECKED(Object, except_obj_raw, 0);
     148             :   // TODO(mstarzinger): Manually box because parameters are not visited yet.
     149             :   Handle<Object> except_obj(except_obj_raw, isolate);
     150        1620 :   if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
     151             :     Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate);
     152             :     Handle<Object> tag;
     153         486 :     if (JSReceiver::GetProperty(isolate, exception,
     154         972 :                                 isolate->factory()->wasm_exception_tag_symbol())
     155         972 :             .ToHandle(&tag)) {
     156         486 :       return *tag;
     157             :     }
     158             :   }
     159         540 :   return ReadOnlyRoots(isolate).undefined_value();
     160             : }
     161             : 
     162        1125 : RUNTIME_FUNCTION(Runtime_WasmExceptionGetValues) {
     163             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     164        1125 :   HandleScope scope(isolate);
     165             :   DCHECK_EQ(1, args.length());
     166             :   DCHECK(isolate->context().is_null());
     167        1125 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     168        1125 :   CONVERT_ARG_CHECKED(Object, except_obj_raw, 0);
     169             :   // TODO(mstarzinger): Manually box because parameters are not visited yet.
     170             :   Handle<Object> except_obj(except_obj_raw, isolate);
     171        3375 :   if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
     172             :     Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate);
     173             :     Handle<Object> values;
     174        1125 :     if (JSReceiver::GetProperty(
     175             :             isolate, exception,
     176        2250 :             isolate->factory()->wasm_exception_values_symbol())
     177        2250 :             .ToHandle(&values)) {
     178             :       DCHECK(values->IsFixedArray());
     179        1125 :       return *values;
     180             :     }
     181             :   }
     182        1125 :   return ReadOnlyRoots(isolate).undefined_value();
     183             : }
     184             : 
     185       39248 : RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
     186             :   DCHECK_EQ(2, args.length());
     187       39248 :   HandleScope scope(isolate);
     188       78496 :   CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[0]);
     189       39248 :   CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 1);
     190             : 
     191             :   // The arg buffer is the raw pointer to the caller's stack. It looks like a
     192             :   // Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just
     193             :   // cast it back to the raw pointer.
     194       78496 :   CHECK(!arg_buffer_obj->IsHeapObject());
     195       78496 :   CHECK(arg_buffer_obj->IsSmi());
     196       39248 :   Address arg_buffer = arg_buffer_obj->ptr();
     197             : 
     198       78496 :   ClearThreadInWasmScope wasm_flag;
     199             : 
     200             :   // Find the frame pointer and instance of the interpreter frame on the stack.
     201             :   Handle<WasmInstanceObject> instance;
     202             :   Address frame_pointer = 0;
     203             :   {
     204       39248 :     StackFrameIterator it(isolate, isolate->thread_local_top());
     205             :     // On top: C entry stub.
     206             :     DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
     207       39248 :     it.Advance();
     208             :     // Next: the wasm interpreter entry.
     209             :     DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type());
     210             :     instance = handle(
     211       39248 :         WasmInterpreterEntryFrame::cast(it.frame())->wasm_instance(), isolate);
     212       39248 :     frame_pointer = it.frame()->fp();
     213             :   }
     214             : 
     215             :   // Set the current isolate's context.
     216             :   DCHECK(isolate->context().is_null());
     217       39248 :   isolate->set_context(instance->native_context());
     218             : 
     219             :   // Run the function in the interpreter. Note that neither the {WasmDebugInfo}
     220             :   // nor the {InterpreterHandle} have to exist, because interpretation might
     221             :   // have been triggered by another Isolate sharing the same WasmEngine.
     222             :   Handle<WasmDebugInfo> debug_info =
     223       39248 :       WasmInstanceObject::GetOrCreateDebugInfo(instance);
     224             :   bool success = WasmDebugInfo::RunInterpreter(
     225       39248 :       isolate, debug_info, frame_pointer, func_index, arg_buffer);
     226             : 
     227       39248 :   if (!success) {
     228             :     DCHECK(isolate->has_pending_exception());
     229             :     return ReadOnlyRoots(isolate).exception();
     230             :   }
     231       39248 :   return ReadOnlyRoots(isolate).undefined_value();
     232             : }
     233             : 
     234         243 : RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
     235             :   SealHandleScope shs(isolate);
     236             :   DCHECK_EQ(0, args.length());
     237             :   DCHECK(!trap_handler::IsTrapHandlerEnabled() ||
     238             :          trap_handler::IsThreadInWasm());
     239             : 
     240         243 :   ClearThreadInWasmScope wasm_flag;
     241             : 
     242             :   // Check if this is a real stack overflow.
     243         243 :   StackLimitCheck check(isolate);
     244         243 :   if (check.JsHasOverflowed()) return isolate->StackOverflow();
     245             : 
     246          64 :   return isolate->stack_guard()->HandleInterrupts();
     247             : }
     248             : 
     249        9661 : RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
     250        9661 :   HandleScope scope(isolate);
     251             :   DCHECK_EQ(2, args.length());
     252       19322 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     253       19322 :   CONVERT_SMI_ARG_CHECKED(func_index, 1);
     254             : 
     255       19322 :   ClearThreadInWasmScope wasm_flag;
     256             : 
     257             : #ifdef DEBUG
     258             :   StackFrameIterator it(isolate, isolate->thread_local_top());
     259             :   // On top: C entry stub.
     260             :   DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
     261             :   it.Advance();
     262             :   // Next: the wasm lazy compile frame.
     263             :   DCHECK_EQ(StackFrame::WASM_COMPILE_LAZY, it.frame()->type());
     264             :   DCHECK_EQ(*instance, WasmCompileLazyFrame::cast(it.frame())->wasm_instance());
     265             : #endif
     266             : 
     267             :   Address entrypoint = wasm::CompileLazy(
     268       19322 :       isolate, instance->module_object()->native_module(), func_index);
     269       19322 :   return Object(entrypoint);
     270             : }
     271             : 
     272             : // Should be called from within a handle scope
     273         672 : Handle<JSArrayBuffer> getSharedArrayBuffer(Handle<WasmInstanceObject> instance,
     274             :                                            Isolate* isolate, uint32_t address) {
     275             :   DCHECK(instance->has_memory_object());
     276        1347 :   Handle<JSArrayBuffer> array_buffer(instance->memory_object()->array_buffer(),
     277        1347 :                                      isolate);
     278             : 
     279             :   // Validation should have failed if the memory was not shared.
     280             :   DCHECK(array_buffer->is_shared());
     281             : 
     282             :   // Should have trapped if address was OOB
     283             :   DCHECK_LT(address, array_buffer->byte_length());
     284         674 :   return array_buffer;
     285             : }
     286             : 
     287         153 : RUNTIME_FUNCTION(Runtime_WasmAtomicWake) {
     288         153 :   HandleScope scope(isolate);
     289             :   DCHECK_EQ(3, args.length());
     290         306 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     291         306 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     292         306 :   CONVERT_NUMBER_CHECKED(uint32_t, count, Uint32, args[2]);
     293             :   Handle<JSArrayBuffer> array_buffer =
     294         153 :       getSharedArrayBuffer(instance, isolate, address);
     295         153 :   return FutexEmulation::Wake(array_buffer, address, count);
     296             : }
     297             : 
     298         521 : double WaitTimeoutInMs(double timeout_ns) {
     299             :   return timeout_ns < 0
     300             :              ? V8_INFINITY
     301             :              : timeout_ns / (base::Time::kNanosecondsPerMicrosecond *
     302         521 :                              base::Time::kMicrosecondsPerMillisecond);
     303             : }
     304             : 
     305         260 : RUNTIME_FUNCTION(Runtime_WasmI32AtomicWait) {
     306         260 :   HandleScope scope(isolate);
     307             :   DCHECK_EQ(4, args.length());
     308         520 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     309         522 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     310         522 :   CONVERT_NUMBER_CHECKED(int32_t, expected_value, Int32, args[2]);
     311         522 :   CONVERT_DOUBLE_ARG_CHECKED(timeout_ns, 3);
     312         261 :   double timeout_ms = WaitTimeoutInMs(timeout_ns);
     313             :   Handle<JSArrayBuffer> array_buffer =
     314         260 :       getSharedArrayBuffer(instance, isolate, address);
     315             :   return FutexEmulation::Wait32(isolate, array_buffer, address, expected_value,
     316         261 :                                 timeout_ms);
     317             : }
     318             : 
     319         260 : RUNTIME_FUNCTION(Runtime_WasmI64AtomicWait) {
     320         260 :   HandleScope scope(isolate);
     321             :   DCHECK_EQ(5, args.length());
     322         521 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     323         522 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     324         522 :   CONVERT_NUMBER_CHECKED(uint32_t, expected_value_high, Uint32, args[2]);
     325         522 :   CONVERT_NUMBER_CHECKED(uint32_t, expected_value_low, Uint32, args[3]);
     326         522 :   CONVERT_DOUBLE_ARG_CHECKED(timeout_ns, 4);
     327         261 :   int64_t expected_value = (static_cast<uint64_t>(expected_value_high) << 32) |
     328         261 :                            static_cast<uint64_t>(expected_value_low);
     329         261 :   double timeout_ms = WaitTimeoutInMs(timeout_ns);
     330             :   Handle<JSArrayBuffer> array_buffer =
     331         261 :       getSharedArrayBuffer(instance, isolate, address);
     332             :   return FutexEmulation::Wait64(isolate, array_buffer, address, expected_value,
     333         261 :                                 timeout_ms);
     334             : }
     335             : 
     336           0 : RUNTIME_FUNCTION(Runtime_WasmTableInit) {
     337           0 :   HandleScope scope(isolate);
     338             :   DCHECK_EQ(5, args.length());
     339             :   auto instance =
     340           0 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     341           0 :   CONVERT_UINT32_ARG_CHECKED(table_index, 0);
     342           0 :   CONVERT_UINT32_ARG_CHECKED(elem_segment_index, 1);
     343           0 :   CONVERT_UINT32_ARG_CHECKED(dst, 2);
     344           0 :   CONVERT_UINT32_ARG_CHECKED(src, 3);
     345           0 :   CONVERT_UINT32_ARG_CHECKED(size, 4);
     346             : 
     347             :   PrintF(
     348             :       "TableInit(table_index=%u, elem_segment_index=%u, dst=%u, src=%u, "
     349             :       "size=%u)\n",
     350           0 :       table_index, elem_segment_index, dst, src, size);
     351             : 
     352           0 :   USE(instance);
     353           0 :   USE(table_index);
     354           0 :   USE(elem_segment_index);
     355           0 :   USE(dst);
     356           0 :   USE(src);
     357           0 :   USE(size);
     358             : 
     359           0 :   UNREACHABLE();
     360             : }
     361             : 
     362        1692 : RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
     363        1692 :   HandleScope scope(isolate);
     364             :   DCHECK_EQ(4, args.length());
     365             :   auto instance =
     366        1692 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     367        3384 :   CONVERT_UINT32_ARG_CHECKED(table_index, 0);
     368        3384 :   CONVERT_UINT32_ARG_CHECKED(dst, 1);
     369        3384 :   CONVERT_UINT32_ARG_CHECKED(src, 2);
     370        3384 :   CONVERT_UINT32_ARG_CHECKED(count, 3);
     371             : 
     372             :   bool oob = !WasmInstanceObject::CopyTableEntries(
     373        1692 :       isolate, instance, table_index, dst, src, count);
     374        1692 :   if (oob) {
     375             :     // Handle out-of-bounds access here in the runtime call, rather
     376             :     // than having the lower-level layers deal with JS exceptions.
     377             :     DCHECK(isolate->context().is_null());
     378        1431 :     isolate->set_context(instance->native_context());
     379             :     Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
     380        1431 :         MessageTemplate::kWasmTrapTableOutOfBounds);
     381        1431 :     return isolate->Throw(*error_obj);
     382             :   }
     383        1692 :   return ReadOnlyRoots(isolate).undefined_value();
     384             : }
     385             : }  // namespace internal
     386      183867 : }  // namespace v8

Generated by: LCOV version 1.10