• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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