blob: c9a42797eb93b5781e5c5ed6c2151e680879efa9 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
Ben Murdochc5610432016-08-08 18:44:38 +01005#include "src/base/atomic-utils.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006#include "src/macro-assembler.h"
7#include "src/objects.h"
Ben Murdochc5610432016-08-08 18:44:38 +01008#include "src/property-descriptor.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/v8.h"
10
11#include "src/simulator.h"
12
13#include "src/wasm/ast-decoder.h"
14#include "src/wasm/module-decoder.h"
Ben Murdochc5610432016-08-08 18:44:38 +010015#include "src/wasm/wasm-function-name-table.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016#include "src/wasm/wasm-module.h"
17#include "src/wasm/wasm-result.h"
18
19#include "src/compiler/wasm-compiler.h"
20
21namespace v8 {
22namespace internal {
23namespace wasm {
24
Ben Murdochda12d292016-06-02 14:46:10 +010025static const char* wasmSections[] = {
Ben Murdochc5610432016-08-08 18:44:38 +010026#define F(enumerator, order, string) string,
Ben Murdochda12d292016-06-02 14:46:10 +010027 FOR_EACH_WASM_SECTION_TYPE(F)
28#undef F
Ben Murdochc5610432016-08-08 18:44:38 +010029 "<unknown>" // entry for "Max"
Ben Murdochda12d292016-06-02 14:46:10 +010030};
31
32static uint8_t wasmSectionsLengths[]{
Ben Murdochc5610432016-08-08 18:44:38 +010033#define F(enumerator, order, string) sizeof(string) - 1,
Ben Murdochda12d292016-06-02 14:46:10 +010034 FOR_EACH_WASM_SECTION_TYPE(F)
35#undef F
Ben Murdochc5610432016-08-08 18:44:38 +010036 9 // entry for "Max"
37};
38
39static uint8_t wasmSectionsOrders[]{
40#define F(enumerator, order, string) order,
41 FOR_EACH_WASM_SECTION_TYPE(F)
42#undef F
43 0 // entry for "Max"
Ben Murdochda12d292016-06-02 14:46:10 +010044};
45
46static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) ==
Ben Murdochc5610432016-08-08 18:44:38 +010047 (size_t)WasmSection::Code::Max + 1,
Ben Murdochda12d292016-06-02 14:46:10 +010048 "expected enum WasmSection::Code to be monotonic from 0");
49
50WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; }
51WasmSection::Code WasmSection::end() { return WasmSection::Code::Max; }
52WasmSection::Code WasmSection::next(WasmSection::Code code) {
53 return (WasmSection::Code)(1 + (uint32_t)code);
54}
55
56const char* WasmSection::getName(WasmSection::Code code) {
57 return wasmSections[(size_t)code];
58}
59
60size_t WasmSection::getNameLength(WasmSection::Code code) {
61 return wasmSectionsLengths[(size_t)code];
62}
63
Ben Murdochc5610432016-08-08 18:44:38 +010064int WasmSection::getOrder(WasmSection::Code code) {
65 return wasmSectionsOrders[(size_t)code];
66}
67
68WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) {
69 // TODO(jfb) Linear search, it may be better to do a common-prefix search.
70 for (Code i = begin(); i != end(); i = next(i)) {
71 if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) {
72 return i;
73 }
74 }
75 return Code::Max;
76}
77
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
79 os << "WASM module with ";
Ben Murdochda12d292016-06-02 14:46:10 +010080 os << (module.min_mem_pages * module.kPageSize) << " min mem";
81 os << (module.max_mem_pages * module.kPageSize) << " max mem";
82 os << module.functions.size() << " functions";
83 os << module.functions.size() << " globals";
84 os << module.functions.size() << " data segments";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 return os;
86}
87
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088std::ostream& operator<<(std::ostream& os, const WasmFunction& function) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010089 os << "WASM function with signature " << *function.sig;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 os << " code bytes: "
92 << (function.code_end_offset - function.code_start_offset);
93 return os;
94}
95
Ben Murdoch097c5b22016-05-18 11:27:45 +010096std::ostream& operator<<(std::ostream& os, const WasmFunctionName& pair) {
97 os << "#" << pair.function_->func_index << ":";
98 if (pair.function_->name_offset > 0) {
99 if (pair.module_) {
Ben Murdochda12d292016-06-02 14:46:10 +0100100 WasmName name = pair.module_->GetName(pair.function_->name_offset,
101 pair.function_->name_length);
Ben Murdochc5610432016-08-08 18:44:38 +0100102 os.write(name.start(), name.length());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100103 } else {
104 os << "+" << pair.function_->func_index;
105 }
106 } else {
107 os << "?";
108 }
109 return os;
110}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111
112// A helper class for compiling multiple wasm functions that offers
113// placeholder code objects for calling functions that are not yet compiled.
114class WasmLinker {
115 public:
116 WasmLinker(Isolate* isolate, size_t size)
117 : isolate_(isolate), placeholder_code_(size), function_code_(size) {}
118
119 // Get the code object for a function, allocating a placeholder if it has
120 // not yet been compiled.
121 Handle<Code> GetFunctionCode(uint32_t index) {
122 DCHECK(index < function_code_.size());
123 if (function_code_[index].is_null()) {
124 // Create a placeholder code object and encode the corresponding index in
125 // the {constant_pool_offset} field of the code object.
126 // TODO(titzer): placeholder code objects are somewhat dangerous.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions.
128 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr};
129 Handle<Code> code = isolate_->factory()->NewCode(
Ben Murdochc5610432016-08-08 18:44:38 +0100130 desc, Code::KindField::encode(Code::WASM_FUNCTION),
131 Handle<Object>::null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 code->set_constant_pool_offset(index + kPlaceholderMarker);
133 placeholder_code_[index] = code;
134 function_code_[index] = code;
135 }
136 return function_code_[index];
137 }
138
139 void Finish(uint32_t index, Handle<Code> code) {
140 DCHECK(index < function_code_.size());
141 function_code_[index] = code;
142 }
143
144 void Link(Handle<FixedArray> function_table,
Ben Murdochda12d292016-06-02 14:46:10 +0100145 std::vector<uint16_t>& functions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 for (size_t i = 0; i < function_code_.size(); i++) {
147 LinkFunction(function_code_[i]);
148 }
Ben Murdochda12d292016-06-02 14:46:10 +0100149 if (!function_table.is_null()) {
150 int table_size = static_cast<int>(functions.size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 DCHECK_EQ(function_table->length(), table_size * 2);
152 for (int i = 0; i < table_size; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100153 function_table->set(i + table_size, *function_code_[functions[i]]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154 }
155 }
156 }
157
158 private:
159 static const int kPlaceholderMarker = 1000000000;
160
161 Isolate* isolate_;
162 std::vector<Handle<Code>> placeholder_code_;
163 std::vector<Handle<Code>> function_code_;
164
165 void LinkFunction(Handle<Code> code) {
166 bool modified = false;
167 int mode_mask = RelocInfo::kCodeTargetMask;
168 AllowDeferredHandleDereference embedding_raw_address;
169 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
170 RelocInfo::Mode mode = it.rinfo()->rmode();
171 if (RelocInfo::IsCodeTarget(mode)) {
172 Code* target =
173 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
174 if (target->kind() == Code::WASM_FUNCTION &&
175 target->constant_pool_offset() >= kPlaceholderMarker) {
176 // Patch direct calls to placeholder code objects.
177 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
178 CHECK(index < function_code_.size());
179 Handle<Code> new_target = function_code_[index];
180 if (target != *new_target) {
181 CHECK_EQ(*placeholder_code_[index], target);
182 it.rinfo()->set_target_address(new_target->instruction_start(),
183 SKIP_WRITE_BARRIER,
184 SKIP_ICACHE_FLUSH);
185 modified = true;
186 }
187 }
188 }
189 }
190 if (modified) {
191 Assembler::FlushICache(isolate_, code->instruction_start(),
192 code->instruction_size());
193 }
194 }
195};
196
197namespace {
198// Internal constants for the layout of the module object.
Ben Murdochc5610432016-08-08 18:44:38 +0100199const int kWasmModuleInternalFieldCount = 5;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200const int kWasmModuleFunctionTable = 0;
201const int kWasmModuleCodeTable = 1;
202const int kWasmMemArrayBuffer = 2;
203const int kWasmGlobalsArrayBuffer = 3;
Ben Murdochc5610432016-08-08 18:44:38 +0100204const int kWasmFunctionNamesArray = 4;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205
Ben Murdochda12d292016-06-02 14:46:10 +0100206size_t AllocateGlobalsOffsets(std::vector<WasmGlobal>& globals) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 uint32_t offset = 0;
Ben Murdochda12d292016-06-02 14:46:10 +0100208 if (globals.size() == 0) return 0;
209 for (WasmGlobal& global : globals) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 byte size = WasmOpcodes::MemSize(global.type);
211 offset = (offset + size - 1) & ~(size - 1); // align
212 global.offset = offset;
213 offset += size;
214 }
215 return offset;
216}
217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218void LoadDataSegments(WasmModule* module, byte* mem_addr, size_t mem_size) {
Ben Murdochda12d292016-06-02 14:46:10 +0100219 for (const WasmDataSegment& segment : module->data_segments) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 if (!segment.init) continue;
Ben Murdochda12d292016-06-02 14:46:10 +0100221 if (!segment.source_size) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222 CHECK_LT(segment.dest_addr, mem_size);
223 CHECK_LE(segment.source_size, mem_size);
224 CHECK_LE(segment.dest_addr + segment.source_size, mem_size);
225 byte* addr = mem_addr + segment.dest_addr;
226 memcpy(addr, module->module_start + segment.source_offset,
227 segment.source_size);
228 }
229}
230
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) {
Ben Murdochda12d292016-06-02 14:46:10 +0100232 if (module->function_table.size() == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 return Handle<FixedArray>::null();
234 }
Ben Murdochda12d292016-06-02 14:46:10 +0100235 int table_size = static_cast<int>(module->function_table.size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
237 for (int i = 0; i < table_size; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100238 WasmFunction* function = &module->functions[module->function_table[i]];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 fixed->set(i, Smi::FromInt(function->sig_index));
240 }
241 return fixed;
242}
243
Ben Murdoch097c5b22016-05-18 11:27:45 +0100244Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 byte** backing_store) {
Ben Murdochda12d292016-06-02 14:46:10 +0100246 if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100247 // TODO(titzer): lift restriction on maximum memory allocated here.
248 *backing_store = nullptr;
249 return Handle<JSArrayBuffer>::null();
250 }
251 void* memory =
252 isolate->array_buffer_allocator()->Allocate(static_cast<int>(size));
253 if (!memory) {
254 *backing_store = nullptr;
255 return Handle<JSArrayBuffer>::null();
256 }
257
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 *backing_store = reinterpret_cast<byte*>(memory);
259
260#if DEBUG
261 // Double check the API allocator actually zero-initialized the memory.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 byte* bytes = reinterpret_cast<byte*>(*backing_store);
263 for (size_t i = 0; i < size; i++) {
264 DCHECK_EQ(0, bytes[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 }
266#endif
267
268 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100269 JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270 buffer->set_is_neuterable(false);
271 return buffer;
272}
Ben Murdoch097c5b22016-05-18 11:27:45 +0100273
274// Set the memory for a module instance to be the {memory} array buffer.
275void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
276 memory->set_is_neuterable(false);
277 instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
278 instance->mem_size = memory->byte_length()->Number();
279 instance->mem_buffer = memory;
280}
281
282// Allocate memory for a module instance as a new JSArrayBuffer.
283bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
284 WasmModuleInstance* instance) {
285 DCHECK(instance->module);
286 DCHECK(instance->mem_buffer.is_null());
287
Ben Murdochda12d292016-06-02 14:46:10 +0100288 if (instance->module->min_mem_pages > WasmModule::kMaxMemPages) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100289 thrower->Error("Out of memory: wasm memory too large");
290 return false;
291 }
Ben Murdochda12d292016-06-02 14:46:10 +0100292 instance->mem_size = WasmModule::kPageSize * instance->module->min_mem_pages;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100293 instance->mem_buffer =
294 NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
295 if (!instance->mem_start) {
296 thrower->Error("Out of memory: wasm memory");
297 instance->mem_size = 0;
298 return false;
299 }
300 return true;
301}
302
303bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
304 WasmModuleInstance* instance) {
305 instance->globals_size = AllocateGlobalsOffsets(instance->module->globals);
306
307 if (instance->globals_size > 0) {
308 instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size,
309 &instance->globals_start);
310 if (!instance->globals_start) {
311 // Not enough space for backing store of globals.
312 thrower->Error("Out of memory: wasm globals");
313 return false;
314 }
315 }
316 return true;
317}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318} // namespace
319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320WasmModule::WasmModule()
Ben Murdoch097c5b22016-05-18 11:27:45 +0100321 : shared_isolate(nullptr),
322 module_start(nullptr),
323 module_end(nullptr),
Ben Murdochda12d292016-06-02 14:46:10 +0100324 min_mem_pages(0),
325 max_mem_pages(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100326 mem_export(false),
327 mem_external(false),
328 start_function_index(-1),
Ben Murdochda12d292016-06-02 14:46:10 +0100329 origin(kWasmOrigin) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000330
Ben Murdochda12d292016-06-02 14:46:10 +0100331static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower,
332 const char* error, uint32_t index,
333 wasm::WasmName module_name,
334 wasm::WasmName function_name) {
Ben Murdochc5610432016-08-08 18:44:38 +0100335 if (function_name.start()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100336 thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s",
Ben Murdochc5610432016-08-08 18:44:38 +0100337 index, module_name.length(), module_name.start(),
338 function_name.length(), function_name.start(), error);
Ben Murdochda12d292016-06-02 14:46:10 +0100339 } else {
340 thrower.Error("Import #%d module=\"%.*s\" error: %s", index,
Ben Murdochc5610432016-08-08 18:44:38 +0100341 module_name.length(), module_name.start(), error);
Ben Murdochda12d292016-06-02 14:46:10 +0100342 }
343 thrower.Error("Import ");
344 return MaybeHandle<JSFunction>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345}
346
Ben Murdochda12d292016-06-02 14:46:10 +0100347static MaybeHandle<JSFunction> LookupFunction(
Ben Murdochc5610432016-08-08 18:44:38 +0100348 ErrorThrower& thrower, Factory* factory, Handle<JSReceiver> ffi,
Ben Murdochda12d292016-06-02 14:46:10 +0100349 uint32_t index, wasm::WasmName module_name, wasm::WasmName function_name) {
350 if (ffi.is_null()) {
351 return ReportFFIError(thrower, "FFI is not an object", index, module_name,
352 function_name);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100353 }
Ben Murdochda12d292016-06-02 14:46:10 +0100354
355 // Look up the module first.
Ben Murdochc5610432016-08-08 18:44:38 +0100356 Handle<String> name = factory->InternalizeUtf8String(module_name);
Ben Murdochda12d292016-06-02 14:46:10 +0100357 MaybeHandle<Object> result = Object::GetProperty(ffi, name);
358 if (result.is_null()) {
359 return ReportFFIError(thrower, "module not found", index, module_name,
360 function_name);
361 }
362
363 Handle<Object> module = result.ToHandleChecked();
364
365 if (!module->IsJSReceiver()) {
366 return ReportFFIError(thrower, "module is not an object or function", index,
367 module_name, function_name);
368 }
369
370 Handle<Object> function;
Ben Murdochc5610432016-08-08 18:44:38 +0100371 if (function_name.start()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100372 // Look up the function in the module.
Ben Murdochc5610432016-08-08 18:44:38 +0100373 Handle<String> name = factory->InternalizeUtf8String(function_name);
Ben Murdochda12d292016-06-02 14:46:10 +0100374 MaybeHandle<Object> result = Object::GetProperty(module, name);
375 if (result.is_null()) {
376 return ReportFFIError(thrower, "function not found", index, module_name,
377 function_name);
378 }
379 function = result.ToHandleChecked();
380 } else {
381 // No function specified. Use the "default export".
382 function = module;
383 }
384
385 if (!function->IsJSFunction()) {
386 return ReportFFIError(thrower, "not a function", index, module_name,
387 function_name);
388 }
389
390 return Handle<JSFunction>::cast(function);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100391}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392
Ben Murdochc5610432016-08-08 18:44:38 +0100393namespace {
394// Fetches the compilation unit of a wasm function and executes its parallel
395// phase.
396bool FetchAndExecuteCompilationUnit(
397 Isolate* isolate,
398 std::vector<compiler::WasmCompilationUnit*>* compilation_units,
399 std::queue<compiler::WasmCompilationUnit*>* executed_units,
400 base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) {
401 DisallowHeapAllocation no_allocation;
402 DisallowHandleAllocation no_handles;
403 DisallowHandleDereference no_deref;
404 DisallowCodeDependencyChange no_dependency_change;
405
406 // - 1 because AtomicIntrement returns the value after the atomic increment.
407 size_t index = next_unit->Increment(1) - 1;
408 if (index >= compilation_units->size()) {
409 return false;
410 }
411
412 compiler::WasmCompilationUnit* unit = compilation_units->at(index);
413 if (unit != nullptr) {
414 compiler::ExecuteCompilation(unit);
415 {
416 base::LockGuard<base::Mutex> guard(result_mutex);
417 executed_units->push(unit);
418 }
419 }
420 return true;
421}
422
423class WasmCompilationTask : public CancelableTask {
424 public:
425 WasmCompilationTask(
426 Isolate* isolate,
427 std::vector<compiler::WasmCompilationUnit*>* compilation_units,
428 std::queue<compiler::WasmCompilationUnit*>* executed_units,
429 base::Semaphore* on_finished, base::Mutex* result_mutex,
430 base::AtomicNumber<size_t>* next_unit)
431 : CancelableTask(isolate),
432 isolate_(isolate),
433 compilation_units_(compilation_units),
434 executed_units_(executed_units),
435 on_finished_(on_finished),
436 result_mutex_(result_mutex),
437 next_unit_(next_unit) {}
438
439 void RunInternal() override {
440 while (FetchAndExecuteCompilationUnit(isolate_, compilation_units_,
441 executed_units_, result_mutex_,
442 next_unit_)) {
443 }
444 on_finished_->Signal();
445 }
446
447 Isolate* isolate_;
448 std::vector<compiler::WasmCompilationUnit*>* compilation_units_;
449 std::queue<compiler::WasmCompilationUnit*>* executed_units_;
450 base::Semaphore* on_finished_;
451 base::Mutex* result_mutex_;
452 base::AtomicNumber<size_t>* next_unit_;
453};
454
455void record_code_size(uint32_t& total_code_size, Code* code) {
456 if (FLAG_print_wasm_code_size) {
457 total_code_size += code->body_size() + code->relocation_info()->length();
458 }
459}
460
461bool CompileWrappersToImportedFunctions(Isolate* isolate, WasmModule* module,
462 const Handle<JSReceiver> ffi,
463 WasmModuleInstance* instance,
464 ErrorThrower* thrower, Factory* factory,
465 ModuleEnv* module_env,
466 uint32_t& total_code_size) {
467 uint32_t index = 0;
468 if (module->import_table.size() > 0) {
469 instance->import_code.reserve(module->import_table.size());
470 for (const WasmImport& import : module->import_table) {
471 WasmName module_name = module->GetNameOrNull(import.module_name_offset,
472 import.module_name_length);
473 WasmName function_name = module->GetNameOrNull(
474 import.function_name_offset, import.function_name_length);
475 MaybeHandle<JSFunction> function = LookupFunction(
476 *thrower, factory, ffi, index, module_name, function_name);
477 if (function.is_null()) return false;
478
479 Handle<Code> code = compiler::CompileWasmToJSWrapper(
480 isolate, module_env, function.ToHandleChecked(), import.sig,
481 module_name, function_name);
482 instance->import_code.push_back(code);
483 record_code_size(total_code_size, *code);
484 index++;
485 }
486 }
487 return true;
488}
489
490void InitializeParallelCompilation(
491 Isolate* isolate, std::vector<WasmFunction>& functions,
492 std::vector<compiler::WasmCompilationUnit*>& compilation_units,
493 ModuleEnv& module_env, ErrorThrower& thrower) {
494 // Create a placeholder code object for all functions.
495 // TODO(ahaas): Maybe we could skip this for external functions.
496 for (uint32_t i = 0; i < functions.size(); i++) {
497 module_env.linker->GetFunctionCode(i);
498 }
499
500 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); i++) {
501 compilation_units[i] = compiler::CreateWasmCompilationUnit(
502 &thrower, isolate, &module_env, &functions[i], i);
503 }
504}
505
506uint32_t* StartCompilationTasks(
507 Isolate* isolate,
508 std::vector<compiler::WasmCompilationUnit*>& compilation_units,
509 std::queue<compiler::WasmCompilationUnit*>& executed_units,
510 const base::SmartPointer<base::Semaphore>& pending_tasks,
511 base::Mutex& result_mutex, base::AtomicNumber<size_t>& next_unit) {
512 const size_t num_tasks =
513 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
514 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
515 uint32_t* task_ids = new uint32_t[num_tasks];
516 for (size_t i = 0; i < num_tasks; i++) {
517 WasmCompilationTask* task =
518 new WasmCompilationTask(isolate, &compilation_units, &executed_units,
519 pending_tasks.get(), &result_mutex, &next_unit);
520 task_ids[i] = task->id();
521 V8::GetCurrentPlatform()->CallOnBackgroundThread(
522 task, v8::Platform::kShortRunningTask);
523 }
524 return task_ids;
525}
526
527void WaitForCompilationTasks(
528 Isolate* isolate, uint32_t* task_ids,
529 const base::SmartPointer<base::Semaphore>& pending_tasks) {
530 const size_t num_tasks =
531 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
532 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
533 for (size_t i = 0; i < num_tasks; i++) {
534 // If the task has not started yet, then we abort it. Otherwise we wait for
535 // it to finish.
536 if (!isolate->cancelable_task_manager()->TryAbort(task_ids[i])) {
537 pending_tasks->Wait();
538 }
539 }
540}
541
542void FinishCompilationUnits(
543 WasmModule* module,
544 std::queue<compiler::WasmCompilationUnit*>& executed_units,
545 std::vector<Handle<Code>>& results, base::Mutex& result_mutex) {
546 while (true) {
547 compiler::WasmCompilationUnit* unit = nullptr;
548 {
549 base::LockGuard<base::Mutex> guard(&result_mutex);
550 if (executed_units.empty()) {
551 break;
552 }
553 unit = executed_units.front();
554 executed_units.pop();
555 }
556 int j = compiler::GetIndexOfWasmCompilationUnit(unit);
557 results[j] = compiler::FinishCompilation(unit);
558 }
559}
560
561bool FinishCompilation(Isolate* isolate, WasmModule* module,
562 const Handle<JSReceiver> ffi,
563 const std::vector<Handle<Code>>& results,
564 const WasmModuleInstance& instance,
565 const Handle<FixedArray>& code_table,
566 ErrorThrower& thrower, Factory* factory,
567 ModuleEnv& module_env, uint32_t& total_code_size,
568 PropertyDescriptor& desc) {
569 for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
570 i < module->functions.size(); i++) {
571 const WasmFunction& func = module->functions[i];
572 if (thrower.error()) break;
573
574 DCHECK_EQ(i, func.func_index);
575 WasmName str = module->GetName(func.name_offset, func.name_length);
576 Handle<Code> code = Handle<Code>::null();
577 Handle<JSFunction> function = Handle<JSFunction>::null();
578 Handle<String> function_name = Handle<String>::null();
579 if (FLAG_wasm_num_compilation_tasks != 0) {
580 code = results[i];
581 } else {
582 // Compile the function.
583 code =
584 compiler::CompileWasmFunction(&thrower, isolate, &module_env, &func);
585 }
586 if (code.is_null()) {
587 thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(),
588 str.start());
589 return false;
590 }
591 if (func.exported) {
592 function_name = factory->InternalizeUtf8String(str);
593 function = compiler::CompileJSToWasmWrapper(
594 isolate, &module_env, function_name, code, instance.js_object, i);
595 record_code_size(total_code_size, function->code());
596 }
597 if (!code.is_null()) {
598 // Install the code into the linker table.
599 module_env.linker->Finish(i, code);
600 code_table->set(i, *code);
601 record_code_size(total_code_size, *code);
602 }
603 if (func.exported) {
604 // Exported functions are installed as read-only properties on the
605 // module.
606 desc.set_value(function);
607 Maybe<bool> status = JSReceiver::DefineOwnProperty(
608 isolate, instance.js_object, function_name, &desc,
609 Object::THROW_ON_ERROR);
610 if (!status.IsJust())
611 thrower.Error("export of %.*s failed.", str.length(), str.start());
612 }
613 }
614 return true;
615}
616} // namespace
617
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000618// Instantiates a wasm module as a JSObject.
619// * allocates a backing store of {mem_size} bytes.
620// * installs a named property "memory" for that buffer if exported
621// * installs named properties on the object for exported functions
622// * compiles wasm code to machine code
623MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
Ben Murdochc5610432016-08-08 18:44:38 +0100624 Handle<JSReceiver> ffi,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000625 Handle<JSArrayBuffer> memory) {
Ben Murdochc5610432016-08-08 18:44:38 +0100626 HistogramTimerScope wasm_instantiate_module_time_scope(
627 isolate->counters()->wasm_instantiate_module_time());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628 this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
629 ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000630 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631
Ben Murdochc5610432016-08-08 18:44:38 +0100632 PropertyDescriptor desc;
633 desc.set_writable(false);
634
635 // If FLAG_print_wasm_code_size is set, this aggregates the sum of all code
636 // objects created for this module.
637 // TODO(titzer): switch this to TRACE_EVENT
638 uint32_t total_code_size = 0;
639
Ben Murdoch097c5b22016-05-18 11:27:45 +0100640 //-------------------------------------------------------------------------
641 // Allocate the instance and its JS counterpart.
642 //-------------------------------------------------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 Handle<Map> map = factory->NewMap(
644 JS_OBJECT_TYPE,
645 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100646 WasmModuleInstance instance(this);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100647 instance.context = isolate->native_context();
648 instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649 Handle<FixedArray> code_table =
Ben Murdochda12d292016-06-02 14:46:10 +0100650 factory->NewFixedArray(static_cast<int>(functions.size()), TENURED);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100651 instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000652
653 //-------------------------------------------------------------------------
Ben Murdoch097c5b22016-05-18 11:27:45 +0100654 // Allocate and initialize the linear memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000655 //-------------------------------------------------------------------------
Ben Murdochc5610432016-08-08 18:44:38 +0100656 isolate->counters()->wasm_min_mem_pages_count()->AddSample(
657 instance.module->min_mem_pages);
658 isolate->counters()->wasm_max_mem_pages_count()->AddSample(
659 instance.module->max_mem_pages);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100660 if (memory.is_null()) {
661 if (!AllocateMemory(&thrower, isolate, &instance)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000662 return MaybeHandle<JSObject>();
663 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100664 } else {
665 SetMemory(&instance, memory);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100667 instance.js_object->SetInternalField(kWasmMemArrayBuffer,
668 *instance.mem_buffer);
669 LoadDataSegments(this, instance.mem_start, instance.mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000670
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 //-------------------------------------------------------------------------
672 // Allocate the globals area if necessary.
673 //-------------------------------------------------------------------------
Ben Murdoch097c5b22016-05-18 11:27:45 +0100674 if (!AllocateGlobals(&thrower, isolate, &instance)) {
675 return MaybeHandle<JSObject>();
676 }
677 if (!instance.globals_buffer.is_null()) {
678 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
679 *instance.globals_buffer);
680 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000681
Ben Murdochc5610432016-08-08 18:44:38 +0100682 HistogramTimerScope wasm_compile_module_time_scope(
683 isolate->counters()->wasm_compile_module_time());
684
Ben Murdoch097c5b22016-05-18 11:27:45 +0100685 instance.function_table = BuildFunctionTable(isolate, this);
Ben Murdochda12d292016-06-02 14:46:10 +0100686 WasmLinker linker(isolate, functions.size());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100687 ModuleEnv module_env;
688 module_env.module = this;
689 module_env.instance = &instance;
690 module_env.linker = &linker;
Ben Murdochda12d292016-06-02 14:46:10 +0100691 module_env.origin = origin;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100692
Ben Murdochc5610432016-08-08 18:44:38 +0100693 //-------------------------------------------------------------------------
694 // Compile wrappers to imported functions.
695 //-------------------------------------------------------------------------
696 if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance,
697 &thrower, factory, &module_env,
698 total_code_size)) {
699 return MaybeHandle<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000701 //-------------------------------------------------------------------------
702 // Compile all functions in the module.
703 //-------------------------------------------------------------------------
Ben Murdochc5610432016-08-08 18:44:38 +0100704 {
705 isolate->counters()->wasm_functions_per_module()->AddSample(
706 static_cast<int>(functions.size()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000707
Ben Murdochc5610432016-08-08 18:44:38 +0100708 // Data structures for the parallel compilation.
709 std::vector<compiler::WasmCompilationUnit*> compilation_units(
710 functions.size());
711 std::queue<compiler::WasmCompilationUnit*> executed_units;
712 std::vector<Handle<Code>> results(functions.size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713
Ben Murdochc5610432016-08-08 18:44:38 +0100714 if (FLAG_wasm_num_compilation_tasks != 0) {
715 //-----------------------------------------------------------------------
716 // For parallel compilation:
717 // 1) The main thread allocates a compilation unit for each wasm function
718 // and stores them in the vector {compilation_units}.
719 // 2) The main thread spawns {WasmCompilationTask} instances which run on
720 // the background threads.
721 // 3.a) The background threads and the main thread pick one compilation
722 // unit at a time and execute the parallel phase of the compilation
723 // unit. After finishing the execution of the parallel phase, the
724 // result is enqueued in {executed_units}.
725 // 3.b) If {executed_units} contains a compilation unit, the main thread
726 // dequeues it and finishes the compilation.
727 // 4) After the parallel phase of all compilation units has started, the
728 // main thread waits for all {WasmCompilationTask} instances to finish.
729 // 5) The main thread finishes the compilation.
730
731 // Turn on the {CanonicalHandleScope} so that the background threads can
732 // use the node cache.
733 CanonicalHandleScope canonical(isolate);
734
735 // 1) The main thread allocates a compilation unit for each wasm function
736 // and stores them in the vector {compilation_units}.
737 InitializeParallelCompilation(isolate, functions, compilation_units,
738 module_env, thrower);
739
740 // Objects for the synchronization with the background threads.
741 base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0));
742 base::Mutex result_mutex;
743 base::AtomicNumber<size_t> next_unit(
744 static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
745
746 // 2) The main thread spawns {WasmCompilationTask} instances which run on
747 // the background threads.
748 base::SmartArrayPointer<uint32_t> task_ids(
749 StartCompilationTasks(isolate, compilation_units, executed_units,
750 pending_tasks, result_mutex, next_unit));
751
752 // 3.a) The background threads and the main thread pick one compilation
753 // unit at a time and execute the parallel phase of the compilation
754 // unit. After finishing the execution of the parallel phase, the
755 // result is enqueued in {executed_units}.
756 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
757 &executed_units, &result_mutex,
758 &next_unit)) {
759 // 3.b) If {executed_units} contains a compilation unit, the main thread
760 // dequeues it and finishes the compilation unit. Compilation units
761 // are finished concurrently to the background threads to save
762 // memory.
763 FinishCompilationUnits(this, executed_units, results, result_mutex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000764 }
Ben Murdochc5610432016-08-08 18:44:38 +0100765 // 4) After the parallel phase of all compilation units has started, the
766 // main thread waits for all {WasmCompilationTask} instances to finish.
767 WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks);
768 // Finish the compilation of the remaining compilation units.
769 FinishCompilationUnits(this, executed_units, results, result_mutex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 }
Ben Murdochc5610432016-08-08 18:44:38 +0100771 // 5) The main thread finishes the compilation.
772 if (!FinishCompilation(isolate, this, ffi, results, instance, code_table,
773 thrower, factory, module_env, total_code_size,
774 desc)) {
775 return MaybeHandle<JSObject>();
Ben Murdochda12d292016-06-02 14:46:10 +0100776 }
777
Ben Murdochc5610432016-08-08 18:44:38 +0100778 // Patch all direct call sites.
779 linker.Link(instance.function_table, this->function_table);
780 instance.js_object->SetInternalField(kWasmModuleFunctionTable,
781 Smi::FromInt(0));
782
783 //-------------------------------------------------------------------------
784 // Create and populate the exports object.
785 //-------------------------------------------------------------------------
786 if (export_table.size() > 0 || mem_export) {
787 // Create the "exports" object.
788 Handle<JSFunction> object_function = Handle<JSFunction>(
789 isolate->native_context()->object_function(), isolate);
790 Handle<JSObject> exports_object =
791 factory->NewJSObject(object_function, TENURED);
792 Handle<String> exports_name = factory->InternalizeUtf8String("exports");
793 JSObject::AddProperty(instance.js_object, exports_name, exports_object,
Ben Murdochda12d292016-06-02 14:46:10 +0100794 READ_ONLY);
Ben Murdochc5610432016-08-08 18:44:38 +0100795
796 // Compile wrappers and add them to the exports object.
797 for (const WasmExport& exp : export_table) {
798 if (thrower.error()) break;
799 WasmName str = GetName(exp.name_offset, exp.name_length);
800 Handle<String> name = factory->InternalizeUtf8String(str);
801 Handle<Code> code = linker.GetFunctionCode(exp.func_index);
802 Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
803 isolate, &module_env, name, code, instance.js_object,
804 exp.func_index);
805 record_code_size(total_code_size, function->code());
806 desc.set_value(function);
807 Maybe<bool> status = JSReceiver::DefineOwnProperty(
808 isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
809 if (!status.IsJust())
810 thrower.Error("export of %.*s failed.", str.length(), str.start());
811 }
812
813 if (mem_export) {
814 // Export the memory as a named property.
815 Handle<String> name = factory->InternalizeUtf8String("memory");
816 JSObject::AddProperty(exports_object, name, instance.mem_buffer,
817 READ_ONLY);
818 }
Ben Murdochda12d292016-06-02 14:46:10 +0100819 }
820 }
821
Ben Murdochc5610432016-08-08 18:44:38 +0100822 //-------------------------------------------------------------------------
823 // Attach an array with function names and an array with offsets into that
824 // first array.
825 //-------------------------------------------------------------------------
826 {
827 Handle<Object> arr = BuildFunctionNamesTable(isolate, module_env.module);
828 instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr);
829 }
830
831 if (FLAG_print_wasm_code_size)
832 printf("Total generated wasm code: %u bytes\n", total_code_size);
833
Ben Murdoch097c5b22016-05-18 11:27:45 +0100834 // Run the start function if one was specified.
835 if (this->start_function_index >= 0) {
836 HandleScope scope(isolate);
837 uint32_t index = static_cast<uint32_t>(this->start_function_index);
838 Handle<String> name = isolate->factory()->NewStringFromStaticChars("start");
839 Handle<Code> code = linker.GetFunctionCode(index);
840 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
841 isolate, &module_env, name, code, instance.js_object, index);
842
843 // Call the JS function.
844 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
845 MaybeHandle<Object> retval =
846 Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
847
848 if (retval.is_null()) {
849 thrower.Error("WASM.instantiateModule(): start function failed");
850 }
851 }
852 return instance.js_object;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000853}
854
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000855Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) {
856 DCHECK(IsValidFunction(index));
857 if (linker) return linker->GetFunctionCode(index);
Ben Murdochda12d292016-06-02 14:46:10 +0100858 return instance ? instance->function_code[index] : Handle<Code>::null();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000859}
860
Ben Murdoch097c5b22016-05-18 11:27:45 +0100861Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
862 DCHECK(IsValidImport(index));
Ben Murdochda12d292016-06-02 14:46:10 +0100863 return instance ? instance->import_code[index] : Handle<Code>::null();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100864}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000865
866compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
867 uint32_t index) {
868 DCHECK(IsValidFunction(index));
869 // Always make a direct call to whatever is in the table at that location.
870 // A wrapper will be generated for FFI calls.
Ben Murdochda12d292016-06-02 14:46:10 +0100871 WasmFunction* function = &module->functions[index];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000872 return GetWasmCallDescriptor(zone, function->sig);
873}
874
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000875int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
876 const byte* module_end, bool asm_js) {
877 HandleScope scope(isolate);
Ben Murdochda12d292016-06-02 14:46:10 +0100878 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000879 // Decode the module, but don't verify function bodies, since we'll
880 // be compiling them anyway.
Ben Murdochda12d292016-06-02 14:46:10 +0100881 ModuleResult result = DecodeWasmModule(isolate, &zone, module_start,
882 module_end, false, kWasmOrigin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000883 if (result.failed()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100884 if (result.val) {
885 delete result.val;
886 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 // Module verification failed. throw.
888 std::ostringstream str;
889 str << "WASM.compileRun() failed: " << result;
890 isolate->Throw(
891 *isolate->factory()->NewStringFromAsciiChecked(str.str().c_str()));
892 return -1;
893 }
894
895 int32_t retval = CompileAndRunWasmModule(isolate, result.val);
896 delete result.val;
897 return retval;
898}
899
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000900int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
901 ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100902 WasmModuleInstance instance(module);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903
Ben Murdoch097c5b22016-05-18 11:27:45 +0100904 // Allocate and initialize the linear memory.
905 if (!AllocateMemory(&thrower, isolate, &instance)) {
906 return -1;
907 }
908 LoadDataSegments(module, instance.mem_start, instance.mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909
Ben Murdoch097c5b22016-05-18 11:27:45 +0100910 // Allocate the globals area if necessary.
911 if (!AllocateGlobals(&thrower, isolate, &instance)) {
912 return -1;
913 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000914
Ben Murdoch097c5b22016-05-18 11:27:45 +0100915 // Build the function table.
916 instance.function_table = BuildFunctionTable(isolate, module);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000917
918 // Create module environment.
Ben Murdochda12d292016-06-02 14:46:10 +0100919 WasmLinker linker(isolate, module->functions.size());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920 ModuleEnv module_env;
921 module_env.module = module;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100922 module_env.instance = &instance;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000923 module_env.linker = &linker;
Ben Murdochda12d292016-06-02 14:46:10 +0100924 module_env.origin = module->origin;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000925
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000926 // Compile all functions.
927 Handle<Code> main_code = Handle<Code>::null(); // record last code.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100928 uint32_t index = 0;
929 int main_index = 0;
Ben Murdochda12d292016-06-02 14:46:10 +0100930 for (const WasmFunction& func : module->functions) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100931 DCHECK_EQ(index, func.func_index);
Ben Murdochc5610432016-08-08 18:44:38 +0100932 // Compile the function and install it in the code table.
933 Handle<Code> code =
934 compiler::CompileWasmFunction(&thrower, isolate, &module_env, &func);
935 if (!code.is_null()) {
936 if (func.exported) {
937 main_code = code;
938 main_index = index;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 }
Ben Murdochc5610432016-08-08 18:44:38 +0100940 linker.Finish(index, code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000941 }
Ben Murdochc5610432016-08-08 18:44:38 +0100942 if (thrower.error()) return -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000943 index++;
944 }
945
Ben Murdoch097c5b22016-05-18 11:27:45 +0100946 if (main_code.is_null()) {
947 thrower.Error("WASM.compileRun() failed: no main code found");
948 return -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100950
951 linker.Link(instance.function_table, instance.module->function_table);
952
953 // Wrap the main code so it can be called as a JS function.
954 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
955 Handle<JSObject> module_object = Handle<JSObject>(0, isolate);
956 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
957 isolate, &module_env, name, main_code, module_object, main_index);
958
959 // Call the JS function.
960 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
961 MaybeHandle<Object> retval =
962 Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
963
964 // The result should be a number.
965 if (retval.is_null()) {
966 thrower.Error("WASM.compileRun() failed: Invocation was null");
967 return -1;
968 }
969 Handle<Object> result = retval.ToHandleChecked();
970 if (result->IsSmi()) {
971 return Smi::cast(*result)->value();
972 }
973 if (result->IsHeapNumber()) {
974 return static_cast<int32_t>(HeapNumber::cast(*result)->value());
975 }
976 thrower.Error("WASM.compileRun() failed: Return value should be number");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000977 return -1;
978}
Ben Murdochc5610432016-08-08 18:44:38 +0100979
980Handle<Object> GetWasmFunctionName(Handle<JSObject> wasm, uint32_t func_index) {
981 Handle<Object> func_names_arr_obj = handle(
982 wasm->GetInternalField(kWasmFunctionNamesArray), wasm->GetIsolate());
983 if (func_names_arr_obj->IsUndefined())
984 return func_names_arr_obj; // Return undefined.
985 return GetWasmFunctionNameFromTable(
986 Handle<ByteArray>::cast(func_names_arr_obj), func_index);
987}
988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000989} // namespace wasm
990} // namespace internal
991} // namespace v8