Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/wasm/wasm-objects.h"
6 : #include "src/utils.h"
7 :
8 : #include "src/assembler-inl.h"
9 : #include "src/base/iterator.h"
10 : #include "src/compiler/wasm-compiler.h"
11 : #include "src/debug/debug-interface.h"
12 : #include "src/objects-inl.h"
13 : #include "src/objects/debug-objects-inl.h"
14 : #include "src/wasm/module-compiler.h"
15 : #include "src/wasm/module-decoder.h"
16 : #include "src/wasm/wasm-code-specialization.h"
17 : #include "src/wasm/wasm-memory.h"
18 : #include "src/wasm/wasm-module.h"
19 : #include "src/wasm/wasm-objects-inl.h"
20 : #include "src/wasm/wasm-text.h"
21 :
22 : #define TRACE(...) \
23 : do { \
24 : if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
25 : } while (false)
26 :
27 : namespace v8 {
28 : namespace internal {
29 :
30 : // Import a few often used types from the wasm namespace.
31 : using GlobalHandleAddress = wasm::GlobalHandleAddress;
32 : using WasmFunction = wasm::WasmFunction;
33 : using WasmModule = wasm::WasmModule;
34 :
35 : namespace {
36 :
37 : // An iterator that returns first the module itself, then all modules linked via
38 : // next, then all linked via prev.
39 : class CompiledModulesIterator
40 : : public v8::base::iterator<std::input_iterator_tag,
41 : Handle<WasmCompiledModule>> {
42 : public:
43 : CompiledModulesIterator(Isolate* isolate,
44 : Handle<WasmCompiledModule> start_module, bool at_end)
45 : : isolate_(isolate),
46 : start_module_(start_module),
47 188 : current_(at_end ? Handle<WasmCompiledModule>::null() : start_module) {}
48 :
49 : Handle<WasmCompiledModule> operator*() const {
50 : DCHECK(!current_.is_null());
51 : return current_;
52 : }
53 :
54 94 : void operator++() { Advance(); }
55 :
56 : bool operator!=(const CompiledModulesIterator& other) {
57 : DCHECK(start_module_.is_identical_to(other.start_module_));
58 : return !current_.is_identical_to(other.current_);
59 : }
60 :
61 : private:
62 94 : void Advance() {
63 : DCHECK(!current_.is_null());
64 94 : if (!is_backwards_) {
65 94 : if (current_->has_weak_next_instance()) {
66 : WeakCell* weak_next = current_->ptr_to_weak_next_instance();
67 0 : if (!weak_next->cleared()) {
68 : current_ =
69 0 : handle(WasmCompiledModule::cast(weak_next->value()), isolate_);
70 0 : return;
71 : }
72 : }
73 : // No more modules in next-links, now try the previous-links.
74 94 : is_backwards_ = true;
75 94 : current_ = start_module_;
76 : }
77 94 : if (current_->has_weak_prev_instance()) {
78 : WeakCell* weak_prev = current_->ptr_to_weak_prev_instance();
79 0 : if (!weak_prev->cleared()) {
80 : current_ =
81 0 : handle(WasmCompiledModule::cast(weak_prev->value()), isolate_);
82 0 : return;
83 : }
84 : }
85 94 : current_ = Handle<WasmCompiledModule>::null();
86 : }
87 :
88 : friend class CompiledModuleInstancesIterator;
89 : Isolate* isolate_;
90 : Handle<WasmCompiledModule> start_module_;
91 : Handle<WasmCompiledModule> current_;
92 : bool is_backwards_ = false;
93 : };
94 :
95 : // An iterator based on the CompiledModulesIterator, but it returns all live
96 : // instances, not the WasmCompiledModules itself.
97 : class CompiledModuleInstancesIterator
98 : : public v8::base::iterator<std::input_iterator_tag,
99 : Handle<WasmInstanceObject>> {
100 : public:
101 188 : CompiledModuleInstancesIterator(Isolate* isolate,
102 : Handle<WasmCompiledModule> start_module,
103 : bool at_end)
104 : : it(isolate, start_module, at_end) {
105 236 : while (NeedToAdvance()) ++it;
106 188 : }
107 :
108 70 : Handle<WasmInstanceObject> operator*() {
109 : return handle(
110 : WasmInstanceObject::cast((*it)->weak_owning_instance()->value()),
111 210 : it.isolate_);
112 : }
113 :
114 70 : void operator++() {
115 70 : do {
116 70 : ++it;
117 : } while (NeedToAdvance());
118 70 : }
119 :
120 : bool operator!=(const CompiledModuleInstancesIterator& other) {
121 : return it != other.it;
122 : }
123 :
124 : private:
125 282 : bool NeedToAdvance() {
126 376 : return !it.current_.is_null() &&
127 164 : (!it.current_->has_weak_owning_instance() ||
128 282 : it.current_->ptr_to_weak_owning_instance()->cleared());
129 : }
130 : CompiledModulesIterator it;
131 : };
132 :
133 : v8::base::iterator_range<CompiledModuleInstancesIterator>
134 94 : iterate_compiled_module_instance_chain(
135 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
136 : return {CompiledModuleInstancesIterator(isolate, compiled_module, false),
137 188 : CompiledModuleInstancesIterator(isolate, compiled_module, true)};
138 : }
139 :
140 : #ifdef DEBUG
141 : bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module,
142 : int func_index, int offset_in_func) {
143 : DisallowHeapAllocation no_gc;
144 : AccountingAllocator alloc;
145 : Zone tmp(&alloc, ZONE_NAME);
146 : wasm::BodyLocalDecls locals(&tmp);
147 : const byte* module_start = compiled_module->module_bytes()->GetChars();
148 : WasmFunction& func = compiled_module->module()->functions[func_index];
149 : wasm::BytecodeIterator iterator(module_start + func.code.offset(),
150 : module_start + func.code.end_offset(),
151 : &locals);
152 : DCHECK_LT(0, locals.encoded_size);
153 : for (uint32_t offset : iterator.offsets()) {
154 : if (offset > static_cast<uint32_t>(offset_in_func)) break;
155 : if (offset == static_cast<uint32_t>(offset_in_func)) return true;
156 : }
157 : return false;
158 : }
159 : #endif // DEBUG
160 :
161 : } // namespace
162 :
163 148074 : Handle<WasmModuleObject> WasmModuleObject::New(
164 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
165 : Handle<JSFunction> module_cons(
166 296148 : isolate->native_context()->wasm_module_constructor());
167 : auto module_object = Handle<WasmModuleObject>::cast(
168 148074 : isolate->factory()->NewJSObject(module_cons));
169 148074 : module_object->set_compiled_module(*compiled_module);
170 : Handle<WeakCell> link_to_module =
171 148074 : isolate->factory()->NewWeakCell(module_object);
172 : compiled_module->set_weak_wasm_module(link_to_module);
173 148074 : return module_object;
174 : }
175 :
176 20 : void WasmModuleObject::ValidateStateForTesting(
177 : Isolate* isolate, Handle<WasmModuleObject> module_obj) {
178 : DisallowHeapAllocation no_gc;
179 : WasmCompiledModule* compiled_module = module_obj->compiled_module();
180 20 : CHECK(compiled_module->has_weak_wasm_module());
181 20 : CHECK_EQ(compiled_module->ptr_to_weak_wasm_module()->value(), *module_obj);
182 20 : CHECK(!compiled_module->has_weak_prev_instance());
183 20 : CHECK(!compiled_module->has_weak_next_instance());
184 20 : CHECK(!compiled_module->has_weak_owning_instance());
185 20 : }
186 :
187 1770 : Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
188 : int64_t maximum,
189 : Handle<FixedArray>* js_functions) {
190 : Handle<JSFunction> table_ctor(
191 3540 : isolate->native_context()->wasm_table_constructor());
192 : auto table_obj = Handle<WasmTableObject>::cast(
193 1770 : isolate->factory()->NewJSObject(table_ctor));
194 :
195 1770 : *js_functions = isolate->factory()->NewFixedArray(initial);
196 1770 : Object* null = isolate->heap()->null_value();
197 12690 : for (int i = 0; i < static_cast<int>(initial); ++i) {
198 10920 : (*js_functions)->set(i, null);
199 : }
200 1770 : table_obj->set_functions(**js_functions);
201 : DCHECK_EQ(maximum, static_cast<int>(maximum));
202 1770 : Handle<Object> max = isolate->factory()->NewNumber(maximum);
203 1770 : table_obj->set_maximum_length(*max);
204 :
205 1770 : Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0);
206 1770 : table_obj->set_dispatch_tables(*dispatch_tables);
207 1770 : return Handle<WasmTableObject>::cast(table_obj);
208 : }
209 :
210 1290 : Handle<FixedArray> WasmTableObject::AddDispatchTable(
211 : Isolate* isolate, Handle<WasmTableObject> table_obj,
212 : Handle<WasmInstanceObject> instance, int table_index,
213 : Handle<FixedArray> function_table, Handle<FixedArray> signature_table) {
214 : Handle<FixedArray> dispatch_tables(table_obj->dispatch_tables());
215 : DCHECK_EQ(0, dispatch_tables->length() % 4);
216 :
217 1290 : if (instance.is_null()) return dispatch_tables;
218 : // TODO(titzer): use weak cells here to avoid leaking instances.
219 :
220 : // Grow the dispatch table and add a new entry at the end.
221 : Handle<FixedArray> new_dispatch_tables =
222 1290 : isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 4);
223 :
224 1290 : new_dispatch_tables->set(dispatch_tables->length() + 0, *instance);
225 : new_dispatch_tables->set(dispatch_tables->length() + 1,
226 : Smi::FromInt(table_index));
227 2580 : new_dispatch_tables->set(dispatch_tables->length() + 2, *function_table);
228 2580 : new_dispatch_tables->set(dispatch_tables->length() + 3, *signature_table);
229 :
230 1290 : table_obj->set_dispatch_tables(*new_dispatch_tables);
231 :
232 1290 : return new_dispatch_tables;
233 : }
234 :
235 3300 : void WasmTableObject::Grow(Isolate* isolate, uint32_t count) {
236 : Handle<FixedArray> dispatch_tables(this->dispatch_tables());
237 : DCHECK_EQ(0, dispatch_tables->length() % 4);
238 530 : uint32_t old_size = functions()->length();
239 :
240 530 : Zone specialization_zone(isolate->allocator(), ZONE_NAME);
241 3300 : for (int i = 0; i < dispatch_tables->length(); i += 4) {
242 : Handle<FixedArray> old_function_table(
243 1120 : FixedArray::cast(dispatch_tables->get(i + 2)));
244 : Handle<FixedArray> old_signature_table(
245 1120 : FixedArray::cast(dispatch_tables->get(i + 3)));
246 : Handle<FixedArray> new_function_table = isolate->global_handles()->Create(
247 2240 : *isolate->factory()->CopyFixedArrayAndGrow(old_function_table, count));
248 : Handle<FixedArray> new_signature_table = isolate->global_handles()->Create(
249 2240 : *isolate->factory()->CopyFixedArrayAndGrow(old_signature_table, count));
250 :
251 : GlobalHandleAddress new_function_table_addr = new_function_table.address();
252 : GlobalHandleAddress new_signature_table_addr =
253 : new_signature_table.address();
254 :
255 1120 : int table_index = Smi::cast(dispatch_tables->get(i + 1))->value();
256 : // Update dispatch tables with new function/signature tables
257 1120 : dispatch_tables->set(i + 2, *new_function_table);
258 1120 : dispatch_tables->set(i + 3, *new_signature_table);
259 :
260 : // Patch the code of the respective instance.
261 : {
262 : DisallowHeapAllocation no_gc;
263 : wasm::CodeSpecialization code_specialization(isolate,
264 1120 : &specialization_zone);
265 : WasmInstanceObject* instance =
266 : WasmInstanceObject::cast(dispatch_tables->get(i));
267 : WasmCompiledModule* compiled_module = instance->compiled_module();
268 : GlobalHandleAddress old_function_table_addr =
269 : WasmCompiledModule::GetTableValue(
270 : compiled_module->ptr_to_function_tables(), table_index);
271 : GlobalHandleAddress old_signature_table_addr =
272 : WasmCompiledModule::GetTableValue(
273 : compiled_module->ptr_to_signature_tables(), table_index);
274 1120 : code_specialization.PatchTableSize(old_size, old_size + count);
275 : code_specialization.RelocatePointer(old_function_table_addr,
276 1120 : new_function_table_addr);
277 : code_specialization.RelocatePointer(old_signature_table_addr,
278 1120 : new_signature_table_addr);
279 1120 : code_specialization.ApplyToWholeInstance(instance);
280 : WasmCompiledModule::UpdateTableValue(
281 : compiled_module->ptr_to_function_tables(), table_index,
282 : new_function_table_addr);
283 : WasmCompiledModule::UpdateTableValue(
284 : compiled_module->ptr_to_signature_tables(), table_index,
285 1120 : new_signature_table_addr);
286 : }
287 530 : }
288 530 : }
289 :
290 3750 : void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
291 : int32_t index, Handle<JSFunction> function) {
292 : Handle<FixedArray> array(table->functions(), isolate);
293 :
294 : Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
295 :
296 : WasmFunction* wasm_function = nullptr;
297 3750 : Handle<Code> code = Handle<Code>::null();
298 : Handle<Object> value = isolate->factory()->null_value();
299 :
300 3750 : if (!function.is_null()) {
301 : auto exported_function = Handle<WasmExportedFunction>::cast(function);
302 2230 : wasm_function = wasm::GetWasmFunctionForExport(isolate, function);
303 : // The verification that {function} is an export was done
304 : // by the caller.
305 : DCHECK_NOT_NULL(wasm_function);
306 : value = function;
307 : // TODO(titzer): Make JSToWasm wrappers just call the WASM to WASM wrapper,
308 : // and then we can just reuse the WASM to WASM wrapper.
309 : Address new_context_address = reinterpret_cast<Address>(
310 2230 : exported_function->instance()->wasm_context()->get());
311 : code = compiler::CompileWasmToWasmWrapper(
312 : isolate, exported_function->GetWasmCode(), wasm_function->sig,
313 4460 : exported_function->function_index(), new_context_address);
314 : }
315 :
316 3750 : UpdateDispatchTables(isolate, dispatch_tables, index, wasm_function, code);
317 3750 : array->set(index, *value);
318 3750 : }
319 :
320 : namespace {
321 :
322 2132 : Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
323 : Handle<JSArrayBuffer> old_buffer,
324 : uint32_t pages, uint32_t maximum_pages) {
325 : Address old_mem_start = nullptr;
326 1962 : uint32_t old_size = 0;
327 1962 : if (!old_buffer.is_null()) {
328 : old_mem_start = static_cast<Address>(old_buffer->backing_store());
329 1962 : CHECK(old_buffer->byte_length()->ToUint32(&old_size));
330 : }
331 : DCHECK_EQ(0, old_size % WasmModule::kPageSize);
332 1962 : uint32_t old_pages = old_size / WasmModule::kPageSize;
333 : DCHECK_GE(std::numeric_limits<uint32_t>::max(),
334 : old_size + pages * WasmModule::kPageSize);
335 1962 : if (old_pages > maximum_pages || pages > maximum_pages - old_pages) {
336 : return Handle<JSArrayBuffer>::null();
337 : }
338 : const bool enable_guard_regions = old_buffer.is_null()
339 : ? trap_handler::UseTrapHandler()
340 1740 : : old_buffer->has_guard_region();
341 : size_t new_size =
342 1740 : static_cast<size_t>(old_pages + pages) * WasmModule::kPageSize;
343 1740 : if (enable_guard_regions && old_size != 0) {
344 : DCHECK_NOT_NULL(old_buffer->backing_store());
345 170 : if (new_size > FLAG_wasm_max_mem_pages * WasmModule::kPageSize ||
346 : new_size > kMaxInt) {
347 : return Handle<JSArrayBuffer>::null();
348 : }
349 : isolate->array_buffer_allocator()->SetProtection(
350 : old_mem_start, new_size,
351 170 : v8::ArrayBuffer::Allocator::Protection::kReadWrite);
352 : reinterpret_cast<v8::Isolate*>(isolate)
353 170 : ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize);
354 170 : Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(new_size);
355 170 : old_buffer->set_byte_length(*length_obj);
356 170 : return old_buffer;
357 : } else {
358 : Handle<JSArrayBuffer> new_buffer;
359 1570 : new_buffer = wasm::NewArrayBuffer(isolate, new_size, enable_guard_regions);
360 1570 : if (new_buffer.is_null() || old_size == 0) return new_buffer;
361 : Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
362 1450 : memcpy(new_mem_start, old_mem_start, old_size);
363 1450 : return new_buffer;
364 : }
365 : }
366 :
367 : // May GC, because SetSpecializationMemInfoFrom may GC
368 19929 : void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
369 : Handle<JSArrayBuffer> buffer) {
370 19929 : instance->set_memory_buffer(*buffer);
371 : auto wasm_context = instance->wasm_context()->get();
372 19929 : wasm_context->mem_start = reinterpret_cast<byte*>(buffer->backing_store());
373 19929 : wasm_context->mem_size = buffer->byte_length()->Number();
374 : #if DEBUG
375 : // To flush out bugs earlier, in DEBUG mode, check that all pages of the
376 : // memory are accessible by reading and writing one byte on each page.
377 : for (uint32_t offset = 0; offset < wasm_context->mem_size;
378 : offset += WasmModule::kPageSize) {
379 : byte val = wasm_context->mem_start[offset];
380 : wasm_context->mem_start[offset] = val;
381 : }
382 : #endif
383 19929 : }
384 :
385 : } // namespace
386 :
387 16084 : Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
388 : Handle<JSArrayBuffer> buffer,
389 : int32_t maximum) {
390 : Handle<JSFunction> memory_ctor(
391 32168 : isolate->native_context()->wasm_memory_constructor());
392 : auto memory_obj = Handle<WasmMemoryObject>::cast(
393 16084 : isolate->factory()->NewJSObject(memory_ctor, TENURED));
394 :
395 16084 : if (buffer.is_null()) {
396 : // If no buffer was provided, create a 0-length one.
397 : buffer = wasm::SetupArrayBuffer(isolate, nullptr, 0, nullptr, 0, false,
398 5120 : trap_handler::UseTrapHandler());
399 : } else {
400 : // Paranoid check that the buffer size makes sense.
401 10964 : uint32_t mem_size = 0;
402 10964 : CHECK(buffer->byte_length()->ToUint32(&mem_size));
403 : }
404 16084 : memory_obj->set_array_buffer(*buffer);
405 : memory_obj->set_maximum_pages(maximum);
406 :
407 16084 : return memory_obj;
408 : }
409 :
410 0 : uint32_t WasmMemoryObject::current_pages() {
411 : uint32_t byte_length;
412 0 : CHECK(array_buffer()->byte_length()->ToUint32(&byte_length));
413 0 : return byte_length / WasmModule::kPageSize;
414 : }
415 :
416 15776 : void WasmMemoryObject::AddInstance(Isolate* isolate,
417 : Handle<WasmMemoryObject> memory,
418 : Handle<WasmInstanceObject> instance) {
419 : Handle<WeakFixedArray> old_instances =
420 : memory->has_instances()
421 : ? Handle<WeakFixedArray>(memory->instances(), isolate)
422 15776 : : Handle<WeakFixedArray>::null();
423 : Handle<WeakFixedArray> new_instances =
424 15776 : WeakFixedArray::Add(old_instances, instance);
425 15776 : memory->set_instances(*new_instances);
426 : Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate);
427 15776 : SetInstanceMemory(isolate, instance, buffer);
428 15776 : }
429 :
430 3143 : void WasmMemoryObject::RemoveInstance(Isolate* isolate,
431 : Handle<WasmMemoryObject> memory,
432 : Handle<WasmInstanceObject> instance) {
433 3143 : if (memory->has_instances()) {
434 3143 : memory->instances()->Remove(instance);
435 : }
436 3143 : }
437 :
438 96 : void WasmMemoryObject::SetupNewBufferWithSameBackingStore(
439 : Isolate* isolate, Handle<WasmMemoryObject> memory_object, uint32_t size) {
440 : // In case of Memory.Grow(0), or Memory.Grow(delta) with guard pages enabled,
441 : // Setup a new buffer, update memory object, and instances associated with the
442 : // memory object, as the current buffer will be detached.
443 : Handle<JSArrayBuffer> old_buffer(memory_object->array_buffer());
444 : Handle<JSArrayBuffer> new_buffer;
445 :
446 : constexpr bool is_external = false;
447 : new_buffer = wasm::SetupArrayBuffer(
448 : isolate, old_buffer->allocation_base(), old_buffer->allocation_length(),
449 96 : old_buffer->backing_store(), size * WasmModule::kPageSize, is_external,
450 288 : old_buffer->has_guard_region());
451 96 : if (memory_object->has_instances()) {
452 : Handle<WeakFixedArray> instances(memory_object->instances(), isolate);
453 252 : for (int i = 0; i < instances->Length(); i++) {
454 104 : Object* elem = instances->Get(i);
455 135 : if (!elem->IsWasmInstanceObject()) continue;
456 : Handle<WasmInstanceObject> instance(WasmInstanceObject::cast(elem),
457 : isolate);
458 73 : SetInstanceMemory(isolate, instance, new_buffer);
459 : }
460 : }
461 96 : memory_object->set_array_buffer(*new_buffer);
462 96 : }
463 :
464 : // static
465 2038 : int32_t WasmMemoryObject::Grow(Isolate* isolate,
466 : Handle<WasmMemoryObject> memory_object,
467 : uint32_t pages) {
468 : Handle<JSArrayBuffer> old_buffer(memory_object->array_buffer());
469 2038 : uint32_t old_size = 0;
470 2038 : CHECK(old_buffer->byte_length()->ToUint32(&old_size));
471 : DCHECK_EQ(0, old_size % WasmModule::kPageSize);
472 : Handle<JSArrayBuffer> new_buffer;
473 : // Return current size if grow by 0.
474 2038 : if (pages == 0) return old_size / WasmModule::kPageSize;
475 :
476 1962 : uint32_t maximum_pages = FLAG_wasm_max_mem_pages;
477 1962 : if (memory_object->has_maximum_pages()) {
478 : maximum_pages = Min(FLAG_wasm_max_mem_pages,
479 1900 : static_cast<uint32_t>(memory_object->maximum_pages()));
480 : }
481 1962 : new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, maximum_pages);
482 1962 : if (new_buffer.is_null()) return -1;
483 :
484 1740 : if (memory_object->has_instances()) {
485 : Handle<WeakFixedArray> instances(memory_object->instances(), isolate);
486 13640 : for (int i = 0; i < instances->Length(); i++) {
487 5120 : Object* elem = instances->Get(i);
488 6160 : if (!elem->IsWasmInstanceObject()) continue;
489 : Handle<WasmInstanceObject> instance(WasmInstanceObject::cast(elem),
490 : isolate);
491 4080 : SetInstanceMemory(isolate, instance, new_buffer);
492 : }
493 : }
494 1740 : memory_object->set_array_buffer(*new_buffer);
495 1740 : return old_size / WasmModule::kPageSize;
496 : }
497 :
498 0 : WasmModuleObject* WasmInstanceObject::module_object() {
499 0 : return *compiled_module()->wasm_module();
500 : }
501 :
502 282524 : WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); }
503 :
504 1042 : Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo(
505 : Handle<WasmInstanceObject> instance) {
506 1042 : if (instance->has_debug_info()) return handle(instance->debug_info());
507 982 : Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance);
508 : DCHECK(instance->has_debug_info());
509 982 : return new_info;
510 : }
511 :
512 191035 : Handle<WasmInstanceObject> WasmInstanceObject::New(
513 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
514 : Handle<JSFunction> instance_cons(
515 382070 : isolate->native_context()->wasm_instance_constructor());
516 : Handle<JSObject> instance_object =
517 191035 : isolate->factory()->NewJSObject(instance_cons, TENURED);
518 :
519 : Handle<WasmInstanceObject> instance(
520 : reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate);
521 :
522 191035 : auto wasm_context = Managed<WasmContext>::Allocate(isolate);
523 191035 : wasm_context->get()->mem_start = nullptr;
524 191035 : wasm_context->get()->mem_size = 0;
525 191035 : wasm_context->get()->globals_start = nullptr;
526 191035 : instance->set_wasm_context(*wasm_context);
527 :
528 191035 : instance->set_compiled_module(*compiled_module);
529 191035 : return instance;
530 : }
531 :
532 156 : int32_t WasmInstanceObject::GetMemorySize() {
533 156 : if (!has_memory_buffer()) return 0;
534 156 : uint32_t bytes = memory_buffer()->byte_length()->Number();
535 : DCHECK_EQ(0, bytes % WasmModule::kPageSize);
536 156 : return bytes / WasmModule::kPageSize;
537 : }
538 :
539 1852 : int32_t WasmInstanceObject::GrowMemory(Isolate* isolate,
540 : Handle<WasmInstanceObject> instance,
541 : uint32_t pages) {
542 2008 : if (pages == 0) return instance->GetMemorySize();
543 : DCHECK(instance->has_memory_object());
544 : return WasmMemoryObject::Grow(
545 1696 : isolate, handle(instance->memory_object(), isolate), pages);
546 : }
547 :
548 0 : uint32_t WasmInstanceObject::GetMaxMemoryPages() {
549 0 : if (has_memory_object()) {
550 0 : if (memory_object()->has_maximum_pages()) {
551 : uint32_t maximum =
552 0 : static_cast<uint32_t>(memory_object()->maximum_pages());
553 0 : if (maximum < FLAG_wasm_max_mem_pages) return maximum;
554 : }
555 : }
556 0 : uint32_t compiled_maximum_pages = compiled_module()->module()->maximum_pages;
557 : Isolate* isolate = GetIsolate();
558 : assert(compiled_module()->module()->is_wasm());
559 : isolate->counters()->wasm_wasm_max_mem_pages_count()->AddSample(
560 0 : compiled_maximum_pages);
561 0 : if (compiled_maximum_pages != 0) return compiled_maximum_pages;
562 0 : return FLAG_wasm_max_mem_pages;
563 : }
564 :
565 133277 : WasmInstanceObject* WasmInstanceObject::GetOwningInstance(Code* code) {
566 : DisallowHeapAllocation no_gc;
567 : DCHECK(code->kind() == Code::WASM_FUNCTION ||
568 : code->kind() == Code::WASM_INTERPRETER_ENTRY);
569 : FixedArray* deopt_data = code->deoptimization_data();
570 : DCHECK_EQ(code->kind() == Code::WASM_INTERPRETER_ENTRY ? 1 : 2,
571 : deopt_data->length());
572 : Object* weak_link = deopt_data->get(0);
573 : DCHECK(weak_link->IsWeakCell());
574 : WeakCell* cell = WeakCell::cast(weak_link);
575 133277 : if (cell->cleared()) return nullptr;
576 133277 : return WasmInstanceObject::cast(cell->value());
577 : }
578 :
579 60 : void WasmInstanceObject::ValidateInstancesChainForTesting(
580 : Isolate* isolate, Handle<WasmModuleObject> module_obj, int instance_count) {
581 60 : CHECK_GE(instance_count, 0);
582 : DisallowHeapAllocation no_gc;
583 : WasmCompiledModule* compiled_module = module_obj->compiled_module();
584 60 : CHECK_EQ(JSObject::cast(compiled_module->ptr_to_weak_wasm_module()->value()),
585 : *module_obj);
586 : Object* prev = nullptr;
587 60 : int found_instances = compiled_module->has_weak_owning_instance() ? 1 : 0;
588 : WasmCompiledModule* current_instance = compiled_module;
589 160 : while (current_instance->has_weak_next_instance()) {
590 50 : CHECK((prev == nullptr && !current_instance->has_weak_prev_instance()) ||
591 : current_instance->ptr_to_weak_prev_instance()->value() == prev);
592 40 : CHECK_EQ(current_instance->ptr_to_weak_wasm_module()->value(), *module_obj);
593 40 : CHECK(current_instance->ptr_to_weak_owning_instance()
594 : ->value()
595 : ->IsWasmInstanceObject());
596 : prev = current_instance;
597 : current_instance = WasmCompiledModule::cast(
598 : current_instance->ptr_to_weak_next_instance()->value());
599 40 : ++found_instances;
600 40 : CHECK_LE(found_instances, instance_count);
601 : }
602 60 : CHECK_EQ(found_instances, instance_count);
603 60 : }
604 :
605 10 : void WasmInstanceObject::ValidateOrphanedInstanceForTesting(
606 : Isolate* isolate, Handle<WasmInstanceObject> instance) {
607 : DisallowHeapAllocation no_gc;
608 : WasmCompiledModule* compiled_module = instance->compiled_module();
609 10 : CHECK(compiled_module->has_weak_wasm_module());
610 10 : CHECK(compiled_module->ptr_to_weak_wasm_module()->cleared());
611 10 : }
612 :
613 145415 : bool WasmExportedFunction::IsWasmExportedFunction(Object* object) {
614 145415 : if (!object->IsJSFunction()) return false;
615 : Handle<JSFunction> js_function(JSFunction::cast(object));
616 143465 : if (Code::JS_TO_WASM_FUNCTION != js_function->code()->kind()) return false;
617 :
618 : Handle<Symbol> symbol(
619 : js_function->GetIsolate()->factory()->wasm_instance_symbol());
620 : MaybeHandle<Object> maybe_result =
621 133885 : JSObject::GetPropertyOrElement(js_function, symbol);
622 : Handle<Object> result;
623 133885 : if (!maybe_result.ToHandle(&result)) return false;
624 133885 : return result->IsWasmInstanceObject();
625 : }
626 :
627 136489 : WasmExportedFunction* WasmExportedFunction::cast(Object* object) {
628 : DCHECK(IsWasmExportedFunction(object));
629 136489 : return reinterpret_cast<WasmExportedFunction*>(object);
630 : }
631 :
632 138345 : WasmInstanceObject* WasmExportedFunction::instance() {
633 : DisallowHeapAllocation no_allocation;
634 : Handle<Symbol> symbol(GetIsolate()->factory()->wasm_instance_symbol());
635 : MaybeHandle<Object> result =
636 138345 : JSObject::GetPropertyOrElement(handle(this), symbol);
637 138345 : return WasmInstanceObject::cast(*(result.ToHandleChecked()));
638 : }
639 :
640 405676 : int WasmExportedFunction::function_index() {
641 : DisallowHeapAllocation no_allocation;
642 : Handle<Symbol> symbol = GetIsolate()->factory()->wasm_function_index_symbol();
643 : MaybeHandle<Object> result =
644 405676 : JSObject::GetPropertyOrElement(handle(this), symbol);
645 405676 : return result.ToHandleChecked()->Number();
646 : }
647 :
648 198486 : Handle<WasmExportedFunction> WasmExportedFunction::New(
649 : Isolate* isolate, Handle<WasmInstanceObject> instance,
650 : MaybeHandle<String> maybe_name, int func_index, int arity,
651 : Handle<Code> export_wrapper) {
652 : DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
653 : Handle<String> name;
654 198486 : if (!maybe_name.ToHandle(&name)) {
655 : EmbeddedVector<char, 16> buffer;
656 188150 : int length = SNPrintF(buffer, "%d", func_index);
657 : name = isolate->factory()
658 : ->NewStringFromOneByte(
659 188150 : Vector<uint8_t>::cast(buffer.SubVector(0, length)))
660 376300 : .ToHandleChecked();
661 : }
662 : Handle<SharedFunctionInfo> shared =
663 198486 : isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false);
664 : shared->set_length(arity);
665 : shared->set_internal_formal_parameter_count(arity);
666 : Handle<JSFunction> js_function = isolate->factory()->NewFunction(
667 198486 : isolate->sloppy_function_map(), name, export_wrapper);
668 :
669 198486 : js_function->set_shared(*shared);
670 : Handle<Symbol> instance_symbol(isolate->factory()->wasm_instance_symbol());
671 198486 : JSObject::AddProperty(js_function, instance_symbol, instance, DONT_ENUM);
672 :
673 : Handle<Symbol> function_index_symbol(
674 : isolate->factory()->wasm_function_index_symbol());
675 : JSObject::AddProperty(js_function, function_index_symbol,
676 396972 : isolate->factory()->NewNumber(func_index), DONT_ENUM);
677 :
678 198486 : return Handle<WasmExportedFunction>::cast(js_function);
679 : }
680 :
681 136115 : Handle<Code> WasmExportedFunction::GetWasmCode() {
682 : DisallowHeapAllocation no_gc;
683 : Handle<Code> export_wrapper_code = handle(this->code());
684 : DCHECK_EQ(export_wrapper_code->kind(), Code::JS_TO_WASM_FUNCTION);
685 : int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
686 382295 : for (RelocIterator it(*export_wrapper_code, mask);; it.next()) {
687 : DCHECK(!it.done());
688 764590 : Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
689 629520 : if (target->kind() != Code::WASM_FUNCTION &&
690 628510 : target->kind() != Code::WASM_TO_JS_FUNCTION &&
691 : target->kind() != Code::WASM_INTERPRETER_ENTRY)
692 : continue;
693 : // There should only be this one call to wasm code.
694 : #ifdef DEBUG
695 : for (it.next(); !it.done(); it.next()) {
696 : Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
697 : DCHECK(code->kind() != Code::WASM_FUNCTION &&
698 : code->kind() != Code::WASM_TO_JS_FUNCTION &&
699 : code->kind() != Code::WASM_INTERPRETER_ENTRY);
700 : }
701 : #endif
702 136115 : return handle(target);
703 246180 : }
704 : UNREACHABLE();
705 : }
706 :
707 0 : bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) {
708 0 : if (!object->IsFixedArray()) return false;
709 : FixedArray* arr = FixedArray::cast(object);
710 0 : if (arr->length() != kFieldCount) return false;
711 : Isolate* isolate = arr->GetIsolate();
712 0 : if (!arr->get(kModuleWrapperIndex)->IsForeign()) return false;
713 0 : if (!arr->get(kModuleBytesIndex)->IsUndefined(isolate) &&
714 : !arr->get(kModuleBytesIndex)->IsSeqOneByteString())
715 : return false;
716 0 : if (!arr->get(kScriptIndex)->IsScript()) return false;
717 0 : if (!arr->get(kAsmJsOffsetTableIndex)->IsUndefined(isolate) &&
718 : !arr->get(kAsmJsOffsetTableIndex)->IsByteArray())
719 : return false;
720 0 : if (!arr->get(kBreakPointInfosIndex)->IsUndefined(isolate) &&
721 : !arr->get(kBreakPointInfosIndex)->IsFixedArray())
722 : return false;
723 0 : return true;
724 : }
725 :
726 1462486 : WasmSharedModuleData* WasmSharedModuleData::cast(Object* object) {
727 : DCHECK(IsWasmSharedModuleData(object));
728 1462486 : return reinterpret_cast<WasmSharedModuleData*>(object);
729 : }
730 :
731 645440 : WasmModule* WasmSharedModuleData::module() {
732 : // We populate the kModuleWrapper field with a Foreign holding the
733 : // address to the address of a WasmModule. This is because we can
734 : // handle both cases when the WasmModule's lifetime is managed through
735 : // a Managed<WasmModule> object, as well as cases when it's managed
736 : // by the embedder. CcTests fall into the latter case.
737 : return *(reinterpret_cast<WasmModule**>(
738 1298051 : Foreign::cast(get(kModuleWrapperIndex))->foreign_address()));
739 : }
740 :
741 185130 : Handle<WasmSharedModuleData> WasmSharedModuleData::New(
742 : Isolate* isolate, Handle<Foreign> module_wrapper,
743 : Handle<SeqOneByteString> module_bytes, Handle<Script> script,
744 : Handle<ByteArray> asm_js_offset_table) {
745 : Handle<FixedArray> arr =
746 185130 : isolate->factory()->NewFixedArray(kFieldCount, TENURED);
747 185130 : arr->set(kModuleWrapperIndex, *module_wrapper);
748 185130 : if (!module_bytes.is_null()) {
749 185130 : arr->set(kModuleBytesIndex, *module_bytes);
750 : }
751 185130 : if (!script.is_null()) {
752 185130 : arr->set(kScriptIndex, *script);
753 : }
754 185130 : if (!asm_js_offset_table.is_null()) {
755 3547 : arr->set(kAsmJsOffsetTableIndex, *asm_js_offset_table);
756 : }
757 :
758 : DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*arr));
759 185130 : return Handle<WasmSharedModuleData>::cast(arr);
760 : }
761 :
762 43759 : bool WasmSharedModuleData::is_asm_js() {
763 43759 : bool asm_js = module()->is_asm_js();
764 : DCHECK_EQ(asm_js, script()->IsUserJavaScript());
765 : DCHECK_EQ(asm_js, has_asm_js_offset_table());
766 43759 : return asm_js;
767 : }
768 :
769 80 : void WasmSharedModuleData::ReinitializeAfterDeserialization(
770 : Isolate* isolate, Handle<WasmSharedModuleData> shared) {
771 : DCHECK(shared->get(kModuleWrapperIndex)->IsUndefined(isolate));
772 : #ifdef DEBUG
773 : // No BreakpointInfo objects should survive deserialization.
774 : if (shared->has_breakpoint_infos()) {
775 : for (int i = 0, e = shared->breakpoint_infos()->length(); i < e; ++i) {
776 : DCHECK(shared->breakpoint_infos()->get(i)->IsUndefined(isolate));
777 : }
778 : }
779 : #endif
780 :
781 160 : shared->set(kBreakPointInfosIndex, isolate->heap()->undefined_value());
782 :
783 : WasmModule* module = nullptr;
784 : {
785 : // We parse the module again directly from the module bytes, so
786 : // the underlying storage must not be moved meanwhile.
787 : DisallowHeapAllocation no_allocation;
788 : SeqOneByteString* module_bytes = shared->module_bytes();
789 : const byte* start =
790 80 : reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
791 80 : const byte* end = start + module_bytes->length();
792 : // TODO(titzer): remember the module origin in the compiled_module
793 : // For now, we assume serialized modules did not originate from asm.js.
794 : wasm::ModuleResult result =
795 160 : SyncDecodeWasmModule(isolate, start, end, false, wasm::kWasmOrigin);
796 80 : CHECK(result.ok());
797 80 : CHECK_NOT_NULL(result.val);
798 : // Take ownership of the WasmModule and immediately transfer it to the
799 : // WasmModuleWrapper below.
800 80 : module = result.val.release();
801 : }
802 :
803 : Handle<wasm::WasmModuleWrapper> module_wrapper =
804 80 : wasm::WasmModuleWrapper::From(isolate, module);
805 :
806 80 : shared->set(kModuleWrapperIndex, *module_wrapper);
807 : DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
808 80 : }
809 :
810 : namespace {
811 :
812 1578 : int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) {
813 1578 : if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt;
814 679 : return BreakPointInfo::cast(break_point_info_or_undef)->source_position();
815 : }
816 :
817 448 : int FindBreakpointInfoInsertPos(Isolate* isolate,
818 : Handle<FixedArray> breakpoint_infos,
819 : int position) {
820 : // Find insert location via binary search, taking care of undefined values on
821 : // the right. Position is always greater than zero.
822 : DCHECK_LT(0, position);
823 :
824 : int left = 0; // inclusive
825 : int right = breakpoint_infos->length(); // exclusive
826 1942 : while (right - left > 1) {
827 1046 : int mid = left + (right - left) / 2;
828 : Object* mid_obj = breakpoint_infos->get(mid);
829 1046 : if (GetBreakpointPos(isolate, mid_obj) <= position) {
830 : left = mid;
831 : } else {
832 : right = mid;
833 : }
834 : }
835 :
836 448 : int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
837 448 : return left_pos < position ? left + 1 : left;
838 : }
839 :
840 : } // namespace
841 :
842 94 : void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
843 : int position,
844 : Handle<Object> break_point_object) {
845 : Isolate* isolate = shared->GetIsolate();
846 : Handle<FixedArray> breakpoint_infos;
847 94 : if (shared->has_breakpoint_infos()) {
848 : breakpoint_infos = handle(shared->breakpoint_infos(), isolate);
849 : } else {
850 44 : breakpoint_infos = isolate->factory()->NewFixedArray(4, TENURED);
851 44 : shared->set(kBreakPointInfosIndex, *breakpoint_infos);
852 : }
853 :
854 : int insert_pos =
855 94 : FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
856 :
857 : // If a BreakPointInfo object already exists for this position, add the new
858 : // breakpoint object and return.
859 178 : if (insert_pos < breakpoint_infos->length() &&
860 84 : GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
861 : position) {
862 : Handle<BreakPointInfo> old_info(
863 : BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
864 0 : BreakPointInfo::SetBreakPoint(old_info, break_point_object);
865 94 : return;
866 : }
867 :
868 : // Enlarge break positions array if necessary.
869 : bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
870 94 : ->IsUndefined(isolate);
871 : Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
872 94 : if (need_realloc) {
873 : new_breakpoint_infos = isolate->factory()->NewFixedArray(
874 10 : 2 * breakpoint_infos->length(), TENURED);
875 10 : shared->set(kBreakPointInfosIndex, *new_breakpoint_infos);
876 : // Copy over the entries [0, insert_pos).
877 70 : for (int i = 0; i < insert_pos; ++i)
878 60 : new_breakpoint_infos->set(i, breakpoint_infos->get(i));
879 : }
880 :
881 : // Move elements [insert_pos+1, ...] up by one.
882 188 : for (int i = insert_pos + 1; i < breakpoint_infos->length(); ++i) {
883 : Object* entry = breakpoint_infos->get(i);
884 74 : if (entry->IsUndefined(isolate)) break;
885 0 : new_breakpoint_infos->set(i + 1, entry);
886 : }
887 :
888 : // Generate new BreakpointInfo.
889 : Handle<BreakPointInfo> breakpoint_info =
890 94 : isolate->factory()->NewBreakPointInfo(position);
891 94 : BreakPointInfo::SetBreakPoint(breakpoint_info, break_point_object);
892 :
893 : // Now insert new position at insert_pos.
894 94 : new_breakpoint_infos->set(insert_pos, *breakpoint_info);
895 : }
896 :
897 152662 : void WasmSharedModuleData::SetBreakpointsOnNewInstance(
898 : Handle<WasmSharedModuleData> shared, Handle<WasmInstanceObject> instance) {
899 305324 : if (!shared->has_breakpoint_infos()) return;
900 : Isolate* isolate = shared->GetIsolate();
901 : Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
902 : isolate);
903 : Handle<WasmDebugInfo> debug_info =
904 0 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
905 :
906 : Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate);
907 : // If the array exists, it should not be empty.
908 : DCHECK_LT(0, breakpoint_infos->length());
909 :
910 0 : for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
911 : Handle<Object> obj(breakpoint_infos->get(i), isolate);
912 0 : if (obj->IsUndefined(isolate)) {
913 : for (; i < e; ++i) {
914 : DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate));
915 : }
916 : break;
917 : }
918 : Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
919 : int position = breakpoint_info->source_position();
920 :
921 : // Find the function for this breakpoint, and set the breakpoint.
922 0 : int func_index = compiled_module->GetContainingFunction(position);
923 : DCHECK_LE(0, func_index);
924 0 : WasmFunction& func = compiled_module->module()->functions[func_index];
925 0 : int offset_in_func = position - func.code.offset();
926 0 : WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
927 : }
928 : }
929 :
930 3571 : void WasmSharedModuleData::PrepareForLazyCompilation(
931 : Handle<WasmSharedModuleData> shared) {
932 3571 : if (shared->has_lazy_compilation_orchestrator()) return;
933 : Isolate* isolate = shared->GetIsolate();
934 : auto orch_handle =
935 3571 : Managed<wasm::LazyCompilationOrchestrator>::Allocate(isolate);
936 3571 : shared->set_lazy_compilation_orchestrator(*orch_handle);
937 : }
938 :
939 185130 : Handle<WasmCompiledModule> WasmCompiledModule::New(
940 : Isolate* isolate, Handle<WasmSharedModuleData> shared,
941 : Handle<FixedArray> code_table, Handle<FixedArray> export_wrappers,
942 186710 : const std::vector<GlobalHandleAddress>& function_tables,
943 1580 : const std::vector<GlobalHandleAddress>& signature_tables) {
944 : DCHECK_EQ(function_tables.size(), signature_tables.size());
945 : Handle<FixedArray> ret =
946 185130 : isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
947 : // WasmCompiledModule::cast would fail since fields are not set yet.
948 : Handle<WasmCompiledModule> compiled_module(
949 : reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
950 : compiled_module->InitId();
951 : compiled_module->set_shared(shared);
952 185130 : compiled_module->set_native_context(isolate->native_context());
953 : compiled_module->set_code_table(code_table);
954 : compiled_module->set_export_wrappers(export_wrappers);
955 : // TODO(mtrofin): we copy these because the order of finalization isn't
956 : // reliable, and we need these at Reset (which is called at
957 : // finalization). If the order were reliable, and top-down, we could instead
958 : // just get them from shared().
959 185130 : compiled_module->set_initial_pages(shared->module()->initial_pages);
960 : compiled_module->set_num_imported_functions(
961 185130 : shared->module()->num_imported_functions);
962 :
963 185130 : int num_function_tables = static_cast<int>(function_tables.size());
964 185130 : if (num_function_tables > 0) {
965 : Handle<FixedArray> st =
966 1580 : isolate->factory()->NewFixedArray(num_function_tables, TENURED);
967 : Handle<FixedArray> ft =
968 1580 : isolate->factory()->NewFixedArray(num_function_tables, TENURED);
969 3160 : for (int i = 0; i < num_function_tables; ++i) {
970 1580 : size_t index = static_cast<size_t>(i);
971 1580 : SetTableValue(isolate, ft, i, function_tables[index]);
972 1580 : SetTableValue(isolate, st, i, signature_tables[index]);
973 : }
974 : // TODO(wasm): setting the empty tables here this way is OK under the
975 : // assumption that we compile and then instantiate. It needs rework if we do
976 : // direct instantiation. The empty tables are used as a default when
977 : // resetting the compiled module.
978 : compiled_module->set_signature_tables(st);
979 : compiled_module->set_empty_signature_tables(st);
980 : compiled_module->set_function_tables(ft);
981 : compiled_module->set_empty_function_tables(ft);
982 : }
983 :
984 : // TODO(mtrofin): copy the rest of the specialization parameters over.
985 : // We're currently OK because we're only using defaults.
986 185130 : return compiled_module;
987 : }
988 :
989 6625 : Handle<WasmCompiledModule> WasmCompiledModule::Clone(
990 : Isolate* isolate, Handle<WasmCompiledModule> module) {
991 : Handle<FixedArray> code_copy =
992 6625 : isolate->factory()->CopyFixedArray(module->code_table());
993 : Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast(
994 6625 : isolate->factory()->CopyFixedArray(module));
995 : ret->InitId();
996 : ret->set_code_table(code_copy);
997 : ret->reset_weak_owning_instance();
998 : ret->reset_weak_next_instance();
999 : ret->reset_weak_prev_instance();
1000 : ret->reset_weak_exported_functions();
1001 6625 : return ret;
1002 : }
1003 :
1004 7000 : void WasmCompiledModule::SetTableValue(Isolate* isolate,
1005 : Handle<FixedArray> table, int index,
1006 : Address value) {
1007 : Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(
1008 7000 : static_cast<double>(reinterpret_cast<size_t>(value)), MUTABLE, TENURED);
1009 7000 : table->set(index, *number);
1010 7000 : }
1011 :
1012 0 : void WasmCompiledModule::UpdateTableValue(FixedArray* table, int index,
1013 : Address value) {
1014 : DisallowHeapAllocation no_gc;
1015 : HeapNumber::cast(table->get(index))
1016 2240 : ->set_value(static_cast<double>(reinterpret_cast<size_t>(value)));
1017 0 : }
1018 :
1019 11120 : Address WasmCompiledModule::GetTableValue(FixedArray* table, int index) {
1020 : DisallowHeapAllocation no_gc;
1021 : double value = HeapNumber::cast(table->get(index))->value();
1022 13536 : return reinterpret_cast<Address>(static_cast<size_t>(value));
1023 : }
1024 :
1025 1080 : void WasmCompiledModule::Reset(Isolate* isolate,
1026 : WasmCompiledModule* compiled_module) {
1027 : DisallowHeapAllocation no_gc;
1028 : TRACE("Resetting %d\n", compiled_module->instance_id());
1029 : Object* undefined = *isolate->factory()->undefined_value();
1030 : Object* fct_obj = compiled_module->ptr_to_code_table();
1031 540 : if (fct_obj != nullptr && fct_obj != undefined) {
1032 : // Patch code to update memory references, global references, and function
1033 : // table references.
1034 540 : Zone specialization_zone(isolate->allocator(), ZONE_NAME);
1035 1080 : wasm::CodeSpecialization code_specialization(isolate, &specialization_zone);
1036 :
1037 : // Reset function tables.
1038 540 : if (compiled_module->has_function_tables()) {
1039 : FixedArray* function_tables = compiled_module->ptr_to_function_tables();
1040 : FixedArray* signature_tables = compiled_module->ptr_to_signature_tables();
1041 : FixedArray* empty_function_tables =
1042 : compiled_module->ptr_to_empty_function_tables();
1043 : FixedArray* empty_signature_tables =
1044 : compiled_module->ptr_to_empty_signature_tables();
1045 44 : if (function_tables != empty_function_tables) {
1046 : DCHECK_EQ(function_tables->length(), empty_function_tables->length());
1047 88 : for (int i = 0, e = function_tables->length(); i < e; ++i) {
1048 : GlobalHandleAddress func_addr =
1049 : WasmCompiledModule::GetTableValue(function_tables, i);
1050 : GlobalHandleAddress sig_addr =
1051 : WasmCompiledModule::GetTableValue(signature_tables, i);
1052 : code_specialization.RelocatePointer(
1053 : func_addr,
1054 44 : WasmCompiledModule::GetTableValue(empty_function_tables, i));
1055 : code_specialization.RelocatePointer(
1056 : sig_addr,
1057 44 : WasmCompiledModule::GetTableValue(empty_signature_tables, i));
1058 : }
1059 : compiled_module->set_ptr_to_function_tables(empty_function_tables);
1060 : compiled_module->set_ptr_to_signature_tables(empty_signature_tables);
1061 : }
1062 : }
1063 :
1064 : FixedArray* functions = FixedArray::cast(fct_obj);
1065 3207 : for (int i = compiled_module->num_imported_functions(),
1066 : end = functions->length();
1067 : i < end; ++i) {
1068 : Code* code = Code::cast(functions->get(i));
1069 : // Skip lazy compile stubs.
1070 2127 : if (code->builtin_index() == Builtins::kWasmCompileLazy) continue;
1071 1359 : if (code->kind() != Code::WASM_FUNCTION) {
1072 : // From here on, there should only be wrappers for exported functions.
1073 : for (; i < end; ++i) {
1074 : DCHECK_EQ(Code::JS_TO_WASM_FUNCTION,
1075 : Code::cast(functions->get(i))->kind());
1076 : }
1077 : break;
1078 : }
1079 : bool changed =
1080 1359 : code_specialization.ApplyToWasmCode(code, SKIP_ICACHE_FLUSH);
1081 : // TODO(wasm): Check if this is faster than passing FLUSH_ICACHE_IF_NEEDED
1082 : // above.
1083 1359 : if (changed) {
1084 56 : Assembler::FlushICache(isolate, code->instruction_start(),
1085 112 : code->instruction_size());
1086 : }
1087 540 : }
1088 : }
1089 540 : }
1090 :
1091 0 : void WasmCompiledModule::InitId() {
1092 : #if DEBUG
1093 : static uint32_t instance_id_counter = 0;
1094 : set(kID_instance_id, Smi::FromInt(instance_id_counter++));
1095 : TRACE("New compiled module id: %d\n", instance_id());
1096 : #endif
1097 0 : }
1098 :
1099 201684 : MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
1100 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
1101 : wasm::WireBytesRef ref) {
1102 : // TODO(wasm): cache strings from modules if it's a performance win.
1103 : Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(),
1104 : isolate);
1105 : return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
1106 201684 : isolate, module_bytes, ref);
1107 : }
1108 :
1109 296490 : MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
1110 : Isolate* isolate, Handle<SeqOneByteString> module_bytes,
1111 : wasm::WireBytesRef ref) {
1112 : DCHECK_GE(module_bytes->length(), ref.end_offset());
1113 : // UTF8 validation happens at decode time.
1114 : DCHECK(unibrow::Utf8::ValidateEncoding(
1115 : reinterpret_cast<const byte*>(module_bytes->GetCharsAddress() +
1116 : ref.offset()),
1117 : ref.length()));
1118 : DCHECK_GE(kMaxInt, ref.offset());
1119 : DCHECK_GE(kMaxInt, ref.length());
1120 : return isolate->factory()->NewStringFromUtf8SubString(
1121 296490 : module_bytes, static_cast<int>(ref.offset()),
1122 794664 : static_cast<int>(ref.length()));
1123 : }
1124 :
1125 0 : bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) {
1126 0 : if (!obj->IsFixedArray()) return false;
1127 : FixedArray* arr = FixedArray::cast(obj);
1128 0 : if (arr->length() != PropertyIndices::Count) return false;
1129 : #define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \
1130 : do { \
1131 : Object* obj = arr->get(kID_##NAME); \
1132 : if (!(TYPE_CHECK)) return false; \
1133 : } while (false);
1134 : // We're OK with undefined, generally, because maybe we don't
1135 : // have a value for that item. For example, we may not have a
1136 : // memory, or globals.
1137 : // We're not OK with the const numbers being undefined. They are
1138 : // expected to be initialized at construction.
1139 : #define WCM_CHECK_OBJECT(TYPE, NAME) \
1140 : WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE())
1141 : #define WCM_CHECK_CONST_OBJECT(TYPE, NAME) \
1142 : WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE())
1143 : #define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \
1144 : WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj))
1145 : #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME)
1146 : #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) \
1147 : WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsSmi())
1148 : #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME)
1149 : #define WCM_CHECK_SMALL_CONST_NUMBER(TYPE, NAME) \
1150 : WCM_CHECK_TYPE(NAME, obj->IsSmi())
1151 : #undef WCM_CHECK_TYPE
1152 : #undef WCM_CHECK_OBJECT
1153 : #undef WCM_CHECK_CONST_OBJECT
1154 : #undef WCM_CHECK_WASM_OBJECT
1155 : #undef WCM_CHECK_WEAK_LINK
1156 : #undef WCM_CHECK_SMALL_NUMBER
1157 : #undef WCM_CHECK
1158 : #undef WCM_CHECK_SMALL_CONST_NUMBER
1159 :
1160 : // All checks passed.
1161 0 : return true;
1162 : }
1163 :
1164 154832 : void WasmCompiledModule::PrintInstancesChain() {
1165 : #if DEBUG
1166 : if (!FLAG_trace_wasm_instances) return;
1167 : for (WasmCompiledModule* current = this; current != nullptr;) {
1168 : PrintF("->%d", current->instance_id());
1169 : if (!current->has_weak_next_instance()) break;
1170 : DCHECK(!current->ptr_to_weak_next_instance()->cleared());
1171 : current =
1172 : WasmCompiledModule::cast(current->ptr_to_weak_next_instance()->value());
1173 : }
1174 : PrintF("\n");
1175 : #endif
1176 154832 : }
1177 :
1178 80 : void WasmCompiledModule::ReinitializeAfterDeserialization(
1179 40 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
1180 : // This method must only be called immediately after deserialization.
1181 : // At this point, no module wrapper exists, so the shared module data is
1182 : // incomplete.
1183 : Handle<WasmSharedModuleData> shared(
1184 : static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)),
1185 : isolate);
1186 : DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
1187 80 : WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
1188 : int function_table_count =
1189 160 : static_cast<int>(compiled_module->module()->function_tables.size());
1190 80 : if (function_table_count > 0) {
1191 : // The tables are of the right size, but contain bogus global handle
1192 : // addresses. Produce new global handles for the empty tables, then reset,
1193 : // which will relocate the code. We end up with a WasmCompiledModule as-if
1194 : // it were just compiled.
1195 : DCHECK(compiled_module->has_function_tables());
1196 : DCHECK(compiled_module->has_signature_tables());
1197 : DCHECK(compiled_module->has_empty_signature_tables());
1198 : DCHECK(compiled_module->has_empty_function_tables());
1199 :
1200 20 : for (int i = 0; i < function_table_count; ++i) {
1201 : Handle<Object> global_func_table_handle =
1202 20 : isolate->global_handles()->Create(isolate->heap()->undefined_value());
1203 : Handle<Object> global_sig_table_handle =
1204 20 : isolate->global_handles()->Create(isolate->heap()->undefined_value());
1205 : GlobalHandleAddress new_func_table = global_func_table_handle.address();
1206 : GlobalHandleAddress new_sig_table = global_sig_table_handle.address();
1207 : SetTableValue(isolate, compiled_module->empty_function_tables(), i,
1208 20 : new_func_table);
1209 : SetTableValue(isolate, compiled_module->empty_signature_tables(), i,
1210 20 : new_sig_table);
1211 : }
1212 : }
1213 :
1214 : // Reset, but don't delete any global handles, because their owning instance
1215 : // may still be active.
1216 80 : WasmCompiledModule::Reset(isolate, *compiled_module);
1217 : DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
1218 80 : }
1219 :
1220 0 : uint32_t WasmCompiledModule::default_mem_size() const {
1221 0 : return initial_pages() * WasmModule::kPageSize;
1222 : }
1223 :
1224 680 : MaybeHandle<String> WasmCompiledModule::GetModuleNameOrNull(
1225 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
1226 680 : WasmModule* module = compiled_module->module();
1227 680 : if (!module->name.is_set()) return {};
1228 : return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
1229 0 : isolate, compiled_module, module->name);
1230 : }
1231 :
1232 2015 : MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull(
1233 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
1234 : uint32_t func_index) {
1235 : DCHECK_LT(func_index, compiled_module->module()->functions.size());
1236 4030 : WasmFunction& function = compiled_module->module()->functions[func_index];
1237 2015 : if (!function.name.is_set()) return {};
1238 : return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
1239 1975 : isolate, compiled_module, function.name);
1240 : }
1241 :
1242 755 : Handle<String> WasmCompiledModule::GetFunctionName(
1243 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
1244 : uint32_t func_index) {
1245 : MaybeHandle<String> name =
1246 755 : GetFunctionNameOrNull(isolate, compiled_module, func_index);
1247 755 : if (!name.is_null()) return name.ToHandleChecked();
1248 0 : return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
1249 : }
1250 :
1251 11259 : Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName(
1252 : uint32_t func_index) {
1253 : DCHECK_GT(module()->functions.size(), func_index);
1254 11259 : WasmFunction& function = module()->functions[func_index];
1255 : SeqOneByteString* bytes = module_bytes();
1256 : DCHECK_GE(bytes->length(), function.name.end_offset());
1257 : return Vector<const uint8_t>(
1258 11259 : bytes->GetCharsAddress() + function.name.offset(),
1259 22518 : function.name.length());
1260 : }
1261 :
1262 40600 : int WasmCompiledModule::GetFunctionOffset(uint32_t func_index) {
1263 81200 : std::vector<WasmFunction>& functions = module()->functions;
1264 81200 : if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
1265 : DCHECK_GE(kMaxInt, functions[func_index].code.offset());
1266 40600 : return static_cast<int>(functions[func_index].code.offset());
1267 : }
1268 :
1269 582 : int WasmCompiledModule::GetContainingFunction(uint32_t byte_offset) {
1270 582 : std::vector<WasmFunction>& functions = module()->functions;
1271 :
1272 : // Binary search for a function containing the given position.
1273 : int left = 0; // inclusive
1274 582 : int right = static_cast<int>(functions.size()); // exclusive
1275 582 : if (right == 0) return false;
1276 1122 : while (right - left > 1) {
1277 540 : int mid = left + (right - left) / 2;
1278 1080 : if (functions[mid].code.offset() <= byte_offset) {
1279 : left = mid;
1280 : } else {
1281 : right = mid;
1282 : }
1283 : }
1284 : // If the found function does not contains the given position, return -1.
1285 582 : WasmFunction& func = functions[left];
1286 1164 : if (byte_offset < func.code.offset() ||
1287 : byte_offset >= func.code.end_offset()) {
1288 : return -1;
1289 : }
1290 :
1291 582 : return left;
1292 : }
1293 :
1294 488 : bool WasmCompiledModule::GetPositionInfo(uint32_t position,
1295 : Script::PositionInfo* info) {
1296 488 : int func_index = GetContainingFunction(position);
1297 488 : if (func_index < 0) return false;
1298 :
1299 488 : WasmFunction& function = module()->functions[func_index];
1300 :
1301 488 : info->line = func_index;
1302 488 : info->column = position - function.code.offset();
1303 488 : info->line_start = function.code.offset();
1304 488 : info->line_end = function.code.end_offset();
1305 488 : return true;
1306 : }
1307 :
1308 : namespace {
1309 :
1310 : enum AsmJsOffsetTableEntryLayout {
1311 : kOTEByteOffset,
1312 : kOTECallPosition,
1313 : kOTENumberConvPosition,
1314 : kOTESize
1315 : };
1316 :
1317 968 : Handle<ByteArray> GetDecodedAsmJsOffsetTable(
1318 : Handle<WasmCompiledModule> compiled_module, Isolate* isolate) {
1319 : DCHECK(compiled_module->is_asm_js());
1320 : Handle<ByteArray> offset_table(
1321 1936 : compiled_module->shared()->asm_js_offset_table(), isolate);
1322 :
1323 : // The last byte in the asm_js_offset_tables ByteArray tells whether it is
1324 : // still encoded (0) or decoded (1).
1325 : enum AsmJsTableType : int { Encoded = 0, Decoded = 1 };
1326 968 : int table_type = offset_table->get(offset_table->length() - 1);
1327 : DCHECK(table_type == Encoded || table_type == Decoded);
1328 968 : if (table_type == Decoded) return offset_table;
1329 :
1330 : wasm::AsmJsOffsetsResult asm_offsets;
1331 : {
1332 : DisallowHeapAllocation no_gc;
1333 78 : const byte* bytes_start = offset_table->GetDataStartAddress();
1334 78 : const byte* bytes_end = bytes_start + offset_table->length() - 1;
1335 78 : asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end);
1336 : }
1337 : // Wasm bytes must be valid and must contain asm.js offset table.
1338 : DCHECK(asm_offsets.ok());
1339 : DCHECK_GE(kMaxInt, asm_offsets.val.size());
1340 156 : int num_functions = static_cast<int>(asm_offsets.val.size());
1341 : int num_imported_functions =
1342 78 : static_cast<int>(compiled_module->module()->num_imported_functions);
1343 : DCHECK_EQ(compiled_module->module()->functions.size(),
1344 : static_cast<size_t>(num_functions) + num_imported_functions);
1345 : int num_entries = 0;
1346 270 : for (int func = 0; func < num_functions; ++func) {
1347 384 : size_t new_size = asm_offsets.val[func].size();
1348 : DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
1349 192 : num_entries += static_cast<int>(new_size);
1350 : }
1351 : // One byte to encode that this is a decoded table.
1352 : DCHECK_GE(kMaxInt,
1353 : 1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
1354 78 : int total_size = 1 + num_entries * kOTESize * kIntSize;
1355 : Handle<ByteArray> decoded_table =
1356 78 : isolate->factory()->NewByteArray(total_size, TENURED);
1357 : decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
1358 156 : compiled_module->shared()->set_asm_js_offset_table(*decoded_table);
1359 :
1360 : int idx = 0;
1361 192 : std::vector<WasmFunction>& wasm_funs = compiled_module->module()->functions;
1362 270 : for (int func = 0; func < num_functions; ++func) {
1363 : std::vector<wasm::AsmJsOffsetEntry>& func_asm_offsets =
1364 192 : asm_offsets.val[func];
1365 192 : if (func_asm_offsets.empty()) continue;
1366 228 : int func_offset = wasm_funs[num_imported_functions + func].code.offset();
1367 480 : for (wasm::AsmJsOffsetEntry& e : func_asm_offsets) {
1368 : // Byte offsets must be strictly monotonously increasing:
1369 : DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
1370 : decoded_table->get_int(idx - kOTESize));
1371 252 : decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
1372 252 : decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
1373 : decoded_table->set_int(idx + kOTENumberConvPosition,
1374 252 : e.source_position_number_conversion);
1375 252 : idx += kOTESize;
1376 : }
1377 : }
1378 : DCHECK_EQ(total_size, idx * kIntSize + 1);
1379 78 : return decoded_table;
1380 : }
1381 :
1382 : } // namespace
1383 :
1384 41126 : int WasmCompiledModule::GetSourcePosition(
1385 : Handle<WasmCompiledModule> compiled_module, uint32_t func_index,
1386 : uint32_t byte_offset, bool is_at_number_conversion) {
1387 : Isolate* isolate = compiled_module->GetIsolate();
1388 41126 : const WasmModule* module = compiled_module->module();
1389 :
1390 41126 : if (!module->is_asm_js()) {
1391 : // for non-asm.js modules, we just add the function's start offset
1392 : // to make a module-relative position.
1393 40158 : return byte_offset + compiled_module->GetFunctionOffset(func_index);
1394 : }
1395 :
1396 : // asm.js modules have an additional offset table that must be searched.
1397 : Handle<ByteArray> offset_table =
1398 968 : GetDecodedAsmJsOffsetTable(compiled_module, isolate);
1399 :
1400 : DCHECK_LT(func_index, module->functions.size());
1401 1936 : uint32_t func_code_offset = module->functions[func_index].code.offset();
1402 968 : uint32_t total_offset = func_code_offset + byte_offset;
1403 :
1404 : // Binary search for the total byte offset.
1405 : int left = 0; // inclusive
1406 968 : int right = offset_table->length() / kIntSize / kOTESize; // exclusive
1407 : DCHECK_LT(left, right);
1408 3772 : while (right - left > 1) {
1409 1836 : int mid = left + (right - left) / 2;
1410 1836 : int mid_entry = offset_table->get_int(kOTESize * mid);
1411 : DCHECK_GE(kMaxInt, mid_entry);
1412 1836 : if (static_cast<uint32_t>(mid_entry) <= total_offset) {
1413 : left = mid;
1414 : } else {
1415 : right = mid;
1416 : }
1417 : }
1418 : // There should be an entry for each position that could show up on the stack
1419 : // trace:
1420 : DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
1421 968 : int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
1422 1936 : return offset_table->get_int(kOTESize * left + idx);
1423 : }
1424 :
1425 89 : v8::debug::WasmDisassembly WasmCompiledModule::DisassembleFunction(
1426 : int func_index) {
1427 : DisallowHeapAllocation no_gc;
1428 :
1429 178 : if (func_index < 0 ||
1430 89 : static_cast<uint32_t>(func_index) >= module()->functions.size())
1431 : return {};
1432 :
1433 : SeqOneByteString* module_bytes_str = module_bytes();
1434 89 : Vector<const byte> module_bytes(module_bytes_str->GetChars(),
1435 89 : module_bytes_str->length());
1436 :
1437 89 : std::ostringstream disassembly_os;
1438 : v8::debug::WasmDisassembly::OffsetTable offset_table;
1439 :
1440 89 : PrintWasmText(module(), module_bytes, static_cast<uint32_t>(func_index),
1441 178 : disassembly_os, &offset_table);
1442 :
1443 178 : return {disassembly_os.str(), std::move(offset_table)};
1444 : }
1445 :
1446 72 : bool WasmCompiledModule::GetPossibleBreakpoints(
1447 : const v8::debug::Location& start, const v8::debug::Location& end,
1448 : std::vector<v8::debug::BreakLocation>* locations) {
1449 : DisallowHeapAllocation no_gc;
1450 :
1451 380 : std::vector<WasmFunction>& functions = module()->functions;
1452 216 : if (start.GetLineNumber() < 0 || start.GetColumnNumber() < 0 ||
1453 144 : (!end.IsEmpty() &&
1454 144 : (end.GetLineNumber() < 0 || end.GetColumnNumber() < 0)))
1455 : return false;
1456 :
1457 : // start_func_index, start_offset and end_func_index is inclusive.
1458 : // end_offset is exclusive.
1459 : // start_offset and end_offset are module-relative byte offsets.
1460 72 : uint32_t start_func_index = start.GetLineNumber();
1461 144 : if (start_func_index >= functions.size()) return false;
1462 72 : int start_func_len = functions[start_func_index].code.length();
1463 72 : if (start.GetColumnNumber() > start_func_len) return false;
1464 : uint32_t start_offset =
1465 66 : functions[start_func_index].code.offset() + start.GetColumnNumber();
1466 : uint32_t end_func_index;
1467 : uint32_t end_offset;
1468 66 : if (end.IsEmpty()) {
1469 : // Default: everything till the end of the Script.
1470 0 : end_func_index = static_cast<uint32_t>(functions.size() - 1);
1471 0 : end_offset = functions[end_func_index].code.end_offset();
1472 : } else {
1473 : // If end is specified: Use it and check for valid input.
1474 66 : end_func_index = static_cast<uint32_t>(end.GetLineNumber());
1475 :
1476 : // Special case: Stop before the start of the next function. Change to: Stop
1477 : // at the end of the function before, such that we don't disassemble the
1478 : // next function also.
1479 66 : if (end.GetColumnNumber() == 0 && end_func_index > 0) {
1480 28 : --end_func_index;
1481 28 : end_offset = functions[end_func_index].code.end_offset();
1482 : } else {
1483 76 : if (end_func_index >= functions.size()) return false;
1484 : end_offset =
1485 38 : functions[end_func_index].code.offset() + end.GetColumnNumber();
1486 38 : if (end_offset > functions[end_func_index].code.end_offset())
1487 : return false;
1488 : }
1489 : }
1490 :
1491 66 : AccountingAllocator alloc;
1492 132 : Zone tmp(&alloc, ZONE_NAME);
1493 66 : const byte* module_start = module_bytes()->GetChars();
1494 :
1495 132 : for (uint32_t func_idx = start_func_index; func_idx <= end_func_index;
1496 : ++func_idx) {
1497 66 : WasmFunction& func = functions[func_idx];
1498 358 : if (func.code.length() == 0) continue;
1499 :
1500 : wasm::BodyLocalDecls locals(&tmp);
1501 : wasm::BytecodeIterator iterator(module_start + func.code.offset(),
1502 : module_start + func.code.end_offset(),
1503 66 : &locals);
1504 : DCHECK_LT(0u, locals.encoded_size);
1505 623 : for (uint32_t offset : iterator.offsets()) {
1506 292 : uint32_t total_offset = func.code.offset() + offset;
1507 292 : if (total_offset >= end_offset) {
1508 : DCHECK_EQ(end_func_index, func_idx);
1509 : break;
1510 : }
1511 265 : if (total_offset < start_offset) continue;
1512 150 : locations->emplace_back(func_idx, offset, debug::kCommonBreakLocation);
1513 : }
1514 : }
1515 66 : return true;
1516 : }
1517 :
1518 94 : bool WasmCompiledModule::SetBreakPoint(
1519 : Handle<WasmCompiledModule> compiled_module, int* position,
1520 : Handle<Object> break_point_object) {
1521 : Isolate* isolate = compiled_module->GetIsolate();
1522 :
1523 : // Find the function for this breakpoint.
1524 94 : int func_index = compiled_module->GetContainingFunction(*position);
1525 94 : if (func_index < 0) return false;
1526 188 : WasmFunction& func = compiled_module->module()->functions[func_index];
1527 94 : int offset_in_func = *position - func.code.offset();
1528 :
1529 : // According to the current design, we should only be called with valid
1530 : // breakable positions.
1531 : DCHECK(IsBreakablePosition(compiled_module, func_index, offset_in_func));
1532 :
1533 : // Insert new break point into break_positions of shared module data.
1534 : WasmSharedModuleData::AddBreakpoint(compiled_module->shared(), *position,
1535 94 : break_point_object);
1536 :
1537 : // Iterate over all instances of this module and tell them to set this new
1538 : // breakpoint.
1539 164 : for (Handle<WasmInstanceObject> instance :
1540 234 : iterate_compiled_module_instance_chain(isolate, compiled_module)) {
1541 : Handle<WasmDebugInfo> debug_info =
1542 70 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
1543 70 : WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
1544 : }
1545 :
1546 94 : return true;
1547 : }
1548 :
1549 354 : MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) {
1550 109 : Isolate* isolate = GetIsolate();
1551 708 : if (!shared()->has_breakpoint_infos()) return {};
1552 :
1553 708 : Handle<FixedArray> breakpoint_infos(shared()->breakpoint_infos(), isolate);
1554 : int insert_pos =
1555 354 : FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
1556 354 : if (insert_pos >= breakpoint_infos->length()) return {};
1557 :
1558 : Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
1559 : isolate);
1560 354 : if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
1561 : Handle<BreakPointInfo> breakpoint_info =
1562 : Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
1563 180 : if (breakpoint_info->source_position() != position) return {};
1564 :
1565 : Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(),
1566 : isolate);
1567 109 : return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
1568 : }
1569 :
1570 11477 : Handle<Code> WasmCompiledModule::CompileLazy(
1571 : Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> caller,
1572 : int offset, int func_index, bool patch_caller) {
1573 22954 : isolate->set_context(*instance->compiled_module()->native_context());
1574 : Object* orch_obj =
1575 22954 : instance->compiled_module()->shared()->lazy_compilation_orchestrator();
1576 : auto* orch =
1577 : Managed<wasm::LazyCompilationOrchestrator>::cast(orch_obj)->get();
1578 : return orch->CompileLazy(isolate, instance, caller, offset, func_index,
1579 11477 : patch_caller);
1580 : }
1581 :
1582 : #undef TRACE
1583 :
1584 : } // namespace internal
1585 : } // namespace v8
|