blob: 02d197c547b5ff8362c836b0f6d25c7fadad1ed7 [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
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
18namespace v8 {
19namespace internal {
20namespace wasm {
21
22std::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
33std::ostream& operator<<(std::ostream& os, const WasmFunction& function) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010034 os << "WASM function with signature " << *function.sig;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036 os << " locals: ";
Ben Murdoch097c5b22016-05-18 11:27:45 +010037 if (function.local_i32_count) os << function.local_i32_count << " i32s ";
38 if (function.local_i64_count) os << function.local_i64_count << " i64s ";
39 if (function.local_f32_count) os << function.local_f32_count << " f32s ";
40 if (function.local_f64_count) os << function.local_f64_count << " f64s ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041
42 os << " code bytes: "
43 << (function.code_end_offset - function.code_start_offset);
44 return os;
45}
46
Ben Murdoch097c5b22016-05-18 11:27:45 +010047std::ostream& operator<<(std::ostream& os, const WasmFunctionName& pair) {
48 os << "#" << pair.function_->func_index << ":";
49 if (pair.function_->name_offset > 0) {
50 if (pair.module_) {
51 os << pair.module_->GetName(pair.function_->name_offset);
52 } else {
53 os << "+" << pair.function_->func_index;
54 }
55 } else {
56 os << "?";
57 }
58 return os;
59}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060
61// A helper class for compiling multiple wasm functions that offers
62// placeholder code objects for calling functions that are not yet compiled.
63class WasmLinker {
64 public:
65 WasmLinker(Isolate* isolate, size_t size)
66 : isolate_(isolate), placeholder_code_(size), function_code_(size) {}
67
68 // Get the code object for a function, allocating a placeholder if it has
69 // not yet been compiled.
70 Handle<Code> GetFunctionCode(uint32_t index) {
71 DCHECK(index < function_code_.size());
72 if (function_code_[index].is_null()) {
73 // Create a placeholder code object and encode the corresponding index in
74 // the {constant_pool_offset} field of the code object.
75 // TODO(titzer): placeholder code objects are somewhat dangerous.
76 Handle<Code> self(nullptr, isolate_);
77 byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions.
78 CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr};
79 Handle<Code> code = isolate_->factory()->NewCode(
80 desc, Code::KindField::encode(Code::WASM_FUNCTION), self);
81 code->set_constant_pool_offset(index + kPlaceholderMarker);
82 placeholder_code_[index] = code;
83 function_code_[index] = code;
84 }
85 return function_code_[index];
86 }
87
88 void Finish(uint32_t index, Handle<Code> code) {
89 DCHECK(index < function_code_.size());
90 function_code_[index] = code;
91 }
92
93 void Link(Handle<FixedArray> function_table,
94 std::vector<uint16_t>* functions) {
95 for (size_t i = 0; i < function_code_.size(); i++) {
96 LinkFunction(function_code_[i]);
97 }
98 if (functions && !function_table.is_null()) {
99 int table_size = static_cast<int>(functions->size());
100 DCHECK_EQ(function_table->length(), table_size * 2);
101 for (int i = 0; i < table_size; i++) {
102 function_table->set(i + table_size, *function_code_[functions->at(i)]);
103 }
104 }
105 }
106
107 private:
108 static const int kPlaceholderMarker = 1000000000;
109
110 Isolate* isolate_;
111 std::vector<Handle<Code>> placeholder_code_;
112 std::vector<Handle<Code>> function_code_;
113
114 void LinkFunction(Handle<Code> code) {
115 bool modified = false;
116 int mode_mask = RelocInfo::kCodeTargetMask;
117 AllowDeferredHandleDereference embedding_raw_address;
118 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
119 RelocInfo::Mode mode = it.rinfo()->rmode();
120 if (RelocInfo::IsCodeTarget(mode)) {
121 Code* target =
122 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
123 if (target->kind() == Code::WASM_FUNCTION &&
124 target->constant_pool_offset() >= kPlaceholderMarker) {
125 // Patch direct calls to placeholder code objects.
126 uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
127 CHECK(index < function_code_.size());
128 Handle<Code> new_target = function_code_[index];
129 if (target != *new_target) {
130 CHECK_EQ(*placeholder_code_[index], target);
131 it.rinfo()->set_target_address(new_target->instruction_start(),
132 SKIP_WRITE_BARRIER,
133 SKIP_ICACHE_FLUSH);
134 modified = true;
135 }
136 }
137 }
138 }
139 if (modified) {
140 Assembler::FlushICache(isolate_, code->instruction_start(),
141 code->instruction_size());
142 }
143 }
144};
145
146namespace {
147// Internal constants for the layout of the module object.
148const int kWasmModuleInternalFieldCount = 4;
149const int kWasmModuleFunctionTable = 0;
150const int kWasmModuleCodeTable = 1;
151const int kWasmMemArrayBuffer = 2;
152const int kWasmGlobalsArrayBuffer = 3;
153
154
155size_t AllocateGlobalsOffsets(std::vector<WasmGlobal>* globals) {
156 uint32_t offset = 0;
157 if (!globals) return 0;
158 for (WasmGlobal& global : *globals) {
159 byte size = WasmOpcodes::MemSize(global.type);
160 offset = (offset + size - 1) & ~(size - 1); // align
161 global.offset = offset;
162 offset += size;
163 }
164 return offset;
165}
166
167
168void LoadDataSegments(WasmModule* module, byte* mem_addr, size_t mem_size) {
169 for (const WasmDataSegment& segment : *module->data_segments) {
170 if (!segment.init) continue;
171 CHECK_LT(segment.dest_addr, mem_size);
172 CHECK_LE(segment.source_size, mem_size);
173 CHECK_LE(segment.dest_addr + segment.source_size, mem_size);
174 byte* addr = mem_addr + segment.dest_addr;
175 memcpy(addr, module->module_start + segment.source_offset,
176 segment.source_size);
177 }
178}
179
180
181Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) {
182 if (!module->function_table || module->function_table->size() == 0) {
183 return Handle<FixedArray>::null();
184 }
185 int table_size = static_cast<int>(module->function_table->size());
186 Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
187 for (int i = 0; i < table_size; i++) {
188 WasmFunction* function =
189 &module->functions->at(module->function_table->at(i));
190 fixed->set(i, Smi::FromInt(function->sig_index));
191 }
192 return fixed;
193}
194
Ben Murdoch097c5b22016-05-18 11:27:45 +0100195Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 byte** backing_store) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100197 if (size > (1 << WasmModule::kMaxMemSize)) {
198 // TODO(titzer): lift restriction on maximum memory allocated here.
199 *backing_store = nullptr;
200 return Handle<JSArrayBuffer>::null();
201 }
202 void* memory =
203 isolate->array_buffer_allocator()->Allocate(static_cast<int>(size));
204 if (!memory) {
205 *backing_store = nullptr;
206 return Handle<JSArrayBuffer>::null();
207 }
208
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 *backing_store = reinterpret_cast<byte*>(memory);
210
211#if DEBUG
212 // Double check the API allocator actually zero-initialized the memory.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100213 byte* bytes = reinterpret_cast<byte*>(*backing_store);
214 for (size_t i = 0; i < size; i++) {
215 DCHECK_EQ(0, bytes[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 }
217#endif
218
219 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 buffer->set_is_neuterable(false);
222 return buffer;
223}
Ben Murdoch097c5b22016-05-18 11:27:45 +0100224
225// Set the memory for a module instance to be the {memory} array buffer.
226void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
227 memory->set_is_neuterable(false);
228 instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
229 instance->mem_size = memory->byte_length()->Number();
230 instance->mem_buffer = memory;
231}
232
233// Allocate memory for a module instance as a new JSArrayBuffer.
234bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
235 WasmModuleInstance* instance) {
236 DCHECK(instance->module);
237 DCHECK(instance->mem_buffer.is_null());
238
239 if (instance->module->min_mem_size_log2 > WasmModule::kMaxMemSize) {
240 thrower->Error("Out of memory: wasm memory too large");
241 return false;
242 }
243 instance->mem_size = static_cast<size_t>(1)
244 << instance->module->min_mem_size_log2;
245 instance->mem_buffer =
246 NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
247 if (!instance->mem_start) {
248 thrower->Error("Out of memory: wasm memory");
249 instance->mem_size = 0;
250 return false;
251 }
252 return true;
253}
254
255bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
256 WasmModuleInstance* instance) {
257 instance->globals_size = AllocateGlobalsOffsets(instance->module->globals);
258
259 if (instance->globals_size > 0) {
260 instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size,
261 &instance->globals_start);
262 if (!instance->globals_start) {
263 // Not enough space for backing store of globals.
264 thrower->Error("Out of memory: wasm globals");
265 return false;
266 }
267 }
268 return true;
269}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270} // namespace
271
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272WasmModule::WasmModule()
Ben Murdoch097c5b22016-05-18 11:27:45 +0100273 : shared_isolate(nullptr),
274 module_start(nullptr),
275 module_end(nullptr),
276 min_mem_size_log2(0),
277 max_mem_size_log2(0),
278 mem_export(false),
279 mem_external(false),
280 start_function_index(-1),
281 globals(nullptr),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 signatures(nullptr),
283 functions(nullptr),
284 data_segments(nullptr),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100285 function_table(nullptr),
286 import_table(nullptr) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287
288WasmModule::~WasmModule() {
289 if (globals) delete globals;
290 if (signatures) delete signatures;
291 if (functions) delete functions;
292 if (data_segments) delete data_segments;
293 if (function_table) delete function_table;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100294 if (import_table) delete import_table;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295}
296
Ben Murdoch097c5b22016-05-18 11:27:45 +0100297static MaybeHandle<JSFunction> LookupFunction(ErrorThrower& thrower,
298 Handle<JSObject> ffi,
299 uint32_t index,
300 Handle<String> name,
301 const char* cstr) {
302 if (!ffi.is_null()) {
303 MaybeHandle<Object> result = Object::GetProperty(ffi, name);
304 if (!result.is_null()) {
305 Handle<Object> obj = result.ToHandleChecked();
306 if (obj->IsJSFunction()) {
307 return Handle<JSFunction>::cast(obj);
308 } else {
309 thrower.Error("FFI function #%d:%s is not a JSFunction.", index, cstr);
310 return MaybeHandle<JSFunction>();
311 }
312 } else {
313 thrower.Error("FFI function #%d:%s not found.", index, cstr);
314 return MaybeHandle<JSFunction>();
315 }
316 } else {
317 thrower.Error("FFI table is not an object.");
318 return MaybeHandle<JSFunction>();
319 }
320}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321
322// Instantiates a wasm module as a JSObject.
323// * allocates a backing store of {mem_size} bytes.
324// * installs a named property "memory" for that buffer if exported
325// * installs named properties on the object for exported functions
326// * compiles wasm code to machine code
327MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
328 Handle<JSObject> ffi,
329 Handle<JSArrayBuffer> memory) {
330 this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
331 ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000333
Ben Murdoch097c5b22016-05-18 11:27:45 +0100334 //-------------------------------------------------------------------------
335 // Allocate the instance and its JS counterpart.
336 //-------------------------------------------------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 Handle<Map> map = factory->NewMap(
338 JS_OBJECT_TYPE,
339 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100340 WasmModuleInstance instance(this);
341 std::vector<Handle<Code>> import_code;
342 instance.context = isolate->native_context();
343 instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 Handle<FixedArray> code_table =
345 factory->NewFixedArray(static_cast<int>(functions->size()), TENURED);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100346 instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000347
348 //-------------------------------------------------------------------------
Ben Murdoch097c5b22016-05-18 11:27:45 +0100349 // Allocate and initialize the linear memory.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350 //-------------------------------------------------------------------------
Ben Murdoch097c5b22016-05-18 11:27:45 +0100351 if (memory.is_null()) {
352 if (!AllocateMemory(&thrower, isolate, &instance)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353 return MaybeHandle<JSObject>();
354 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100355 } else {
356 SetMemory(&instance, memory);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100358 instance.js_object->SetInternalField(kWasmMemArrayBuffer,
359 *instance.mem_buffer);
360 LoadDataSegments(this, instance.mem_start, instance.mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361
362 if (mem_export) {
363 // Export the memory as a named property.
364 Handle<String> name = factory->InternalizeUtf8String("memory");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100365 JSObject::AddProperty(instance.js_object, name, instance.mem_buffer,
366 READ_ONLY);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 }
368
369 //-------------------------------------------------------------------------
370 // Allocate the globals area if necessary.
371 //-------------------------------------------------------------------------
Ben Murdoch097c5b22016-05-18 11:27:45 +0100372 if (!AllocateGlobals(&thrower, isolate, &instance)) {
373 return MaybeHandle<JSObject>();
374 }
375 if (!instance.globals_buffer.is_null()) {
376 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
377 *instance.globals_buffer);
378 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379
Ben Murdoch097c5b22016-05-18 11:27:45 +0100380 //-------------------------------------------------------------------------
381 // Compile wrappers to imported functions.
382 //-------------------------------------------------------------------------
383 uint32_t index = 0;
384 instance.function_table = BuildFunctionTable(isolate, this);
385 WasmLinker linker(isolate, functions->size());
386 ModuleEnv module_env;
387 module_env.module = this;
388 module_env.instance = &instance;
389 module_env.linker = &linker;
390 module_env.asm_js = false;
391
392 if (import_table->size() > 0) {
393 instance.import_code = &import_code;
394 instance.import_code->reserve(import_table->size());
395 for (const WasmImport& import : *import_table) {
396 const char* cstr = GetName(import.function_name_offset);
397 Handle<String> name = factory->InternalizeUtf8String(cstr);
398 MaybeHandle<JSFunction> function =
399 LookupFunction(thrower, ffi, index, name, cstr);
400 if (function.is_null()) return MaybeHandle<JSObject>();
401 Handle<Code> code = compiler::CompileWasmToJSWrapper(
402 isolate, &module_env, function.ToHandleChecked(), import.sig, cstr);
403 instance.import_code->push_back(code);
404 index++;
405 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406 }
407
408 //-------------------------------------------------------------------------
409 // Compile all functions in the module.
410 //-------------------------------------------------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411
412 // First pass: compile each function and initialize the code table.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100413 index = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 for (const WasmFunction& func : *functions) {
415 if (thrower.error()) break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416 DCHECK_EQ(index, func.func_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417
418 const char* cstr = GetName(func.name_offset);
419 Handle<String> name = factory->InternalizeUtf8String(cstr);
420 Handle<Code> code = Handle<Code>::null();
421 Handle<JSFunction> function = Handle<JSFunction>::null();
422 if (func.external) {
423 // Lookup external function in FFI object.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100424 MaybeHandle<JSFunction> function =
425 LookupFunction(thrower, ffi, index, name, cstr);
426 if (function.is_null()) return MaybeHandle<JSObject>();
427 code = compiler::CompileWasmToJSWrapper(
428 isolate, &module_env, function.ToHandleChecked(), func.sig, cstr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 } else {
430 // Compile the function.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100431 code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 if (code.is_null()) {
433 thrower.Error("Compilation of #%d:%s failed.", index, cstr);
434 return MaybeHandle<JSObject>();
435 }
436 if (func.exported) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100437 function = compiler::CompileJSToWasmWrapper(
438 isolate, &module_env, name, code, instance.js_object, index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 }
440 }
441 if (!code.is_null()) {
442 // Install the code into the linker table.
443 linker.Finish(index, code);
444 code_table->set(index, *code);
445 }
446 if (func.exported) {
447 // Exported functions are installed as read-only properties on the module.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100448 JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000449 }
450 index++;
451 }
452
453 // Second pass: patch all direct call sites.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100454 linker.Link(instance.function_table, this->function_table);
455 instance.js_object->SetInternalField(kWasmModuleFunctionTable,
456 Smi::FromInt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457
Ben Murdoch097c5b22016-05-18 11:27:45 +0100458 // Run the start function if one was specified.
459 if (this->start_function_index >= 0) {
460 HandleScope scope(isolate);
461 uint32_t index = static_cast<uint32_t>(this->start_function_index);
462 Handle<String> name = isolate->factory()->NewStringFromStaticChars("start");
463 Handle<Code> code = linker.GetFunctionCode(index);
464 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
465 isolate, &module_env, name, code, instance.js_object, index);
466
467 // Call the JS function.
468 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
469 MaybeHandle<Object> retval =
470 Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
471
472 if (retval.is_null()) {
473 thrower.Error("WASM.instantiateModule(): start function failed");
474 }
475 }
476 return instance.js_object;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477}
478
479
480Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) {
481 DCHECK(IsValidFunction(index));
482 if (linker) return linker->GetFunctionCode(index);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100483 if (instance && instance->function_code) {
484 return instance->function_code->at(index);
485 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486 return Handle<Code>::null();
487}
488
Ben Murdoch097c5b22016-05-18 11:27:45 +0100489Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
490 DCHECK(IsValidImport(index));
491 if (instance && instance->import_code) {
492 return instance->import_code->at(index);
493 }
494 return Handle<Code>::null();
495}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496
497compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
498 uint32_t index) {
499 DCHECK(IsValidFunction(index));
500 // Always make a direct call to whatever is in the table at that location.
501 // A wrapper will be generated for FFI calls.
502 WasmFunction* function = &module->functions->at(index);
503 return GetWasmCallDescriptor(zone, function->sig);
504}
505
506
507int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
508 const byte* module_end, bool asm_js) {
509 HandleScope scope(isolate);
510 Zone zone;
511 // Decode the module, but don't verify function bodies, since we'll
512 // be compiling them anyway.
513 ModuleResult result =
514 DecodeWasmModule(isolate, &zone, module_start, module_end, false, false);
515 if (result.failed()) {
516 // Module verification failed. throw.
517 std::ostringstream str;
518 str << "WASM.compileRun() failed: " << result;
519 isolate->Throw(
520 *isolate->factory()->NewStringFromAsciiChecked(str.str().c_str()));
521 return -1;
522 }
523
524 int32_t retval = CompileAndRunWasmModule(isolate, result.val);
525 delete result.val;
526 return retval;
527}
528
529
530int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
531 ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100532 WasmModuleInstance instance(module);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533
Ben Murdoch097c5b22016-05-18 11:27:45 +0100534 // Allocate and initialize the linear memory.
535 if (!AllocateMemory(&thrower, isolate, &instance)) {
536 return -1;
537 }
538 LoadDataSegments(module, instance.mem_start, instance.mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000539
Ben Murdoch097c5b22016-05-18 11:27:45 +0100540 // Allocate the globals area if necessary.
541 if (!AllocateGlobals(&thrower, isolate, &instance)) {
542 return -1;
543 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000544
Ben Murdoch097c5b22016-05-18 11:27:45 +0100545 // Build the function table.
546 instance.function_table = BuildFunctionTable(isolate, module);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547
548 // Create module environment.
549 WasmLinker linker(isolate, module->functions->size());
550 ModuleEnv module_env;
551 module_env.module = module;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100552 module_env.instance = &instance;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000553 module_env.linker = &linker;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 module_env.asm_js = false;
555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 // Compile all functions.
557 Handle<Code> main_code = Handle<Code>::null(); // record last code.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100558 uint32_t index = 0;
559 int main_index = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560 for (const WasmFunction& func : *module->functions) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100561 DCHECK_EQ(index, func.func_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 if (!func.external) {
563 // Compile the function and install it in the code table.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100564 Handle<Code> code =
565 compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 if (!code.is_null()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100567 if (func.exported) {
568 main_code = code;
569 main_index = index;
570 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000571 linker.Finish(index, code);
572 }
573 if (thrower.error()) return -1;
574 }
575 index++;
576 }
577
Ben Murdoch097c5b22016-05-18 11:27:45 +0100578 if (main_code.is_null()) {
579 thrower.Error("WASM.compileRun() failed: no main code found");
580 return -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100582
583 linker.Link(instance.function_table, instance.module->function_table);
584
585 // Wrap the main code so it can be called as a JS function.
586 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
587 Handle<JSObject> module_object = Handle<JSObject>(0, isolate);
588 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
589 isolate, &module_env, name, main_code, module_object, main_index);
590
591 // Call the JS function.
592 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
593 MaybeHandle<Object> retval =
594 Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
595
596 // The result should be a number.
597 if (retval.is_null()) {
598 thrower.Error("WASM.compileRun() failed: Invocation was null");
599 return -1;
600 }
601 Handle<Object> result = retval.ToHandleChecked();
602 if (result->IsSmi()) {
603 return Smi::cast(*result)->value();
604 }
605 if (result->IsHeapNumber()) {
606 return static_cast<int32_t>(HeapNumber::cast(*result)->value());
607 }
608 thrower.Error("WASM.compileRun() failed: Return value should be number");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 return -1;
610}
611} // namespace wasm
612} // namespace internal
613} // namespace v8