runtime-wasm.cc 11.3 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/runtime/runtime-utils.h"

#include "src/arguments.h"
#include "src/assembler.h"
9
#include "src/compiler/wasm-compiler.h"
10 11 12
#include "src/conversions.h"
#include "src/debug/debug.h"
#include "src/factory.h"
13
#include "src/frame-constants.h"
14
#include "src/objects-inl.h"
15
#include "src/objects/frame-array-inl.h"
eholk's avatar
eholk committed
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-code-manager.h"
20
#include "src/wasm/wasm-constants.h"
21
#include "src/wasm/wasm-engine.h"
22
#include "src/wasm/wasm-objects.h"
23 24 25 26

namespace v8 {
namespace internal {

27
namespace {
28

29
WasmInstanceObject* GetWasmInstanceOnStackTop(Isolate* isolate) {
30 31 32 33
  DisallowHeapAllocation no_allocation;
  const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
  Address pc =
      Memory::Address_at(entry + StandardFrameConstants::kCallerPCOffset);
34 35 36
  WasmInstanceObject* owning_instance = nullptr;
  if (FLAG_wasm_jit_to_native) {
    owning_instance = WasmInstanceObject::GetOwningInstance(
37
        isolate->wasm_engine()->code_manager()->LookupCode(pc));
38 39 40 41
  } else {
    owning_instance = WasmInstanceObject::GetOwningInstanceGC(
        isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code);
  }
42
  CHECK_NOT_NULL(owning_instance);
43 44
  return owning_instance;
}
45

46 47 48
Context* GetWasmContextOnStackTop(Isolate* isolate) {
  return GetWasmInstanceOnStackTop(isolate)
      ->compiled_module()
49
      ->native_context();
50
}
51 52 53 54 55

class ClearThreadInWasmScope {
 public:
  explicit ClearThreadInWasmScope(bool coming_from_wasm)
      : coming_from_wasm_(coming_from_wasm) {
56
    DCHECK_EQ(trap_handler::IsTrapHandlerEnabled() && coming_from_wasm,
57 58 59 60 61 62 63 64 65 66 67 68
              trap_handler::IsThreadInWasm());
    if (coming_from_wasm) trap_handler::ClearThreadInWasm();
  }
  ~ClearThreadInWasmScope() {
    DCHECK(!trap_handler::IsThreadInWasm());
    if (coming_from_wasm_) trap_handler::SetThreadInWasm();
  }

 private:
  const bool coming_from_wasm_;
};

69 70
}  // namespace

71 72 73
RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());
jpp's avatar
jpp committed
74
  CONVERT_UINT32_ARG_CHECKED(delta_pages, 0);
75 76
  Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate),
                                      isolate);
77

78 79 80
  // This runtime function is always being called from wasm code.
  ClearThreadInWasmScope flag_scope(true);

81 82
  // Set the current isolate's context.
  DCHECK_NULL(isolate->context());
83
  isolate->set_context(instance->compiled_module()->native_context());
84

85
  return *isolate->factory()->NewNumberFromInt(
86
      WasmInstanceObject::GrowMemory(isolate, instance, delta_pages));
87
}
88

89 90 91 92 93
RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
  DCHECK_EQ(1, args.length());
  CONVERT_SMI_ARG_CHECKED(message_id, 0);
  ClearThreadInWasmScope clear_wasm_flag(isolate->context() == nullptr);

94
  HandleScope scope(isolate);
95
  DCHECK_NULL(isolate->context());
96
  isolate->set_context(GetWasmContextOnStackTop(isolate));
97 98 99 100 101
  Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError(
      static_cast<MessageTemplate::Template>(message_id));
  return isolate->Throw(*error_obj);
}

102 103 104 105 106 107 108 109
RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
  SealHandleScope shs(isolate);
  DCHECK_LE(0, args.length());
  DCHECK_NULL(isolate->context());
  isolate->set_context(GetWasmContextOnStackTop(isolate));
  return isolate->StackOverflow();
}

110 111 112 113 114 115
RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
  HandleScope scope(isolate);
  DCHECK_EQ(0, args.length());
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
}
jpp's avatar
jpp committed
116

117 118
RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
  // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
jpp's avatar
jpp committed
119
  HandleScope scope(isolate);
