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/base/memory.h"
6 #include "src/common/message-template.h"
7 #include "src/compiler/wasm-compiler.h"
8 #include "src/debug/debug.h"
9 #include "src/execution/arguments-inl.h"
10 #include "src/execution/frame-constants.h"
11 #include "src/execution/frames.h"
12 #include "src/heap/factory.h"
13 #include "src/logging/counters.h"
14 #include "src/numbers/conversions.h"
15 #include "src/objects/frame-array-inl.h"
16 #include "src/objects/objects-inl.h"
17 #include "src/runtime/runtime-utils.h"
18 #include "src/trap-handler/trap-handler.h"
19 #include "src/wasm/module-compiler.h"
20 #include "src/wasm/value-type.h"
21 #include "src/wasm/wasm-code-manager.h"
22 #include "src/wasm/wasm-constants.h"
23 #include "src/wasm/wasm-debug.h"
24 #include "src/wasm/wasm-engine.h"
25 #include "src/wasm/wasm-objects.h"
26 #include "src/wasm/wasm-subtyping.h"
27 #include "src/wasm/wasm-value.h"
28
29 namespace v8 {
30 namespace internal {
31
32 namespace {
33
34 template <typename FrameType, StackFrame::Type... skipped_frame_types>
35 class FrameFinder {
36 static_assert(sizeof...(skipped_frame_types) > 0,
37 "Specify at least one frame to skip");
38
39 public:
FrameFinder(Isolate * isolate)40 explicit FrameFinder(Isolate* isolate)
41 : frame_iterator_(isolate, isolate->thread_local_top()) {
42 for (auto type : {skipped_frame_types...}) {
43 DCHECK_EQ(type, frame_iterator_.frame()->type());
44 USE(type);
45 frame_iterator_.Advance();
46 }
47 // Type check the frame where the iterator stopped now.
48 DCHECK_NOT_NULL(frame());
49 }
50
frame()51 FrameType* frame() { return FrameType::cast(frame_iterator_.frame()); }
52
53 private:
54 StackFrameIterator frame_iterator_;
55 };
56
GetWasmInstanceOnStackTop(Isolate * isolate)57 WasmInstanceObject GetWasmInstanceOnStackTop(Isolate* isolate) {
58 return FrameFinder<WasmFrame, StackFrame::EXIT>(isolate)
59 .frame()
60 ->wasm_instance();
61 }
62
GetNativeContextFromWasmInstanceOnStackTop(Isolate * isolate)63 Context GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) {
64 return GetWasmInstanceOnStackTop(isolate).native_context();
65 }
66
67 class ClearThreadInWasmScope {
68 public:
ClearThreadInWasmScope()69 ClearThreadInWasmScope() {
70 DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
71 trap_handler::IsThreadInWasm());
72 trap_handler::ClearThreadInWasm();
73 }
~ClearThreadInWasmScope()74 ~ClearThreadInWasmScope() {
75 DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
76 !trap_handler::IsThreadInWasm());
77 trap_handler::SetThreadInWasm();
78 }
79 };
80
ThrowWasmError(Isolate * isolate,MessageTemplate message)81 Object ThrowWasmError(Isolate* isolate, MessageTemplate message) {
82 HandleScope scope(isolate);
83 Handle<JSObject> error_obj = isolate->factory()->NewWasmRuntimeError(message);
84 JSObject::AddProperty(isolate, error_obj,
85 isolate->factory()->wasm_uncatchable_symbol(),
86 isolate->factory()->true_value(), NONE);
87 return isolate->Throw(*error_obj);
88 }
89 } // namespace
90
RUNTIME_FUNCTION(Runtime_WasmIsValidRefValue)91 RUNTIME_FUNCTION(Runtime_WasmIsValidRefValue) {
92 // This code is called from wrappers, so the "thread is wasm" flag is not set.
93 DCHECK(!trap_handler::IsThreadInWasm());
94 HandleScope scope(isolate);
95 DCHECK_EQ(3, args.length());
96 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0)
97 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
98 // Make sure ValueType fits properly in a Smi.
99 STATIC_ASSERT(wasm::ValueType::kLastUsedBit + 1 <= kSmiValueSize);
100 CONVERT_SMI_ARG_CHECKED(raw_type, 2);
101
102 wasm::ValueType type = wasm::ValueType::FromRawBitField(raw_type);
103 const char* error_message;
104
105 bool result = internal::wasm::TypecheckJSObject(isolate, instance->module(),
106 value, type, &error_message);
107 return Smi::FromInt(result);
108 }
109
RUNTIME_FUNCTION(Runtime_WasmMemoryGrow)110 RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) {
111 ClearThreadInWasmScope flag_scope;
112 HandleScope scope(isolate);
113 DCHECK_EQ(2, args.length());
114 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
115 // {delta_pages} is checked to be a positive smi in the WasmMemoryGrow builtin
116 // which calls this runtime function.
117 CONVERT_UINT32_ARG_CHECKED(delta_pages, 1);
118
119 int ret = WasmMemoryObject::Grow(
120 isolate, handle(instance->memory_object(), isolate), delta_pages);
121 // The WasmMemoryGrow builtin which calls this runtime function expects us to
122 // always return a Smi.
123 return Smi::FromInt(ret);
124 }
125
RUNTIME_FUNCTION(Runtime_ThrowWasmError)126 RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
127 ClearThreadInWasmScope clear_wasm_flag;
128 DCHECK_EQ(1, args.length());
129 CONVERT_SMI_ARG_CHECKED(message_id, 0);
130 return ThrowWasmError(isolate, MessageTemplateFromInt(message_id));
131 }
132
RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow)133 RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
134 ClearThreadInWasmScope clear_wasm_flag;
135 SealHandleScope shs(isolate);
136 DCHECK_LE(0, args.length());
137 return isolate->StackOverflow();
138 }
139
RUNTIME_FUNCTION(Runtime_WasmThrowJSTypeError)140 RUNTIME_FUNCTION(Runtime_WasmThrowJSTypeError) {
141 // This runtime function is called both from wasm and from e.g. js-to-js
142 // functions. Hence the "thread in wasm" flag can be either set or not. Both
143 // is OK, since throwing will trigger unwinding anyway, which sets the flag
144 // correctly depending on the handler.
145 HandleScope scope(isolate);
146 DCHECK_EQ(0, args.length());
147 THROW_NEW_ERROR_RETURN_FAILURE(
148 isolate, NewTypeError(MessageTemplate::kWasmTrapJSTypeError));
149 }
150
RUNTIME_FUNCTION(Runtime_WasmThrowCreate)151 RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
152 ClearThreadInWasmScope clear_wasm_flag;
153 // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
154 HandleScope scope(isolate);
155 DCHECK_EQ(2, args.length());
156 DCHECK(isolate->context().is_null());
157 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
158 CONVERT_ARG_CHECKED(WasmExceptionTag, tag_raw, 0);
159 CONVERT_SMI_ARG_CHECKED(size, 1);
160 // TODO(wasm): Manually box because parameters are not visited yet.
161 Handle<Object> tag(tag_raw, isolate);
162 Handle<Object> exception = isolate->factory()->NewWasmRuntimeError(
163 MessageTemplate::kWasmExceptionError);
164 CHECK(!Object::SetProperty(isolate, exception,
165 isolate->factory()->wasm_exception_tag_symbol(),
166 tag, StoreOrigin::kMaybeKeyed,
167 Just(ShouldThrow::kThrowOnError))
168 .is_null());
169 Handle<FixedArray> values = isolate->factory()->NewFixedArray(size);
170 CHECK(!Object::SetProperty(isolate, exception,
171 isolate->factory()->wasm_exception_values_symbol(),
172 values, StoreOrigin::kMaybeKeyed,
173 Just(ShouldThrow::kThrowOnError))
174 .is_null());
175 return *exception;
176 }
177
RUNTIME_FUNCTION(Runtime_WasmStackGuard)178 RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
179 ClearThreadInWasmScope wasm_flag;
180 SealHandleScope shs(isolate);
181 DCHECK_EQ(0, args.length());
182
183 // Check if this is a real stack overflow.
184 StackLimitCheck check(isolate);
185 if (check.JsHasOverflowed()) return isolate->StackOverflow();
186
187 return isolate->stack_guard()->HandleInterrupts();
188 }
189
RUNTIME_FUNCTION(Runtime_WasmCompileLazy)190 RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
191 ClearThreadInWasmScope wasm_flag;
192 HandleScope scope(isolate);
193 DCHECK_EQ(2, args.length());
194 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
195 CONVERT_SMI_ARG_CHECKED(func_index, 1);
196
197 #ifdef DEBUG
198 FrameFinder<WasmCompileLazyFrame, StackFrame::EXIT> frame_finder(isolate);
199 DCHECK_EQ(*instance, frame_finder.frame()->wasm_instance());
200 #endif
201
202 DCHECK(isolate->context().is_null());
203 isolate->set_context(instance->native_context());
204 auto* native_module = instance->module_object().native_module();
205 bool success = wasm::CompileLazy(isolate, native_module, func_index);
206 if (!success) {
207 DCHECK(isolate->has_pending_exception());
208 return ReadOnlyRoots(isolate).exception();
209 }
210
211 Address entrypoint = native_module->GetCallTargetForFunction(func_index);
212
213 return Object(entrypoint);
214 }
215
RUNTIME_FUNCTION(Runtime_WasmCompileWrapper)216 RUNTIME_FUNCTION(Runtime_WasmCompileWrapper) {
217 HandleScope scope(isolate);
218 DCHECK_EQ(2, args.length());
219 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
220 CONVERT_ARG_HANDLE_CHECKED(WasmExportedFunctionData, function_data, 1);
221 DCHECK(isolate->context().is_null());
222 isolate->set_context(instance->native_context());
223
224 const wasm::WasmModule* module = instance->module();
225 const int function_index = function_data->function_index();
226 const wasm::WasmFunction function = module->functions[function_index];
227 const wasm::FunctionSig* sig = function.sig;
228
229 MaybeHandle<WasmExternalFunction> maybe_result =
230 WasmInstanceObject::GetWasmExternalFunction(isolate, instance,
231 function_index);
232
233 Handle<WasmExternalFunction> result;
234 if (!maybe_result.ToHandle(&result)) {
235 // We expect the result to be empty in the case of the start function,
236 // which is not an exported function to begin with.
237 DCHECK_EQ(function_index, module->start_function_index);
238 return ReadOnlyRoots(isolate).undefined_value();
239 }
240
241 Handle<Code> wrapper =
242 wasm::JSToWasmWrapperCompilationUnit::CompileSpecificJSToWasmWrapper(
243 isolate, sig, module);
244
245 result->set_code(*wrapper);
246
247 function_data->set_wrapper_code(*wrapper);
248
249 return ReadOnlyRoots(isolate).undefined_value();
250 }
251
RUNTIME_FUNCTION(Runtime_WasmTriggerTierUp)252 RUNTIME_FUNCTION(Runtime_WasmTriggerTierUp) {
253 HandleScope scope(isolate);
254 DCHECK_EQ(1, args.length());
255 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
256
257 FrameFinder<WasmFrame, StackFrame::EXIT> frame_finder(isolate);
258 int func_index = frame_finder.frame()->function_index();
259 auto* native_module = instance->module_object().native_module();
260
261 wasm::TriggerTierUp(isolate, native_module, func_index);
262
263 return ReadOnlyRoots(isolate).undefined_value();
264 }
265
RUNTIME_FUNCTION(Runtime_WasmAtomicNotify)266 RUNTIME_FUNCTION(Runtime_WasmAtomicNotify) {
267 ClearThreadInWasmScope clear_wasm_flag;
268 HandleScope scope(isolate);
269 DCHECK_EQ(3, args.length());
270 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
271 CONVERT_DOUBLE_ARG_CHECKED(offset_double, 1);
272 uintptr_t offset = static_cast<uintptr_t>(offset_double);
273 CONVERT_NUMBER_CHECKED(uint32_t, count, Uint32, args[2]);
274 Handle<JSArrayBuffer> array_buffer{instance->memory_object().array_buffer(),
275 isolate};
276 // Should have trapped if address was OOB.
277 DCHECK_LT(offset, array_buffer->byte_length());
278 if (!array_buffer->is_shared()) return Smi::FromInt(0);
279 return FutexEmulation::Wake(array_buffer, offset, count);
280 }
281
RUNTIME_FUNCTION(Runtime_WasmI32AtomicWait)282 RUNTIME_FUNCTION(Runtime_WasmI32AtomicWait) {
283 ClearThreadInWasmScope clear_wasm_flag;
284 HandleScope scope(isolate);
285 DCHECK_EQ(4, args.length());
286 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
287 CONVERT_DOUBLE_ARG_CHECKED(offset_double, 1);
288 uintptr_t offset = static_cast<uintptr_t>(offset_double);
289 CONVERT_NUMBER_CHECKED(int32_t, expected_value, Int32, args[2]);
290 CONVERT_ARG_HANDLE_CHECKED(BigInt, timeout_ns, 3);
291
292 Handle<JSArrayBuffer> array_buffer{instance->memory_object().array_buffer(),
293 isolate};
294 // Should have trapped if address was OOB.
295 DCHECK_LT(offset, array_buffer->byte_length());
296
297 // Trap if memory is not shared.
298 if (!array_buffer->is_shared()) {
299 return ThrowWasmError(isolate, MessageTemplate::kAtomicsWaitNotAllowed);
300 }
301 return FutexEmulation::WaitWasm32(isolate, array_buffer, offset,
302 expected_value, timeout_ns->AsInt64());
303 }
304
RUNTIME_FUNCTION(Runtime_WasmI64AtomicWait)305 RUNTIME_FUNCTION(Runtime_WasmI64AtomicWait) {
306 ClearThreadInWasmScope clear_wasm_flag;
307 HandleScope scope(isolate);
308 DCHECK_EQ(4, args.length());
309 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
310 CONVERT_DOUBLE_ARG_CHECKED(offset_double, 1);
311 uintptr_t offset = static_cast<uintptr_t>(offset_double);
312 CONVERT_ARG_HANDLE_CHECKED(BigInt, expected_value, 2);
313 CONVERT_ARG_HANDLE_CHECKED(BigInt, timeout_ns, 3);
314
315 Handle<JSArrayBuffer> array_buffer{instance->memory_object().array_buffer(),
316 isolate};
317 // Should have trapped if address was OOB.
318 DCHECK_LT(offset, array_buffer->byte_length());
319
320 // Trap if memory is not shared.
321 if (!array_buffer->is_shared()) {
322 return ThrowWasmError(isolate, MessageTemplate::kAtomicsWaitNotAllowed);
323 }
324 return FutexEmulation::WaitWasm64(isolate, array_buffer, offset,
325 expected_value->AsInt64(),
326 timeout_ns->AsInt64());
327 }
328
329 namespace {
ThrowTableOutOfBounds(Isolate * isolate,Handle<WasmInstanceObject> instance)330 Object ThrowTableOutOfBounds(Isolate* isolate,
331 Handle<WasmInstanceObject> instance) {
332 // Handle out-of-bounds access here in the runtime call, rather
333 // than having the lower-level layers deal with JS exceptions.
334 if (isolate->context().is_null()) {
335 isolate->set_context(instance->native_context());
336 }
337 Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
338 MessageTemplate::kWasmTrapTableOutOfBounds);
339 return isolate->Throw(*error_obj);
340 }
341 } // namespace
342
RUNTIME_FUNCTION(Runtime_WasmRefFunc)343 RUNTIME_FUNCTION(Runtime_WasmRefFunc) {
344 ClearThreadInWasmScope flag_scope;
345 HandleScope scope(isolate);
346 DCHECK_EQ(2, args.length());
347 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
348 CONVERT_UINT32_ARG_CHECKED(function_index, 1);
349
350 Handle<WasmExternalFunction> function =
351 WasmInstanceObject::GetOrCreateWasmExternalFunction(isolate, instance,
352 function_index);
353
354 return *function;
355 }
356
RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet)357 RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet) {
358 ClearThreadInWasmScope flag_scope;
359 HandleScope scope(isolate);
360 DCHECK_EQ(3, args.length());
361 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
362 CONVERT_UINT32_ARG_CHECKED(table_index, 1);
363 CONVERT_UINT32_ARG_CHECKED(entry_index, 2);
364 DCHECK_LT(table_index, instance->tables().length());
365 auto table = handle(
366 WasmTableObject::cast(instance->tables().get(table_index)), isolate);
367 // We only use the runtime call for lazily initialized function references.
368 DCHECK(
369 table->instance().IsUndefined()
370 ? table->type() == wasm::kWasmFuncRef
371 : IsSubtypeOf(table->type(), wasm::kWasmFuncRef,
372 WasmInstanceObject::cast(table->instance()).module()));
373
374 if (!WasmTableObject::IsInBounds(isolate, table, entry_index)) {
375 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
376 }
377
378 return *WasmTableObject::Get(isolate, table, entry_index);
379 }
380
RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet)381 RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) {
382 ClearThreadInWasmScope flag_scope;
383 HandleScope scope(isolate);
384 DCHECK_EQ(4, args.length());
385 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
386 CONVERT_UINT32_ARG_CHECKED(table_index, 1);
387 CONVERT_UINT32_ARG_CHECKED(entry_index, 2);
388 CONVERT_ARG_CHECKED(Object, element_raw, 3);
389 // TODO(wasm): Manually box because parameters are not visited yet.
390 Handle<Object> element(element_raw, isolate);
391 DCHECK_LT(table_index, instance->tables().length());
392 auto table = handle(
393 WasmTableObject::cast(instance->tables().get(table_index)), isolate);
394 // We only use the runtime call for function references.
395 DCHECK(
396 table->instance().IsUndefined()
397 ? table->type() == wasm::kWasmFuncRef
398 : IsSubtypeOf(table->type(), wasm::kWasmFuncRef,
399 WasmInstanceObject::cast(table->instance()).module()));
400
401 if (!WasmTableObject::IsInBounds(isolate, table, entry_index)) {
402 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
403 }
404 WasmTableObject::Set(isolate, table, entry_index, element);
405 return ReadOnlyRoots(isolate).undefined_value();
406 }
407
RUNTIME_FUNCTION(Runtime_WasmTableInit)408 RUNTIME_FUNCTION(Runtime_WasmTableInit) {
409 ClearThreadInWasmScope flag_scope;
410 HandleScope scope(isolate);
411 DCHECK_EQ(6, args.length());
412 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
413 CONVERT_UINT32_ARG_CHECKED(table_index, 1);
414 CONVERT_UINT32_ARG_CHECKED(elem_segment_index, 2);
415 static_assert(
416 wasm::kV8MaxWasmTableSize < kSmiMaxValue,
417 "Make sure clamping to Smi range doesn't make an invalid call valid");
418 CONVERT_UINT32_ARG_CHECKED(dst, 3);
419 CONVERT_UINT32_ARG_CHECKED(src, 4);
420 CONVERT_UINT32_ARG_CHECKED(count, 5);
421
422 DCHECK(!isolate->context().is_null());
423
424 bool oob = !WasmInstanceObject::InitTableEntries(
425 isolate, instance, table_index, elem_segment_index, dst, src, count);
426 if (oob) return ThrowTableOutOfBounds(isolate, instance);
427 return ReadOnlyRoots(isolate).undefined_value();
428 }
429
RUNTIME_FUNCTION(Runtime_WasmTableCopy)430 RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
431 ClearThreadInWasmScope flag_scope;
432 HandleScope scope(isolate);
433 DCHECK_EQ(6, args.length());
434 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
435 CONVERT_UINT32_ARG_CHECKED(table_dst_index, 1);
436 CONVERT_UINT32_ARG_CHECKED(table_src_index, 2);
437 static_assert(
438 wasm::kV8MaxWasmTableSize < kSmiMaxValue,
439 "Make sure clamping to Smi range doesn't make an invalid call valid");
440 CONVERT_UINT32_ARG_CHECKED(dst, 3);
441 CONVERT_UINT32_ARG_CHECKED(src, 4);
442 CONVERT_UINT32_ARG_CHECKED(count, 5);
443
444 DCHECK(!isolate->context().is_null());
445
446 bool oob = !WasmInstanceObject::CopyTableEntries(
447 isolate, instance, table_dst_index, table_src_index, dst, src, count);
448 if (oob) return ThrowTableOutOfBounds(isolate, instance);
449 return ReadOnlyRoots(isolate).undefined_value();
450 }
451
RUNTIME_FUNCTION(Runtime_WasmTableGrow)452 RUNTIME_FUNCTION(Runtime_WasmTableGrow) {
453 ClearThreadInWasmScope flag_scope;
454 HandleScope scope(isolate);
455 DCHECK_EQ(3, args.length());
456 auto instance =
457 Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
458 CONVERT_UINT32_ARG_CHECKED(table_index, 0);
459 CONVERT_ARG_CHECKED(Object, value_raw, 1);
460 // TODO(wasm): Manually box because parameters are not visited yet.
461 Handle<Object> value(value_raw, isolate);
462 CONVERT_UINT32_ARG_CHECKED(delta, 2);
463
464 Handle<WasmTableObject> table(
465 WasmTableObject::cast(instance->tables().get(table_index)), isolate);
466 int result = WasmTableObject::Grow(isolate, table, delta, value);
467
468 return Smi::FromInt(result);
469 }
470
RUNTIME_FUNCTION(Runtime_WasmTableFill)471 RUNTIME_FUNCTION(Runtime_WasmTableFill) {
472 ClearThreadInWasmScope flag_scope;
473 HandleScope scope(isolate);
474 DCHECK_EQ(4, args.length());
475 auto instance =
476 Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
477 CONVERT_UINT32_ARG_CHECKED(table_index, 0);
478 CONVERT_UINT32_ARG_CHECKED(start, 1);
479 CONVERT_ARG_CHECKED(Object, value_raw, 2);
480 // TODO(wasm): Manually box because parameters are not visited yet.
481 Handle<Object> value(value_raw, isolate);
482 CONVERT_UINT32_ARG_CHECKED(count, 3);
483
484 Handle<WasmTableObject> table(
485 WasmTableObject::cast(instance->tables().get(table_index)), isolate);
486
487 uint32_t table_size = table->current_length();
488
489 if (start > table_size) {
490 return ThrowTableOutOfBounds(isolate, instance);
491 }
492
493 // Even when table.fill goes out-of-bounds, as many entries as possible are
494 // put into the table. Only afterwards we trap.
495 uint32_t fill_count = std::min(count, table_size - start);
496 if (fill_count < count) {
497 return ThrowTableOutOfBounds(isolate, instance);
498 }
499 WasmTableObject::Fill(isolate, table, start, value, fill_count);
500
501 return ReadOnlyRoots(isolate).undefined_value();
502 }
503
RUNTIME_FUNCTION(Runtime_WasmDebugBreak)504 RUNTIME_FUNCTION(Runtime_WasmDebugBreak) {
505 ClearThreadInWasmScope flag_scope;
506 HandleScope scope(isolate);
507 DCHECK_EQ(0, args.length());
508 FrameFinder<WasmFrame, StackFrame::EXIT, StackFrame::WASM_DEBUG_BREAK>
509 frame_finder(isolate);
510 auto instance = handle(frame_finder.frame()->wasm_instance(), isolate);
511 int position = frame_finder.frame()->position();
512 isolate->set_context(instance->native_context());
513
514 // Enter the debugger.
515 DebugScope debug_scope(isolate->debug());
516
517 WasmFrame* frame = frame_finder.frame();
518 auto* debug_info = frame->native_module()->GetDebugInfo();
519 if (debug_info->IsStepping(frame)) {
520 debug_info->ClearStepping(isolate);
521 StepAction stepAction = isolate->debug()->last_step_action();
522 isolate->debug()->ClearStepping();
523 isolate->debug()->OnDebugBreak(isolate->factory()->empty_fixed_array(),
524 stepAction);
525 return ReadOnlyRoots(isolate).undefined_value();
526 }
527
528 // Check whether we hit a breakpoint.
529 Handle<Script> script(instance->module_object().script(), isolate);
530 Handle<FixedArray> breakpoints;
531 if (WasmScript::CheckBreakPoints(isolate, script, position)
532 .ToHandle(&breakpoints)) {
533 debug_info->ClearStepping(isolate);
534 StepAction stepAction = isolate->debug()->last_step_action();
535 isolate->debug()->ClearStepping();
536 if (isolate->debug()->break_points_active()) {
537 // We hit one or several breakpoints. Notify the debug listeners.
538 isolate->debug()->OnDebugBreak(breakpoints, stepAction);
539 }
540 }
541
542 return ReadOnlyRoots(isolate).undefined_value();
543 }
544
RUNTIME_FUNCTION(Runtime_WasmAllocateRtt)545 RUNTIME_FUNCTION(Runtime_WasmAllocateRtt) {
546 ClearThreadInWasmScope flag_scope;
547 HandleScope scope(isolate);
548 DCHECK_EQ(2, args.length());
549 CONVERT_UINT32_ARG_CHECKED(type_index, 0);
550 CONVERT_ARG_HANDLE_CHECKED(Map, parent, 1);
551 Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate),
552 isolate);
553 return *wasm::AllocateSubRtt(isolate, instance, type_index, parent);
554 }
555
556 } // namespace internal
557 } // namespace v8
558