LCOV - code coverage report
Current view: top level - src/runtime - runtime-wasm.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 179 182 98.4 %
Date: 2019-04-19 Functions: 26 47 55.3 %

          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             : #include "src/wasm/wasm-value.h"
      24             : 
      25             : namespace v8 {
      26             : namespace internal {
      27             : 
      28             : namespace {
      29             : 
      30        4288 : WasmInstanceObject GetWasmInstanceOnStackTop(Isolate* isolate) {
      31        4288 :   StackFrameIterator it(isolate, isolate->thread_local_top());
      32             :   // On top: C entry stub.
      33             :   DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
      34        4288 :   it.Advance();
      35             :   // Next: the wasm compiled frame.
      36             :   DCHECK(it.frame()->is_wasm_compiled());
      37             :   WasmCompiledFrame* frame = WasmCompiledFrame::cast(it.frame());
      38        8576 :   return frame->wasm_instance();
      39             : }
      40             : 
      41        2232 : Context GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) {
      42        4464 :   return GetWasmInstanceOnStackTop(isolate)->native_context();
      43             : }
      44             : 
      45             : class ClearThreadInWasmScope {
      46             :  public:
      47             :   ClearThreadInWasmScope() {
      48             :     DCHECK_EQ(trap_handler::IsTrapHandlerEnabled(),
      49             :               trap_handler::IsThreadInWasm());
      50             :     trap_handler::ClearThreadInWasm();
      51             :   }
      52             :   ~ClearThreadInWasmScope() {
      53             :     DCHECK(!trap_handler::IsThreadInWasm());
      54             :     trap_handler::SetThreadInWasm();
      55             :   }
      56             : };
      57             : 
      58      147732 : Object ThrowWasmError(Isolate* isolate, MessageTemplate message) {
      59             :   HandleScope scope(isolate);
      60      147732 :   Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(message);
      61      295464 :   return isolate->Throw(*error_obj);
      62             : }
      63             : }  // namespace
      64             : 
      65         672 : RUNTIME_FUNCTION(Runtime_WasmIsValidAnyFuncValue) {
      66             :   HandleScope scope(isolate);
      67             :   DCHECK_EQ(1, args.length());
      68             :   CONVERT_ARG_HANDLE_CHECKED(Object, function, 0);
      69             : 
      70         336 :   if (function->IsNull(isolate)) {
      71             :     return Smi::FromInt(true);
      72             :   }
      73         320 :   if (WasmExportedFunction::IsWasmExportedFunction(*function)) {
      74             :     return Smi::FromInt(true);
      75             :   }
      76             :   return Smi::FromInt(false);
      77             : }
      78             : 
      79        3856 : RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) {
      80             :   HandleScope scope(isolate);
      81             :   DCHECK_EQ(2, args.length());
      82        1928 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
      83             :   // {delta_pages} is checked to be a positive smi in the WasmMemoryGrow builtin
      84             :   // which calls this runtime function.
      85        3856 :   CONVERT_UINT32_ARG_CHECKED(delta_pages, 1);
      86             : 
      87             :   // This runtime function is always being called from wasm code.
      88             :   ClearThreadInWasmScope flag_scope;
      89             : 
      90        1928 :   int ret = WasmMemoryObject::Grow(
      91        1928 :       isolate, handle(instance->memory_object(), isolate), delta_pages);
      92             :   // The WasmMemoryGrow builtin which calls this runtime function expects us to
      93             :   // always return a Smi.
      94             :   return Smi::FromInt(ret);
      95             : }
      96             : 
      97      295336 : RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
      98             :   ClearThreadInWasmScope clear_wasm_flag;
      99             :   DCHECK_EQ(1, args.length());
     100      147668 :   CONVERT_SMI_ARG_CHECKED(message_id, 0);
     101      147668 :   return ThrowWasmError(isolate, MessageTemplateFromInt(message_id));
     102             : }
     103             : 
     104         140 : RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
     105             :   SealHandleScope shs(isolate);
     106             :   DCHECK_LE(0, args.length());
     107          70 :   return isolate->StackOverflow();
     108             : }
     109             : 
     110         288 : RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
     111             :   HandleScope scope(isolate);
     112             :   DCHECK_EQ(0, args.length());
     113         288 :   THROW_NEW_ERROR_RETURN_FAILURE(
     114             :       isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
     115             : }
     116             : 
     117        1408 : RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
     118             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     119             :   HandleScope scope(isolate);
     120             :   DCHECK_EQ(2, args.length());
     121             :   DCHECK(isolate->context().is_null());
     122         704 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     123         704 :   CONVERT_ARG_CHECKED(WasmExceptionTag, tag_raw, 0);
     124         704 :   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         704 :       MessageTemplate::kWasmExceptionError);
     129        2112 :   CHECK(!Object::SetProperty(isolate, exception,
     130             :                              isolate->factory()->wasm_exception_tag_symbol(),
     131             :                              tag, StoreOrigin::kMaybeKeyed,
     132             :                              Just(ShouldThrow::kThrowOnError))
     133             :              .is_null());
     134         704 :   Handle<FixedArray> values = isolate->factory()->NewFixedArray(size);
     135        2112 :   CHECK(!Object::SetProperty(isolate, exception,
     136             :                              isolate->factory()->wasm_exception_values_symbol(),
     137             :                              values, StoreOrigin::kMaybeKeyed,
     138             :                              Just(ShouldThrow::kThrowOnError))
     139             :              .is_null());
     140             :   return *exception;
     141             : }
     142             : 
     143         960 : RUNTIME_FUNCTION(Runtime_WasmExceptionGetTag) {
     144             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     145             :   HandleScope scope(isolate);
     146             :   DCHECK_EQ(1, args.length());
     147             :   DCHECK(isolate->context().is_null());
     148         480 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     149             :   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        2096 : RUNTIME_FUNCTION(Runtime_WasmExceptionGetValues) {
     156             :   // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
     157             :   HandleScope scope(isolate);
     158             :   DCHECK_EQ(1, args.length());
     159             :   DCHECK(isolate->context().is_null());
     160        1048 :   isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
     161             :   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        2096 :   return *WasmExceptionPackage::GetExceptionValues(isolate, except_obj);
     165             : }
     166             : 
     167       74762 : RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
     168             :   DCHECK_EQ(2, args.length());
     169             :   HandleScope scope(isolate);
     170       74762 :   CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[0]);
     171             :   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       37381 :   CHECK(!arg_buffer_obj->IsHeapObject());
     177       37381 :   CHECK(arg_buffer_obj->IsSmi());
     178             :   Address arg_buffer = arg_buffer_obj->ptr();
     179             : 
     180             :   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       74762 :     StackFrameIterator it(isolate, isolate->thread_local_top());
     187             :     // On top: C entry stub.
     188             :     DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
     189       37381 :     it.Advance();
     190             :     // Next: the wasm interpreter entry.
     191             :     DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type());
     192             :     instance = handle(
     193       37381 :         WasmInterpreterEntryFrame::cast(it.frame())->wasm_instance(), isolate);
     194             :     frame_pointer = it.frame()->fp();
     195             :   }
     196             : 
     197             :   // Reserve buffers for argument and return values.
     198             :   DCHECK_GE(instance->module()->functions.size(), func_index);
     199      112143 :   wasm::FunctionSig* sig = instance->module()->functions[func_index].sig;
     200             :   DCHECK_GE(kMaxInt, sig->parameter_count());
     201       37381 :   int num_params = static_cast<int>(sig->parameter_count());
     202       37381 :   ScopedVector<wasm::WasmValue> wasm_args(num_params);
     203             :   DCHECK_GE(kMaxInt, sig->return_count());
     204       37381 :   int num_returns = static_cast<int>(sig->return_count());
     205       37381 :   ScopedVector<wasm::WasmValue> wasm_rets(num_returns);
     206             : 
     207             :   // Copy the arguments for the {arg_buffer} into a vector of {WasmValue}. This
     208             :   // also boxes reference types into handles, which needs to happen before any
     209             :   // methods that could trigger a GC are being called.
     210             :   Address arg_buf_ptr = arg_buffer;
     211      156303 :   for (int i = 0; i < num_params; ++i) {
     212             : #define CASE_ARG_TYPE(type, ctype)                                          \
     213             :   case wasm::type:                                                          \
     214             :     DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetParam(i)),       \
     215             :               sizeof(ctype));                                               \
     216             :     wasm_args[i] = wasm::WasmValue(ReadUnalignedValue<ctype>(arg_buf_ptr)); \
     217             :     arg_buf_ptr += sizeof(ctype);                                           \
     218             :     break;
     219      118922 :     switch (sig->GetParam(i)) {
     220       12081 :       CASE_ARG_TYPE(kWasmI32, uint32_t)
     221       15024 :       CASE_ARG_TYPE(kWasmI64, uint64_t)
     222        1444 :       CASE_ARG_TYPE(kWasmF32, float)
     223       28664 :       CASE_ARG_TYPE(kWasmF64, double)
     224             : #undef CASE_ARG_TYPE
     225             :       case wasm::kWasmAnyRef:
     226             :       case wasm::kWasmAnyFunc:
     227             :       case wasm::kWasmExceptRef: {
     228             :         DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetParam(i)),
     229             :                   kSystemPointerSize);
     230             :         Handle<Object> ref(ReadUnalignedValue<Object>(arg_buf_ptr), isolate);
     231        2248 :         wasm_args[i] = wasm::WasmValue(ref);
     232        2248 :         arg_buf_ptr += kSystemPointerSize;
     233             :         break;
     234             :       }
     235             :       default:
     236           0 :         UNREACHABLE();
     237             :     }
     238             :   }
     239             : 
     240             :   // Set the current isolate's context.
     241             :   DCHECK(isolate->context().is_null());
     242             :   isolate->set_context(instance->native_context());
     243             : 
     244             :   // Run the function in the interpreter. Note that neither the {WasmDebugInfo}
     245             :   // nor the {InterpreterHandle} have to exist, because interpretation might
     246             :   // have been triggered by another Isolate sharing the same WasmEngine.
     247             :   Handle<WasmDebugInfo> debug_info =
     248       37381 :       WasmInstanceObject::GetOrCreateDebugInfo(instance);
     249             :   bool success = WasmDebugInfo::RunInterpreter(
     250       37381 :       isolate, debug_info, frame_pointer, func_index, wasm_args, wasm_rets);
     251             : 
     252             :   // Early return on failure.
     253       37381 :   if (!success) {
     254             :     DCHECK(isolate->has_pending_exception());
     255             :     return ReadOnlyRoots(isolate).exception();
     256             :   }
     257             : 
     258             :   // Copy return values from the vector of {WasmValue} into {arg_buffer}. This
     259             :   // also un-boxes reference types from handles into raw pointers.
     260             :   arg_buf_ptr = arg_buffer;
     261      101037 :   for (int i = 0; i < num_returns; ++i) {
     262             : #define CASE_RET_TYPE(type, ctype)                                     \
     263             :   case wasm::type:                                                     \
     264             :     DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetReturn(i)), \
     265             :               sizeof(ctype));                                          \
     266             :     WriteUnalignedValue<ctype>(arg_buf_ptr, wasm_rets[i].to<ctype>()); \
     267             :     arg_buf_ptr += sizeof(ctype);                                      \
     268             :     break;
     269       67030 :     switch (sig->GetReturn(i)) {
     270        6147 :       CASE_RET_TYPE(kWasmI32, uint32_t)
     271         332 :       CASE_RET_TYPE(kWasmI64, uint64_t)
     272          32 :       CASE_RET_TYPE(kWasmF32, float)
     273       26468 :       CASE_RET_TYPE(kWasmF64, double)
     274             : #undef CASE_RET_TYPE
     275             :       case wasm::kWasmAnyRef:
     276             :       case wasm::kWasmAnyFunc:
     277             :       case wasm::kWasmExceptRef: {
     278             :         DCHECK_EQ(wasm::ValueTypes::ElementSizeInBytes(sig->GetReturn(i)),
     279             :                   kSystemPointerSize);
     280             :         WriteUnalignedValue<Object>(arg_buf_ptr, *wasm_rets[i].to_anyref());
     281         536 :         arg_buf_ptr += kSystemPointerSize;
     282             :         break;
     283             :       }
     284             :       default:
     285           0 :         UNREACHABLE();
     286             :     }
     287             :   }
     288             : 
     289             :   return ReadOnlyRoots(isolate).undefined_value();
     290             : }
     291             : 
     292         268 : RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
     293             :   SealHandleScope shs(isolate);
     294             :   DCHECK_EQ(0, args.length());
     295             :   DCHECK(!trap_handler::IsTrapHandlerEnabled() ||
     296             :          trap_handler::IsThreadInWasm());
     297             : 
     298             :   ClearThreadInWasmScope wasm_flag;
     299             : 
     300             :   // Check if this is a real stack overflow.
     301             :   StackLimitCheck check(isolate);
     302         134 :   if (check.JsHasOverflowed()) return isolate->StackOverflow();
     303             : 
     304          36 :   return isolate->stack_guard()->HandleInterrupts();
     305             : }
     306             : 
     307       16290 : RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
     308             :   HandleScope scope(isolate);
     309             :   DCHECK_EQ(2, args.length());
     310        8145 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     311        8145 :   CONVERT_SMI_ARG_CHECKED(func_index, 1);
     312             : 
     313             :   // This runtime function is always called from wasm code.
     314             :   ClearThreadInWasmScope flag_scope;
     315             : 
     316             : #ifdef DEBUG
     317             :   StackFrameIterator it(isolate, isolate->thread_local_top());
     318             :   // On top: C entry stub.
     319             :   DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
     320             :   it.Advance();
     321             :   // Next: the wasm lazy compile frame.
     322             :   DCHECK_EQ(StackFrame::WASM_COMPILE_LAZY, it.frame()->type());
     323             :   DCHECK_EQ(*instance, WasmCompileLazyFrame::cast(it.frame())->wasm_instance());
     324             : #endif
     325             : 
     326             :   DCHECK(isolate->context().is_null());
     327             :   isolate->set_context(instance->native_context());
     328        8145 :   auto* native_module = instance->module_object()->native_module();
     329        8145 :   bool success = wasm::CompileLazy(isolate, native_module, func_index);
     330        8145 :   if (!success) {
     331             :     DCHECK(isolate->has_pending_exception());
     332             :     return ReadOnlyRoots(isolate).exception();
     333             :   }
     334             : 
     335        8121 :   Address entrypoint = native_module->GetCallTargetForFunction(func_index);
     336             : 
     337             :   return Object(entrypoint);
     338             : }
     339             : 
     340             : // Should be called from within a handle scope
     341         655 : Handle<JSArrayBuffer> getSharedArrayBuffer(Handle<WasmInstanceObject> instance,
     342             :                                            Isolate* isolate, uint32_t address) {
     343             :   DCHECK(instance->has_memory_object());
     344             :   Handle<JSArrayBuffer> array_buffer(instance->memory_object()->array_buffer(),
     345             :                                      isolate);
     346             : 
     347             :   // Validation should have failed if the memory was not shared.
     348             :   DCHECK(array_buffer->is_shared());
     349             : 
     350             :   // Should have trapped if address was OOB
     351             :   DCHECK_LT(address, array_buffer->byte_length());
     352         654 :   return array_buffer;
     353             : }
     354             : 
     355         272 : RUNTIME_FUNCTION(Runtime_WasmAtomicNotify) {
     356             :   HandleScope scope(isolate);
     357             :   DCHECK_EQ(3, args.length());
     358         136 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     359         272 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     360         272 :   CONVERT_NUMBER_CHECKED(uint32_t, count, Uint32, args[2]);
     361             :   Handle<JSArrayBuffer> array_buffer =
     362         136 :       getSharedArrayBuffer(instance, isolate, address);
     363         136 :   return FutexEmulation::Wake(array_buffer, address, count);
     364             : }
     365             : 
     366           0 : double WaitTimeoutInMs(double timeout_ns) {
     367             :   return timeout_ns < 0
     368             :              ? V8_INFINITY
     369             :              : timeout_ns / (base::Time::kNanosecondsPerMicrosecond *
     370         519 :                              base::Time::kMicrosecondsPerMillisecond);
     371             : }
     372             : 
     373         518 : RUNTIME_FUNCTION(Runtime_WasmI32AtomicWait) {
     374             :   HandleScope scope(isolate);
     375             :   DCHECK_EQ(4, args.length());
     376         259 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     377         520 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     378         520 :   CONVERT_NUMBER_CHECKED(int32_t, expected_value, Int32, args[2]);
     379         260 :   CONVERT_DOUBLE_ARG_CHECKED(timeout_ns, 3);
     380             :   double timeout_ms = WaitTimeoutInMs(timeout_ns);
     381             :   Handle<JSArrayBuffer> array_buffer =
     382         260 :       getSharedArrayBuffer(instance, isolate, address);
     383             :   return FutexEmulation::Wait32(isolate, array_buffer, address, expected_value,
     384         259 :                                 timeout_ms);
     385             : }
     386             : 
     387         520 : RUNTIME_FUNCTION(Runtime_WasmI64AtomicWait) {
     388             :   HandleScope scope(isolate);
     389             :   DCHECK_EQ(5, args.length());
     390         260 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     391         520 :   CONVERT_NUMBER_CHECKED(uint32_t, address, Uint32, args[1]);
     392         520 :   CONVERT_NUMBER_CHECKED(uint32_t, expected_value_high, Uint32, args[2]);
     393         520 :   CONVERT_NUMBER_CHECKED(uint32_t, expected_value_low, Uint32, args[3]);
     394         259 :   CONVERT_DOUBLE_ARG_CHECKED(timeout_ns, 4);
     395         259 :   int64_t expected_value = (static_cast<uint64_t>(expected_value_high) << 32) |
     396         259 :                            static_cast<uint64_t>(expected_value_low);
     397             :   double timeout_ms = WaitTimeoutInMs(timeout_ns);
     398             :   Handle<JSArrayBuffer> array_buffer =
     399         259 :       getSharedArrayBuffer(instance, isolate, address);
     400             :   return FutexEmulation::Wait64(isolate, array_buffer, address, expected_value,
     401         259 :                                 timeout_ms);
     402             : }
     403             : 
     404             : namespace {
     405        1464 : Object ThrowTableOutOfBounds(Isolate* isolate,
     406             :                              Handle<WasmInstanceObject> instance) {
     407             :   // Handle out-of-bounds access here in the runtime call, rather
     408             :   // than having the lower-level layers deal with JS exceptions.
     409        1464 :   if (isolate->context().is_null()) {
     410             :     isolate->set_context(instance->native_context());
     411             :   }
     412             :   Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
     413        1464 :       MessageTemplate::kWasmTrapTableOutOfBounds);
     414        1464 :   return isolate->Throw(*error_obj);
     415             : }
     416             : }  // namespace
     417             : 
     418         240 : RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet) {
     419             :   // This runtime function is always being called from wasm code.
     420             :   ClearThreadInWasmScope flag_scope;
     421             : 
     422             :   HandleScope scope(isolate);
     423             :   DCHECK_EQ(3, args.length());
     424         120 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     425         240 :   CONVERT_UINT32_ARG_CHECKED(table_index, 1);
     426         240 :   CONVERT_UINT32_ARG_CHECKED(entry_index, 2);
     427             :   DCHECK_LT(table_index, instance->tables()->length());
     428             :   auto table = handle(
     429         240 :       WasmTableObject::cast(instance->tables()->get(table_index)), isolate);
     430             : 
     431         120 :   if (!WasmTableObject::IsInBounds(isolate, table, entry_index)) {
     432          16 :     return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
     433             :   }
     434             : 
     435         208 :   return *WasmTableObject::Get(isolate, table, entry_index);
     436             : }
     437             : 
     438          80 : RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) {
     439             :   // This runtime function is always being called from wasm code.
     440             :   ClearThreadInWasmScope flag_scope;
     441             : 
     442             :   HandleScope scope(isolate);
     443             :   DCHECK_EQ(4, args.length());
     444          40 :   CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
     445          80 :   CONVERT_UINT32_ARG_CHECKED(table_index, 1);
     446          80 :   CONVERT_UINT32_ARG_CHECKED(entry_index, 2);
     447             :   CONVERT_ARG_CHECKED(Object, element_raw, 3);
     448             :   // TODO(mstarzinger): Manually box because parameters are not visited yet.
     449             :   Handle<Object> element(element_raw, isolate);
     450             :   DCHECK_LT(table_index, instance->tables()->length());
     451             :   auto table = handle(
     452          80 :       WasmTableObject::cast(instance->tables()->get(table_index)), isolate);
     453             : 
     454          40 :   if (!WasmTableObject::IsInBounds(isolate, table, entry_index)) {
     455          16 :     return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
     456             :   }
     457          24 :   WasmTableObject::Set(isolate, table, entry_index, element);
     458             :   return ReadOnlyRoots(isolate).undefined_value();
     459             : }
     460             : 
     461         304 : RUNTIME_FUNCTION(Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance) {
     462             :   HandleScope scope(isolate);
     463             :   DCHECK_EQ(3, args.length());
     464             :   auto instance =
     465         152 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     466         304 :   CONVERT_UINT32_ARG_CHECKED(table_index, 0);
     467         304 :   CONVERT_UINT32_ARG_CHECKED(entry_index, 1);
     468         304 :   CONVERT_UINT32_ARG_CHECKED(sig_index, 2);
     469             :   DCHECK(isolate->context().is_null());
     470             :   isolate->set_context(instance->native_context());
     471             : 
     472             :   DCHECK_LT(table_index, instance->tables()->length());
     473             :   auto table_obj = handle(
     474         304 :       WasmTableObject::cast(instance->tables()->get(table_index)), isolate);
     475             : 
     476             :   // This check is already done in generated code.
     477             :   DCHECK(WasmTableObject::IsInBounds(isolate, table_obj, entry_index));
     478             : 
     479             :   bool is_valid;
     480             :   bool is_null;
     481         152 :   MaybeHandle<WasmInstanceObject> maybe_target_instance;
     482             :   int function_index;
     483         152 :   WasmTableObject::GetFunctionTableEntry(
     484             :       isolate, table_obj, entry_index, &is_valid, &is_null,
     485         152 :       &maybe_target_instance, &function_index);
     486             : 
     487         152 :   CHECK(is_valid);
     488         152 :   if (is_null) {
     489             :     // We throw a signature mismatch trap to be in sync with the generated
     490             :     // code. There we do a signature check instead of a null-check. Trap
     491             :     // reasons are not defined in the spec. Otherwise, a null-check is
     492             :     // performed before a signature, according to the spec.
     493          16 :     return ThrowWasmError(isolate, MessageTemplate::kWasmTrapFuncSigMismatch);
     494             :   }
     495             : 
     496             :   // Now we do the signature check.
     497             :   Handle<WasmInstanceObject> target_instance =
     498             :       maybe_target_instance.ToHandleChecked();
     499             : 
     500             :   const wasm::WasmModule* target_module =
     501         136 :       target_instance->module_object()->native_module()->module();
     502             : 
     503         272 :   wasm::FunctionSig* target_sig = target_module->functions[function_index].sig;
     504             : 
     505         136 :   auto target_sig_id = instance->module()->signature_map.Find(*target_sig);
     506         408 :   uint32_t expected_sig_id = instance->module()->signature_ids[sig_index];
     507             : 
     508         136 :   if (expected_sig_id != static_cast<uint32_t>(target_sig_id)) {
     509          16 :     return ThrowWasmError(isolate, MessageTemplate::kWasmTrapFuncSigMismatch);
     510             :   }
     511             : 
     512         240 :   if (function_index <
     513         240 :       static_cast<int>(target_instance->module()->num_imported_functions)) {
     514             :     // The function in the target instance was imported. Use its imports table,
     515             :     // which contains a tuple needed by the import wrapper.
     516             :     ImportedFunctionEntry entry(target_instance, function_index);
     517           8 :     return entry.object_ref();
     518             :   }
     519             :   return *target_instance;
     520             : }
     521             : 
     522         240 : RUNTIME_FUNCTION(Runtime_WasmIndirectCallGetTargetAddress) {
     523             :   HandleScope scope(isolate);
     524             :   DCHECK_EQ(2, args.length());
     525             :   auto instance =
     526         120 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     527         240 :   CONVERT_UINT32_ARG_CHECKED(table_index, 0);
     528         240 :   CONVERT_UINT32_ARG_CHECKED(entry_index, 1);
     529             : 
     530             :   DCHECK_LT(table_index, instance->tables()->length());
     531             :   auto table_obj = handle(
     532         240 :       WasmTableObject::cast(instance->tables()->get(table_index)), isolate);
     533             : 
     534             :   DCHECK(WasmTableObject::IsInBounds(isolate, table_obj, entry_index));
     535             : 
     536             :   bool is_valid;
     537             :   bool is_null;
     538         120 :   MaybeHandle<WasmInstanceObject> maybe_target_instance;
     539             :   int function_index;
     540         120 :   WasmTableObject::GetFunctionTableEntry(
     541             :       isolate, table_obj, entry_index, &is_valid, &is_null,
     542         120 :       &maybe_target_instance, &function_index);
     543             : 
     544         120 :   CHECK(is_valid);
     545             :   // The null-check should already have been done in
     546             :   // Runtime_WasmIndirectCallCheckSignatureAndGetTargetInstance. That runtime
     547             :   // function should always be called first.
     548         120 :   CHECK(!is_null);
     549             : 
     550             :   Handle<WasmInstanceObject> target_instance =
     551             :       maybe_target_instance.ToHandleChecked();
     552             : 
     553             :   Address call_target = 0;
     554         240 :   if (function_index <
     555         240 :       static_cast<int>(target_instance->module()->num_imported_functions)) {
     556             :     // The function in the target instance was imported. Use its imports table,
     557             :     // which contains a tuple needed by the import wrapper.
     558             :     ImportedFunctionEntry entry(target_instance, function_index);
     559           8 :     call_target = entry.target();
     560             :   } else {
     561             :     // The function in the target instance was not imported.
     562         224 :     call_target = target_instance->GetCallTarget(function_index);
     563             :   }
     564             : 
     565             :   // The return value is an address and not a SMI. However, the address is
     566             :   // always aligned, and a SMI uses the same space as {Address}.
     567         120 :   CHECK(HAS_SMI_TAG(call_target));
     568             :   return Smi(call_target);
     569             : }
     570             : 
     571         448 : RUNTIME_FUNCTION(Runtime_WasmTableInit) {
     572             :   HandleScope scope(isolate);
     573             :   DCHECK_EQ(5, args.length());
     574             :   auto instance =
     575         224 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     576         448 :   CONVERT_UINT32_ARG_CHECKED(table_index, 0);
     577         448 :   CONVERT_UINT32_ARG_CHECKED(elem_segment_index, 1);
     578         448 :   CONVERT_UINT32_ARG_CHECKED(dst, 2);
     579         448 :   CONVERT_UINT32_ARG_CHECKED(src, 3);
     580         448 :   CONVERT_UINT32_ARG_CHECKED(count, 4);
     581             : 
     582             :   DCHECK(isolate->context().is_null());
     583             :   isolate->set_context(instance->native_context());
     584             : 
     585         224 :   bool oob = !WasmInstanceObject::InitTableEntries(
     586             :       isolate, instance, table_index, elem_segment_index, dst, src, count);
     587         224 :   if (oob) return ThrowTableOutOfBounds(isolate, instance);
     588             :   return ReadOnlyRoots(isolate).undefined_value();
     589             : }
     590             : 
     591        3120 : RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
     592             :   HandleScope scope(isolate);
     593             :   DCHECK_EQ(5, args.length());
     594             :   auto instance =
     595        1560 :       Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
     596        3120 :   CONVERT_UINT32_ARG_CHECKED(table_src_index, 0);
     597        3120 :   CONVERT_UINT32_ARG_CHECKED(table_dst_index, 1);
     598        3120 :   CONVERT_UINT32_ARG_CHECKED(dst, 2);
     599        3120 :   CONVERT_UINT32_ARG_CHECKED(src, 3);
     600        3120 :   CONVERT_UINT32_ARG_CHECKED(count, 4);
     601             : 
     602        1560 :   bool oob = !WasmInstanceObject::CopyTableEntries(
     603             :       isolate, instance, table_src_index, table_dst_index, dst, src, count);
     604        1560 :   if (oob) return ThrowTableOutOfBounds(isolate, instance);
     605             :   return ReadOnlyRoots(isolate).undefined_value();
     606             : }
     607             : }  // namespace internal
     608      122036 : }  // namespace v8

Generated by: LCOV version 1.10