Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 1 | // Copyright 2015 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/macro-assembler.h" |
| 6 | #include "src/objects.h" |
| 7 | #include "src/v8.h" |
| 8 | |
| 9 | #include "src/simulator.h" |
| 10 | |
| 11 | #include "src/wasm/ast-decoder.h" |
| 12 | #include "src/wasm/module-decoder.h" |
| 13 | #include "src/wasm/wasm-module.h" |
| 14 | #include "src/wasm/wasm-result.h" |
| 15 | |
| 16 | #include "src/compiler/wasm-compiler.h" |
| 17 | |
| 18 | namespace v8 { |
| 19 | namespace internal { |
| 20 | namespace wasm { |
| 21 | |
| 22 | std::ostream& operator<<(std::ostream& os, const WasmModule& module) { |
| 23 | os << "WASM module with "; |
| 24 | os << (1 << module.min_mem_size_log2) << " min mem"; |
| 25 | os << (1 << module.max_mem_size_log2) << " max mem"; |
| 26 | if (module.functions) os << module.functions->size() << " functions"; |
| 27 | if (module.globals) os << module.functions->size() << " globals"; |
| 28 | if (module.data_segments) os << module.functions->size() << " data segments"; |
| 29 | return os; |
| 30 | } |
| 31 | |
| 32 | |
| 33 | std::ostream& operator<<(std::ostream& os, const WasmFunction& function) { |
| 34 | os << "WASM function with signature "; |
| 35 | |
| 36 | // TODO(titzer): factor out rendering of signatures. |
| 37 | if (function.sig->return_count() == 0) os << "v"; |
| 38 | for (size_t i = 0; i < function.sig->return_count(); i++) { |
| 39 | os << WasmOpcodes::ShortNameOf(function.sig->GetReturn(i)); |
| 40 | } |
| 41 | os << "_"; |
| 42 | if (function.sig->parameter_count() == 0) os << "v"; |
| 43 | for (size_t i = 0; i < function.sig->parameter_count(); i++) { |
| 44 | os << WasmOpcodes::ShortNameOf(function.sig->GetParam(i)); |
| 45 | } |
| 46 | os << " locals: "; |
| 47 | if (function.local_int32_count) |
| 48 | os << function.local_int32_count << " int32s "; |
| 49 | if (function.local_int64_count) |
| 50 | os << function.local_int64_count << " int64s "; |
| 51 | if (function.local_float32_count) |
| 52 | os << function.local_float32_count << " float32s "; |
| 53 | if (function.local_float64_count) |
| 54 | os << function.local_float64_count << " float64s "; |
| 55 | |
| 56 | os << " code bytes: " |
| 57 | << (function.code_end_offset - function.code_start_offset); |
| 58 | return os; |
| 59 | } |
| 60 | |
| 61 | |
| 62 | // A helper class for compiling multiple wasm functions that offers |
| 63 | // placeholder code objects for calling functions that are not yet compiled. |
| 64 | class WasmLinker { |
| 65 | public: |
| 66 | WasmLinker(Isolate* isolate, size_t size) |
| 67 | : isolate_(isolate), placeholder_code_(size), function_code_(size) {} |
| 68 | |
| 69 | // Get the code object for a function, allocating a placeholder if it has |
| 70 | // not yet been compiled. |
| 71 | Handle<Code> GetFunctionCode(uint32_t index) { |
| 72 | DCHECK(index < function_code_.size()); |
| 73 | if (function_code_[index].is_null()) { |
| 74 | // Create a placeholder code object and encode the corresponding index in |
| 75 | // the {constant_pool_offset} field of the code object. |
| 76 | // TODO(titzer): placeholder code objects are somewhat dangerous. |
| 77 | Handle<Code> self(nullptr, isolate_); |
| 78 | byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. |
| 79 | CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; |
| 80 | Handle<Code> code = isolate_->factory()->NewCode( |
| 81 | desc, Code::KindField::encode(Code::WASM_FUNCTION), self); |
| 82 | code->set_constant_pool_offset(index + kPlaceholderMarker); |
| 83 | placeholder_code_[index] = code; |
| 84 | function_code_[index] = code; |
| 85 | } |
| 86 | return function_code_[index]; |
| 87 | } |
| 88 | |
| 89 | void Finish(uint32_t index, Handle<Code> code) { |
| 90 | DCHECK(index < function_code_.size()); |
| 91 | function_code_[index] = code; |
| 92 | } |
| 93 | |
| 94 | void Link(Handle<FixedArray> function_table, |
| 95 | std::vector<uint16_t>* functions) { |
| 96 | for (size_t i = 0; i < function_code_.size(); i++) { |
| 97 | LinkFunction(function_code_[i]); |
| 98 | } |
| 99 | if (functions && !function_table.is_null()) { |
| 100 | int table_size = static_cast<int>(functions->size()); |
| 101 | DCHECK_EQ(function_table->length(), table_size * 2); |
| 102 | for (int i = 0; i < table_size; i++) { |
| 103 | function_table->set(i + table_size, *function_code_[functions->at(i)]); |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | private: |
| 109 | static const int kPlaceholderMarker = 1000000000; |
| 110 | |
| 111 | Isolate* isolate_; |
| 112 | std::vector<Handle<Code>> placeholder_code_; |
| 113 | std::vector<Handle<Code>> function_code_; |
| 114 | |
| 115 | void LinkFunction(Handle<Code> code) { |
| 116 | bool modified = false; |
| 117 | int mode_mask = RelocInfo::kCodeTargetMask; |
| 118 | AllowDeferredHandleDereference embedding_raw_address; |
| 119 | for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { |
| 120 | RelocInfo::Mode mode = it.rinfo()->rmode(); |
| 121 | if (RelocInfo::IsCodeTarget(mode)) { |
| 122 | Code* target = |
| 123 | Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| 124 | if (target->kind() == Code::WASM_FUNCTION && |
| 125 | target->constant_pool_offset() >= kPlaceholderMarker) { |
| 126 | // Patch direct calls to placeholder code objects. |
| 127 | uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; |
| 128 | CHECK(index < function_code_.size()); |
| 129 | Handle<Code> new_target = function_code_[index]; |
| 130 | if (target != *new_target) { |
| 131 | CHECK_EQ(*placeholder_code_[index], target); |
| 132 | it.rinfo()->set_target_address(new_target->instruction_start(), |
| 133 | SKIP_WRITE_BARRIER, |
| 134 | SKIP_ICACHE_FLUSH); |
| 135 | modified = true; |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | } |
| 140 | if (modified) { |
| 141 | Assembler::FlushICache(isolate_, code->instruction_start(), |
| 142 | code->instruction_size()); |
| 143 | } |
| 144 | } |
| 145 | }; |
| 146 | |
| 147 | namespace { |
| 148 | // Internal constants for the layout of the module object. |
| 149 | const int kWasmModuleInternalFieldCount = 4; |
| 150 | const int kWasmModuleFunctionTable = 0; |
| 151 | const int kWasmModuleCodeTable = 1; |
| 152 | const int kWasmMemArrayBuffer = 2; |
| 153 | const int kWasmGlobalsArrayBuffer = 3; |
| 154 | |
| 155 | |
| 156 | size_t AllocateGlobalsOffsets(std::vector<WasmGlobal>* globals) { |
| 157 | uint32_t offset = 0; |
| 158 | if (!globals) return 0; |
| 159 | for (WasmGlobal& global : *globals) { |
| 160 | byte size = WasmOpcodes::MemSize(global.type); |
| 161 | offset = (offset + size - 1) & ~(size - 1); // align |
| 162 | global.offset = offset; |
| 163 | offset += size; |
| 164 | } |
| 165 | return offset; |
| 166 | } |
| 167 | |
| 168 | |
| 169 | void LoadDataSegments(WasmModule* module, byte* mem_addr, size_t mem_size) { |
| 170 | for (const WasmDataSegment& segment : *module->data_segments) { |
| 171 | if (!segment.init) continue; |
| 172 | CHECK_LT(segment.dest_addr, mem_size); |
| 173 | CHECK_LE(segment.source_size, mem_size); |
| 174 | CHECK_LE(segment.dest_addr + segment.source_size, mem_size); |
| 175 | byte* addr = mem_addr + segment.dest_addr; |
| 176 | memcpy(addr, module->module_start + segment.source_offset, |
| 177 | segment.source_size); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | |
| 182 | Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) { |
| 183 | if (!module->function_table || module->function_table->size() == 0) { |
| 184 | return Handle<FixedArray>::null(); |
| 185 | } |
| 186 | int table_size = static_cast<int>(module->function_table->size()); |
| 187 | Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size); |
| 188 | for (int i = 0; i < table_size; i++) { |
| 189 | WasmFunction* function = |
| 190 | &module->functions->at(module->function_table->at(i)); |
| 191 | fixed->set(i, Smi::FromInt(function->sig_index)); |
| 192 | } |
| 193 | return fixed; |
| 194 | } |
| 195 | |
| 196 | |
| 197 | Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, int size, |
| 198 | byte** backing_store) { |
| 199 | void* memory = isolate->array_buffer_allocator()->Allocate(size); |
| 200 | if (!memory) return Handle<JSArrayBuffer>::null(); |
| 201 | *backing_store = reinterpret_cast<byte*>(memory); |
| 202 | |
| 203 | #if DEBUG |
| 204 | // Double check the API allocator actually zero-initialized the memory. |
| 205 | for (int i = 0; i < size; i++) { |
| 206 | DCHECK_EQ(0, (*backing_store)[i]); |
| 207 | } |
| 208 | #endif |
| 209 | |
| 210 | Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); |
| 211 | JSArrayBuffer::Setup(buffer, isolate, false, memory, size); |
| 212 | buffer->set_is_neuterable(false); |
| 213 | return buffer; |
| 214 | } |
| 215 | } // namespace |
| 216 | |
| 217 | |
| 218 | WasmModule::WasmModule() |
| 219 | : globals(nullptr), |
| 220 | signatures(nullptr), |
| 221 | functions(nullptr), |
| 222 | data_segments(nullptr), |
| 223 | function_table(nullptr) {} |
| 224 | |
| 225 | |
| 226 | WasmModule::~WasmModule() { |
| 227 | if (globals) delete globals; |
| 228 | if (signatures) delete signatures; |
| 229 | if (functions) delete functions; |
| 230 | if (data_segments) delete data_segments; |
| 231 | if (function_table) delete function_table; |
| 232 | } |
| 233 | |
| 234 | |
| 235 | // Instantiates a wasm module as a JSObject. |
| 236 | // * allocates a backing store of {mem_size} bytes. |
| 237 | // * installs a named property "memory" for that buffer if exported |
| 238 | // * installs named properties on the object for exported functions |
| 239 | // * compiles wasm code to machine code |
| 240 | MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, |
| 241 | Handle<JSObject> ffi, |
| 242 | Handle<JSArrayBuffer> memory) { |
| 243 | this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate. |
| 244 | ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
| 245 | |
| 246 | Factory* factory = isolate->factory(); |
| 247 | // Memory is bigger than maximum supported size. |
| 248 | if (memory.is_null() && min_mem_size_log2 > kMaxMemSize) { |
| 249 | thrower.Error("Out of memory: wasm memory too large"); |
| 250 | return MaybeHandle<JSObject>(); |
| 251 | } |
| 252 | |
| 253 | Handle<Map> map = factory->NewMap( |
| 254 | JS_OBJECT_TYPE, |
| 255 | JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); |
| 256 | |
| 257 | //------------------------------------------------------------------------- |
| 258 | // Allocate the module object. |
| 259 | //------------------------------------------------------------------------- |
| 260 | Handle<JSObject> module = factory->NewJSObjectFromMap(map, TENURED); |
| 261 | Handle<FixedArray> code_table = |
| 262 | factory->NewFixedArray(static_cast<int>(functions->size()), TENURED); |
| 263 | |
| 264 | //------------------------------------------------------------------------- |
| 265 | // Allocate the linear memory. |
| 266 | //------------------------------------------------------------------------- |
| 267 | uint32_t mem_size = 1 << min_mem_size_log2; |
| 268 | byte* mem_addr = nullptr; |
| 269 | Handle<JSArrayBuffer> mem_buffer; |
| 270 | if (!memory.is_null()) { |
| 271 | memory->set_is_neuterable(false); |
| 272 | mem_addr = reinterpret_cast<byte*>(memory->backing_store()); |
| 273 | mem_size = memory->byte_length()->Number(); |
| 274 | mem_buffer = memory; |
| 275 | } else { |
| 276 | mem_buffer = NewArrayBuffer(isolate, mem_size, &mem_addr); |
| 277 | if (!mem_addr) { |
| 278 | // Not enough space for backing store of memory |
| 279 | thrower.Error("Out of memory: wasm memory"); |
| 280 | return MaybeHandle<JSObject>(); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | // Load initialized data segments. |
| 285 | LoadDataSegments(this, mem_addr, mem_size); |
| 286 | |
| 287 | module->SetInternalField(kWasmMemArrayBuffer, *mem_buffer); |
| 288 | |
| 289 | if (mem_export) { |
| 290 | // Export the memory as a named property. |
| 291 | Handle<String> name = factory->InternalizeUtf8String("memory"); |
| 292 | JSObject::AddProperty(module, name, mem_buffer, READ_ONLY); |
| 293 | } |
| 294 | |
| 295 | //------------------------------------------------------------------------- |
| 296 | // Allocate the globals area if necessary. |
| 297 | //------------------------------------------------------------------------- |
| 298 | size_t globals_size = AllocateGlobalsOffsets(globals); |
| 299 | byte* globals_addr = nullptr; |
| 300 | if (globals_size > 0) { |
| 301 | Handle<JSArrayBuffer> globals_buffer = |
| 302 | NewArrayBuffer(isolate, mem_size, &globals_addr); |
| 303 | if (!globals_addr) { |
| 304 | // Not enough space for backing store of globals. |
| 305 | thrower.Error("Out of memory: wasm globals"); |
| 306 | return MaybeHandle<JSObject>(); |
| 307 | } |
| 308 | |
| 309 | module->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer); |
| 310 | } else { |
| 311 | module->SetInternalField(kWasmGlobalsArrayBuffer, Smi::FromInt(0)); |
| 312 | } |
| 313 | |
| 314 | //------------------------------------------------------------------------- |
| 315 | // Compile all functions in the module. |
| 316 | //------------------------------------------------------------------------- |
| 317 | int index = 0; |
| 318 | WasmLinker linker(isolate, functions->size()); |
| 319 | ModuleEnv module_env; |
| 320 | module_env.module = this; |
| 321 | module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr); |
| 322 | module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr) + mem_size; |
| 323 | module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr); |
| 324 | module_env.linker = &linker; |
| 325 | module_env.function_code = nullptr; |
| 326 | module_env.function_table = BuildFunctionTable(isolate, this); |
| 327 | module_env.memory = memory; |
| 328 | module_env.context = isolate->native_context(); |
| 329 | module_env.asm_js = false; |
| 330 | |
| 331 | // First pass: compile each function and initialize the code table. |
| 332 | for (const WasmFunction& func : *functions) { |
| 333 | if (thrower.error()) break; |
| 334 | |
| 335 | const char* cstr = GetName(func.name_offset); |
| 336 | Handle<String> name = factory->InternalizeUtf8String(cstr); |
| 337 | Handle<Code> code = Handle<Code>::null(); |
| 338 | Handle<JSFunction> function = Handle<JSFunction>::null(); |
| 339 | if (func.external) { |
| 340 | // Lookup external function in FFI object. |
| 341 | if (!ffi.is_null()) { |
| 342 | MaybeHandle<Object> result = Object::GetProperty(ffi, name); |
| 343 | if (!result.is_null()) { |
| 344 | Handle<Object> obj = result.ToHandleChecked(); |
| 345 | if (obj->IsJSFunction()) { |
| 346 | function = Handle<JSFunction>::cast(obj); |
| 347 | code = compiler::CompileWasmToJSWrapper(isolate, &module_env, |
| 348 | function, index); |
| 349 | } else { |
| 350 | thrower.Error("FFI function #%d:%s is not a JSFunction.", index, |
| 351 | cstr); |
| 352 | return MaybeHandle<JSObject>(); |
| 353 | } |
| 354 | } else { |
| 355 | thrower.Error("FFI function #%d:%s not found.", index, cstr); |
| 356 | return MaybeHandle<JSObject>(); |
| 357 | } |
| 358 | } else { |
| 359 | thrower.Error("FFI table is not an object."); |
| 360 | return MaybeHandle<JSObject>(); |
| 361 | } |
| 362 | } else { |
| 363 | // Compile the function. |
| 364 | code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func, |
| 365 | index); |
| 366 | if (code.is_null()) { |
| 367 | thrower.Error("Compilation of #%d:%s failed.", index, cstr); |
| 368 | return MaybeHandle<JSObject>(); |
| 369 | } |
| 370 | if (func.exported) { |
| 371 | function = compiler::CompileJSToWasmWrapper(isolate, &module_env, name, |
| 372 | code, module, index); |
| 373 | } |
| 374 | } |
| 375 | if (!code.is_null()) { |
| 376 | // Install the code into the linker table. |
| 377 | linker.Finish(index, code); |
| 378 | code_table->set(index, *code); |
| 379 | } |
| 380 | if (func.exported) { |
| 381 | // Exported functions are installed as read-only properties on the module. |
| 382 | JSObject::AddProperty(module, name, function, READ_ONLY); |
| 383 | } |
| 384 | index++; |
| 385 | } |
| 386 | |
| 387 | // Second pass: patch all direct call sites. |
| 388 | linker.Link(module_env.function_table, this->function_table); |
| 389 | |
| 390 | module->SetInternalField(kWasmModuleFunctionTable, Smi::FromInt(0)); |
| 391 | module->SetInternalField(kWasmModuleCodeTable, *code_table); |
| 392 | return module; |
| 393 | } |
| 394 | |
| 395 | |
| 396 | Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) { |
| 397 | DCHECK(IsValidFunction(index)); |
| 398 | if (linker) return linker->GetFunctionCode(index); |
| 399 | if (function_code) return function_code->at(index); |
| 400 | return Handle<Code>::null(); |
| 401 | } |
| 402 | |
| 403 | |
| 404 | compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, |
| 405 | uint32_t index) { |
| 406 | DCHECK(IsValidFunction(index)); |
| 407 | // Always make a direct call to whatever is in the table at that location. |
| 408 | // A wrapper will be generated for FFI calls. |
| 409 | WasmFunction* function = &module->functions->at(index); |
| 410 | return GetWasmCallDescriptor(zone, function->sig); |
| 411 | } |
| 412 | |
| 413 | |
| 414 | int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, |
| 415 | const byte* module_end, bool asm_js) { |
| 416 | HandleScope scope(isolate); |
| 417 | Zone zone; |
| 418 | // Decode the module, but don't verify function bodies, since we'll |
| 419 | // be compiling them anyway. |
| 420 | ModuleResult result = |
| 421 | DecodeWasmModule(isolate, &zone, module_start, module_end, false, false); |
| 422 | if (result.failed()) { |
| 423 | // Module verification failed. throw. |
| 424 | std::ostringstream str; |
| 425 | str << "WASM.compileRun() failed: " << result; |
| 426 | isolate->Throw( |
| 427 | *isolate->factory()->NewStringFromAsciiChecked(str.str().c_str())); |
| 428 | return -1; |
| 429 | } |
| 430 | |
| 431 | int32_t retval = CompileAndRunWasmModule(isolate, result.val); |
| 432 | delete result.val; |
| 433 | return retval; |
| 434 | } |
| 435 | |
| 436 | |
| 437 | int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) { |
| 438 | ErrorThrower thrower(isolate, "CompileAndRunWasmModule"); |
| 439 | |
| 440 | // Allocate temporary linear memory and globals. |
| 441 | size_t mem_size = 1 << module->min_mem_size_log2; |
| 442 | size_t globals_size = AllocateGlobalsOffsets(module->globals); |
| 443 | |
| 444 | base::SmartArrayPointer<byte> mem_addr(new byte[mem_size]); |
| 445 | base::SmartArrayPointer<byte> globals_addr(new byte[globals_size]); |
| 446 | |
| 447 | memset(mem_addr.get(), 0, mem_size); |
| 448 | memset(globals_addr.get(), 0, globals_size); |
| 449 | |
| 450 | // Create module environment. |
| 451 | WasmLinker linker(isolate, module->functions->size()); |
| 452 | ModuleEnv module_env; |
| 453 | module_env.module = module; |
| 454 | module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr.get()); |
| 455 | module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr.get()) + mem_size; |
| 456 | module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr.get()); |
| 457 | module_env.linker = &linker; |
| 458 | module_env.function_code = nullptr; |
| 459 | module_env.function_table = BuildFunctionTable(isolate, module); |
| 460 | module_env.asm_js = false; |
| 461 | |
| 462 | // Load data segments. |
| 463 | // TODO(titzer): throw instead of crashing if segments don't fit in memory? |
| 464 | LoadDataSegments(module, mem_addr.get(), mem_size); |
| 465 | |
| 466 | // Compile all functions. |
| 467 | Handle<Code> main_code = Handle<Code>::null(); // record last code. |
| 468 | int index = 0; |
| 469 | for (const WasmFunction& func : *module->functions) { |
| 470 | if (!func.external) { |
| 471 | // Compile the function and install it in the code table. |
| 472 | Handle<Code> code = compiler::CompileWasmFunction( |
| 473 | thrower, isolate, &module_env, func, index); |
| 474 | if (!code.is_null()) { |
| 475 | if (func.exported) main_code = code; |
| 476 | linker.Finish(index, code); |
| 477 | } |
| 478 | if (thrower.error()) return -1; |
| 479 | } |
| 480 | index++; |
| 481 | } |
| 482 | |
| 483 | if (!main_code.is_null()) { |
| 484 | linker.Link(module_env.function_table, module->function_table); |
| 485 | #if USE_SIMULATOR && V8_TARGET_ARCH_ARM64 |
| 486 | // Run the main code on arm64 simulator. |
| 487 | Simulator* simulator = Simulator::current(isolate); |
| 488 | Simulator::CallArgument args[] = {Simulator::CallArgument(0), |
| 489 | Simulator::CallArgument::End()}; |
| 490 | return static_cast<int32_t>(simulator->CallInt64(main_code->entry(), args)); |
| 491 | #elif USE_SIMULATOR |
| 492 | // Run the main code on simulator. |
| 493 | Simulator* simulator = Simulator::current(isolate); |
| 494 | return static_cast<int32_t>( |
| 495 | simulator->Call(main_code->entry(), 4, 0, 0, 0, 0)); |
| 496 | #else |
| 497 | // Run the main code as raw machine code. |
| 498 | int32_t (*raw_func)() = reinterpret_cast<int32_t (*)()>( |
| 499 | reinterpret_cast<uintptr_t>(main_code->entry())); |
| 500 | return raw_func(); |
| 501 | #endif |
| 502 | } else { |
| 503 | // No main code was found. |
| 504 | isolate->Throw(*isolate->factory()->NewStringFromStaticChars( |
| 505 | "WASM.compileRun() failed: no valid main code produced.")); |
| 506 | } |
| 507 | return -1; |
| 508 | } |
| 509 | } // namespace wasm |
| 510 | } // namespace internal |
| 511 | } // namespace v8 |