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

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

Issue 2710603006: [wasm] Move compilation-related methods to CompilationHelper in wasm-module.cc. (Closed)
Patch Set: Smaller buffer Created 3 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/compiler/wasm-compiler.cc ('k') | no next file » | 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 <memory> 5 #include <memory>
6 6
7 #include "src/assembler-inl.h" 7 #include "src/assembler-inl.h"
8 #include "src/base/adapters.h" 8 #include "src/base/adapters.h"
9 #include "src/base/atomic-utils.h" 9 #include "src/base/atomic-utils.h"
10 #include "src/code-stubs.h" 10 #include "src/code-stubs.h"
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 #if V8_TARGET_ARCH_64_BIT 69 #if V8_TARGET_ARCH_64_BIT
70 const bool kGuardRegionsSupported = true; 70 const bool kGuardRegionsSupported = true;
71 #else 71 #else
72 const bool kGuardRegionsSupported = false; 72 const bool kGuardRegionsSupported = false;
73 #endif 73 #endif
74 74
75 bool EnableGuardRegions() { 75 bool EnableGuardRegions() {
76 return FLAG_wasm_guard_pages && kGuardRegionsSupported; 76 return FLAG_wasm_guard_pages && kGuardRegionsSupported;
77 } 77 }
78 78
79 static void RecordStats(Isolate* isolate, Code* code) {
80 isolate->counters()->wasm_generated_code_size()->Increment(code->body_size());
81 isolate->counters()->wasm_reloc_size()->Increment(
82 code->relocation_info()->length());
83 }
84
85 static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) {
86 DisallowHeapAllocation no_gc;
87 for (int i = 0; i < functions->length(); ++i) {
88 RecordStats(isolate, Code::cast(functions->get(i)));
89 }
90 }
91
79 void* TryAllocateBackingStore(Isolate* isolate, size_t size, 92 void* TryAllocateBackingStore(Isolate* isolate, size_t size,
80 bool enable_guard_regions, bool& is_external) { 93 bool enable_guard_regions, bool& is_external) {
81 is_external = false; 94 is_external = false;
82 // TODO(eholk): Right now enable_guard_regions has no effect on 32-bit 95 // TODO(eholk): Right now enable_guard_regions has no effect on 32-bit
83 // systems. It may be safer to fail instead, given that other code might do 96 // systems. It may be safer to fail instead, given that other code might do
84 // things that would be unsafe if they expected guard pages where there 97 // things that would be unsafe if they expected guard pages where there
85 // weren't any. 98 // weren't any.
86 if (enable_guard_regions && kGuardRegionsSupported) { 99 if (enable_guard_regions && kGuardRegionsSupported) {
87 // TODO(eholk): On Windows we want to make sure we don't commit the guard 100 // TODO(eholk): On Windows we want to make sure we don't commit the guard
88 // pages yet. 101 // pages yet.
(...skipping 25 matching lines...) Expand all
114 } 127 }
115 128
116 void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) { 129 void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) {
117 for (int i = 0; i < code_table->length(); ++i) { 130 for (int i = 0; i < code_table->length(); ++i) {
118 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); 131 Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
119 Assembler::FlushICache(isolate, code->instruction_start(), 132 Assembler::FlushICache(isolate, code->instruction_start(),
120 code->instruction_size()); 133 code->instruction_size());
121 } 134 }
122 } 135 }
123 136
124 // Fetches the compilation unit of a wasm function and executes its parallel 137 Handle<Script> CreateWasmScript(Isolate* isolate,
125 // phase. 138 const ModuleWireBytes& wire_bytes) {
126 bool FetchAndExecuteCompilationUnit( 139 Handle<Script> script =
127 Isolate* isolate, 140 isolate->factory()->NewScript(isolate->factory()->empty_string());
128 std::vector<compiler::WasmCompilationUnit*>* compilation_units, 141 FixedArray* array = isolate->native_context()->embedder_data();
129 std::queue<compiler::WasmCompilationUnit*>* executed_units, 142 script->set_context_data(array->get(v8::Context::kDebugIdIndex));
130 base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) { 143 script->set_type(Script::TYPE_WASM);
131 DisallowHeapAllocation no_allocation; 144
132 DisallowHandleAllocation no_handles; 145 int hash = StringHasher::HashSequentialString(
133 DisallowHandleDereference no_deref; 146 reinterpret_cast<const char*>(wire_bytes.start()), wire_bytes.length(),
134 DisallowCodeDependencyChange no_dependency_change; 147 kZeroHashSeed);
135 148
136 // - 1 because AtomicIncrement returns the value after the atomic increment. 149 const int kBufferSize = 32;
137 size_t index = next_unit->Increment(1) - 1; 150 char buffer[kBufferSize];
138 if (index >= compilation_units->size()) { 151 int url_chars = SNPrintF(ArrayVector(buffer), "wasm://wasm/%08x", hash);
139 return false; 152 DCHECK(url_chars >= 0 && url_chars < kBufferSize);
140 } 153 MaybeHandle<String> url_str = isolate->factory()->NewStringFromOneByte(
141 154 Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), url_chars),
142 compiler::WasmCompilationUnit* unit = compilation_units->at(index); 155 TENURED);
143 if (unit != nullptr) { 156 script->set_source_url(*url_str.ToHandleChecked());
144 unit->ExecuteCompilation(); 157
145 base::LockGuard<base::Mutex> guard(result_mutex); 158 int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
146 executed_units->push(unit); 159 DCHECK(name_chars >= 0 && name_chars < kBufferSize);
147 } 160 MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
148 return true; 161 Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
162 TENURED);
163 script->set_name(*name_str.ToHandleChecked());
164
165 return script;
149 } 166 }
150 167
151 class WasmCompilationTask : public CancelableTask { 168 class JSToWasmWrapperCache {
152 public: 169 public:
153 WasmCompilationTask( 170 Handle<Code> CloneOrCompileJSToWasmWrapper(Isolate* isolate,
154 Isolate* isolate, 171 const wasm::WasmModule* module,
155 std::vector<compiler::WasmCompilationUnit*>* compilation_units, 172 Handle<Code> wasm_code,
156 std::queue<compiler::WasmCompilationUnit*>* executed_units, 173 uint32_t index) {
157 base::Semaphore* on_finished, base::Mutex* result_mutex, 174 const wasm::WasmFunction* func = &module->functions[index];
158 base::AtomicNumber<size_t>* next_unit) 175 int cached_idx = sig_map_.Find(func->sig);
159 : CancelableTask(isolate), 176 if (cached_idx >= 0) {
160 isolate_(isolate), 177 Handle<Code> code = isolate->factory()->CopyCode(code_cache_[cached_idx]);
161 compilation_units_(compilation_units), 178 // Now patch the call to wasm code.
162 executed_units_(executed_units), 179 for (RelocIterator it(*code, RelocInfo::kCodeTargetMask);; it.next()) {
163 on_finished_(on_finished), 180 DCHECK(!it.done());
164 result_mutex_(result_mutex), 181 Code* target =
165 next_unit_(next_unit) {} 182 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
166 183 if (target->kind() == Code::WASM_FUNCTION ||
167 void RunInternal() override { 184 target->kind() == Code::WASM_TO_JS_FUNCTION ||
168 while (FetchAndExecuteCompilationUnit(isolate_, compilation_units_, 185 target->builtin_index() == Builtins::kIllegal) {
169 executed_units_, result_mutex_, 186 it.rinfo()->set_target_address(wasm_code->instruction_start());
170 next_unit_)) { 187 break;
171 } 188 }
172 on_finished_->Signal(); 189 }
173 } 190 return code;
191 }
192
193 Handle<Code> code =
194 compiler::CompileJSToWasmWrapper(isolate, module, wasm_code, index);
195 uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig);
196 DCHECK_EQ(code_cache_.size(), new_cache_idx);
197 USE(new_cache_idx);
198 code_cache_.push_back(code);
199 return code;
200 }
201
202 private:
203 // sig_map_ maps signatures to an index in code_cache_.
204 wasm::SignatureMap sig_map_;
205 std::vector<Handle<Code>> code_cache_;
206 };
207
208 // A helper for compiling an entire module.
209 class CompilationHelper {
210 public:
211 CompilationHelper(Isolate* isolate, WasmModule* module)
212 : isolate_(isolate), module_(module) {}
213
214 // The actual runnable task that performs compilations in the background.
215 class CompilationTask : public CancelableTask {
216 public:
217 CompilationHelper* helper_;
218 explicit CompilationTask(CompilationHelper* helper)
219 : CancelableTask(helper->isolate_), helper_(helper) {}
220
221 void RunInternal() override {
222 while (helper_->FetchAndExecuteCompilationUnit()) {
223 }
224 helper_->module_->pending_tasks.get()->Signal();
225 }
226 };
174 227
175 Isolate* isolate_; 228 Isolate* isolate_;
176 std::vector<compiler::WasmCompilationUnit*>* compilation_units_; 229 WasmModule* module_;
177 std::queue<compiler::WasmCompilationUnit*>* executed_units_; 230 std::vector<compiler::WasmCompilationUnit*> compilation_units_;
178 base::Semaphore* on_finished_; 231 std::queue<compiler::WasmCompilationUnit*> executed_units_;
179 base::Mutex* result_mutex_; 232 base::Mutex result_mutex_;
180 base::AtomicNumber<size_t>* next_unit_; 233 base::AtomicNumber<size_t> next_unit_;
181 }; 234
182 235 // Run by each compilation task and by the main thread.
183 static void RecordStats(Isolate* isolate, Code* code) { 236 bool FetchAndExecuteCompilationUnit() {
184 isolate->counters()->wasm_generated_code_size()->Increment(code->body_size()); 237 DisallowHeapAllocation no_allocation;
185 isolate->counters()->wasm_reloc_size()->Increment( 238 DisallowHandleAllocation no_handles;
186 code->relocation_info()->length()); 239 DisallowHandleDereference no_deref;
187 } 240 DisallowCodeDependencyChange no_dependency_change;
188 241
189 static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) { 242 // - 1 because AtomicIncrement returns the value after the atomic increment.
190 DisallowHeapAllocation no_gc; 243 size_t index = next_unit_.Increment(1) - 1;
191 for (int i = 0; i < functions->length(); ++i) { 244 if (index >= compilation_units_.size()) {
192 RecordStats(isolate, Code::cast(functions->get(i))); 245 return false;
193 } 246 }
194 } 247
195 248 compiler::WasmCompilationUnit* unit = compilation_units_.at(index);
196 void InitializeParallelCompilation( 249 if (unit != nullptr) {
197 Isolate* isolate, const std::vector<WasmFunction>& functions, 250 unit->ExecuteCompilation();
198 std::vector<compiler::WasmCompilationUnit*>& compilation_units, 251 base::LockGuard<base::Mutex> guard(&result_mutex_);
199 ModuleBytesEnv& module_env, ErrorThrower* thrower) { 252 executed_units_.push(unit);
200 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) { 253 }
201 const WasmFunction* func = &functions[i]; 254 return true;
202 compilation_units[i] = 255 }
203 func->imported ? nullptr : new compiler::WasmCompilationUnit( 256
204 thrower, isolate, &module_env, func, i); 257 void InitializeParallelCompilation(const std::vector<WasmFunction>& functions,
205 } 258 ModuleBytesEnv& module_env,
206 } 259 ErrorThrower* thrower) {
207 260 compilation_units_.reserve(functions.size());
208 uint32_t* StartCompilationTasks( 261 for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
209 Isolate* isolate, 262 ++i) {
210 std::vector<compiler::WasmCompilationUnit*>& compilation_units, 263 const WasmFunction* func = &functions[i];
211 std::queue<compiler::WasmCompilationUnit*>& executed_units, 264 compilation_units_.push_back(
212 base::Semaphore* pending_tasks, base::Mutex& result_mutex, 265 func->imported ? nullptr
213 base::AtomicNumber<size_t>& next_unit) { 266 : new compiler::WasmCompilationUnit(
214 const size_t num_tasks = 267 thrower, isolate_, &module_env, func, i));
215 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks), 268 }
216 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads()); 269 }
217 uint32_t* task_ids = new uint32_t[num_tasks]; 270
218 for (size_t i = 0; i < num_tasks; ++i) { 271 uint32_t* StartCompilationTasks() {
219 WasmCompilationTask* task = 272 const size_t num_tasks =
220 new WasmCompilationTask(isolate, &compilation_units, &executed_units, 273 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
221 pending_tasks, &result_mutex, &next_unit); 274 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
222 task_ids[i] = task->id(); 275 uint32_t* task_ids = new uint32_t[num_tasks];
223 V8::GetCurrentPlatform()->CallOnBackgroundThread( 276 for (size_t i = 0; i < num_tasks; ++i) {
224 task, v8::Platform::kShortRunningTask); 277 CompilationTask* task = new CompilationTask(this);
225 } 278 task_ids[i] = task->id();
226 return task_ids; 279 V8::GetCurrentPlatform()->CallOnBackgroundThread(
227 } 280 task, v8::Platform::kShortRunningTask);
228 281 }
229 void WaitForCompilationTasks(Isolate* isolate, uint32_t* task_ids, 282 return task_ids;
230 base::Semaphore* pending_tasks) { 283 }
231 const size_t num_tasks = 284
232 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks), 285 void WaitForCompilationTasks(uint32_t* task_ids) {
233 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads()); 286 const size_t num_tasks =
234 for (size_t i = 0; i < num_tasks; ++i) { 287 Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
235 // If the task has not started yet, then we abort it. Otherwise we wait for 288 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
236 // it to finish. 289 for (size_t i = 0; i < num_tasks; ++i) {
237 if (isolate->cancelable_task_manager()->TryAbort(task_ids[i]) != 290 // If the task has not started yet, then we abort it. Otherwise we wait
238 CancelableTaskManager::kTaskAborted) { 291 // for
239 pending_tasks->Wait(); 292 // it to finish.
240 } 293 if (isolate_->cancelable_task_manager()->TryAbort(task_ids[i]) !=
241 } 294 CancelableTaskManager::kTaskAborted) {
242 } 295 module_->pending_tasks.get()->Wait();
243 296 }
244 void FinishCompilationUnits( 297 }
245 std::queue<compiler::WasmCompilationUnit*>& executed_units, 298 }
246 std::vector<Handle<Code>>& results, base::Mutex& result_mutex) { 299
247 while (true) { 300 void FinishCompilationUnits(std::vector<Handle<Code>>& results) {
248 compiler::WasmCompilationUnit* unit = nullptr; 301 while (true) {
249 { 302 compiler::WasmCompilationUnit* unit = nullptr;
250 base::LockGuard<base::Mutex> guard(&result_mutex); 303 {
251 if (executed_units.empty()) { 304 base::LockGuard<base::Mutex> guard(&result_mutex_);
305 if (executed_units_.empty()) {
306 break;
307 }
308 unit = executed_units_.front();
309 executed_units_.pop();
310 }
311 int j = unit->index();
312 results[j] = unit->FinishCompilation();
313 delete unit;
314 }
315 }
316
317 void CompileInParallel(ModuleBytesEnv* module_env,
318 std::vector<Handle<Code>>& results,
319 ErrorThrower* thrower) {
320 const WasmModule* module = module_env->module_env.module;
321 // Data structures for the parallel compilation.
322
323 //-----------------------------------------------------------------------
324 // For parallel compilation:
325 // 1) The main thread allocates a compilation unit for each wasm function
326 // and stores them in the vector {compilation_units}.
327 // 2) The main thread spawns {CompilationTask} instances which run on
328 // the background threads.
329 // 3.a) The background threads and the main thread pick one compilation
330 // unit at a time and execute the parallel phase of the compilation
331 // unit. After finishing the execution of the parallel phase, the
332 // result is enqueued in {executed_units}.
333 // 3.b) If {executed_units} contains a compilation unit, the main thread
334 // dequeues it and finishes the compilation.
335 // 4) After the parallel phase of all compilation units has started, the
336 // main thread waits for all {CompilationTask} instances to finish.
337 // 5) The main thread finishes the compilation.
338
339 // Turn on the {CanonicalHandleScope} so that the background threads can
340 // use the node cache.
341 CanonicalHandleScope canonical(isolate_);
342
343 // 1) The main thread allocates a compilation unit for each wasm function
344 // and stores them in the vector {compilation_units}.
345 InitializeParallelCompilation(module->functions, *module_env, thrower);
346
347 // Objects for the synchronization with the background threads.
348 base::AtomicNumber<size_t> next_unit(
349 static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
350
351 // 2) The main thread spawns {CompilationTask} instances which run on
352 // the background threads.
353 std::unique_ptr<uint32_t[]> task_ids(StartCompilationTasks());
354
355 // 3.a) The background threads and the main thread pick one compilation
356 // unit at a time and execute the parallel phase of the compilation
357 // unit. After finishing the execution of the parallel phase, the
358 // result is enqueued in {executed_units}.
359 while (FetchAndExecuteCompilationUnit()) {
360 // 3.b) If {executed_units} contains a compilation unit, the main thread
361 // dequeues it and finishes the compilation unit. Compilation units
362 // are finished concurrently to the background threads to save
363 // memory.
364 FinishCompilationUnits(results);
365 }
366 // 4) After the parallel phase of all compilation units has started, the
367 // main thread waits for all {CompilationTask} instances to finish.
368 WaitForCompilationTasks(task_ids.get());
369 // Finish the compilation of the remaining compilation units.
370 FinishCompilationUnits(results);
371 }
372
373 void CompileSequentially(ModuleBytesEnv* module_env,
374 std::vector<Handle<Code>>& results,
375 ErrorThrower* thrower) {
376 DCHECK(!thrower->error());
377
378 const WasmModule* module = module_env->module_env.module;
379 for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
380 i < module->functions.size(); ++i) {
381 const WasmFunction& func = module->functions[i];
382 if (func.imported)
383 continue; // Imports are compiled at instantiation time.
384
385 Handle<Code> code = Handle<Code>::null();
386 // Compile the function.
387 code = compiler::WasmCompilationUnit::CompileWasmFunction(
388 thrower, isolate_, module_env, &func);
389 if (code.is_null()) {
390 WasmName str = module_env->wire_bytes.GetName(&func);
391 thrower->CompileError("Compilation of #%d:%.*s failed.", i,
392 str.length(), str.start());
252 break; 393 break;
253 } 394 }
254 unit = executed_units.front(); 395 results[i] = code;
255 executed_units.pop(); 396 }
256 } 397 }
257 int j = unit->index(); 398
258 results[j] = unit->FinishCompilation(); 399 MaybeHandle<WasmModuleObject> CompileToModuleObject(
259 delete unit; 400 ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
260 } 401 Handle<Script> asm_js_script,
402 Vector<const byte> asm_js_offset_table_bytes) {
403 Factory* factory = isolate_->factory();
404 // The {module_wrapper} will take ownership of the {WasmModule} object,
405 // and it will be destroyed when the GC reclaims the wrapper object.
406 Handle<WasmModuleWrapper> module_wrapper =
407 WasmModuleWrapper::New(isolate_, module_);
408 WasmInstance temp_instance(module_);
409 temp_instance.context = isolate_->native_context();
410 temp_instance.mem_size = WasmModule::kPageSize * module_->min_mem_pages;
411 temp_instance.mem_start = nullptr;
412 temp_instance.globals_start = nullptr;
413
414 // Initialize the indirect tables with placeholders.
415 int function_table_count =
416 static_cast<int>(module_->function_tables.size());
417 Handle<FixedArray> function_tables =
418 factory->NewFixedArray(function_table_count, TENURED);
419 Handle<FixedArray> signature_tables =
420 factory->NewFixedArray(function_table_count, TENURED);
421 for (int i = 0; i < function_table_count; ++i) {
422 temp_instance.function_tables[i] = factory->NewFixedArray(1, TENURED);
423 temp_instance.signature_tables[i] = factory->NewFixedArray(1, TENURED);
424 function_tables->set(i, *temp_instance.function_tables[i]);
425 signature_tables->set(i, *temp_instance.signature_tables[i]);
426 }
427
428 HistogramTimerScope wasm_compile_module_time_scope(
429 isolate_->counters()->wasm_compile_module_time());
430
431 ModuleBytesEnv module_env(module_, &temp_instance, wire_bytes);
432
433 // The {code_table} array contains import wrappers and functions (which
434 // are both included in {functions.size()}, and export wrappers.
435 int code_table_size = static_cast<int>(module_->functions.size() +
436 module_->num_exported_functions);
437 Handle<FixedArray> code_table =
438 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
439
440 // Initialize the code table with the illegal builtin. All call sites will
441 // be
442 // patched at instantiation.
443 Handle<Code> illegal_builtin = isolate_->builtins()->Illegal();
444 for (uint32_t i = 0; i < module_->functions.size(); ++i) {
445 code_table->set(static_cast<int>(i), *illegal_builtin);
446 temp_instance.function_code[i] = illegal_builtin;
447 }
448
449 isolate_->counters()->wasm_functions_per_module()->AddSample(
450 static_cast<int>(module_->functions.size()));
451 CompilationHelper helper(isolate_, module_);
452 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
453 // Avoid a race condition by collecting results into a second vector.
454 std::vector<Handle<Code>> results(temp_instance.function_code);
455 helper.CompileInParallel(&module_env, results, thrower);
456 temp_instance.function_code.swap(results);
457 } else {
458 helper.CompileSequentially(&module_env, temp_instance.function_code,
459 thrower);
460 }
461 if (thrower->error()) return {};
462
463 // At this point, compilation has completed. Update the code table.
464 for (size_t i = FLAG_skip_compiling_wasm_funcs;
465 i < temp_instance.function_code.size(); ++i) {
466 Code* code = *temp_instance.function_code[i];
467 code_table->set(static_cast<int>(i), code);
468 RecordStats(isolate_, code);
469 }
470
471 // Create heap objects for script, module bytes and asm.js offset table to
472 // be
473 // stored in the shared module data.
474 Handle<Script> script;
475 Handle<ByteArray> asm_js_offset_table;
476 if (asm_js_script.is_null()) {
477 script = CreateWasmScript(isolate_, wire_bytes);
478 } else {
479 script = asm_js_script;
480 asm_js_offset_table =
481 isolate_->factory()->NewByteArray(asm_js_offset_table_bytes.length());
482 asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
483 asm_js_offset_table_bytes.length());
484 }
485 // TODO(wasm): only save the sections necessary to deserialize a
486 // {WasmModule}. E.g. function bodies could be omitted.
487 Handle<String> module_bytes =
488 factory
489 ->NewStringFromOneByte({wire_bytes.start(), wire_bytes.length()},
490 TENURED)
491 .ToHandleChecked();
492 DCHECK(module_bytes->IsSeqOneByteString());
493
494 // Create the shared module data.
495 // TODO(clemensh): For the same module (same bytes / same hash), we should
496 // only have one WasmSharedModuleData. Otherwise, we might only set
497 // breakpoints on a (potentially empty) subset of the instances.
498
499 Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
500 isolate_, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes),
501 script, asm_js_offset_table);
502
503 // Create the compiled module object, and populate with compiled functions
504 // and information needed at instantiation time. This object needs to be
505 // serializable. Instantiation may occur off a deserialized version of this
506 // object.
507 Handle<WasmCompiledModule> compiled_module =
508 WasmCompiledModule::New(isolate_, shared);
509 compiled_module->set_num_imported_functions(
510 module_->num_imported_functions);
511 compiled_module->set_code_table(code_table);
512 compiled_module->set_min_mem_pages(module_->min_mem_pages);
513 compiled_module->set_max_mem_pages(module_->max_mem_pages);
514 if (function_table_count > 0) {
515 compiled_module->set_function_tables(function_tables);
516 compiled_module->set_signature_tables(signature_tables);
517 compiled_module->set_empty_function_tables(function_tables);
518 }
519
520 // If we created a wasm script, finish it now and make it public to the
521 // debugger.
522 if (asm_js_script.is_null()) {
523 script->set_wasm_compiled_module(*compiled_module);
524 isolate_->debug()->OnAfterCompile(script);
525 }
526
527 // Compile JS->WASM wrappers for exported functions.
528 JSToWasmWrapperCache js_to_wasm_cache;
529 int func_index = 0;
530 for (auto exp : module_->export_table) {
531 if (exp.kind != kExternalFunction) continue;
532 Handle<Code> wasm_code(Code::cast(code_table->get(exp.index)), isolate_);
533 Handle<Code> wrapper_code =
534 js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(isolate_, module_,
535 wasm_code, exp.index);
536 int export_index =
537 static_cast<int>(module_->functions.size() + func_index);
538 code_table->set(export_index, *wrapper_code);
539 RecordStats(isolate_, *wrapper_code);
540 func_index++;
541 }
542
543 return WasmModuleObject::New(isolate_, compiled_module);
261 } 544 }
262 545 };
263 void CompileInParallel(Isolate* isolate, ModuleBytesEnv* module_env,
264 std::vector<Handle<Code>>& functions,
265 ErrorThrower* thrower) {
266 const WasmModule* module = module_env->module_env.module;
267 // Data structures for the parallel compilation.
268 std::vector<compiler::WasmCompilationUnit*> compilation_units(
269 module->functions.size());
270 std::queue<compiler::WasmCompilationUnit*> executed_units;
271
272 //-----------------------------------------------------------------------
273 // For parallel compilation:
274 // 1) The main thread allocates a compilation unit for each wasm function
275 // and stores them in the vector {compilation_units}.
276 // 2) The main thread spawns {WasmCompilationTask} instances which run on
277 // the background threads.
278 // 3.a) The background threads and the main thread pick one compilation
279 // unit at a time and execute the parallel phase of the compilation
280 // unit. After finishing the execution of the parallel phase, the
281 // result is enqueued in {executed_units}.
282 // 3.b) If {executed_units} contains a compilation unit, the main thread
283 // dequeues it and finishes the compilation.
284 // 4) After the parallel phase of all compilation units has started, the
285 // main thread waits for all {WasmCompilationTask} instances to finish.
286 // 5) The main thread finishes the compilation.
287
288 // Turn on the {CanonicalHandleScope} so that the background threads can
289 // use the node cache.
290 CanonicalHandleScope canonical(isolate);
291
292 // 1) The main thread allocates a compilation unit for each wasm function
293 // and stores them in the vector {compilation_units}.
294 InitializeParallelCompilation(isolate, module->functions, compilation_units,
295 *module_env, thrower);
296
297 // Objects for the synchronization with the background threads.
298 base::Mutex result_mutex;
299 base::AtomicNumber<size_t> next_unit(
300 static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
301
302 // 2) The main thread spawns {WasmCompilationTask} instances which run on
303 // the background threads.
304 std::unique_ptr<uint32_t[]> task_ids(StartCompilationTasks(
305 isolate, compilation_units, executed_units, module->pending_tasks.get(),
306 result_mutex, next_unit));
307
308 // 3.a) The background threads and the main thread pick one compilation
309 // unit at a time and execute the parallel phase of the compilation
310 // unit. After finishing the execution of the parallel phase, the
311 // result is enqueued in {executed_units}.
312 while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
313 &executed_units, &result_mutex,
314 &next_unit)) {
315 // 3.b) If {executed_units} contains a compilation unit, the main thread
316 // dequeues it and finishes the compilation unit. Compilation units
317 // are finished concurrently to the background threads to save
318 // memory.
319 FinishCompilationUnits(executed_units, functions, result_mutex);
320 }
321 // 4) After the parallel phase of all compilation units has started, the
322 // main thread waits for all {WasmCompilationTask} instances to finish.
323 WaitForCompilationTasks(isolate, task_ids.get(), module->pending_tasks.get());
324 // Finish the compilation of the remaining compilation units.
325 FinishCompilationUnits(executed_units, functions, result_mutex);
326 }
327
328 void CompileSequentially(Isolate* isolate, ModuleBytesEnv* module_env,
329 std::vector<Handle<Code>>& functions,
330 ErrorThrower* thrower) {
331 DCHECK(!thrower->error());
332
333 const WasmModule* module = module_env->module_env.module;
334 for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
335 i < module->functions.size(); ++i) {
336 const WasmFunction& func = module->functions[i];
337 if (func.imported) continue; // Imports are compiled at instantiation time.
338
339 Handle<Code> code = Handle<Code>::null();
340 // Compile the function.
341 code = compiler::WasmCompilationUnit::CompileWasmFunction(
342 thrower, isolate, module_env, &func);
343 if (code.is_null()) {
344 WasmName str = module_env->wire_bytes.GetName(&func);
345 thrower->CompileError("Compilation of #%d:%.*s failed.", i, str.length(),
346 str.start());
347 break;
348 }
349 // Install the code into the linker table.
350 functions[i] = code;
351 }
352 }
353 546
354 static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner, 547 static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner,
355 WasmCompiledModule* compiled_module) { 548 WasmCompiledModule* compiled_module) {
356 TRACE("Resetting %d\n", compiled_module->instance_id()); 549 TRACE("Resetting %d\n", compiled_module->instance_id());
357 Object* undefined = *isolate->factory()->undefined_value(); 550 Object* undefined = *isolate->factory()->undefined_value();
358 Object* fct_obj = compiled_module->ptr_to_code_table(); 551 Object* fct_obj = compiled_module->ptr_to_code_table();
359 if (fct_obj != nullptr && fct_obj != undefined) { 552 if (fct_obj != nullptr && fct_obj != undefined) {
360 uint32_t old_mem_size = compiled_module->mem_size(); 553 uint32_t old_mem_size = compiled_module->mem_size();
361 uint32_t default_mem_size = compiled_module->default_mem_size(); 554 uint32_t default_mem_size = compiled_module->default_mem_size();
362 Object* mem_start = compiled_module->maybe_ptr_to_memory(); 555 Object* mem_start = compiled_module->maybe_ptr_to_memory();
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 Handle<WasmCompiledModule> compiled_module, int func_index) { 730 Handle<WasmCompiledModule> compiled_module, int func_index) {
538 WasmModule* module = compiled_module->module(); 731 WasmModule* module = compiled_module->module();
539 if (func_index < 0 || 732 if (func_index < 0 ||
540 static_cast<size_t>(func_index) > module->functions.size()) { 733 static_cast<size_t>(func_index) > module->functions.size()) {
541 return {0, 0}; 734 return {0, 0};
542 } 735 }
543 WasmFunction& func = module->functions[func_index]; 736 WasmFunction& func = module->functions[func_index];
544 return {static_cast<int>(func.code_start_offset), 737 return {static_cast<int>(func.code_start_offset),
545 static_cast<int>(func.code_end_offset - func.code_start_offset)}; 738 static_cast<int>(func.code_end_offset - func.code_start_offset)};
546 } 739 }
547
548 Handle<Script> CreateWasmScript(Isolate* isolate,
549 const ModuleWireBytes& wire_bytes) {
550 Handle<Script> script =
551 isolate->factory()->NewScript(isolate->factory()->empty_string());
552 FixedArray* array = isolate->native_context()->embedder_data();
553 script->set_context_data(array->get(v8::Context::kDebugIdIndex));
554 script->set_type(Script::TYPE_WASM);
555
556 int hash = StringHasher::HashSequentialString(
557 reinterpret_cast<const char*>(wire_bytes.start()), wire_bytes.length(),
558 kZeroHashSeed);
559
560 const int kBufferSize = 50;
561 char buffer[kBufferSize];
562 int url_chars = SNPrintF(ArrayVector(buffer), "wasm://wasm/%08x", hash);
563 DCHECK(url_chars >= 0 && url_chars < kBufferSize);
564 MaybeHandle<String> url_str = isolate->factory()->NewStringFromOneByte(
565 Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), url_chars),
566 TENURED);
567 script->set_source_url(*url_str.ToHandleChecked());
568
569 int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
570 DCHECK(name_chars >= 0 && name_chars < kBufferSize);
571 MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
572 Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
573 TENURED);
574 script->set_name(*name_str.ToHandleChecked());
575
576 return script;
577 }
578
579 class JSToWasmWrapperCache {
580 public:
581 Handle<Code> CloneOrCompileJSToWasmWrapper(Isolate* isolate,
582 const wasm::WasmModule* module,
583 Handle<Code> wasm_code,
584 uint32_t index) {
585 const wasm::WasmFunction* func = &module->functions[index];
586 int cached_idx = sig_map_.Find(func->sig);
587 if (cached_idx >= 0) {
588 Handle<Code> code = isolate->factory()->CopyCode(code_cache_[cached_idx]);
589 // Now patch the call to wasm code.
590 for (RelocIterator it(*code, RelocInfo::kCodeTargetMask);; it.next()) {
591 DCHECK(!it.done());
592 Code* target =
593 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
594 if (target->kind() == Code::WASM_FUNCTION ||
595 target->kind() == Code::WASM_TO_JS_FUNCTION ||
596 target->builtin_index() == Builtins::kIllegal) {
597 it.rinfo()->set_target_address(wasm_code->instruction_start());
598 break;
599 }
600 }
601 return code;
602 }
603
604 Handle<Code> code =
605 compiler::CompileJSToWasmWrapper(isolate, module, wasm_code, index);
606 uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig);
607 DCHECK_EQ(code_cache_.size(), new_cache_idx);
608 USE(new_cache_idx);
609 code_cache_.push_back(code);
610 return code;
611 }
612
613 private:
614 // sig_map_ maps signatures to an index in code_cache_.
615 wasm::SignatureMap sig_map_;
616 std::vector<Handle<Code>> code_cache_;
617 };
618
619 } // namespace 740 } // namespace
620 741
621 Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store, 742 Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store,
622 size_t size, bool is_external, 743 size_t size, bool is_external,
623 bool enable_guard_regions) { 744 bool enable_guard_regions) {
624 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 745 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
625 JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store, 746 JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store,
626 static_cast<int>(size)); 747 static_cast<int>(size));
627 buffer->set_is_neuterable(false); 748 buffer->set_is_neuterable(false);
628 buffer->set_has_guard_region(enable_guard_regions); 749 buffer->set_has_guard_region(enable_guard_regions);
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 } 837 }
717 838
718 int wasm::GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module, 839 int wasm::GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
719 int func_index) { 840 int func_index) {
720 return GetFunctionOffsetAndLength(compiled_module, func_index).first; 841 return GetFunctionOffsetAndLength(compiled_module, func_index).first;
721 } 842 }
722 843
723 WasmModule::WasmModule(Zone* owned) 844 WasmModule::WasmModule(Zone* owned)
724 : owned_zone(owned), pending_tasks(new base::Semaphore(0)) {} 845 : owned_zone(owned), pending_tasks(new base::Semaphore(0)) {}
725 846
726 MaybeHandle<WasmModuleObject> CompileToModuleObject(
727 Isolate* isolate, WasmModule* m, ErrorThrower* thrower,
728 const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
729 Vector<const byte> asm_js_offset_table_bytes) {
730 Factory* factory = isolate->factory();
731 MaybeHandle<WasmModuleObject> nothing;
732 // The {module_wrapper} will take ownership of the {WasmModule} object,
733 // and it will be destroyed when the GC reclaims the wrapper object.
734 Handle<WasmModuleWrapper> module_wrapper = WasmModuleWrapper::New(isolate, m);
735 WasmInstance temp_instance(m);
736 temp_instance.context = isolate->native_context();
737 temp_instance.mem_size = WasmModule::kPageSize * m->min_mem_pages;
738 temp_instance.mem_start = nullptr;
739 temp_instance.globals_start = nullptr;
740
741 // Initialize the indirect tables with placeholders.
742 int function_table_count = static_cast<int>(m->function_tables.size());
743 Handle<FixedArray> function_tables =
744 factory->NewFixedArray(function_table_count, TENURED);
745 Handle<FixedArray> signature_tables =
746 factory->NewFixedArray(function_table_count, TENURED);
747 for (int i = 0; i < function_table_count; ++i) {
748 temp_instance.function_tables[i] = factory->NewFixedArray(1, TENURED);
749 temp_instance.signature_tables[i] = factory->NewFixedArray(1, TENURED);
750 function_tables->set(i, *temp_instance.function_tables[i]);
751 signature_tables->set(i, *temp_instance.signature_tables[i]);
752 }
753
754 HistogramTimerScope wasm_compile_module_time_scope(
755 isolate->counters()->wasm_compile_module_time());
756
757 ModuleBytesEnv module_env(m, &temp_instance, wire_bytes);
758
759 // The {code_table} array contains import wrappers and functions (which
760 // are both included in {functions.size()}, and export wrappers.
761 int code_table_size =
762 static_cast<int>(m->functions.size() + m->num_exported_functions);
763 Handle<FixedArray> code_table =
764 factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
765
766 // Initialize the code table with the illegal builtin. All call sites will be
767 // patched at instantiation.
768 Handle<Code> illegal_builtin = isolate->builtins()->Illegal();
769 for (uint32_t i = 0; i < m->functions.size(); ++i) {
770 code_table->set(static_cast<int>(i), *illegal_builtin);
771 temp_instance.function_code[i] = illegal_builtin;
772 }
773
774 isolate->counters()->wasm_functions_per_module()->AddSample(
775 static_cast<int>(m->functions.size()));
776 if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
777 // Avoid a race condition by collecting results into a second vector.
778 std::vector<Handle<Code>> results(temp_instance.function_code);
779 CompileInParallel(isolate, &module_env, results, thrower);
780 temp_instance.function_code.swap(results);
781 } else {
782 CompileSequentially(isolate, &module_env, temp_instance.function_code,
783 thrower);
784 }
785 if (thrower->error()) return nothing;
786
787 // At this point, compilation has completed. Update the code table.
788 for (size_t i = FLAG_skip_compiling_wasm_funcs;
789 i < temp_instance.function_code.size(); ++i) {
790 Code* code = *temp_instance.function_code[i];
791 code_table->set(static_cast<int>(i), code);
792 RecordStats(isolate, code);
793 }
794
795 // Create heap objects for script, module bytes and asm.js offset table to be
796 // stored in the shared module data.
797 Handle<Script> script;
798 Handle<ByteArray> asm_js_offset_table;
799 if (asm_js_script.is_null()) {
800 script = CreateWasmScript(isolate, wire_bytes);
801 } else {
802 script = asm_js_script;
803 asm_js_offset_table =
804 isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length());
805 asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
806 asm_js_offset_table_bytes.length());
807 }
808 // TODO(wasm): only save the sections necessary to deserialize a
809 // {WasmModule}. E.g. function bodies could be omitted.
810 Handle<String> module_bytes =
811 factory
812 ->NewStringFromOneByte({wire_bytes.start(), wire_bytes.length()},
813 TENURED)
814 .ToHandleChecked();
815 DCHECK(module_bytes->IsSeqOneByteString());
816
817 // Create the shared module data.
818 // TODO(clemensh): For the same module (same bytes / same hash), we should
819 // only have one WasmSharedModuleData. Otherwise, we might only set
820 // breakpoints on a (potentially empty) subset of the instances.
821
822 Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
823 isolate, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes),
824 script, asm_js_offset_table);
825
826 // Create the compiled module object, and populate with compiled functions
827 // and information needed at instantiation time. This object needs to be
828 // serializable. Instantiation may occur off a deserialized version of this
829 // object.
830 Handle<WasmCompiledModule> compiled_module =
831 WasmCompiledModule::New(isolate, shared);
832 compiled_module->set_num_imported_functions(m->num_imported_functions);
833 compiled_module->set_code_table(code_table);
834 compiled_module->set_min_mem_pages(m->min_mem_pages);
835 compiled_module->set_max_mem_pages(m->max_mem_pages);
836 if (function_table_count > 0) {
837 compiled_module->set_function_tables(function_tables);
838 compiled_module->set_signature_tables(signature_tables);
839 compiled_module->set_empty_function_tables(function_tables);
840 }
841
842 // If we created a wasm script, finish it now and make it public to the
843 // debugger.
844 if (asm_js_script.is_null()) {
845 script->set_wasm_compiled_module(*compiled_module);
846 isolate->debug()->OnAfterCompile(script);
847 }
848
849 // Compile JS->WASM wrappers for exported functions.
850 JSToWasmWrapperCache js_to_wasm_cache;
851 int func_index = 0;
852 for (auto exp : m->export_table) {
853 if (exp.kind != kExternalFunction) continue;
854 Handle<Code> wasm_code(Code::cast(code_table->get(exp.index)), isolate);
855 Handle<Code> wrapper_code = js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(
856 isolate, m, wasm_code, exp.index);
857 int export_index = static_cast<int>(m->functions.size() + func_index);
858 code_table->set(export_index, *wrapper_code);
859 RecordStats(isolate, *wrapper_code);
860 func_index++;
861 }
862
863 return WasmModuleObject::New(isolate, compiled_module);
864 }
865
866 static WasmFunction* GetWasmFunctionForImportWrapper(Isolate* isolate, 847 static WasmFunction* GetWasmFunctionForImportWrapper(Isolate* isolate,
867 Handle<Object> target) { 848 Handle<Object> target) {
868 if (target->IsJSFunction()) { 849 if (target->IsJSFunction()) {
869 Handle<JSFunction> func = Handle<JSFunction>::cast(target); 850 Handle<JSFunction> func = Handle<JSFunction>::cast(target);
870 if (func->code()->kind() == Code::JS_TO_WASM_FUNCTION) { 851 if (func->code()->kind() == Code::JS_TO_WASM_FUNCTION) {
871 auto exported = Handle<WasmExportedFunction>::cast(func); 852 auto exported = Handle<WasmExportedFunction>::cast(func);
872 Handle<WasmInstanceObject> other_instance(exported->instance(), isolate); 853 Handle<WasmInstanceObject> other_instance(exported->instance(), isolate);
873 int func_index = exported->function_index(); 854 int func_index = exported->function_index();
874 return &other_instance->module()->functions[func_index]; 855 return &other_instance->module()->functions[func_index];
875 } 856 }
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
975 module_(module_object->compiled_module()->module()), 956 module_(module_object->compiled_module()->module()),
976 thrower_(thrower), 957 thrower_(thrower),
977 module_object_(module_object), 958 module_object_(module_object),
978 ffi_(ffi.is_null() ? Handle<JSReceiver>::null() 959 ffi_(ffi.is_null() ? Handle<JSReceiver>::null()
979 : ffi.ToHandleChecked()), 960 : ffi.ToHandleChecked()),
980 memory_(memory.is_null() ? Handle<JSArrayBuffer>::null() 961 memory_(memory.is_null() ? Handle<JSArrayBuffer>::null()
981 : memory.ToHandleChecked()) {} 962 : memory.ToHandleChecked()) {}
982 963
983 // Build an instance, in all of its glory. 964 // Build an instance, in all of its glory.
984 MaybeHandle<WasmInstanceObject> Build() { 965 MaybeHandle<WasmInstanceObject> Build() {
985 MaybeHandle<WasmInstanceObject> nothing;
986
987 // Check that an imports argument was provided, if the module requires it. 966 // Check that an imports argument was provided, if the module requires it.
988 // No point in continuing otherwise. 967 // No point in continuing otherwise.
989 if (!module_->import_table.empty() && ffi_.is_null()) { 968 if (!module_->import_table.empty() && ffi_.is_null()) {
990 thrower_->TypeError( 969 thrower_->TypeError(
991 "Imports argument must be present and must be an object"); 970 "Imports argument must be present and must be an object");
992 return nothing; 971 return {};
993 } 972 }
994 973
995 HistogramTimerScope wasm_instantiate_module_time_scope( 974 HistogramTimerScope wasm_instantiate_module_time_scope(
996 isolate_->counters()->wasm_instantiate_module_time()); 975 isolate_->counters()->wasm_instantiate_module_time());
997 Factory* factory = isolate_->factory(); 976 Factory* factory = isolate_->factory();
998 977
999 //-------------------------------------------------------------------------- 978 //--------------------------------------------------------------------------
1000 // Reuse the compiled module (if no owner), otherwise clone. 979 // Reuse the compiled module (if no owner), otherwise clone.
1001 //-------------------------------------------------------------------------- 980 //--------------------------------------------------------------------------
1002 Handle<FixedArray> code_table; 981 Handle<FixedArray> code_table;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1079 //-------------------------------------------------------------------------- 1058 //--------------------------------------------------------------------------
1080 MaybeHandle<JSArrayBuffer> old_globals; 1059 MaybeHandle<JSArrayBuffer> old_globals;
1081 uint32_t globals_size = module_->globals_size; 1060 uint32_t globals_size = module_->globals_size;
1082 if (globals_size > 0) { 1061 if (globals_size > 0) {
1083 const bool enable_guard_regions = false; 1062 const bool enable_guard_regions = false;
1084 Handle<JSArrayBuffer> global_buffer = 1063 Handle<JSArrayBuffer> global_buffer =
1085 NewArrayBuffer(isolate_, globals_size, enable_guard_regions); 1064 NewArrayBuffer(isolate_, globals_size, enable_guard_regions);
1086 globals_ = global_buffer; 1065 globals_ = global_buffer;
1087 if (globals_.is_null()) { 1066 if (globals_.is_null()) {
1088 thrower_->RangeError("Out of memory: wasm globals"); 1067 thrower_->RangeError("Out of memory: wasm globals");
1089 return nothing; 1068 return {};
1090 } 1069 }
1091 Address old_globals_start = nullptr; 1070 Address old_globals_start = nullptr;
1092 if (!owner.is_null()) { 1071 if (!owner.is_null()) {
1093 DCHECK(owner.ToHandleChecked()->has_globals_buffer()); 1072 DCHECK(owner.ToHandleChecked()->has_globals_buffer());
1094 old_globals_start = static_cast<Address>( 1073 old_globals_start = static_cast<Address>(
1095 owner.ToHandleChecked()->globals_buffer()->backing_store()); 1074 owner.ToHandleChecked()->globals_buffer()->backing_store());
1096 } 1075 }
1097 Address new_globals_start = 1076 Address new_globals_start =
1098 static_cast<Address>(global_buffer->backing_store()); 1077 static_cast<Address>(global_buffer->backing_store());
1099 code_specialization.RelocateGlobals(old_globals_start, new_globals_start); 1078 code_specialization.RelocateGlobals(old_globals_start, new_globals_start);
1100 instance->set_globals_buffer(*global_buffer); 1079 instance->set_globals_buffer(*global_buffer);
1101 } 1080 }
1102 1081
1103 //-------------------------------------------------------------------------- 1082 //--------------------------------------------------------------------------
1104 // Prepare for initialization of function tables. 1083 // Prepare for initialization of function tables.
1105 //-------------------------------------------------------------------------- 1084 //--------------------------------------------------------------------------
1106 int function_table_count = 1085 int function_table_count =
1107 static_cast<int>(module_->function_tables.size()); 1086 static_cast<int>(module_->function_tables.size());
1108 table_instances_.reserve(module_->function_tables.size()); 1087 table_instances_.reserve(module_->function_tables.size());
1109 for (int index = 0; index < function_table_count; ++index) { 1088 for (int index = 0; index < function_table_count; ++index) {
1110 table_instances_.push_back( 1089 table_instances_.push_back(
1111 {Handle<WasmTableObject>::null(), Handle<FixedArray>::null(), 1090 {Handle<WasmTableObject>::null(), Handle<FixedArray>::null(),
1112 Handle<FixedArray>::null(), Handle<FixedArray>::null()}); 1091 Handle<FixedArray>::null(), Handle<FixedArray>::null()});
1113 } 1092 }
1114 1093
1115 //-------------------------------------------------------------------------- 1094 //--------------------------------------------------------------------------
1116 // Process the imports for the module. 1095 // Process the imports for the module.
1117 //-------------------------------------------------------------------------- 1096 //--------------------------------------------------------------------------
1118 int num_imported_functions = ProcessImports(code_table, instance); 1097 int num_imported_functions = ProcessImports(code_table, instance);
1119 if (num_imported_functions < 0) return nothing; 1098 if (num_imported_functions < 0) return {};
1120 1099
1121 //-------------------------------------------------------------------------- 1100 //--------------------------------------------------------------------------
1122 // Process the initialization for the module's globals. 1101 // Process the initialization for the module's globals.
1123 //-------------------------------------------------------------------------- 1102 //--------------------------------------------------------------------------
1124 InitGlobals(); 1103 InitGlobals();
1125 1104
1126 //-------------------------------------------------------------------------- 1105 //--------------------------------------------------------------------------
1127 // Set up the indirect function tables for the new instance. 1106 // Set up the indirect function tables for the new instance.
1128 //-------------------------------------------------------------------------- 1107 //--------------------------------------------------------------------------
1129 if (function_table_count > 0) 1108 if (function_table_count > 0)
1130 InitializeTables(code_table, instance, &code_specialization); 1109 InitializeTables(code_table, instance, &code_specialization);
1131 1110
1132 //-------------------------------------------------------------------------- 1111 //--------------------------------------------------------------------------
1133 // Set up the memory for the new instance. 1112 // Set up the memory for the new instance.
1134 //-------------------------------------------------------------------------- 1113 //--------------------------------------------------------------------------
1135 MaybeHandle<JSArrayBuffer> old_memory; 1114 MaybeHandle<JSArrayBuffer> old_memory;
1136 1115
1137 uint32_t min_mem_pages = module_->min_mem_pages; 1116 uint32_t min_mem_pages = module_->min_mem_pages;
1138 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); 1117 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
1139 1118
1140 if (!memory_.is_null()) { 1119 if (!memory_.is_null()) {
1141 // Set externally passed ArrayBuffer non neuterable. 1120 // Set externally passed ArrayBuffer non neuterable.
1142 memory_->set_is_neuterable(false); 1121 memory_->set_is_neuterable(false);
1143 1122
1144 DCHECK_IMPLIES(EnableGuardRegions(), module_->origin == kAsmJsOrigin || 1123 DCHECK_IMPLIES(EnableGuardRegions(), module_->origin == kAsmJsOrigin ||
1145 memory_->has_guard_region()); 1124 memory_->has_guard_region());
1146 } else if (min_mem_pages > 0) { 1125 } else if (min_mem_pages > 0) {
1147 memory_ = AllocateMemory(min_mem_pages); 1126 memory_ = AllocateMemory(min_mem_pages);
1148 if (memory_.is_null()) return nothing; // failed to allocate memory 1127 if (memory_.is_null()) return {}; // failed to allocate memory
1149 } 1128 }
1150 1129
1151 //-------------------------------------------------------------------------- 1130 //--------------------------------------------------------------------------
1152 // Check that indirect function table segments are within bounds. 1131 // Check that indirect function table segments are within bounds.
1153 //-------------------------------------------------------------------------- 1132 //--------------------------------------------------------------------------
1154 for (WasmTableInit& table_init : module_->table_inits) { 1133 for (WasmTableInit& table_init : module_->table_inits) {
1155 DCHECK(table_init.table_index < table_instances_.size()); 1134 DCHECK(table_init.table_index < table_instances_.size());
1156 uint32_t base = EvalUint32InitExpr(table_init.offset); 1135 uint32_t base = EvalUint32InitExpr(table_init.offset);
1157 uint32_t table_size = 1136 uint32_t table_size =
1158 table_instances_[table_init.table_index].function_table->length(); 1137 table_instances_[table_init.table_index].function_table->length();
1159 if (!in_bounds(base, static_cast<uint32_t>(table_init.entries.size()), 1138 if (!in_bounds(base, static_cast<uint32_t>(table_init.entries.size()),
1160 table_size)) { 1139 table_size)) {
1161 thrower_->LinkError("table initializer is out of bounds"); 1140 thrower_->LinkError("table initializer is out of bounds");
1162 return nothing; 1141 return {};
1163 } 1142 }
1164 } 1143 }
1165 1144
1166 //-------------------------------------------------------------------------- 1145 //--------------------------------------------------------------------------
1167 // Check that memory segments are within bounds. 1146 // Check that memory segments are within bounds.
1168 //-------------------------------------------------------------------------- 1147 //--------------------------------------------------------------------------
1169 for (WasmDataSegment& seg : module_->data_segments) { 1148 for (WasmDataSegment& seg : module_->data_segments) {
1170 uint32_t base = EvalUint32InitExpr(seg.dest_addr); 1149 uint32_t base = EvalUint32InitExpr(seg.dest_addr);
1171 uint32_t mem_size = memory_.is_null() 1150 uint32_t mem_size = memory_.is_null()
1172 ? 0 : static_cast<uint32_t>(memory_->byte_length()->Number()); 1151 ? 0 : static_cast<uint32_t>(memory_->byte_length()->Number());
1173 if (!in_bounds(base, seg.source_size, mem_size)) { 1152 if (!in_bounds(base, seg.source_size, mem_size)) {
1174 thrower_->LinkError("data segment is out of bounds"); 1153 thrower_->LinkError("data segment is out of bounds");
1175 return nothing; 1154 return {};
1176 } 1155 }
1177 } 1156 }
1178 1157
1179 //-------------------------------------------------------------------------- 1158 //--------------------------------------------------------------------------
1180 // Initialize memory. 1159 // Initialize memory.
1181 //-------------------------------------------------------------------------- 1160 //--------------------------------------------------------------------------
1182 if (!memory_.is_null()) { 1161 if (!memory_.is_null()) {
1183 instance->set_memory_buffer(*memory_); 1162 instance->set_memory_buffer(*memory_);
1184 Address mem_start = static_cast<Address>(memory_->backing_store()); 1163 Address mem_start = static_cast<Address>(memory_->backing_store());
1185 uint32_t mem_size = 1164 uint32_t mem_size =
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
1333 MaybeHandle<Object> retval = 1312 MaybeHandle<Object> retval =
1334 Execution::Call(isolate_, startup_fct, undefined, 0, nullptr); 1313 Execution::Call(isolate_, startup_fct, undefined, 0, nullptr);
1335 1314
1336 if (retval.is_null()) { 1315 if (retval.is_null()) {
1337 DCHECK(isolate_->has_pending_exception()); 1316 DCHECK(isolate_->has_pending_exception());
1338 isolate_->OptionalRescheduleException(false); 1317 isolate_->OptionalRescheduleException(false);
1339 // It's unfortunate that the new instance is already linked in the 1318 // It's unfortunate that the new instance is already linked in the
1340 // chain. However, we need to set up everything before executing the 1319 // chain. However, we need to set up everything before executing the
1341 // start function, such that stack trace information can be generated 1320 // start function, such that stack trace information can be generated
1342 // correctly already in the start function. 1321 // correctly already in the start function.
1343 return nothing; 1322 return {};
1344 } 1323 }
1345 } 1324 }
1346 1325
1347 DCHECK(!isolate_->has_pending_exception()); 1326 DCHECK(!isolate_->has_pending_exception());
1348 TRACE("Finishing instance %d\n", compiled_module_->instance_id()); 1327 TRACE("Finishing instance %d\n", compiled_module_->instance_id());
1349 TRACE_CHAIN(module_object_->compiled_module()); 1328 TRACE_CHAIN(module_object_->compiled_module());
1350 return instance; 1329 return instance;
1351 } 1330 }
1352 1331
1353 private: 1332 private:
(...skipping 1252 matching lines...) Expand 10 before | Expand all | Expand 10 after
2606 ModuleResult result = 2585 ModuleResult result =
2607 DecodeWasmModule(isolate, bytes.start(), bytes.end(), true, kWasmOrigin); 2586 DecodeWasmModule(isolate, bytes.start(), bytes.end(), true, kWasmOrigin);
2608 if (result.val) delete result.val; 2587 if (result.val) delete result.val;
2609 return result.ok(); 2588 return result.ok();
2610 } 2589 }
2611 2590
2612 MaybeHandle<WasmModuleObject> wasm::SyncCompileTranslatedAsmJs( 2591 MaybeHandle<WasmModuleObject> wasm::SyncCompileTranslatedAsmJs(
2613 Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes, 2592 Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
2614 Handle<Script> asm_js_script, 2593 Handle<Script> asm_js_script,
2615 Vector<const byte> asm_js_offset_table_bytes) { 2594 Vector<const byte> asm_js_offset_table_bytes) {
2616 MaybeHandle<WasmModuleObject> nothing;
2617 2595
2618 ModuleResult result = DecodeWasmModule(isolate, bytes.start(), bytes.end(), 2596 ModuleResult result = DecodeWasmModule(isolate, bytes.start(), bytes.end(),
2619 false, kAsmJsOrigin); 2597 false, kAsmJsOrigin);
2620 if (result.failed()) { 2598 if (result.failed()) {
2621 // TODO(titzer): use Result<std::unique_ptr<const WasmModule*>>? 2599 // TODO(titzer): use Result<std::unique_ptr<const WasmModule*>>?
2622 if (result.val) delete result.val; 2600 if (result.val) delete result.val;
2623 thrower->CompileFailed("Wasm decoding failed", result); 2601 thrower->CompileFailed("Wasm decoding failed", result);
2624 return nothing; 2602 return {};
2625 } 2603 }
2626 2604
2627 return CompileToModuleObject(isolate, const_cast<WasmModule*>(result.val), 2605 CompilationHelper helper(isolate, const_cast<WasmModule*>(result.val));
2628 thrower, bytes, asm_js_script, 2606 return helper.CompileToModuleObject(thrower, bytes, asm_js_script,
2629 asm_js_offset_table_bytes); 2607 asm_js_offset_table_bytes);
2630 } 2608 }
2631 2609
2632 MaybeHandle<WasmModuleObject> wasm::SyncCompile(Isolate* isolate, 2610 MaybeHandle<WasmModuleObject> wasm::SyncCompile(Isolate* isolate,
2633 ErrorThrower* thrower, 2611 ErrorThrower* thrower,
2634 const ModuleWireBytes& bytes) { 2612 const ModuleWireBytes& bytes) {
2635 MaybeHandle<WasmModuleObject> nothing;
2636
2637 if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) { 2613 if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) {
2638 thrower->CompileError("Wasm code generation disallowed in this context"); 2614 thrower->CompileError("Wasm code generation disallowed in this context");
2639 return nothing; 2615 return {};
2640 } 2616 }
2641 2617
2642 ModuleResult result = 2618 ModuleResult result =
2643 DecodeWasmModule(isolate, bytes.start(), bytes.end(), false, kWasmOrigin); 2619 DecodeWasmModule(isolate, bytes.start(), bytes.end(), false, kWasmOrigin);
2644 if (result.failed()) { 2620 if (result.failed()) {
2645 if (result.val) delete result.val; 2621 if (result.val) delete result.val;
2646 thrower->CompileFailed("Wasm decoding failed", result); 2622 thrower->CompileFailed("Wasm decoding failed", result);
2647 return nothing; 2623 return {};
2648 } 2624 }
2649 2625
2650 return CompileToModuleObject(isolate, const_cast<WasmModule*>(result.val), 2626 CompilationHelper helper(isolate, const_cast<WasmModule*>(result.val));
2651 thrower, bytes, Handle<Script>(), 2627 return helper.CompileToModuleObject(thrower, bytes, Handle<Script>(),
2652 Vector<const byte>()); 2628 Vector<const byte>());
2653 } 2629 }
2654 2630
2655 MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate( 2631 MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate(
2656 Isolate* isolate, ErrorThrower* thrower, 2632 Isolate* isolate, ErrorThrower* thrower,
2657 Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports, 2633 Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
2658 MaybeHandle<JSArrayBuffer> memory) { 2634 MaybeHandle<JSArrayBuffer> memory) {
2659 InstantiationHelper helper(isolate, thrower, module_object, imports, memory); 2635 InstantiationHelper helper(isolate, thrower, module_object, imports, memory);
2660 return helper.Build(); 2636 return helper.Build();
2661 } 2637 }
2662 2638
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
2732 Handle<String> module_property_name = 2708 Handle<String> module_property_name =
2733 isolate->factory()->InternalizeUtf8String("module"); 2709 isolate->factory()->InternalizeUtf8String("module");
2734 Handle<String> instance_property_name = 2710 Handle<String> instance_property_name =
2735 isolate->factory()->InternalizeUtf8String("instance"); 2711 isolate->factory()->InternalizeUtf8String("instance");
2736 JSObject::AddProperty(ret, module_property_name, module, NONE); 2712 JSObject::AddProperty(ret, module_property_name, module, NONE);
2737 JSObject::AddProperty(ret, instance_property_name, 2713 JSObject::AddProperty(ret, instance_property_name,
2738 instance_object.ToHandleChecked(), NONE); 2714 instance_object.ToHandleChecked(), NONE);
2739 2715
2740 ResolvePromise(isolate, promise, ret); 2716 ResolvePromise(isolate, promise, ret);
2741 } 2717 }
OLDNEW
« no previous file with comments | « src/compiler/wasm-compiler.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698