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
|