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/frames-inl.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/wasm-module.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 85150 : WasmInstanceObject* GetWasmInstanceOnStackTop(Isolate* isolate) {
27 : DisallowHeapAllocation no_allocation;
28 42575 : const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
29 : Address pc =
30 42575 : Memory::Address_at(entry + StandardFrameConstants::kCallerPCOffset);
31 42575 : Code* code = isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
32 : DCHECK_EQ(Code::WASM_FUNCTION, code->kind());
33 42575 : WasmInstanceObject* owning_instance = wasm::GetOwningWasmInstance(code);
34 42575 : CHECK_NOT_NULL(owning_instance);
35 42575 : return owning_instance;
36 : }
37 36733 : Context* GetWasmContextOnStackTop(Isolate* isolate) {
38 : return GetWasmInstanceOnStackTop(isolate)
39 : ->compiled_module()
40 73466 : ->ptr_to_native_context();
41 : }
42 : } // namespace
43 :
44 9168 : RUNTIME_FUNCTION(Runtime_WasmMemorySize) {
45 4584 : HandleScope scope(isolate);
46 : DCHECK_EQ(0, args.length());
47 :
48 4584 : int32_t mem_size = GetWasmInstanceOnStackTop(isolate)->GetMemorySize();
49 9168 : return *isolate->factory()->NewNumberFromInt(mem_size);
50 : }
51 :
52 2516 : RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
53 1258 : HandleScope scope(isolate);
54 : DCHECK_EQ(1, args.length());
55 2516 : CONVERT_UINT32_ARG_CHECKED(delta_pages, 0);
56 : Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate),
57 1258 : isolate);
58 :
59 : // Set the current isolate's context.
60 : DCHECK_NULL(isolate->context());
61 1258 : isolate->set_context(instance->compiled_module()->ptr_to_native_context());
62 :
63 : return *isolate->factory()->NewNumberFromInt(
64 2516 : WasmInstanceObject::GrowMemory(isolate, instance, delta_pages));
65 : }
66 :
67 36123 : Object* ThrowRuntimeError(Isolate* isolate, int message_id, int byte_offset,
68 : bool patch_source_position) {
69 : HandleScope scope(isolate);
70 : DCHECK_NULL(isolate->context());
71 36123 : isolate->set_context(GetWasmContextOnStackTop(isolate));
72 : Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
73 36123 : static_cast<MessageTemplate::Template>(message_id));
74 :
75 36123 : if (!patch_source_position) {
76 33933 : return isolate->Throw(*error_obj);
77 : }
78 :
79 : // For wasm traps, the byte offset (a.k.a source position) can not be
80 : // determined from relocation info, since the explicit checks for traps
81 : // converge in one singe block which calls this runtime function.
82 : // We hence pass the byte offset explicitely, and patch it into the top-most
83 : // frame (a wasm frame) on the collected stack trace.
84 : // TODO(wasm): This implementation is temporary, see bug #5007:
85 : // https://bugs.chromium.org/p/v8/issues/detail?id=5007
86 : Handle<JSObject> error = Handle<JSObject>::cast(error_obj);
87 : Handle<Object> stack_trace_obj = JSReceiver::GetDataProperty(
88 2190 : error, isolate->factory()->stack_trace_symbol());
89 : // Patch the stack trace (array of <receiver, function, code, position>).
90 2190 : if (stack_trace_obj->IsJSArray()) {
91 : Handle<FrameArray> stack_elements(
92 : FrameArray::cast(JSArray::cast(*stack_trace_obj)->elements()));
93 : DCHECK(stack_elements->Code(0)->kind() == AbstractCode::WASM_FUNCTION);
94 : DCHECK(stack_elements->Offset(0)->value() >= 0);
95 2190 : stack_elements->SetOffset(0, Smi::FromInt(-1 - byte_offset));
96 : }
97 :
98 : // Patch the detailed stack trace (array of JSObjects with various
99 : // properties).
100 : Handle<Object> detailed_stack_trace_obj = JSReceiver::GetDataProperty(
101 2190 : error, isolate->factory()->detailed_stack_trace_symbol());
102 2190 : if (detailed_stack_trace_obj->IsFixedArray()) {
103 : Handle<FixedArray> stack_elements(
104 : FixedArray::cast(*detailed_stack_trace_obj));
105 : DCHECK_GE(stack_elements->length(), 1);
106 : Handle<StackFrameInfo> top_frame(
107 : StackFrameInfo::cast(stack_elements->get(0)));
108 1 : if (top_frame->column_number()) {
109 1 : top_frame->set_column_number(byte_offset + 1);
110 : }
111 : }
112 :
113 2190 : return isolate->Throw(*error_obj);
114 : }
115 :
116 67866 : RUNTIME_FUNCTION(Runtime_ThrowWasmErrorFromTrapIf) {
117 : DCHECK_EQ(1, args.length());
118 67866 : CONVERT_SMI_ARG_CHECKED(message_id, 0);
119 33933 : return ThrowRuntimeError(isolate, message_id, 0, false);
120 : }
121 :
122 4380 : RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
123 : DCHECK_EQ(2, args.length());
124 4380 : CONVERT_SMI_ARG_CHECKED(message_id, 0);
125 4380 : CONVERT_SMI_ARG_CHECKED(byte_offset, 1);
126 2190 : return ThrowRuntimeError(isolate, message_id, byte_offset, true);
127 : }
128 :
129 0 : RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
130 : SealHandleScope shs(isolate);
131 : DCHECK_LE(0, args.length());
132 : DCHECK_NULL(isolate->context());
133 0 : isolate->set_context(GetWasmContextOnStackTop(isolate));
134 0 : return isolate->StackOverflow();
135 : }
136 :
137 210 : RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
138 105 : HandleScope scope(isolate);
139 : DCHECK_EQ(0, args.length());
140 210 : THROW_NEW_ERROR_RETURN_FAILURE(
141 105 : isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
142 : }
143 :
144 720 : RUNTIME_FUNCTION(Runtime_WasmThrow) {
145 360 : HandleScope scope(isolate);
146 : DCHECK_EQ(2, args.length());
147 720 : CONVERT_SMI_ARG_CHECKED(lower, 0);
148 720 : CONVERT_SMI_ARG_CHECKED(upper, 1);
149 :
150 360 : const int32_t thrown_value = (upper << 16) | lower;
151 :
152 : // Set the current isolate's context.
153 : DCHECK_NULL(isolate->context());
154 360 : isolate->set_context(GetWasmContextOnStackTop(isolate));
155 :
156 720 : return isolate->Throw(*isolate->factory()->NewNumberFromInt(thrown_value));
157 : }
158 :
159 630 : RUNTIME_FUNCTION(Runtime_WasmGetCaughtExceptionValue) {
160 315 : HandleScope scope(isolate);
161 : DCHECK_EQ(1, args.length());
162 315 : Object* exception = args[0];
163 : // The unwinder will only deliver exceptions to wasm if the exception is a
164 : // Number or a Smi (which we have just converted to a Number.) This logic
165 : // lives in Isolate::is_catchable_by_wasm(Object*).
166 315 : CHECK(exception->IsNumber());
167 315 : return exception;
168 : }
169 :
170 6694422 : RUNTIME_FUNCTION(Runtime_SetThreadInWasm) {
171 3347211 : trap_handler::SetThreadInWasm();
172 3347211 : return isolate->heap()->undefined_value();
173 : }
174 :
175 6689592 : RUNTIME_FUNCTION(Runtime_ClearThreadInWasm) {
176 3344796 : trap_handler::ClearThreadInWasm();
177 3344796 : return isolate->heap()->undefined_value();
178 : }
179 :
180 102850 : RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
181 : DCHECK_EQ(3, args.length());
182 51425 : HandleScope scope(isolate);
183 102850 : CONVERT_ARG_HANDLE_CHECKED(JSObject, instance_obj, 0);
184 102850 : CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[1]);
185 51425 : CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 2);
186 51425 : CHECK(WasmInstanceObject::IsWasmInstanceObject(*instance_obj));
187 : Handle<WasmInstanceObject> instance =
188 51425 : Handle<WasmInstanceObject>::cast(instance_obj);
189 :
190 : // The arg buffer is the raw pointer to the caller's stack. It looks like a
191 : // Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just
192 : // cast it back to the raw pointer.
193 51425 : CHECK(!arg_buffer_obj->IsHeapObject());
194 51425 : CHECK(arg_buffer_obj->IsSmi());
195 : uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj);
196 :
197 : // Set the current isolate's context.
198 : DCHECK_NULL(isolate->context());
199 51425 : isolate->set_context(instance->compiled_module()->ptr_to_native_context());
200 :
201 : // Find the frame pointer of the interpreter entry.
202 : Address frame_pointer = 0;
203 : {
204 51425 : StackFrameIterator it(isolate, isolate->thread_local_top());
205 : // On top: C entry stub.
206 : DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
207 51425 : it.Advance();
208 : // Next: the wasm interpreter entry.
209 : DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type());
210 51425 : frame_pointer = it.frame()->fp();
211 : }
212 :
213 : bool success = instance->debug_info()->RunInterpreter(frame_pointer,
214 51425 : func_index, arg_buffer);
215 :
216 51425 : if (!success) {
217 : DCHECK(isolate->has_pending_exception());
218 225 : return isolate->heap()->exception();
219 : }
220 51200 : return isolate->heap()->undefined_value();
221 : }
222 :
223 500 : RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
224 : SealHandleScope shs(isolate);
225 : DCHECK_EQ(0, args.length());
226 : DCHECK(!trap_handler::UseTrapHandler() || trap_handler::IsThreadInWasm());
227 :
228 : struct ClearAndRestoreThreadInWasm {
229 500 : ClearAndRestoreThreadInWasm() { trap_handler::ClearThreadInWasm(); }
230 :
231 500 : ~ClearAndRestoreThreadInWasm() { trap_handler::SetThreadInWasm(); }
232 500 : } restore_thread_in_wasm;
233 :
234 : // Set the current isolate's context.
235 : DCHECK_NULL(isolate->context());
236 250 : isolate->set_context(GetWasmContextOnStackTop(isolate));
237 :
238 : // Check if this is a real stack overflow.
239 250 : StackLimitCheck check(isolate);
240 250 : if (check.JsHasOverflowed()) return isolate->StackOverflow();
241 :
242 188 : return isolate->stack_guard()->HandleInterrupts();
243 : }
244 :
245 25398 : RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
246 : DCHECK(args.length() == 0);
247 12699 : HandleScope scope(isolate);
248 :
249 25398 : return *wasm::CompileLazy(isolate);
250 : }
251 :
252 : } // namespace internal
253 : } // namespace v8
|