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/runtime/runtime-utils.h"
6 :
7 : #include "src/arguments.h"
8 : #include "src/assembler.h"
9 : #include "src/compiler/wasm-compiler.h"
10 : #include "src/conversions.h"
11 : #include "src/debug/debug.h"
12 : #include "src/factory.h"
13 : #include "src/frame-constants.h"
14 : #include "src/objects-inl.h"
15 : #include "src/objects/frame-array-inl.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-objects.h"
20 : #include "src/wasm/wasm-opcodes.h"
21 :
22 : namespace v8 {
23 : namespace internal {
24 :
25 : namespace {
26 :
27 84486 : WasmInstanceObject* GetWasmInstanceOnStackTop(Isolate* isolate) {
28 : DisallowHeapAllocation no_allocation;
29 42243 : const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
30 : Address pc =
31 42243 : Memory::Address_at(entry + StandardFrameConstants::kCallerPCOffset);
32 42243 : Code* code = isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
33 : DCHECK_EQ(Code::WASM_FUNCTION, code->kind());
34 : WasmInstanceObject* owning_instance =
35 42243 : WasmInstanceObject::GetOwningInstance(code);
36 42243 : CHECK_NOT_NULL(owning_instance);
37 42243 : return owning_instance;
38 : }
39 40455 : Context* GetWasmContextOnStackTop(Isolate* isolate) {
40 : return GetWasmInstanceOnStackTop(isolate)
41 : ->compiled_module()
42 80910 : ->ptr_to_native_context();
43 : }
44 :
45 : class ClearThreadInWasmScope {
46 : public:
47 85717 : explicit ClearThreadInWasmScope(bool coming_from_wasm)
48 85717 : : coming_from_wasm_(coming_from_wasm) {
49 : DCHECK_EQ(trap_handler::UseTrapHandler() && coming_from_wasm,
50 : trap_handler::IsThreadInWasm());
51 85717 : if (coming_from_wasm) trap_handler::ClearThreadInWasm();
52 85717 : }
53 85717 : ~ClearThreadInWasmScope() {
54 : DCHECK(!trap_handler::IsThreadInWasm());
55 85717 : if (coming_from_wasm_) trap_handler::SetThreadInWasm();
56 85717 : }
57 :
58 : private:
59 : const bool coming_from_wasm_;
60 : };
61 :
62 : } // namespace
63 :
64 3576 : RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
65 1788 : HandleScope scope(isolate);
66 : DCHECK_EQ(1, args.length());
67 3576 : CONVERT_UINT32_ARG_CHECKED(delta_pages, 0);
68 : Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate),
69 1788 : isolate);
70 :
71 : // This runtime function is always being called from wasm code.
72 3576 : ClearThreadInWasmScope flag_scope(true);
73 :
74 : // Set the current isolate's context.
75 : DCHECK_NULL(isolate->context());
76 1788 : isolate->set_context(instance->compiled_module()->ptr_to_native_context());
77 :
78 : return *isolate->factory()->NewNumberFromInt(
79 5364 : WasmInstanceObject::GrowMemory(isolate, instance, delta_pages));
80 : }
81 :
82 38662 : Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset,
83 : bool patch_source_position) {
84 : HandleScope scope(isolate);
85 : DCHECK_NULL(isolate->context());
86 38662 : isolate->set_context(GetWasmContextOnStackTop(isolate));
87 : Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
88 38662 : static_cast<MessageTemplate::Template>(message_id));
89 :
90 38662 : if (!patch_source_position) {
91 38662 : return isolate->Throw(*error_obj);
92 : }
93 :
94 : // For wasm traps, the byte offset (a.k.a source position) can not be
95 : // determined from relocation info, since the explicit checks for traps
96 : // converge in one singe block which calls this runtime function.
97 : // We hence pass the byte offset explicitely, and patch it into the top-most
98 : // frame (a wasm frame) on the collected stack trace.
99 : // TODO(wasm): This implementation is temporary, see bug #5007:
100 : // https://bugs.chromium.org/p/v8/issues/detail?id=5007
101 : Handle<JSObject> error = Handle<JSObject>::cast(error_obj);
102 : Handle<Object> stack_trace_obj = JSReceiver::GetDataProperty(
103 0 : error, isolate->factory()->stack_trace_symbol());
104 : // Patch the stack trace (array of <receiver, function, code, position>).
105 0 : if (stack_trace_obj->IsJSArray()) {
106 : Handle<FrameArray> stack_elements(
107 : FrameArray::cast(JSArray::cast(*stack_trace_obj)->elements()));
108 : DCHECK(stack_elements->Code(0)->kind() == AbstractCode::WASM_FUNCTION);
109 : DCHECK_LE(0, stack_elements->Offset(0)->value());
110 0 : stack_elements->SetOffset(0, Smi::FromInt(-1 - byte_offset));
111 : }
112 :
113 : // Patch the detailed stack trace (array of JSObjects with various
114 : // properties).
115 : Handle<Object> detailed_stack_trace_obj = JSReceiver::GetDataProperty(
116 0 : error, isolate->factory()->detailed_stack_trace_symbol());
117 0 : if (detailed_stack_trace_obj->IsFixedArray()) {
118 : Handle<FixedArray> stack_elements(
119 : FixedArray::cast(*detailed_stack_trace_obj));
120 : DCHECK_GE(stack_elements->length(), 1);
121 : Handle<StackFrameInfo> top_frame(
122 : StackFrameInfo::cast(stack_elements->get(0)));
123 0 : if (top_frame->column_number()) {
124 0 : top_frame->set_column_number(byte_offset + 1);
125 : }
126 : }
127 :
128 0 : return isolate->Throw(*error_obj);
129 : }
130 :
131 77324 : RUNTIME_FUNCTION(Runtime_ThrowWasmErrorFromTrapIf) {
132 : DCHECK_EQ(1, args.length());
133 77324 : CONVERT_SMI_ARG_CHECKED(message_id, 0);
134 38662 : ClearThreadInWasmScope clear_wasm_flag(isolate->context() == nullptr);
135 38662 : return ThrowRuntimeError(isolate, message_id, 0, false);
136 : }
137 :
138 0 : RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
139 : DCHECK_EQ(2, args.length());
140 0 : CONVERT_SMI_ARG_CHECKED(message_id, 0);
141 0 : CONVERT_SMI_ARG_CHECKED(byte_offset, 1);
142 0 : ClearThreadInWasmScope clear_wasm_flag(isolate->context() == nullptr);
143 0 : return ThrowRuntimeError(isolate, message_id, byte_offset, true);
144 : }
145 :
146 200 : RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
147 : SealHandleScope shs(isolate);
148 : DCHECK_LE(0, args.length());
149 : DCHECK_NULL(isolate->context());
150 100 : isolate->set_context(GetWasmContextOnStackTop(isolate));
151 100 : return isolate->StackOverflow();
152 : }
153 :
154 140 : RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
155 70 : HandleScope scope(isolate);
156 : DCHECK_EQ(0, args.length());
157 140 : THROW_NEW_ERROR_RETURN_FAILURE(
158 70 : isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
159 : }
160 :
161 500 : RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
162 : // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
163 250 : HandleScope scope(isolate);
164 : DCHECK_NULL(isolate->context());
165 250 : isolate->set_context(GetWasmContextOnStackTop(isolate));
166 : DCHECK_EQ(2, args.length());
167 : Handle<Object> exception = isolate->factory()->NewWasmRuntimeError(
168 : static_cast<MessageTemplate::Template>(
169 250 : MessageTemplate::kWasmExceptionError));
170 250 : isolate->set_wasm_caught_exception(*exception);
171 500 : CONVERT_ARG_HANDLE_CHECKED(Smi, id, 0);
172 500 : CHECK(!JSReceiver::SetProperty(exception,
173 : isolate->factory()->InternalizeUtf8String(
174 : wasm::WasmException::kRuntimeIdStr),
175 : id, LanguageMode::kStrict)
176 : .is_null());
177 500 : CONVERT_SMI_ARG_CHECKED(size, 1);
178 : Handle<JSTypedArray> values =
179 250 : isolate->factory()->NewJSTypedArray(ElementsKind::UINT16_ELEMENTS, size);
180 500 : CHECK(!JSReceiver::SetProperty(exception,
181 : isolate->factory()->InternalizeUtf8String(
182 : wasm::WasmException::kRuntimeValuesStr),
183 : values, LanguageMode::kStrict)
184 : .is_null());
185 250 : return isolate->heap()->undefined_value();
186 : }
187 :
188 840 : RUNTIME_FUNCTION(Runtime_WasmThrow) {
189 : // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
190 280 : HandleScope scope(isolate);
191 : DCHECK_NULL(isolate->context());
192 280 : isolate->set_context(GetWasmContextOnStackTop(isolate));
193 : DCHECK_EQ(0, args.length());
194 280 : Handle<Object> exception(isolate->get_wasm_caught_exception(), isolate);
195 280 : CHECK(!exception.is_null());
196 280 : isolate->clear_wasm_caught_exception();
197 280 : return isolate->Throw(*exception);
198 : }
199 :
200 480 : RUNTIME_FUNCTION(Runtime_WasmGetExceptionRuntimeId) {
201 : // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
202 160 : HandleScope scope(isolate);
203 : DCHECK_NULL(isolate->context());
204 160 : isolate->set_context(GetWasmContextOnStackTop(isolate));
205 160 : Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate);
206 320 : if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
207 : Handle<JSReceiver> exception(JSReceiver::cast(*except_obj));
208 : Handle<Object> tag;
209 160 : if (JSReceiver::GetProperty(exception,
210 : isolate->factory()->InternalizeUtf8String(
211 320 : wasm::WasmException::kRuntimeIdStr))
212 320 : .ToHandle(&tag)) {
213 160 : if (tag->IsSmi()) {
214 160 : return *tag;
215 : }
216 : }
217 : }
218 0 : return Smi::FromInt(wasm::WasmModule::kInvalidExceptionTag);
219 : }
220 :
221 900 : RUNTIME_FUNCTION(Runtime_WasmExceptionGetElement) {
222 : // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
223 300 : HandleScope scope(isolate);
224 : DCHECK_NULL(isolate->context());
225 300 : isolate->set_context(GetWasmContextOnStackTop(isolate));
226 : DCHECK_EQ(1, args.length());
227 300 : Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate);
228 600 : if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
229 : Handle<JSReceiver> exception(JSReceiver::cast(*except_obj));
230 : Handle<Object> values_obj;
231 300 : if (JSReceiver::GetProperty(exception,
232 : isolate->factory()->InternalizeUtf8String(
233 600 : wasm::WasmException::kRuntimeValuesStr))
234 600 : .ToHandle(&values_obj)) {
235 300 : if (values_obj->IsJSTypedArray()) {
236 300 : Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj);
237 300 : CHECK_EQ(values->type(), kExternalUint16Array);
238 600 : CONVERT_SMI_ARG_CHECKED(index, 0);
239 300 : CHECK_LT(index, Smi::ToInt(values->length()));
240 : auto* vals =
241 600 : reinterpret_cast<uint16_t*>(values->GetBuffer()->allocation_base());
242 300 : return Smi::FromInt(vals[index]);
243 : }
244 : }
245 : }
246 0 : return Smi::FromInt(0);
247 : }
248 :
249 1740 : RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) {
250 : // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
251 580 : HandleScope scope(isolate);
252 : DCHECK_EQ(2, args.length());
253 : DCHECK_NULL(isolate->context());
254 580 : isolate->set_context(GetWasmContextOnStackTop(isolate));
255 580 : Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate);
256 1160 : if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
257 : Handle<JSReceiver> exception(JSReceiver::cast(*except_obj));
258 : Handle<Object> values_obj;
259 580 : if (JSReceiver::GetProperty(exception,
260 : isolate->factory()->InternalizeUtf8String(
261 1160 : wasm::WasmException::kRuntimeValuesStr))
262 1160 : .ToHandle(&values_obj)) {
263 580 : if (values_obj->IsJSTypedArray()) {
264 580 : Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj);
265 580 : CHECK_EQ(values->type(), kExternalUint16Array);
266 1160 : CONVERT_SMI_ARG_CHECKED(index, 0);
267 580 : CHECK_LT(index, Smi::ToInt(values->length()));
268 1160 : CONVERT_SMI_ARG_CHECKED(value, 1);
269 : auto* vals =
270 1160 : reinterpret_cast<uint16_t*>(values->GetBuffer()->allocation_base());
271 580 : vals[index] = static_cast<uint16_t>(value);
272 : }
273 : }
274 : }
275 580 : return isolate->heap()->undefined_value();
276 : }
277 :
278 90288 : RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
279 : DCHECK_EQ(3, args.length());
280 45144 : HandleScope scope(isolate);
281 90288 : CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
282 90288 : CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[1]);
283 45144 : CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 2);
284 :
285 : // The arg buffer is the raw pointer to the caller's stack. It looks like a
286 : // Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just
287 : // cast it back to the raw pointer.
288 45144 : CHECK(!arg_buffer_obj->IsHeapObject());
289 45144 : CHECK(arg_buffer_obj->IsSmi());
290 : uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj);
291 :
292 90288 : ClearThreadInWasmScope wasm_flag(true);
293 :
294 : // Set the current isolate's context.
295 : DCHECK_NULL(isolate->context());
296 45144 : isolate->set_context(instance->compiled_module()->ptr_to_native_context());
297 :
298 : // Find the frame pointer of the interpreter entry.
299 : Address frame_pointer = 0;
300 : {
301 45144 : StackFrameIterator it(isolate, isolate->thread_local_top());
302 : // On top: C entry stub.
303 : DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
304 45144 : it.Advance();
305 : // Next: the wasm interpreter entry.
306 : DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type());
307 45144 : frame_pointer = it.frame()->fp();
308 : }
309 :
310 : bool success = instance->debug_info()->RunInterpreter(frame_pointer,
311 45144 : func_index, arg_buffer);
312 :
313 45144 : if (!success) {
314 : DCHECK(isolate->has_pending_exception());
315 210 : return isolate->heap()->exception();
316 : }
317 90078 : return isolate->heap()->undefined_value();
318 : }
319 :
320 246 : RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
321 : SealHandleScope shs(isolate);
322 : DCHECK_EQ(0, args.length());
323 : DCHECK(!trap_handler::UseTrapHandler() || trap_handler::IsThreadInWasm());
324 :
325 246 : ClearThreadInWasmScope wasm_flag(true);
326 :
327 : // Set the current isolate's context.
328 : DCHECK_NULL(isolate->context());
329 123 : isolate->set_context(GetWasmContextOnStackTop(isolate));
330 :
331 : // Check if this is a real stack overflow.
332 123 : StackLimitCheck check(isolate);
333 123 : if (check.JsHasOverflowed()) return isolate->StackOverflow();
334 :
335 33 : return isolate->stack_guard()->HandleInterrupts();
336 : }
337 :
338 22954 : RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
339 : DCHECK_EQ(0, args.length());
340 11477 : HandleScope scope(isolate);
341 :
342 22954 : return *wasm::CompileLazy(isolate);
343 : }
344 :
345 : } // namespace internal
346 : } // namespace v8
|