Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: src/wasm/wasm-module.cc

Issue 1637923002: [wasm] Factor out WasmModuleInstance from ModuleEnv. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Finish comment. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/wasm-module.h ('k') | test/cctest/wasm/test-run-wasm-js.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/macro-assembler.h" 5 #include "src/macro-assembler.h"
6 #include "src/objects.h" 6 #include "src/objects.h"
7 #include "src/v8.h" 7 #include "src/v8.h"
8 8
9 #include "src/simulator.h" 9 #include "src/simulator.h"
10 10
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 int table_size = static_cast<int>(module->function_table->size()); 176 int table_size = static_cast<int>(module->function_table->size());
177 Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size); 177 Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
178 for (int i = 0; i < table_size; i++) { 178 for (int i = 0; i < table_size; i++) {
179 WasmFunction* function = 179 WasmFunction* function =
180 &module->functions->at(module->function_table->at(i)); 180 &module->functions->at(module->function_table->at(i));
181 fixed->set(i, Smi::FromInt(function->sig_index)); 181 fixed->set(i, Smi::FromInt(function->sig_index));
182 } 182 }
183 return fixed; 183 return fixed;
184 } 184 }
185 185
186 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
187 byte** backing_store) {
188 if (size > (1 << WasmModule::kMaxMemSize)) {
189 // TODO(titzer): lift restriction on maximum memory allocated here.
190 *backing_store = nullptr;
191 return Handle<JSArrayBuffer>::null();
192 }
193 void* memory =
194 isolate->array_buffer_allocator()->Allocate(static_cast<int>(size));
195 if (!memory) {
196 *backing_store = nullptr;
197 return Handle<JSArrayBuffer>::null();
198 }
186 199
187 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, int size,
188 byte** backing_store) {
189 void* memory = isolate->array_buffer_allocator()->Allocate(size);
190 if (!memory) return Handle<JSArrayBuffer>::null();
191 *backing_store = reinterpret_cast<byte*>(memory); 200 *backing_store = reinterpret_cast<byte*>(memory);
192 201
193 #if DEBUG 202 #if DEBUG
194 // Double check the API allocator actually zero-initialized the memory. 203 // Double check the API allocator actually zero-initialized the memory.
195 for (int i = 0; i < size; i++) { 204 byte* bytes = reinterpret_cast<byte*>(*backing_store);
196 DCHECK_EQ(0, (*backing_store)[i]); 205 for (size_t i = 0; i < size; i++) {
206 DCHECK_EQ(0, bytes[i]);
197 } 207 }
198 #endif 208 #endif
199 209
200 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 210 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
201 JSArrayBuffer::Setup(buffer, isolate, false, memory, size); 211 JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
202 buffer->set_is_neuterable(false); 212 buffer->set_is_neuterable(false);
203 return buffer; 213 return buffer;
204 } 214 }
215
216 // Set the memory for a module instance to be the {memory} array buffer.
217 void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
218 memory->set_is_neuterable(false);
219 instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
220 instance->mem_size = memory->byte_length()->Number();
221 instance->mem_buffer = memory;
222 }
223
224 // Allocate memory for a module instance as a new JSArrayBuffer.
225 bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
226 WasmModuleInstance* instance) {
227 DCHECK(instance->module);
228 DCHECK(instance->mem_buffer.is_null());
229
230 if (instance->module->min_mem_size_log2 > WasmModule::kMaxMemSize) {
231 thrower->Error("Out of memory: wasm memory too large");
232 return false;
233 }
234 instance->mem_size = static_cast<size_t>(1)
235 << instance->module->min_mem_size_log2;
236 instance->mem_buffer =
237 NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
238 if (!instance->mem_start) {
239 thrower->Error("Out of memory: wasm memory");
240 instance->mem_size = 0;
241 return false;
242 }
243 return true;
244 }
245
246 bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
247 WasmModuleInstance* instance) {
248 instance->globals_size = AllocateGlobalsOffsets(instance->module->globals);
249
250 if (instance->globals_size > 0) {
251 instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size,
252 &instance->globals_start);
253 if (!instance->globals_start) {
254 // Not enough space for backing store of globals.
255 thrower->Error("Out of memory: wasm globals");
256 return false;
257 }
258 }
259 return true;
260 }
205 } // namespace 261 } // namespace
206 262
207 263
208 WasmModule::WasmModule() 264 WasmModule::WasmModule()
209 : globals(nullptr), 265 : globals(nullptr),
210 signatures(nullptr), 266 signatures(nullptr),
211 functions(nullptr), 267 functions(nullptr),
212 data_segments(nullptr), 268 data_segments(nullptr),
213 function_table(nullptr) {} 269 function_table(nullptr) {}
214 270
(...skipping 10 matching lines...) Expand all
225 // Instantiates a wasm module as a JSObject. 281 // Instantiates a wasm module as a JSObject.
226 // * allocates a backing store of {mem_size} bytes. 282 // * allocates a backing store of {mem_size} bytes.
227 // * installs a named property "memory" for that buffer if exported 283 // * installs a named property "memory" for that buffer if exported
228 // * installs named properties on the object for exported functions 284 // * installs named properties on the object for exported functions
229 // * compiles wasm code to machine code 285 // * compiles wasm code to machine code
230 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, 286 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
231 Handle<JSObject> ffi, 287 Handle<JSObject> ffi,
232 Handle<JSArrayBuffer> memory) { 288 Handle<JSArrayBuffer> memory) {
233 this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate. 289 this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
234 ErrorThrower thrower(isolate, "WasmModule::Instantiate()"); 290 ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
291 Factory* factory = isolate->factory();
235 292
236 Factory* factory = isolate->factory(); 293 //-------------------------------------------------------------------------
237 // Memory is bigger than maximum supported size. 294 // Allocate the instance and its JS counterpart.
238 if (memory.is_null() && min_mem_size_log2 > kMaxMemSize) { 295 //-------------------------------------------------------------------------
239 thrower.Error("Out of memory: wasm memory too large");
240 return MaybeHandle<JSObject>();
241 }
242
243 Handle<Map> map = factory->NewMap( 296 Handle<Map> map = factory->NewMap(
244 JS_OBJECT_TYPE, 297 JS_OBJECT_TYPE,
245 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); 298 JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
299 WasmModuleInstance instance(this);
300 instance.context = isolate->native_context();
301 instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
302 Handle<FixedArray> code_table =
303 factory->NewFixedArray(static_cast<int>(functions->size()), TENURED);
304 instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
246 305
247 //------------------------------------------------------------------------- 306 //-------------------------------------------------------------------------
248 // Allocate the module object. 307 // Allocate and initialize the linear memory.
249 //------------------------------------------------------------------------- 308 //-------------------------------------------------------------------------
250 Handle<JSObject> module = factory->NewJSObjectFromMap(map, TENURED); 309 if (memory.is_null()) {
251 Handle<FixedArray> code_table = 310 if (!AllocateMemory(&thrower, isolate, &instance)) {
252 factory->NewFixedArray(static_cast<int>(functions->size()), TENURED);
253
254 //-------------------------------------------------------------------------
255 // Allocate the linear memory.
256 //-------------------------------------------------------------------------
257 uint32_t mem_size = 1 << min_mem_size_log2;
258 byte* mem_addr = nullptr;
259 Handle<JSArrayBuffer> mem_buffer;
260 if (!memory.is_null()) {
261 memory->set_is_neuterable(false);
262 mem_addr = reinterpret_cast<byte*>(memory->backing_store());
263 mem_size = memory->byte_length()->Number();
264 mem_buffer = memory;
265 } else {
266 mem_buffer = NewArrayBuffer(isolate, mem_size, &mem_addr);
267 if (!mem_addr) {
268 // Not enough space for backing store of memory
269 thrower.Error("Out of memory: wasm memory");
270 return MaybeHandle<JSObject>(); 311 return MaybeHandle<JSObject>();
271 } 312 }
313 } else {
314 SetMemory(&instance, memory);
272 } 315 }
273 316 instance.js_object->SetInternalField(kWasmMemArrayBuffer,
274 // Load initialized data segments. 317 *instance.mem_buffer);
275 LoadDataSegments(this, mem_addr, mem_size); 318 LoadDataSegments(this, instance.mem_start, instance.mem_size);
276
277 module->SetInternalField(kWasmMemArrayBuffer, *mem_buffer);
278 319
279 if (mem_export) { 320 if (mem_export) {
280 // Export the memory as a named property. 321 // Export the memory as a named property.
281 Handle<String> name = factory->InternalizeUtf8String("memory"); 322 Handle<String> name = factory->InternalizeUtf8String("memory");
282 JSObject::AddProperty(module, name, mem_buffer, READ_ONLY); 323 JSObject::AddProperty(instance.js_object, name, instance.mem_buffer,
324 READ_ONLY);
283 } 325 }
284 326
285 //------------------------------------------------------------------------- 327 //-------------------------------------------------------------------------
286 // Allocate the globals area if necessary. 328 // Allocate the globals area if necessary.
287 //------------------------------------------------------------------------- 329 //-------------------------------------------------------------------------
288 size_t globals_size = AllocateGlobalsOffsets(globals); 330 if (!AllocateGlobals(&thrower, isolate, &instance)) {
289 byte* globals_addr = nullptr; 331 return MaybeHandle<JSObject>();
290 if (globals_size > 0) { 332 }
291 Handle<JSArrayBuffer> globals_buffer = 333 if (!instance.globals_buffer.is_null()) {
292 NewArrayBuffer(isolate, mem_size, &globals_addr); 334 instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
293 if (!globals_addr) { 335 *instance.globals_buffer);
294 // Not enough space for backing store of globals.
295 thrower.Error("Out of memory: wasm globals");
296 return MaybeHandle<JSObject>();
297 }
298
299 module->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
300 } else {
301 module->SetInternalField(kWasmGlobalsArrayBuffer, Smi::FromInt(0));
302 } 336 }
303 337
304 //------------------------------------------------------------------------- 338 //-------------------------------------------------------------------------
305 // Compile all functions in the module. 339 // Compile all functions in the module.
306 //------------------------------------------------------------------------- 340 //-------------------------------------------------------------------------
341 instance.function_table = BuildFunctionTable(isolate, this);
307 int index = 0; 342 int index = 0;
308 WasmLinker linker(isolate, functions->size()); 343 WasmLinker linker(isolate, functions->size());
309 ModuleEnv module_env; 344 ModuleEnv module_env;
310 module_env.module = this; 345 module_env.module = this;
311 module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr); 346 module_env.instance = &instance;
312 module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr) + mem_size;
313 module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr);
314 module_env.linker = &linker; 347 module_env.linker = &linker;
315 module_env.function_code = nullptr;
316 module_env.function_table = BuildFunctionTable(isolate, this);
317 module_env.memory = memory;
318 module_env.context = isolate->native_context();
319 module_env.asm_js = false; 348 module_env.asm_js = false;
320 349
321 // First pass: compile each function and initialize the code table. 350 // First pass: compile each function and initialize the code table.
322 for (const WasmFunction& func : *functions) { 351 for (const WasmFunction& func : *functions) {
323 if (thrower.error()) break; 352 if (thrower.error()) break;
324 353
325 const char* cstr = GetName(func.name_offset); 354 const char* cstr = GetName(func.name_offset);
326 Handle<String> name = factory->InternalizeUtf8String(cstr); 355 Handle<String> name = factory->InternalizeUtf8String(cstr);
327 Handle<Code> code = Handle<Code>::null(); 356 Handle<Code> code = Handle<Code>::null();
328 Handle<JSFunction> function = Handle<JSFunction>::null(); 357 Handle<JSFunction> function = Handle<JSFunction>::null();
(...skipping 22 matching lines...) Expand all
351 } 380 }
352 } else { 381 } else {
353 // Compile the function. 382 // Compile the function.
354 code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func, 383 code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func,
355 index); 384 index);
356 if (code.is_null()) { 385 if (code.is_null()) {
357 thrower.Error("Compilation of #%d:%s failed.", index, cstr); 386 thrower.Error("Compilation of #%d:%s failed.", index, cstr);
358 return MaybeHandle<JSObject>(); 387 return MaybeHandle<JSObject>();
359 } 388 }
360 if (func.exported) { 389 if (func.exported) {
361 function = compiler::CompileJSToWasmWrapper(isolate, &module_env, name, 390 function = compiler::CompileJSToWasmWrapper(
362 code, module, index); 391 isolate, &module_env, name, code, instance.js_object, index);
363 } 392 }
364 } 393 }
365 if (!code.is_null()) { 394 if (!code.is_null()) {
366 // Install the code into the linker table. 395 // Install the code into the linker table.
367 linker.Finish(index, code); 396 linker.Finish(index, code);
368 code_table->set(index, *code); 397 code_table->set(index, *code);
369 } 398 }
370 if (func.exported) { 399 if (func.exported) {
371 // Exported functions are installed as read-only properties on the module. 400 // Exported functions are installed as read-only properties on the module.
372 JSObject::AddProperty(module, name, function, READ_ONLY); 401 JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
373 } 402 }
374 index++; 403 index++;
375 } 404 }
376 405
377 // Second pass: patch all direct call sites. 406 // Second pass: patch all direct call sites.
378 linker.Link(module_env.function_table, this->function_table); 407 linker.Link(instance.function_table, this->function_table);
379 408 instance.js_object->SetInternalField(kWasmModuleFunctionTable,
380 module->SetInternalField(kWasmModuleFunctionTable, Smi::FromInt(0)); 409 Smi::FromInt(0));
381 module->SetInternalField(kWasmModuleCodeTable, *code_table); 410 return instance.js_object;
382 return module;
383 } 411 }
384 412
385 413
386 Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) { 414 Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) {
387 DCHECK(IsValidFunction(index)); 415 DCHECK(IsValidFunction(index));
388 if (linker) return linker->GetFunctionCode(index); 416 if (linker) return linker->GetFunctionCode(index);
389 if (function_code) return function_code->at(index); 417 if (instance && instance->function_code) {
418 return instance->function_code->at(index);
419 }
390 return Handle<Code>::null(); 420 return Handle<Code>::null();
391 } 421 }
392 422
393 423
394 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone, 424 compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
395 uint32_t index) { 425 uint32_t index) {
396 DCHECK(IsValidFunction(index)); 426 DCHECK(IsValidFunction(index));
397 // Always make a direct call to whatever is in the table at that location. 427 // Always make a direct call to whatever is in the table at that location.
398 // A wrapper will be generated for FFI calls. 428 // A wrapper will be generated for FFI calls.
399 WasmFunction* function = &module->functions->at(index); 429 WasmFunction* function = &module->functions->at(index);
(...skipping 19 matching lines...) Expand all
419 } 449 }
420 450
421 int32_t retval = CompileAndRunWasmModule(isolate, result.val); 451 int32_t retval = CompileAndRunWasmModule(isolate, result.val);
422 delete result.val; 452 delete result.val;
423 return retval; 453 return retval;
424 } 454 }
425 455
426 456
427 int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) { 457 int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
428 ErrorThrower thrower(isolate, "CompileAndRunWasmModule"); 458 ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
459 WasmModuleInstance instance(module);
429 460
430 // Allocate temporary linear memory and globals. 461 // Allocate and initialize the linear memory.
431 size_t mem_size = 1 << module->min_mem_size_log2; 462 if (!AllocateMemory(&thrower, isolate, &instance)) {
432 size_t globals_size = AllocateGlobalsOffsets(module->globals); 463 return -1;
464 }
465 LoadDataSegments(module, instance.mem_start, instance.mem_size);
433 466
434 base::SmartArrayPointer<byte> mem_addr(new byte[mem_size]); 467 // Allocate the globals area if necessary.
435 base::SmartArrayPointer<byte> globals_addr(new byte[globals_size]); 468 if (!AllocateGlobals(&thrower, isolate, &instance)) {
469 return -1;
470 }
436 471
437 memset(mem_addr.get(), 0, mem_size); 472 // Build the function table.
438 memset(globals_addr.get(), 0, globals_size); 473 instance.function_table = BuildFunctionTable(isolate, module);
439 474
440 // Create module environment. 475 // Create module environment.
441 WasmLinker linker(isolate, module->functions->size()); 476 WasmLinker linker(isolate, module->functions->size());
442 ModuleEnv module_env; 477 ModuleEnv module_env;
443 module_env.module = module; 478 module_env.module = module;
444 module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr.get()); 479 module_env.instance = &instance;
445 module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr.get()) + mem_size;
446 module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr.get());
447 module_env.linker = &linker; 480 module_env.linker = &linker;
448 module_env.function_code = nullptr;
449 module_env.function_table = BuildFunctionTable(isolate, module);
450 module_env.asm_js = false; 481 module_env.asm_js = false;
451 482
452 // Load data segments.
453 // TODO(titzer): throw instead of crashing if segments don't fit in memory?
454 LoadDataSegments(module, mem_addr.get(), mem_size);
455
456 // Compile all functions. 483 // Compile all functions.
457 Handle<Code> main_code = Handle<Code>::null(); // record last code. 484 Handle<Code> main_code = Handle<Code>::null(); // record last code.
458 int index = 0; 485 int index = 0;
459 int main_index = 0; 486 int main_index = 0;
460 for (const WasmFunction& func : *module->functions) { 487 for (const WasmFunction& func : *module->functions) {
461 if (!func.external) { 488 if (!func.external) {
462 // Compile the function and install it in the code table. 489 // Compile the function and install it in the code table.
463 Handle<Code> code = compiler::CompileWasmFunction( 490 Handle<Code> code = compiler::CompileWasmFunction(
464 thrower, isolate, &module_env, func, index); 491 thrower, isolate, &module_env, func, index);
465 if (!code.is_null()) { 492 if (!code.is_null()) {
466 if (func.exported) { 493 if (func.exported) {
467 main_code = code; 494 main_code = code;
468 main_index = index; 495 main_index = index;
469 } 496 }
470 linker.Finish(index, code); 497 linker.Finish(index, code);
471 } 498 }
472 if (thrower.error()) return -1; 499 if (thrower.error()) return -1;
473 } 500 }
474 index++; 501 index++;
475 } 502 }
476 503
477 if (main_code.is_null()) { 504 if (main_code.is_null()) {
478 thrower.Error("WASM.compileRun() failed: no main code found"); 505 thrower.Error("WASM.compileRun() failed: no main code found");
479 return -1; 506 return -1;
480 } 507 }
481 508
482 linker.Link(module_env.function_table, module->function_table); 509 linker.Link(instance.function_table, instance.module->function_table);
483 510
484 // Wrap the main code so it can be called as a JS function. 511 // Wrap the main code so it can be called as a JS function.
485 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); 512 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
486 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); 513 Handle<JSObject> module_object = Handle<JSObject>(0, isolate);
487 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper( 514 Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
488 isolate, &module_env, name, main_code, module_object, main_index); 515 isolate, &module_env, name, main_code, module_object, main_index);
489 516
490 // Call the JS function. 517 // Call the JS function.
491 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); 518 Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
492 MaybeHandle<Object> retval = 519 MaybeHandle<Object> retval =
(...skipping 10 matching lines...) Expand all
503 } 530 }
504 if (result->IsHeapNumber()) { 531 if (result->IsHeapNumber()) {
505 return static_cast<int32_t>(HeapNumber::cast(*result)->value()); 532 return static_cast<int32_t>(HeapNumber::cast(*result)->value());
506 } 533 }
507 thrower.Error("WASM.compileRun() failed: Return value should be number"); 534 thrower.Error("WASM.compileRun() failed: Return value should be number");
508 return -1; 535 return -1;
509 } 536 }
510 } // namespace wasm 537 } // namespace wasm
511 } // namespace internal 538 } // namespace internal
512 } // namespace v8 539 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/wasm-module.h ('k') | test/cctest/wasm/test-run-wasm-js.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698