120 121
  DCHECK_NULL(isolate->context());
  isolate->set_context(GetWasmContextOnStackTop(isolate));
122 123
  DCHECK_EQ(2, args.length());
  Handle<Object> exception = isolate->factory()->NewWasmRuntimeError(
124 125
      static_cast<MessageTemplate::Template>(
          MessageTemplate::kWasmExceptionError));
126 127 128 129 130
  isolate->set_wasm_caught_exception(*exception);
  CONVERT_ARG_HANDLE_CHECKED(Smi, id, 0);
  CHECK(!JSReceiver::SetProperty(exception,
                                 isolate->factory()->InternalizeUtf8String(
                                     wasm::WasmException::kRuntimeIdStr),
131
                                 id, LanguageMode::kStrict)
132 133 134 135 136 137 138
             .is_null());
  CONVERT_SMI_ARG_CHECKED(size, 1);
  Handle<JSTypedArray> values =
      isolate->factory()->NewJSTypedArray(ElementsKind::UINT16_ELEMENTS, size);
  CHECK(!JSReceiver::SetProperty(exception,
                                 isolate->factory()->InternalizeUtf8String(
                                     wasm::WasmException::kRuntimeValuesStr),
139
                                 values, LanguageMode::kStrict)
140
             .is_null());
141
  return isolate->heap()->undefined_value();
jpp's avatar
jpp committed
142 143
}

144 145
RUNTIME_FUNCTION(Runtime_WasmThrow) {
  // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
146
  HandleScope scope(isolate);
147 148
  DCHECK_NULL(isolate->context());
  isolate->set_context(GetWasmContextOnStackTop(isolate));
149
  DCHECK_EQ(0, args.length());
150 151
  Handle<Object> exception(isolate->get_wasm_caught_exception(), isolate);
  CHECK(!exception.is_null());
152
  isolate->clear_wasm_caught_exception();
153
  return isolate->Throw(*exception);
154 155
}

156 157
RUNTIME_FUNCTION(Runtime_WasmGetExceptionRuntimeId) {
  // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
158
  HandleScope scope(isolate);
159 160 161 162 163 164 165 166 167 168 169 170 171 172
  DCHECK_NULL(isolate->context());
  isolate->set_context(GetWasmContextOnStackTop(isolate));
  Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate);
  if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
    Handle<JSReceiver> exception(JSReceiver::cast(*except_obj));
    Handle<Object> tag;
    if (JSReceiver::GetProperty(exception,
                                isolate->factory()->InternalizeUtf8String(
                                    wasm::WasmException::kRuntimeIdStr))
            .ToHandle(&tag)) {
      if (tag->IsSmi()) {
        return *tag;
      }
    }
173
  }
174
  return Smi::FromInt(wasm::kInvalidExceptionTag);
175 176
}

177 178
RUNTIME_FUNCTION(Runtime_WasmExceptionGetElement) {
  // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
179
  HandleScope scope(isolate);
180 181
  DCHECK_NULL(isolate->context());
  isolate->set_context(GetWasmContextOnStackTop(isolate));
182
  DCHECK_EQ(1, args.length());
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
  Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate);
  if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
    Handle<JSReceiver> exception(JSReceiver::cast(*except_obj));
    Handle<Object> values_obj;
    if (JSReceiver::GetProperty(exception,
                                isolate->factory()->InternalizeUtf8String(
                                    wasm::WasmException::kRuntimeValuesStr))
            .ToHandle(&values_obj)) {
      if (values_obj->IsJSTypedArray()) {
        Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj);
        CHECK_EQ(values->type(), kExternalUint16Array);
        CONVERT_SMI_ARG_CHECKED(index, 0);
        CHECK_LT(index, Smi::ToInt(values->length()));
        auto* vals =
            reinterpret_cast<uint16_t*>(values->GetBuffer()->allocation_base());
        return Smi::FromInt(vals[index]);
      }
    }
  }
  return Smi::FromInt(0);
}

RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) {
  // TODO(kschimpf): Can this be replaced with equivalent TurboFan code/calls.
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  DCHECK_NULL(isolate->context());
  isolate->set_context(GetWasmContextOnStackTop(isolate));
  Handle<Object> except_obj(isolate->get_wasm_caught_exception(), isolate);
  if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
    Handle<JSReceiver> exception(JSReceiver::cast(*except_obj));
    Handle<Object> values_obj;
    if (JSReceiver::GetProperty(exception,
                                isolate->factory()->InternalizeUtf8String(
                                    wasm::WasmException::kRuntimeValuesStr))
            .ToHandle(&values_obj)) {
      if (values_obj->IsJSTypedArray()) {
        Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj);
        CHECK_EQ(values->type(), kExternalUint16Array);
        CONVERT_SMI_ARG_CHECKED(index, 0);
        CHECK_LT(index, Smi::ToInt(values->length()));
        CONVERT_SMI_ARG_CHECKED(value, 1);
        auto* vals =
            reinterpret_cast<uint16_t*>(values->GetBuffer()->allocation_base());
        vals[index] = static_cast<uint16_t>(value);
      }
    }
  }
  return isolate->heap()->undefined_value();
232 233
}

234
RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
235
  DCHECK_EQ(2, args.length());
236
  HandleScope scope(isolate);
237 238 239
  CONVERT_NUMBER_CHECKED(int32_t, func_index, Int32, args[0]);
  CONVERT_ARG_HANDLE_CHECKED(Object, arg_buffer_obj, 1);
  Handle<WasmInstanceObject> instance(GetWasmInstanceOnStackTop(isolate));
240 241 242 243 244 245 246 247

  // The arg buffer is the raw pointer to the caller's stack. It looks like a
  // Smi (lowest bit not set, as checked by IsSmi), but is no valid Smi. We just
  // cast it back to the raw pointer.
  CHECK(!arg_buffer_obj->IsHeapObject());
  CHECK(arg_buffer_obj->IsSmi());
  uint8_t* arg_buffer = reinterpret_cast<uint8_t*>(*arg_buffer_obj);

248 249
  ClearThreadInWasmScope wasm_flag(true);

250 251
  // Set the current isolate's context.
  DCHECK_NULL(isolate->context());
252
  isolate->set_context(instance->compiled_module()->native_context());
253

254 255 256 257 258 259 260 261 262 263 264 265 266 267
  // Find the frame pointer of the interpreter entry.
  Address frame_pointer = 0;
  {
    StackFrameIterator it(isolate, isolate->thread_local_top());
    // On top: C entry stub.
    DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
    it.Advance();
    // Next: the wasm interpreter entry.
    DCHECK_EQ(StackFrame::WASM_INTERPRETER_ENTRY, it.frame()->type());
    frame_pointer = it.frame()->fp();
  }

  bool success = instance->debug_info()->RunInterpreter(frame_pointer,
                                                        func_index, arg_buffer);
268

269 270 271 272
  if (!success) {
    DCHECK(isolate->has_pending_exception());
    return isolate->heap()->exception();
  }
273 274 275
  return isolate->heap()->undefined_value();
}

276 277 278
RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(0, args.length());
279 280
  DCHECK(!trap_handler::IsTrapHandlerEnabled() ||
         trap_handler::IsThreadInWasm());
281

282
  ClearThreadInWasmScope wasm_flag(true);
283 284 285 286 287 288 289 290 291 292 293 294

  // Set the current isolate's context.
  DCHECK_NULL(isolate->context());
  isolate->set_context(GetWasmContextOnStackTop(isolate));

  // Check if this is a real stack overflow.
  StackLimitCheck check(isolate);
  if (check.JsHasOverflowed()) return isolate->StackOverflow();

  return isolate->stack_guard()->HandleInterrupts();
}

295
RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
296
  DCHECK_EQ(0, args.length());
297 298
  HandleScope scope(isolate);

299 300 301 302 303 304 305 306 307
  if (FLAG_wasm_jit_to_native) {
    Address new_func = wasm::CompileLazy(isolate);
    // The alternative to this is having 2 lazy compile builtins. The builtins
    // are part of the snapshot, so the flag has no impact on the codegen there.
    return reinterpret_cast<Object*>(new_func - Code::kHeaderSize +
                                     kHeapObjectTag);
  } else {
    return *wasm::CompileLazyOnGCHeap(isolate);
  }
308 309
}

310 311
}  // namespace internal
}  // namespace v8