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 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 22 | static const char* wasmSections[] = { |
| 23 | #define F(enumerator, string) string, |
| 24 | FOR_EACH_WASM_SECTION_TYPE(F) |
| 25 | #undef F |
| 26 | }; |
| 27 | |
| 28 | static uint8_t wasmSectionsLengths[]{ |
| 29 | #define F(enumerator, string) sizeof(string) - 1, |
| 30 | FOR_EACH_WASM_SECTION_TYPE(F) |
| 31 | #undef F |
| 32 | }; |
| 33 | |
| 34 | static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) == |
| 35 | (size_t)WasmSection::Code::Max, |
| 36 | "expected enum WasmSection::Code to be monotonic from 0"); |
| 37 | |
| 38 | WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; } |
| 39 | WasmSection::Code WasmSection::end() { return WasmSection::Code::Max; } |
| 40 | WasmSection::Code WasmSection::next(WasmSection::Code code) { |
| 41 | return (WasmSection::Code)(1 + (uint32_t)code); |
| 42 | } |
| 43 | |
| 44 | const char* WasmSection::getName(WasmSection::Code code) { |
| 45 | return wasmSections[(size_t)code]; |
| 46 | } |
| 47 | |
| 48 | size_t WasmSection::getNameLength(WasmSection::Code code) { |
| 49 | return wasmSectionsLengths[(size_t)code]; |
| 50 | } |
| 51 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 52 | std::ostream& operator<<(std::ostream& os, const WasmModule& module) { |
| 53 | os << "WASM module with "; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 54 | os << (module.min_mem_pages * module.kPageSize) << " min mem"; |
| 55 | os << (module.max_mem_pages * module.kPageSize) << " max mem"; |
| 56 | os << module.functions.size() << " functions"; |
| 57 | os << module.functions.size() << " globals"; |
| 58 | os << module.functions.size() << " data segments"; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 59 | return os; |
| 60 | } |
| 61 | |
| 62 | |
| 63 | std::ostream& operator<<(std::ostream& os, const WasmFunction& function) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 64 | os << "WASM function with signature " << *function.sig; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 65 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 66 | os << " locals: "; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 67 | if (function.local_i32_count) os << function.local_i32_count << " i32s "; |
| 68 | if (function.local_i64_count) os << function.local_i64_count << " i64s "; |
| 69 | if (function.local_f32_count) os << function.local_f32_count << " f32s "; |
| 70 | if (function.local_f64_count) os << function.local_f64_count << " f64s "; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 71 | |
| 72 | os << " code bytes: " |
| 73 | << (function.code_end_offset - function.code_start_offset); |
| 74 | return os; |
| 75 | } |
| 76 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 77 | std::ostream& operator<<(std::ostream& os, const WasmFunctionName& pair) { |
| 78 | os << "#" << pair.function_->func_index << ":"; |
| 79 | if (pair.function_->name_offset > 0) { |
| 80 | if (pair.module_) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 81 | WasmName name = pair.module_->GetName(pair.function_->name_offset, |
| 82 | pair.function_->name_length); |
| 83 | os.write(name.name, name.length); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 84 | } else { |
| 85 | os << "+" << pair.function_->func_index; |
| 86 | } |
| 87 | } else { |
| 88 | os << "?"; |
| 89 | } |
| 90 | return os; |
| 91 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 92 | |
| 93 | // A helper class for compiling multiple wasm functions that offers |
| 94 | // placeholder code objects for calling functions that are not yet compiled. |
| 95 | class WasmLinker { |
| 96 | public: |
| 97 | WasmLinker(Isolate* isolate, size_t size) |
| 98 | : isolate_(isolate), placeholder_code_(size), function_code_(size) {} |
| 99 | |
| 100 | // Get the code object for a function, allocating a placeholder if it has |
| 101 | // not yet been compiled. |
| 102 | Handle<Code> GetFunctionCode(uint32_t index) { |
| 103 | DCHECK(index < function_code_.size()); |
| 104 | if (function_code_[index].is_null()) { |
| 105 | // Create a placeholder code object and encode the corresponding index in |
| 106 | // the {constant_pool_offset} field of the code object. |
| 107 | // TODO(titzer): placeholder code objects are somewhat dangerous. |
| 108 | Handle<Code> self(nullptr, isolate_); |
| 109 | byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions. |
| 110 | CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr}; |
| 111 | Handle<Code> code = isolate_->factory()->NewCode( |
| 112 | desc, Code::KindField::encode(Code::WASM_FUNCTION), self); |
| 113 | code->set_constant_pool_offset(index + kPlaceholderMarker); |
| 114 | placeholder_code_[index] = code; |
| 115 | function_code_[index] = code; |
| 116 | } |
| 117 | return function_code_[index]; |
| 118 | } |
| 119 | |
| 120 | void Finish(uint32_t index, Handle<Code> code) { |
| 121 | DCHECK(index < function_code_.size()); |
| 122 | function_code_[index] = code; |
| 123 | } |
| 124 | |
| 125 | void Link(Handle<FixedArray> function_table, |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 126 | std::vector<uint16_t>& functions) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 127 | for (size_t i = 0; i < function_code_.size(); i++) { |
| 128 | LinkFunction(function_code_[i]); |
| 129 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 130 | if (!function_table.is_null()) { |
| 131 | int table_size = static_cast<int>(functions.size()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 132 | DCHECK_EQ(function_table->length(), table_size * 2); |
| 133 | for (int i = 0; i < table_size; i++) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 134 | function_table->set(i + table_size, *function_code_[functions[i]]); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 135 | } |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | private: |
| 140 | static const int kPlaceholderMarker = 1000000000; |
| 141 | |
| 142 | Isolate* isolate_; |
| 143 | std::vector<Handle<Code>> placeholder_code_; |
| 144 | std::vector<Handle<Code>> function_code_; |
| 145 | |
| 146 | void LinkFunction(Handle<Code> code) { |
| 147 | bool modified = false; |
| 148 | int mode_mask = RelocInfo::kCodeTargetMask; |
| 149 | AllowDeferredHandleDereference embedding_raw_address; |
| 150 | for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { |
| 151 | RelocInfo::Mode mode = it.rinfo()->rmode(); |
| 152 | if (RelocInfo::IsCodeTarget(mode)) { |
| 153 | Code* target = |
| 154 | Code::GetCodeFromTargetAddress(it.rinfo()->target_address()); |
| 155 | if (target->kind() == Code::WASM_FUNCTION && |
| 156 | target->constant_pool_offset() >= kPlaceholderMarker) { |
| 157 | // Patch direct calls to placeholder code objects. |
| 158 | uint32_t index = target->constant_pool_offset() - kPlaceholderMarker; |
| 159 | CHECK(index < function_code_.size()); |
| 160 | Handle<Code> new_target = function_code_[index]; |
| 161 | if (target != *new_target) { |
| 162 | CHECK_EQ(*placeholder_code_[index], target); |
| 163 | it.rinfo()->set_target_address(new_target->instruction_start(), |
| 164 | SKIP_WRITE_BARRIER, |
| 165 | SKIP_ICACHE_FLUSH); |
| 166 | modified = true; |
| 167 | } |
| 168 | } |
| 169 | } |
| 170 | } |
| 171 | if (modified) { |
| 172 | Assembler::FlushICache(isolate_, code->instruction_start(), |
| 173 | code->instruction_size()); |
| 174 | } |
| 175 | } |
| 176 | }; |
| 177 | |
| 178 | namespace { |
| 179 | // Internal constants for the layout of the module object. |
| 180 | const int kWasmModuleInternalFieldCount = 4; |
| 181 | const int kWasmModuleFunctionTable = 0; |
| 182 | const int kWasmModuleCodeTable = 1; |
| 183 | const int kWasmMemArrayBuffer = 2; |
| 184 | const int kWasmGlobalsArrayBuffer = 3; |
| 185 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 186 | size_t AllocateGlobalsOffsets(std::vector<WasmGlobal>& globals) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 187 | uint32_t offset = 0; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 188 | if (globals.size() == 0) return 0; |
| 189 | for (WasmGlobal& global : globals) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 190 | byte size = WasmOpcodes::MemSize(global.type); |
| 191 | offset = (offset + size - 1) & ~(size - 1); // align |
| 192 | global.offset = offset; |
| 193 | offset += size; |
| 194 | } |
| 195 | return offset; |
| 196 | } |
| 197 | |
| 198 | |
| 199 | void LoadDataSegments(WasmModule* module, byte* mem_addr, size_t mem_size) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 200 | for (const WasmDataSegment& segment : module->data_segments) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 201 | if (!segment.init) continue; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 202 | if (!segment.source_size) continue; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 203 | CHECK_LT(segment.dest_addr, mem_size); |
| 204 | CHECK_LE(segment.source_size, mem_size); |
| 205 | CHECK_LE(segment.dest_addr + segment.source_size, mem_size); |
| 206 | byte* addr = mem_addr + segment.dest_addr; |
| 207 | memcpy(addr, module->module_start + segment.source_offset, |
| 208 | segment.source_size); |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | |
| 213 | Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 214 | if (module->function_table.size() == 0) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 215 | return Handle<FixedArray>::null(); |
| 216 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 217 | int table_size = static_cast<int>(module->function_table.size()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 218 | Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size); |
| 219 | for (int i = 0; i < table_size; i++) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 220 | WasmFunction* function = &module->functions[module->function_table[i]]; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 221 | fixed->set(i, Smi::FromInt(function->sig_index)); |
| 222 | } |
| 223 | return fixed; |
| 224 | } |
| 225 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 226 | Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size, |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 227 | byte** backing_store) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 228 | if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 229 | // TODO(titzer): lift restriction on maximum memory allocated here. |
| 230 | *backing_store = nullptr; |
| 231 | return Handle<JSArrayBuffer>::null(); |
| 232 | } |
| 233 | void* memory = |
| 234 | isolate->array_buffer_allocator()->Allocate(static_cast<int>(size)); |
| 235 | if (!memory) { |
| 236 | *backing_store = nullptr; |
| 237 | return Handle<JSArrayBuffer>::null(); |
| 238 | } |
| 239 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 240 | *backing_store = reinterpret_cast<byte*>(memory); |
| 241 | |
| 242 | #if DEBUG |
| 243 | // Double check the API allocator actually zero-initialized the memory. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 244 | byte* bytes = reinterpret_cast<byte*>(*backing_store); |
| 245 | for (size_t i = 0; i < size; i++) { |
| 246 | DCHECK_EQ(0, bytes[i]); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 247 | } |
| 248 | #endif |
| 249 | |
| 250 | Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 251 | JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size)); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 252 | buffer->set_is_neuterable(false); |
| 253 | return buffer; |
| 254 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 255 | |
| 256 | // Set the memory for a module instance to be the {memory} array buffer. |
| 257 | void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) { |
| 258 | memory->set_is_neuterable(false); |
| 259 | instance->mem_start = reinterpret_cast<byte*>(memory->backing_store()); |
| 260 | instance->mem_size = memory->byte_length()->Number(); |
| 261 | instance->mem_buffer = memory; |
| 262 | } |
| 263 | |
| 264 | // Allocate memory for a module instance as a new JSArrayBuffer. |
| 265 | bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate, |
| 266 | WasmModuleInstance* instance) { |
| 267 | DCHECK(instance->module); |
| 268 | DCHECK(instance->mem_buffer.is_null()); |
| 269 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 270 | if (instance->module->min_mem_pages > WasmModule::kMaxMemPages) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 271 | thrower->Error("Out of memory: wasm memory too large"); |
| 272 | return false; |
| 273 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 274 | instance->mem_size = WasmModule::kPageSize * instance->module->min_mem_pages; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 275 | instance->mem_buffer = |
| 276 | NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start); |
| 277 | if (!instance->mem_start) { |
| 278 | thrower->Error("Out of memory: wasm memory"); |
| 279 | instance->mem_size = 0; |
| 280 | return false; |
| 281 | } |
| 282 | return true; |
| 283 | } |
| 284 | |
| 285 | bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate, |
| 286 | WasmModuleInstance* instance) { |
| 287 | instance->globals_size = AllocateGlobalsOffsets(instance->module->globals); |
| 288 | |
| 289 | if (instance->globals_size > 0) { |
| 290 | instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size, |
| 291 | &instance->globals_start); |
| 292 | if (!instance->globals_start) { |
| 293 | // Not enough space for backing store of globals. |
| 294 | thrower->Error("Out of memory: wasm globals"); |
| 295 | return false; |
| 296 | } |
| 297 | } |
| 298 | return true; |
| 299 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 300 | } // namespace |
| 301 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 302 | WasmModule::WasmModule() |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 303 | : shared_isolate(nullptr), |
| 304 | module_start(nullptr), |
| 305 | module_end(nullptr), |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 306 | min_mem_pages(0), |
| 307 | max_mem_pages(0), |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 308 | mem_export(false), |
| 309 | mem_external(false), |
| 310 | start_function_index(-1), |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 311 | origin(kWasmOrigin) {} |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 312 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 313 | static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower, |
| 314 | const char* error, uint32_t index, |
| 315 | wasm::WasmName module_name, |
| 316 | wasm::WasmName function_name) { |
| 317 | if (function_name.name) { |
| 318 | thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s", |
| 319 | index, module_name.length, module_name.name, |
| 320 | function_name.length, function_name.name, error); |
| 321 | } else { |
| 322 | thrower.Error("Import #%d module=\"%.*s\" error: %s", index, |
| 323 | module_name.length, module_name.name, error); |
| 324 | } |
| 325 | thrower.Error("Import "); |
| 326 | return MaybeHandle<JSFunction>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 327 | } |
| 328 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 329 | static MaybeHandle<JSFunction> LookupFunction( |
| 330 | ErrorThrower& thrower, Factory* factory, Handle<JSObject> ffi, |
| 331 | uint32_t index, wasm::WasmName module_name, wasm::WasmName function_name) { |
| 332 | if (ffi.is_null()) { |
| 333 | return ReportFFIError(thrower, "FFI is not an object", index, module_name, |
| 334 | function_name); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 335 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 336 | |
| 337 | // Look up the module first. |
| 338 | Handle<String> name = factory->InternalizeUtf8String( |
| 339 | Vector<const char>(module_name.name, module_name.length)); |
| 340 | MaybeHandle<Object> result = Object::GetProperty(ffi, name); |
| 341 | if (result.is_null()) { |
| 342 | return ReportFFIError(thrower, "module not found", index, module_name, |
| 343 | function_name); |
| 344 | } |
| 345 | |
| 346 | Handle<Object> module = result.ToHandleChecked(); |
| 347 | |
| 348 | if (!module->IsJSReceiver()) { |
| 349 | return ReportFFIError(thrower, "module is not an object or function", index, |
| 350 | module_name, function_name); |
| 351 | } |
| 352 | |
| 353 | Handle<Object> function; |
| 354 | if (function_name.name) { |
| 355 | // Look up the function in the module. |
| 356 | Handle<String> name = factory->InternalizeUtf8String( |
| 357 | Vector<const char>(function_name.name, function_name.length)); |
| 358 | MaybeHandle<Object> result = Object::GetProperty(module, name); |
| 359 | if (result.is_null()) { |
| 360 | return ReportFFIError(thrower, "function not found", index, module_name, |
| 361 | function_name); |
| 362 | } |
| 363 | function = result.ToHandleChecked(); |
| 364 | } else { |
| 365 | // No function specified. Use the "default export". |
| 366 | function = module; |
| 367 | } |
| 368 | |
| 369 | if (!function->IsJSFunction()) { |
| 370 | return ReportFFIError(thrower, "not a function", index, module_name, |
| 371 | function_name); |
| 372 | } |
| 373 | |
| 374 | return Handle<JSFunction>::cast(function); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 375 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 376 | |
| 377 | // Instantiates a wasm module as a JSObject. |
| 378 | // * allocates a backing store of {mem_size} bytes. |
| 379 | // * installs a named property "memory" for that buffer if exported |
| 380 | // * installs named properties on the object for exported functions |
| 381 | // * compiles wasm code to machine code |
| 382 | MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, |
| 383 | Handle<JSObject> ffi, |
| 384 | Handle<JSArrayBuffer> memory) { |
| 385 | this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate. |
| 386 | ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 387 | Factory* factory = isolate->factory(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 388 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 389 | //------------------------------------------------------------------------- |
| 390 | // Allocate the instance and its JS counterpart. |
| 391 | //------------------------------------------------------------------------- |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 392 | Handle<Map> map = factory->NewMap( |
| 393 | JS_OBJECT_TYPE, |
| 394 | JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 395 | WasmModuleInstance instance(this); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 396 | instance.context = isolate->native_context(); |
| 397 | instance.js_object = factory->NewJSObjectFromMap(map, TENURED); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 398 | Handle<FixedArray> code_table = |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 399 | factory->NewFixedArray(static_cast<int>(functions.size()), TENURED); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 400 | instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 401 | |
| 402 | //------------------------------------------------------------------------- |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 403 | // Allocate and initialize the linear memory. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 404 | //------------------------------------------------------------------------- |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 405 | if (memory.is_null()) { |
| 406 | if (!AllocateMemory(&thrower, isolate, &instance)) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 407 | return MaybeHandle<JSObject>(); |
| 408 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 409 | } else { |
| 410 | SetMemory(&instance, memory); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 411 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 412 | instance.js_object->SetInternalField(kWasmMemArrayBuffer, |
| 413 | *instance.mem_buffer); |
| 414 | LoadDataSegments(this, instance.mem_start, instance.mem_size); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 415 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 416 | //------------------------------------------------------------------------- |
| 417 | // Allocate the globals area if necessary. |
| 418 | //------------------------------------------------------------------------- |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 419 | if (!AllocateGlobals(&thrower, isolate, &instance)) { |
| 420 | return MaybeHandle<JSObject>(); |
| 421 | } |
| 422 | if (!instance.globals_buffer.is_null()) { |
| 423 | instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer, |
| 424 | *instance.globals_buffer); |
| 425 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 426 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 427 | //------------------------------------------------------------------------- |
| 428 | // Compile wrappers to imported functions. |
| 429 | //------------------------------------------------------------------------- |
| 430 | uint32_t index = 0; |
| 431 | instance.function_table = BuildFunctionTable(isolate, this); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 432 | WasmLinker linker(isolate, functions.size()); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 433 | ModuleEnv module_env; |
| 434 | module_env.module = this; |
| 435 | module_env.instance = &instance; |
| 436 | module_env.linker = &linker; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 437 | module_env.origin = origin; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 438 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 439 | if (import_table.size() > 0) { |
| 440 | instance.import_code.reserve(import_table.size()); |
| 441 | for (const WasmImport& import : import_table) { |
| 442 | WasmName module_name = |
| 443 | GetNameOrNull(import.module_name_offset, import.module_name_length); |
| 444 | WasmName function_name = GetNameOrNull(import.function_name_offset, |
| 445 | import.function_name_length); |
| 446 | MaybeHandle<JSFunction> function = LookupFunction( |
| 447 | thrower, factory, ffi, index, module_name, function_name); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 448 | if (function.is_null()) return MaybeHandle<JSObject>(); |
| 449 | Handle<Code> code = compiler::CompileWasmToJSWrapper( |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 450 | isolate, &module_env, function.ToHandleChecked(), import.sig, |
| 451 | module_name, function_name); |
| 452 | instance.import_code.push_back(code); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 453 | index++; |
| 454 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 455 | } |
| 456 | |
| 457 | //------------------------------------------------------------------------- |
| 458 | // Compile all functions in the module. |
| 459 | //------------------------------------------------------------------------- |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 460 | |
| 461 | // First pass: compile each function and initialize the code table. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 462 | index = FLAG_skip_compiling_wasm_funcs; |
| 463 | while (index < functions.size()) { |
| 464 | const WasmFunction& func = functions[index]; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 465 | if (thrower.error()) break; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 466 | DCHECK_EQ(index, func.func_index); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 467 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 468 | WasmName str = GetName(func.name_offset, func.name_length); |
| 469 | WasmName str_null = {nullptr, 0}; |
| 470 | Handle<String> name = factory->InternalizeUtf8String( |
| 471 | Vector<const char>(str.name, str.length)); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 472 | Handle<Code> code = Handle<Code>::null(); |
| 473 | Handle<JSFunction> function = Handle<JSFunction>::null(); |
| 474 | if (func.external) { |
| 475 | // Lookup external function in FFI object. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 476 | MaybeHandle<JSFunction> function = |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 477 | LookupFunction(thrower, factory, ffi, index, str, str_null); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 478 | if (function.is_null()) return MaybeHandle<JSObject>(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 479 | code = compiler::CompileWasmToJSWrapper(isolate, &module_env, |
| 480 | function.ToHandleChecked(), |
| 481 | func.sig, str, str_null); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 482 | } else { |
| 483 | // Compile the function. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 484 | code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 485 | if (code.is_null()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 486 | thrower.Error("Compilation of #%d:%.*s failed.", index, str.length, |
| 487 | str.name); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 488 | return MaybeHandle<JSObject>(); |
| 489 | } |
| 490 | if (func.exported) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 491 | function = compiler::CompileJSToWasmWrapper( |
| 492 | isolate, &module_env, name, code, instance.js_object, index); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 493 | } |
| 494 | } |
| 495 | if (!code.is_null()) { |
| 496 | // Install the code into the linker table. |
| 497 | linker.Finish(index, code); |
| 498 | code_table->set(index, *code); |
| 499 | } |
| 500 | if (func.exported) { |
| 501 | // Exported functions are installed as read-only properties on the module. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 502 | JSObject::AddProperty(instance.js_object, name, function, READ_ONLY); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 503 | } |
| 504 | index++; |
| 505 | } |
| 506 | |
| 507 | // Second pass: patch all direct call sites. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 508 | linker.Link(instance.function_table, this->function_table); |
| 509 | instance.js_object->SetInternalField(kWasmModuleFunctionTable, |
| 510 | Smi::FromInt(0)); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 511 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 512 | //------------------------------------------------------------------------- |
| 513 | // Create and populate the exports object. |
| 514 | //------------------------------------------------------------------------- |
| 515 | if (export_table.size() > 0 || mem_export) { |
| 516 | index = 0; |
| 517 | // Create the "exports" object. |
| 518 | Handle<JSFunction> object_function = Handle<JSFunction>( |
| 519 | isolate->native_context()->object_function(), isolate); |
| 520 | Handle<JSObject> exports_object = |
| 521 | factory->NewJSObject(object_function, TENURED); |
| 522 | Handle<String> exports_name = factory->InternalizeUtf8String("exports"); |
| 523 | JSObject::AddProperty(instance.js_object, exports_name, exports_object, |
| 524 | READ_ONLY); |
| 525 | |
| 526 | // Compile wrappers and add them to the exports object. |
| 527 | for (const WasmExport& exp : export_table) { |
| 528 | if (thrower.error()) break; |
| 529 | WasmName str = GetName(exp.name_offset, exp.name_length); |
| 530 | Handle<String> name = factory->InternalizeUtf8String( |
| 531 | Vector<const char>(str.name, str.length)); |
| 532 | Handle<Code> code = linker.GetFunctionCode(exp.func_index); |
| 533 | Handle<JSFunction> function = compiler::CompileJSToWasmWrapper( |
| 534 | isolate, &module_env, name, code, instance.js_object, exp.func_index); |
| 535 | JSObject::AddProperty(exports_object, name, function, READ_ONLY); |
| 536 | } |
| 537 | |
| 538 | if (mem_export) { |
| 539 | // Export the memory as a named property. |
| 540 | Handle<String> name = factory->InternalizeUtf8String("memory"); |
| 541 | JSObject::AddProperty(exports_object, name, instance.mem_buffer, |
| 542 | READ_ONLY); |
| 543 | } |
| 544 | } |
| 545 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 546 | // Run the start function if one was specified. |
| 547 | if (this->start_function_index >= 0) { |
| 548 | HandleScope scope(isolate); |
| 549 | uint32_t index = static_cast<uint32_t>(this->start_function_index); |
| 550 | Handle<String> name = isolate->factory()->NewStringFromStaticChars("start"); |
| 551 | Handle<Code> code = linker.GetFunctionCode(index); |
| 552 | Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( |
| 553 | isolate, &module_env, name, code, instance.js_object, index); |
| 554 | |
| 555 | // Call the JS function. |
| 556 | Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); |
| 557 | MaybeHandle<Object> retval = |
| 558 | Execution::Call(isolate, jsfunc, undefined, 0, nullptr); |
| 559 | |
| 560 | if (retval.is_null()) { |
| 561 | thrower.Error("WASM.instantiateModule(): start function failed"); |
| 562 | } |
| 563 | } |
| 564 | return instance.js_object; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 565 | } |
| 566 | |
| 567 | |
| 568 | Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) { |
| 569 | DCHECK(IsValidFunction(index)); |
| 570 | if (linker) return linker->GetFunctionCode(index); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 571 | return instance ? instance->function_code[index] : Handle<Code>::null(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 572 | } |
| 573 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 574 | Handle<Code> ModuleEnv::GetImportCode(uint32_t index) { |
| 575 | DCHECK(IsValidImport(index)); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 576 | return instance ? instance->import_code[index] : Handle<Code>::null(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 577 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 578 | |
| 579 | compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, |
| 580 | uint32_t index) { |
| 581 | DCHECK(IsValidFunction(index)); |
| 582 | // Always make a direct call to whatever is in the table at that location. |
| 583 | // A wrapper will be generated for FFI calls. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 584 | WasmFunction* function = &module->functions[index]; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 585 | return GetWasmCallDescriptor(zone, function->sig); |
| 586 | } |
| 587 | |
| 588 | |
| 589 | int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, |
| 590 | const byte* module_end, bool asm_js) { |
| 591 | HandleScope scope(isolate); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 592 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 593 | // Decode the module, but don't verify function bodies, since we'll |
| 594 | // be compiling them anyway. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 595 | ModuleResult result = DecodeWasmModule(isolate, &zone, module_start, |
| 596 | module_end, false, kWasmOrigin); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 597 | if (result.failed()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 598 | if (result.val) { |
| 599 | delete result.val; |
| 600 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 601 | // Module verification failed. throw. |
| 602 | std::ostringstream str; |
| 603 | str << "WASM.compileRun() failed: " << result; |
| 604 | isolate->Throw( |
| 605 | *isolate->factory()->NewStringFromAsciiChecked(str.str().c_str())); |
| 606 | return -1; |
| 607 | } |
| 608 | |
| 609 | int32_t retval = CompileAndRunWasmModule(isolate, result.val); |
| 610 | delete result.val; |
| 611 | return retval; |
| 612 | } |
| 613 | |
| 614 | |
| 615 | int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) { |
| 616 | ErrorThrower thrower(isolate, "CompileAndRunWasmModule"); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 617 | WasmModuleInstance instance(module); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 618 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 619 | // Allocate and initialize the linear memory. |
| 620 | if (!AllocateMemory(&thrower, isolate, &instance)) { |
| 621 | return -1; |
| 622 | } |
| 623 | LoadDataSegments(module, instance.mem_start, instance.mem_size); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 624 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 625 | // Allocate the globals area if necessary. |
| 626 | if (!AllocateGlobals(&thrower, isolate, &instance)) { |
| 627 | return -1; |
| 628 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 629 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 630 | // Build the function table. |
| 631 | instance.function_table = BuildFunctionTable(isolate, module); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 632 | |
| 633 | // Create module environment. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 634 | WasmLinker linker(isolate, module->functions.size()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 635 | ModuleEnv module_env; |
| 636 | module_env.module = module; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 637 | module_env.instance = &instance; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 638 | module_env.linker = &linker; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 639 | module_env.origin = module->origin; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 640 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 641 | // Compile all functions. |
| 642 | Handle<Code> main_code = Handle<Code>::null(); // record last code. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 643 | uint32_t index = 0; |
| 644 | int main_index = 0; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 645 | for (const WasmFunction& func : module->functions) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 646 | DCHECK_EQ(index, func.func_index); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 647 | if (!func.external) { |
| 648 | // Compile the function and install it in the code table. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 649 | Handle<Code> code = |
| 650 | compiler::CompileWasmFunction(thrower, isolate, &module_env, func); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 651 | if (!code.is_null()) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 652 | if (func.exported) { |
| 653 | main_code = code; |
| 654 | main_index = index; |
| 655 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 656 | linker.Finish(index, code); |
| 657 | } |
| 658 | if (thrower.error()) return -1; |
| 659 | } |
| 660 | index++; |
| 661 | } |
| 662 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 663 | if (main_code.is_null()) { |
| 664 | thrower.Error("WASM.compileRun() failed: no main code found"); |
| 665 | return -1; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 666 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 667 | |
| 668 | linker.Link(instance.function_table, instance.module->function_table); |
| 669 | |
| 670 | // Wrap the main code so it can be called as a JS function. |
| 671 | Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); |
| 672 | Handle<JSObject> module_object = Handle<JSObject>(0, isolate); |
| 673 | Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( |
| 674 | isolate, &module_env, name, main_code, module_object, main_index); |
| 675 | |
| 676 | // Call the JS function. |
| 677 | Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); |
| 678 | MaybeHandle<Object> retval = |
| 679 | Execution::Call(isolate, jsfunc, undefined, 0, nullptr); |
| 680 | |
| 681 | // The result should be a number. |
| 682 | if (retval.is_null()) { |
| 683 | thrower.Error("WASM.compileRun() failed: Invocation was null"); |
| 684 | return -1; |
| 685 | } |
| 686 | Handle<Object> result = retval.ToHandleChecked(); |
| 687 | if (result->IsSmi()) { |
| 688 | return Smi::cast(*result)->value(); |
| 689 | } |
| 690 | if (result->IsHeapNumber()) { |
| 691 | return static_cast<int32_t>(HeapNumber::cast(*result)->value()); |
| 692 | } |
| 693 | thrower.Error("WASM.compileRun() failed: Return value should be number"); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 694 | return -1; |
| 695 | } |
| 696 | } // namespace wasm |
| 697 | } // namespace internal |
| 698 | } // namespace v8 |