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/debug/debug.h" 9 #include "src/frame-constants.h" 10 #include "src/heap/factory.h" 11 #include "src/objects-inl.h" 12 #include "src/objects/frame-array-inl.h" 13 #include "src/runtime/runtime-utils.h" 14 #include "src/trap-handler/trap-handler.h" 15 #include "src/v8memory.h" 16 #include "src/wasm/module-compiler.h" 17 #include "src/wasm/wasm-code-manager.h" 18 #include "src/wasm/wasm-constants.h" 19 #include "src/wasm/wasm-engine.h" 20 #include "src/wasm/wasm-objects.h" 21 22 namespace v8 { 23 namespace internal { 24 25 namespace { 26 27 WasmInstanceObject* GetWasmInstanceOnStackTop(Isolate* isolate) { 28 StackFrameIterator it(isolate, isolate->thread_local_top()); 29 // On top: C entry stub. 30 DCHECK_EQ(StackFrame::EXIT, it.frame()->type()); 31 it.Advance(); 32 // Next: the wasm (compiled or interpreted) frame. 33 WasmInstanceObject* result = nullptr; 34 if (it.frame()->is_wasm_compiled()) { 35 result = WasmCompiledFrame::cast(it.frame())->wasm_instance(); 36 } else { 37 DCHECK(it.frame()->is_wasm_interpreter_entry()); 38 result = WasmInterpreterEntryFrame::cast(it.frame())->wasm_instance(); 39 } 40 return result; 41 } 42 43 Context* GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) { 44 return GetWasmInstanceOnStackTop(isolate)->native_context(); 45 } 46 47 class ClearThreadInWasmScope { 48 public: 49 explicit ClearThreadInWasmScope(bool coming_from_wasm) 50 : coming_from_wasm_(coming_from_wasm) { 51 DCHECK_EQ(trap_handler::IsTrapHandlerEnabled() && coming_from_wasm, 52 trap_handler::IsThreadInWasm()); 53 if (coming_from_wasm) trap_handler::ClearThreadInWasm(); 54 } 55 ~ClearThreadInWasmScope() { 56 DCHECK(!trap_handler::IsThreadInWasm()); 57 if (coming_from_wasm_) trap_handler::SetThreadInWasm(); 58 } 59 60 private: 61 const bool coming_from_wasm_; 62 }; 63 64 } // namespace 65 66 RUNTIME_FUNCTION(Runtime_WasmGrowMemory) { 67 HandleScope scope(isolate); 68 DCHECK_EQ(2, args.length()); 69 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0); 70 // {delta_pages} is checked to be a positive smi in the WasmGrowMemory builtin 71 // which calls this runtime function. 72 CONVERT_UINT32_ARG_CHECKED(delta_pages, 1); 73 74 // This runtime function is always being called from wasm code. 75 ClearThreadInWasmScope flag_scope(true); 76 77 // Set the current isolate's context. 78 DCHECK_NULL(isolate->context()); 79 isolate->set_context(instance->native_context()); 80 81 int ret = WasmMemoryObject::Grow( 82 isolate, handle(instance->memory_object(), isolate), delta_pages); 83 // The WasmGrowMemory builtin which calls this runtime function expects us to 84 // always return a Smi. 85 return Smi::FromInt(ret); 86 } 87 88 RUNTIME_FUNCTION(Runtime_ThrowWasmError) { 89 DCHECK_EQ(1, args.length()); 90 CONVERT_SMI_ARG_CHECKED(message_id, 0); 91 ClearThreadInWasmScope clear_wasm_flag(isolate->context() == nullptr); 92 93 HandleScope scope(isolate); 94 DCHECK_NULL(isolate->context()); 95 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 96 Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError( 97 static_cast<MessageTemplate::Template>(message_id)); 98 return isolate->Throw(*error_obj); 99 } 100 101 RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) { 102 SealHandleScope shs(isolate); 103 DCHECK_LE(0, args.length()); 104 DCHECK_NULL(isolate->context()); 105 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 106 return isolate->StackOverflow(); 107 } 108 109 RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) { 110 HandleScope scope(isolate); 111 DCHECK_EQ(0, args.length()); 112 THROW_NEW_ERROR_RETURN_FAILURE( 113 isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError)); 114 } 115 116 RUNTIME_FUNCTION(Runtime_WasmThrowCreate) { 117 // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls. 118 HandleScope scope(isolate); 119 DCHECK_NULL(isolate->context()); 120 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 121 DCHECK_EQ(2, args.length()); 122 Handle<Object> exception = isolate->factory()->NewWasmRuntimeError( 123 static_cast<MessageTemplate::Template>( 124 MessageTemplate::kWasmExceptionError)); 125 isolate->set_wasm_caught_exception(*exception); 126 CONVERT_ARG_HANDLE_CHECKED(Smi, id, 0); 127 CHECK(!JSReceiver::SetProperty(isolate, exception, 128 isolate->factory()->InternalizeUtf8String( 129 wasm::WasmException::kRuntimeIdStr), 130 id, LanguageMode::kStrict) 131 .is_null()); 132 CONVERT_SMI_ARG_CHECKED(size, 1); 133 Handle<JSTypedArray> values = 134 isolate->factory()->NewJSTypedArray(ElementsKind::UINT16_ELEMENTS, size); 135 CHECK(!JSReceiver::SetProperty(isolate, exception, 136 isolate->factory()->InternalizeUtf8String( 137 wasm::WasmException::kRuntimeValuesStr), 138 values, LanguageMode::kStrict) 139 .is_null()); 140 return ReadOnlyRoots(isolate).undefined_value(); 141 } 142 143 RUNTIME_FUNCTION(Runtime_WasmThrow) { 144 // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls. 145 HandleScope scope(isolate); 146 DCHECK_NULL(isolate->context()); 147 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 148 DCHECK_EQ(0, args.length()); 149 Handle<Object> exception(isolate->get_wasm_caught_exception(), isolate); 150 CHECK(!exception.is_null()); 151 isolate->clear_wasm_caught_exception(); 152 return isolate->Throw(*exception); 153 } 154 155 RUNTIME_FUNCTION(Runtime_WasmGetExceptionRuntimeId) { 156 // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls. 157 HandleScope scope(isolate); 158 DCHECK_NULL(isolate->context()); 159 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 160 Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate); 161 if (!except_obj.is_null() && except_obj->IsJSReceiver()) { 162 Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate); 163 Handle<Object> tag; 164 if (JSReceiver::GetProperty(isolate, exception, 165 isolate->factory()->InternalizeUtf8String( 166 wasm::WasmException::kRuntimeIdStr)) 167 .ToHandle(&tag)) { 168 if (tag->IsSmi()) { 169 return *tag; 170 } 171 } 172 } 173 return Smi::FromInt(wasm::kInvalidExceptionTag); 174 } 175 176 RUNTIME_FUNCTION(Runtime_WasmExceptionGetElement) { 177 // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls. 178 HandleScope scope(isolate); 179 DCHECK_NULL(isolate->context()); 180 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 181 DCHECK_EQ(1, args.length()); 182 Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate); 183 if (!except_obj.is_null() && except_obj->IsJSReceiver()) { 184 Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate); 185 Handle<Object> values_obj; 186 if (JSReceiver::GetProperty(isolate, exception, 187 isolate->factory()->InternalizeUtf8String( 188 wasm::WasmException::kRuntimeValuesStr)) 189 .ToHandle(&values_obj)) { 190 if (values_obj->IsJSTypedArray()) { 191 Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj); 192 CHECK_EQ(values->type(), kExternalUint16Array); 193 CONVERT_SMI_ARG_CHECKED(index, 0); 194 CHECK_LT(index, Smi::ToInt(values->length())); 195 auto* vals = 196 reinterpret_cast<uint16_t*>(values->GetBuffer()->backing_store()); 197 return Smi::FromInt(vals[index]); 198 } 199 } 200 } 201 return Smi::FromInt(0); 202 } 203 204 RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) { 205 // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls. 206 HandleScope scope(isolate); 207 DCHECK_EQ(2, args.length()); 208 DCHECK_NULL(isolate->context()); 209 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 210 Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate); 211 if (!except_obj.is_null() && except_obj->IsJSReceiver()) { 212 Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate); 213 Handle<Object> values_obj; 214 if (JSReceiver::GetProperty(isolate, exception, 215 isolate->factory()->InternalizeUtf8String( 216 wasm::WasmException::kRuntimeValuesStr)) 217 .ToHandle(&values_obj)) { 218 if (values_obj->IsJSTypedArray()) { 219 Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj); 220 CHECK_EQ(values->type(), kExternalUint16Array); 221 CONVERT_SMI_ARG_CHECKED(index, 0); 222 CHECK_LT(index, Smi::ToInt(values->length())); 223 CONVERT_SMI_ARG_CHECKED(value, 1); 224 auto* vals = 225 reinterpret_cast<uint16_t*>(values->GetBuffer()->backing_store()); 226 vals[index] = static_cast<uint16_t>(value); 227 } 228 } 229 } 230 return ReadOnlyRoots(isolate).undefined_value(); 231 } 232 233 RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) { 234 DCHECK_EQ(2, args.length()); 235 HandleScope scope(isolate); 236 CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[0]); 237 CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 1); 238 Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate), 239 isolate); 240 241 // The arg buffer is the raw pointer to the caller's stack. It looks like a 242 // Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just 243 // cast it back to the raw pointer. 244 CHECK(!arg_buffer_obj->IsHeapObject()); 245 CHECK(arg_buffer_obj->IsSmi()); 246 Address arg_buffer = reinterpret_cast<Address>(*arg_buffer_obj); 247 248 ClearThreadInWasmScope wasm_flag(true); 249 250 // Set the current isolate's context. 251 DCHECK_NULL(isolate->context()); 252 isolate->set_context(instance->native_context()); 253 254 // Find the frame pointer of the interpreter entry. 255 Address frame_pointer = 0; 256 { 257 StackFrameIterator it(isolate, isolate->thread_local_top()); 258 // On top: C entry stub. 259 DCHECK_EQ(StackFrame::EXIT, it.frame()->type()); 260 it.Advance(); 261 // Next: the wasm interpreter entry. 262 DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type()); 263 frame_pointer = it.frame()->fp(); 264 } 265 266 // Run the function in the interpreter. Note that neither the {WasmDebugInfo} 267 // nor the {InterpreterHandle} have to exist, because interpretation might 268 // have been triggered by another Isolate sharing the same WasmEngine. 269 Handle<WasmDebugInfo> debug_info = 270 WasmInstanceObject::GetOrCreateDebugInfo(instance); 271 bool success = WasmDebugInfo::RunInterpreter( 272 isolate, debug_info, frame_pointer, func_index, arg_buffer); 273 274 if (!success) { 275 DCHECK(isolate->has_pending_exception()); 276 return ReadOnlyRoots(isolate).exception(); 277 } 278 return ReadOnlyRoots(isolate).undefined_value(); 279 } 280 281 RUNTIME_FUNCTION(Runtime_WasmStackGuard) { 282 SealHandleScope shs(isolate); 283 DCHECK_EQ(0, args.length()); 284 DCHECK(!trap_handler::IsTrapHandlerEnabled() || 285 trap_handler::IsThreadInWasm()); 286 287 ClearThreadInWasmScope wasm_flag(true); 288 289 // Set the current isolate's context. 290 DCHECK_NULL(isolate->context()); 291 isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate)); 292 293 // Check if this is a real stack overflow. 294 StackLimitCheck check(isolate); 295 if (check.JsHasOverflowed()) return isolate->StackOverflow(); 296 297 return isolate->stack_guard()->HandleInterrupts(); 298 } 299 300 RUNTIME_FUNCTION(Runtime_WasmCompileLazy) { 301 HandleScope scope(isolate); 302 DCHECK_EQ(2, args.length()); 303 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0); 304 CONVERT_SMI_ARG_CHECKED(func_index, 1); 305 306 ClearThreadInWasmScope wasm_flag(true); 307 308 #ifdef DEBUG 309 StackFrameIterator it(isolate, isolate->thread_local_top()); 310 // On top: C entry stub. 311 DCHECK_EQ(StackFrame::EXIT, it.frame()->type()); 312 it.Advance(); 313 // Next: the wasm lazy compile frame. 314 DCHECK_EQ(StackFrame::WASM_COMPILE_LAZY, it.frame()->type()); 315 DCHECK_EQ(*instance, WasmCompileLazyFrame::cast(it.frame())->wasm_instance()); 316 #endif 317 318 Address entrypoint = wasm::CompileLazy( 319 isolate, instance->module_object()->native_module(), func_index); 320 return reinterpret_cast<Object*>(entrypoint); 321 } 322 323 } // namespace internal 324 } // namespace v8 325