LCOV - code coverage report
Current view: top level - src/runtime - runtime-wasm.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 147 151 97.4 %
Date: 2019-02-19 Functions: 24 41 58.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        3872 : WasmInstanceObject GetWasmInstanceOnStackTop(Isolate* isolate) {
      30        3872 :   StackFrameIterator it(isolate, isolate->thread_local_top());
      31             :   // On top: C entry stub.
      32             :   DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
      33        3872 :   it.Advance();
      34             :   // Next: the wasm compiled frame.
      35             :   DCHECK(it.frame()->is_wasm_compiled());
      36        3872 :   WasmCompiledFrame* frame = WasmCompiledFrame::cast(it.frame());
      37        7744 :   return frame->wasm_instance();
      38             : }
      39             : 
      40        2184 : Context GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) {
      41        2184 :   return GetWasmInstanceOnStackTop(isolate)->native_context();
      42             : }
      43             : 
      44             : class ClearThreadInWasmScope {
      45             :  public:
      46      192213 :   ClearThreadInWasmScope() {
      47             :     DCHECK_EQ(trap_handler::IsTrapHandlerEnabled(),
      48             :               trap_handler::IsThreadInWasm());
      49             :     trap_handler::ClearThreadInWasm();
      50      192213 :   }
      51      192213 :   ~ClearThreadInWasmScope() {
      52             :     DCHECK(!trap_handler::IsThreadInWasm());
      53             :     trap_handler::SetThreadInWasm();
      54      192213 :   }
      55             : };
      56             : 
      57             : }  // namespace
      58             : 
      59          64 : RUNTIME_FUNCTION(Runtime_WasmIsValidAnyFuncValue) {
      60          64 :   HandleScope scope(isolate);
      61             :   DCHECK_EQ(1, args.length());
      62          64 :   CONVERT_ARG_HANDLE_CHECKED(Object, function, 0);
      63             : 
      64         128 :   if (function->IsNull(isolate)) {
      65           0 :     return Smi::FromInt(true);
      66             :   }
      67          64 :   if (WasmExportedFunction::IsWasmExportedFunction(*function)) {
      68          48 :     return Smi::FromInt(true);
      69             :   }
      70          16 :   return Smi::FromInt(false);
      71             : }
      72             : 
      73        1944 : RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) {
      74        1944 :   HandleScope scope(isolate);
      75             :   DCHECK_EQ(2, args.length());
      76        3888 :   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        3888 :   CONVERT_UINT32_ARG_CHECKED(delta_pages, 1);
      80             : 
      81             :   // This runtime function is always being called from wasm code.
      82        3888 :   ClearThreadInWasmScope flag_scope;
      83             : 
      84             :   int ret = WasmMemoryObject::Grow(
      85        5832 :       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        3888 :   return Smi::FromInt(ret);
      89             : }
      90             : 
      91      148555 : RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
      92             :   DCHECK_EQ(1, args.length());
      93      297110 :   CONVERT_SMI_ARG_CHECKED(message_id, 0);
      94      148555 :   ClearThreadInWasmScope clear_wasm_flag;
      95             : 
      96      297110 :   HandleScope scope(isolate);
      97             :   Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
      98      148555 :       MessageTemplateFromInt(message_id));
      99      297110 :   return isolate->Throw(*error_obj);
     100             : }
     101             : 
     102           0 : RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
     103             :   SealHandleScope shs(isolate);
     104             :   DCHECK_LE(0, args.length());
     105             :   DCHECK(isolate->context().is_null());
     106           0 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     107           0 :   return isolate->StackOverflow();
     108             : }
     109             : 
     110         120 : RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
     111         120 :   HandleScope scope(isolate);
     112             :   DCHECK_EQ(0, args.length());
     113         240 :   THROW_NEW_ERROR_RETURN_FAILURE(
     114         120 :       isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
     115             : }
     116             : 
     117         680 : RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
     118             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     119         680 :   HandleScope scope(isolate);
     120             :   DCHECK_EQ(2, args.length());
     121             :   DCHECK(isolate->context().is_null());
     122         680 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     123        1360 :   CONVERT_ARG_CHECKED(WasmExceptionTag, tag_raw, 0);
     124        1360 :   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         680 :       MessageTemplate::kWasmExceptionError);
     129        1360 :   CHECK(!Object::SetProperty(isolate, exception,
     130             :                              isolate->factory()->wasm_exception_tag_symbol(),
     131             :                              tag, StoreOrigin::kMaybeKeyed,
     132             :                              Just(ShouldThrow::kThrowOnError))
     133             :              .is_null());
     134         680 :   Handle<FixedArray> values = isolate->factory()->NewFixedArray(size);
     135        2040 :   CHECK(!Object::SetProperty(isolate, exception,
     136             :                              isolate->factory()->wasm_exception_values_symbol(),
     137             :                              values, StoreOrigin::kMaybeKeyed,
     138             :                              Just(ShouldThrow::kThrowOnError))
     139             :              .is_null());
     140         680 :   return *exception;
     141             : }
     142             : 
     143         480 : RUNTIME_FUNCTION(Runtime_WasmExceptionGetTag) {
     144             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     145         480 :   HandleScope scope(isolate);
     146             :   DCHECK_EQ(1, args.length());
     147             :   DCHECK(isolate->context().is_null());
     148         480 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     149         480 :   CONVERT_ARG_CHECKED(Object, except_obj_raw, 0);
     150             :   // TODO(mstarzinger): Manually box because parameters are not visited yet.
     151             :   Handle<Object> except_obj(except_obj_raw, isolate);
     152         960 :   return *WasmExceptionPackage::GetExceptionTag(isolate, except_obj);
     153             : }
     154             : 
     155        1024 : RUNTIME_FUNCTION(Runtime_WasmExceptionGetValues) {
     156             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     157        1024 :   HandleScope scope(isolate);
     158             :   DCHECK_EQ(1, args.length());
     159             :   DCHECK(isolate->context().is_null());
     160        1024 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     161        1024 :   CONVERT_ARG_CHECKED(Object, except_obj_raw, 0);
     162             :   // TODO(mstarzinger): Manually box because parameters are not visited yet.
     163             :   Handle<Object> except_obj(except_obj_raw, isolate);
     164        2048 :   return *WasmExceptionPackage::GetExceptionValues(isolate, except_obj);
     165             : }
     166             : 
     167       33452 : RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
     168             :   DCHECK_EQ(2, args.length());
     169       33452 :   HandleScope scope(isolate);
     170       66904 :   CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[0]);
     171       33452 :   CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 1);
     172             : 
     173             :   // The arg buffer is the raw pointer to the caller's stack. It looks like a
     174             :   // Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just
     175             :   // cast it back to the raw pointer.
     176       66904 :   CHECK(!arg_buffer_obj->IsHeapObject());
     177       66904 :   CHECK(arg_buffer_obj->IsSmi());
     178       33452 :   Address arg_buffer = arg_buffer_obj->ptr();
     179             : 
     180       66904 :   ClearThreadInWasmScope wasm_flag;
     181             : 
     182             :   // Find the frame pointer and instance of the interpreter frame on the stack.
     183             :   Handle<WasmInstanceObject> instance;
     184             :   Address frame_pointer = 0;
     185             :   {
     186       33452 :     StackFrameIterator it(isolate, isolate->thread_local_top());
     187             :     // On top: C entry stub.
     188             :     DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
     189       33452 :     it.Advance();
     190             :     // Next: the wasm interpreter entry.
     191             :     DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type());
     192             :     instance = handle(
     193       33452 :         WasmInterpreterEntryFrame::cast(it.frame())->wasm_instance(), isolate);
     194       33452 :     frame_pointer = it.frame()->fp();
     195             :   }
     196             : 
     197             :   // Set the current isolate's context.
     198             :   DCHECK(isolate->context().is_null());
     199       33452 :   isolate->set_context(instance->native_context());
     200             : 
     201             :   // Run the function in the interpreter. Note that neither the {WasmDebugInfo}
     202             :   // nor the {InterpreterHandle} have to exist, because interpretation might
     203             :   // have been triggered by another Isolate sharing the same WasmEngine.
     204             :   Handle<WasmDebugInfo> debug_info =
     205       33452 :       WasmInstanceObject::GetOrCreateDebugInfo(instance);
     206             :   bool success = WasmDebugInfo::RunInterpreter(
     207       33452 :       isolate, debug_info, frame_pointer, func_index, arg_buffer);
     208             : 
     209       33452 :   if (!success) {
     210             :     DCHECK(isolate->has_pending_exception());
     211             :     return ReadOnlyRoots(isolate).exception();
     212             :   }
     213       33452 :   return ReadOnlyRoots(isolate).undefined_value();
     214             : }
     215             : 
     216         222 : RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
     217             :   SealHandleScope shs(isolate);
     218             :   DCHECK_EQ(0, args.length());
     219             :   DCHECK(!trap_handler::IsTrapHandlerEnabled() ||
     220             :          trap_handler::IsThreadInWasm());
     221             : 
     222         222 :   ClearThreadInWasmScope wasm_flag;
     223             : 
     224             :   // Check if this is a real stack overflow.
     225         222 :   StackLimitCheck check(isolate);
     226         222 :   if (check.JsHasOverflowed()) return isolate->StackOverflow();
     227             : 
     228          54 :   return isolate->stack_guard()->HandleInterrupts();
     229             : }
     230             : 
     231        8040 : RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
     232        8040 :   HandleScope scope(isolate);
     233             :   DCHECK_EQ(2, args.length());
     234       16080 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     235       16080 :   CONVERT_SMI_ARG_CHECKED(func_index, 1);
     236             : 
     237       16080 :   ClearThreadInWasmScope wasm_flag;
     238             : 
     239             : #ifdef DEBUG
     240             :   StackFrameIterator it(isolate, isolate->thread_local_top());
     241             :   // On top: C entry stub.
     242             :   DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
     243             :   it.Advance();
     244             :   // Next: the wasm lazy compile frame.
     245             :   DCHECK_EQ(StackFrame::WASM_COMPILE_LAZY, it.frame()->type());
     246             :   DCHECK_EQ(*instance, WasmCompileLazyFrame::cast(it.frame())->wasm_instance());
     247             : #endif
     248             : 
     249             :   Address entrypoint = wasm::CompileLazy(
     250       16080 :       isolate, instance->module_object()->native_module(), func_index);
     251       16080 :   return Object(entrypoint);
     252             : }
     253             : 
     254             : // Should be called from within a handle scope
     255         596 : Handle<JSArrayBuffer> getSharedArrayBuffer(Handle<WasmInstanceObject> instance,
     256             :                                            Isolate* isolate, uint32_t address) {
     257             :   DCHECK(instance->has_memory_object());
     258        1196 :   Handle<JSArrayBuffer> array_buffer(instance->memory_object()->array_buffer(),
     259        1196 :                                      isolate);
     260             : 
     261             :   // Validation should have failed if the memory was not shared.
     262             :   DCHECK(array_buffer->is_shared());
     263             : 
     264             :   // Should have trapped if address was OOB
     265             :   DCHECK_LT(address, array_buffer->byte_length());
     266         600 :   return array_buffer;
     267             : }
     268             : 
     269         136 : RUNTIME_FUNCTION(Runtime_WasmAtomicWake) {
     270         136 :   HandleScope scope(isolate);
     271             :   DCHECK_EQ(3, args.length());
     272         272 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     273         272 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     274         272 :   CONVERT_NUMBER_CHECKED(uint32_t, count, Uint32, args[2]);
     275             :   Handle<JSArrayBuffer> array_buffer =
     276         136 :       getSharedArrayBuffer(instance, isolate, address);
     277         136 :   return FutexEmulation::Wake(array_buffer, address, count);
     278             : }
     279             : 
     280         461 : double WaitTimeoutInMs(double timeout_ns) {
     281             :   return timeout_ns < 0
     282             :              ? V8_INFINITY
     283             :              : timeout_ns / (base::Time::kNanosecondsPerMicrosecond *
     284         461 :                              base::Time::kMicrosecondsPerMillisecond);
     285             : }
     286             : 
     287         231 : RUNTIME_FUNCTION(Runtime_WasmI32AtomicWait) {
     288         231 :   HandleScope scope(isolate);
     289             :   DCHECK_EQ(4, args.length());
     290         460 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     291         462 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     292         464 :   CONVERT_NUMBER_CHECKED(int32_t, expected_value, Int32, args[2]);
     293         464 :   CONVERT_DOUBLE_ARG_CHECKED(timeout_ns, 3);
     294         231 :   double timeout_ms = WaitTimeoutInMs(timeout_ns);
     295             :   Handle<JSArrayBuffer> array_buffer =
     296         231 :       getSharedArrayBuffer(instance, isolate, address);
     297             :   return FutexEmulation::Wait32(isolate, array_buffer, address, expected_value,
     298         232 :                                 timeout_ms);
     299             : }
     300             : 
     301         231 : RUNTIME_FUNCTION(Runtime_WasmI64AtomicWait) {
     302         231 :   HandleScope scope(isolate);
     303             :   DCHECK_EQ(5, args.length());
     304         463 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     305         463 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     306         463 :   CONVERT_NUMBER_CHECKED(uint32_t, expected_value_high, Uint32, args[2]);
     307         464 :   CONVERT_NUMBER_CHECKED(uint32_t, expected_value_low, Uint32, args[3]);
     308         463 :   CONVERT_DOUBLE_ARG_CHECKED(timeout_ns, 4);
     309         231 :   int64_t expected_value = (static_cast<uint64_t>(expected_value_high) << 32) |
     310         231 :                            static_cast<uint64_t>(expected_value_low);
     311         231 :   double timeout_ms = WaitTimeoutInMs(timeout_ns);
     312             :   Handle<JSArrayBuffer> array_buffer =
     313         231 :       getSharedArrayBuffer(instance, isolate, address);
     314             :   return FutexEmulation::Wait64(isolate, array_buffer, address, expected_value,
     315         232 :                                 timeout_ms);
     316             : }
     317             : 
     318             : namespace {
     319        1416 : Object ThrowTableOutOfBounds(Isolate* isolate,
     320             :                              Handle<WasmInstanceObject> instance) {
     321             :   // Handle out-of-bounds access here in the runtime call, rather
     322             :   // than having the lower-level layers deal with JS exceptions.
     323        1416 :   if (isolate->context().is_null()) {
     324        2576 :     isolate->set_context(instance->native_context());
     325             :   }
     326             :   Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
     327        1416 :       MessageTemplate::kWasmTrapTableOutOfBounds);
     328        1416 :   return isolate->Throw(*error_obj);
     329             : }
     330             : }  // namespace
     331             : 
     332         184 : RUNTIME_FUNCTION(Runtime_WasmTableInit) {
     333         184 :   HandleScope scope(isolate);
     334             :   DCHECK_EQ(5, args.length());
     335             :   auto instance =
     336         184 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     337         368 :   CONVERT_UINT32_ARG_CHECKED(table_index, 0);
     338         368 :   CONVERT_UINT32_ARG_CHECKED(elem_segment_index, 1);
     339         368 :   CONVERT_UINT32_ARG_CHECKED(dst, 2);
     340         368 :   CONVERT_UINT32_ARG_CHECKED(src, 3);
     341         368 :   CONVERT_UINT32_ARG_CHECKED(count, 4);
     342             : 
     343             :   DCHECK(isolate->context().is_null());
     344         184 :   isolate->set_context(instance->native_context());
     345             : 
     346             :   bool oob = !WasmInstanceObject::InitTableEntries(
     347         184 :       isolate, instance, table_index, elem_segment_index, dst, src, count);
     348         184 :   if (oob) return ThrowTableOutOfBounds(isolate, instance);
     349         184 :   return ReadOnlyRoots(isolate).undefined_value();
     350             : }
     351             : 
     352        1504 : RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
     353        1504 :   HandleScope scope(isolate);
     354             :   DCHECK_EQ(5, args.length());
     355             :   auto instance =
     356        1504 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     357        3008 :   CONVERT_UINT32_ARG_CHECKED(table_src_index, 0);
     358        3008 :   CONVERT_UINT32_ARG_CHECKED(table_dst_index, 1);
     359        3008 :   CONVERT_UINT32_ARG_CHECKED(dst, 2);
     360        3008 :   CONVERT_UINT32_ARG_CHECKED(src, 3);
     361        3008 :   CONVERT_UINT32_ARG_CHECKED(count, 4);
     362             : 
     363             :   bool oob = !WasmInstanceObject::CopyTableEntries(
     364        1504 :       isolate, instance, table_src_index, table_dst_index, dst, src, count);
     365        1504 :   if (oob) return ThrowTableOutOfBounds(isolate, instance);
     366        1504 :   return ReadOnlyRoots(isolate).undefined_value();
     367             : }
     368             : }  // namespace internal
     369      178779 : }  // namespace v8

Generated by: LCOV version 1.10