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/wasm/module-decoder.h"
14 : #include "src/wasm/wasm-code-specialization.h"
15 : #include "src/wasm/wasm-module.h"
16 : #include "src/wasm/wasm-text.h"
17 :
18 : #define TRACE(...) \
19 : do { \
20 : if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
21 : } while (false)
22 :
23 : #define TRACE_CHAIN(instance) \
24 : do { \
25 : instance->PrintInstancesChain(); \
26 : } while (false)
27 :
28 : using namespace v8::internal;
29 : using namespace v8::internal::wasm;
30 :
31 : #define DEFINE_GETTER0(getter, Container, name, field, type) \
32 : type* Container::name() { return type::cast(getter(field)); }
33 :
34 : #define DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \
35 : DEFINE_GETTER0(getter, Container, name, field, type) \
36 : void Container::set_##name(type* value) { return setter(field, value); }
37 :
38 : #define DEFINE_OPTIONAL_ACCESSORS0(getter, setter, Container, name, field, \
39 : type) \
40 : DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \
41 : bool Container::has_##name() { \
42 : return !getter(field)->IsUndefined(GetIsolate()); \
43 : }
44 :
45 : #define DEFINE_OPTIONAL_GETTER0(getter, Container, name, field, type) \
46 : DEFINE_GETTER0(getter, Container, name, field, type) \
47 : bool Container::has_##name() { \
48 : return !getter(field)->IsUndefined(GetIsolate()); \
49 : }
50 :
51 : #define DEFINE_GETTER0(getter, Container, name, field, type) \
52 : type* Container::name() { return type::cast(getter(field)); }
53 :
54 : #define DEFINE_OBJ_GETTER(Container, name, field, type) \
55 : DEFINE_GETTER0(GetEmbedderField, Container, name, field, type)
56 : #define DEFINE_OBJ_ACCESSORS(Container, name, field, type) \
57 : DEFINE_ACCESSORS0(GetEmbedderField, SetEmbedderField, Container, name, \
58 : field, type)
59 : #define DEFINE_OPTIONAL_OBJ_ACCESSORS(Container, name, field, type) \
60 : DEFINE_OPTIONAL_ACCESSORS0(GetEmbedderField, SetEmbedderField, Container, \
61 : name, field, type)
62 : #define DEFINE_ARR_GETTER(Container, name, field, type) \
63 : DEFINE_GETTER0(get, Container, name, field, type)
64 : #define DEFINE_ARR_ACCESSORS(Container, name, field, type) \
65 : DEFINE_ACCESSORS0(get, set, Container, name, field, type)
66 : #define DEFINE_OPTIONAL_ARR_ACCESSORS(Container, name, field, type) \
67 : DEFINE_OPTIONAL_ACCESSORS0(get, set, Container, name, field, type)
68 : #define DEFINE_OPTIONAL_ARR_GETTER(Container, name, field, type) \
69 : DEFINE_OPTIONAL_GETTER0(get, Container, name, field, type)
70 :
71 : namespace {
72 :
73 : // An iterator that returns first the module itself, then all modules linked via
74 : // next, then all linked via prev.
75 : class CompiledModulesIterator
76 : : public std::iterator<std::input_iterator_tag,
77 : Handle<WasmCompiledModule>> {
78 : public:
79 : CompiledModulesIterator(Isolate* isolate,
80 : Handle<WasmCompiledModule> start_module, bool at_end)
81 : : isolate_(isolate),
82 : start_module_(start_module),
83 212 : current_(at_end ? Handle<WasmCompiledModule>::null() : start_module) {}
84 :
85 : Handle<WasmCompiledModule> operator*() const {
86 : DCHECK(!current_.is_null());
87 : return current_;
88 : }
89 :
90 106 : void operator++() { Advance(); }
91 :
92 : bool operator!=(const CompiledModulesIterator& other) {
93 : DCHECK(start_module_.is_identical_to(other.start_module_));
94 : return !current_.is_identical_to(other.current_);
95 : }
96 :
97 : private:
98 106 : void Advance() {
99 : DCHECK(!current_.is_null());
100 106 : if (!is_backwards_) {
101 106 : if (current_->has_weak_next_instance()) {
102 : WeakCell* weak_next = current_->ptr_to_weak_next_instance();
103 0 : if (!weak_next->cleared()) {
104 : current_ =
105 0 : handle(WasmCompiledModule::cast(weak_next->value()), isolate_);
106 0 : return;
107 : }
108 : }
109 : // No more modules in next-links, now try the previous-links.
110 106 : is_backwards_ = true;
111 106 : current_ = start_module_;
112 : }
113 106 : if (current_->has_weak_prev_instance()) {
114 : WeakCell* weak_prev = current_->ptr_to_weak_prev_instance();
115 0 : if (!weak_prev->cleared()) {
116 : current_ =
117 0 : handle(WasmCompiledModule::cast(weak_prev->value()), isolate_);
118 0 : return;
119 : }
120 : }
121 106 : current_ = Handle<WasmCompiledModule>::null();
122 : }
123 :
124 : friend class CompiledModuleInstancesIterator;
125 : Isolate* isolate_;
126 : Handle<WasmCompiledModule> start_module_;
127 : Handle<WasmCompiledModule> current_;
128 : bool is_backwards_ = false;
129 : };
130 :
131 : // An iterator based on the CompiledModulesIterator, but it returns all live
132 : // instances, not the WasmCompiledModules itself.
133 : class CompiledModuleInstancesIterator
134 : : public std::iterator<std::input_iterator_tag,
135 : Handle<WasmInstanceObject>> {
136 : public:
137 212 : CompiledModuleInstancesIterator(Isolate* isolate,
138 : Handle<WasmCompiledModule> start_module,
139 : bool at_end)
140 : : it(isolate, start_module, at_end) {
141 268 : while (NeedToAdvance()) ++it;
142 212 : }
143 :
144 78 : Handle<WasmInstanceObject> operator*() {
145 : return handle(
146 : WasmInstanceObject::cast((*it)->weak_owning_instance()->value()),
147 234 : it.isolate_);
148 : }
149 :
150 78 : void operator++() {
151 78 : do {
152 78 : ++it;
153 : } while (NeedToAdvance());
154 78 : }
155 :
156 : bool operator!=(const CompiledModuleInstancesIterator& other) {
157 : return it != other.it;
158 : }
159 :
160 : private:
161 318 : bool NeedToAdvance() {
162 424 : return !it.current_.is_null() &&
163 184 : (!it.current_->has_weak_owning_instance() ||
164 318 : it.current_->ptr_to_weak_owning_instance()->cleared());
165 : }
166 : CompiledModulesIterator it;
167 : };
168 :
169 : v8::base::iterator_range<CompiledModuleInstancesIterator>
170 106 : iterate_compiled_module_instance_chain(
171 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
172 : return {CompiledModuleInstancesIterator(isolate, compiled_module, false),
173 212 : CompiledModuleInstancesIterator(isolate, compiled_module, true)};
174 : }
175 :
176 : #ifdef DEBUG
177 : bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module,
178 : int func_index, int offset_in_func) {
179 : DisallowHeapAllocation no_gc;
180 : AccountingAllocator alloc;
181 : Zone tmp(&alloc, ZONE_NAME);
182 : BodyLocalDecls locals(&tmp);
183 : const byte* module_start = compiled_module->module_bytes()->GetChars();
184 : WasmFunction& func = compiled_module->module()->functions[func_index];
185 : BytecodeIterator iterator(module_start + func.code_start_offset,
186 : module_start + func.code_end_offset, &locals);
187 : DCHECK_LT(0, locals.encoded_size);
188 : for (uint32_t offset : iterator.offsets()) {
189 : if (offset > static_cast<uint32_t>(offset_in_func)) break;
190 : if (offset == static_cast<uint32_t>(offset_in_func)) return true;
191 : }
192 : return false;
193 : }
194 : #endif // DEBUG
195 :
196 : } // namespace
197 :
198 15955 : Handle<WasmModuleObject> WasmModuleObject::New(
199 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
200 15955 : WasmModule* module = compiled_module->module();
201 : Handle<JSObject> module_object;
202 15955 : if (module->is_wasm()) {
203 : Handle<JSFunction> module_cons(
204 24678 : isolate->native_context()->wasm_module_constructor());
205 12339 : module_object = isolate->factory()->NewJSObject(module_cons);
206 24678 : Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym());
207 : Object::SetProperty(module_object, module_sym, module_object, STRICT)
208 24678 : .Check();
209 : } else {
210 : DCHECK(module->is_asm_js());
211 : Handle<Map> map = isolate->factory()->NewMap(
212 : JS_OBJECT_TYPE,
213 3616 : JSObject::kHeaderSize + WasmModuleObject::kFieldCount * kPointerSize);
214 3616 : module_object = isolate->factory()->NewJSObjectFromMap(map, TENURED);
215 : }
216 : module_object->SetEmbedderField(WasmModuleObject::kCompiledModule,
217 15955 : *compiled_module);
218 : Handle<WeakCell> link_to_module =
219 15955 : isolate->factory()->NewWeakCell(module_object);
220 : compiled_module->set_weak_wasm_module(link_to_module);
221 15955 : return Handle<WasmModuleObject>::cast(module_object);
222 : }
223 :
224 87606 : WasmModuleObject* WasmModuleObject::cast(Object* object) {
225 : DCHECK(object->IsJSObject());
226 : // TODO(titzer): brand check for WasmModuleObject.
227 87606 : return reinterpret_cast<WasmModuleObject*>(object);
228 : }
229 :
230 210 : bool WasmModuleObject::IsWasmModuleObject(Object* object) {
231 420 : return object->IsJSObject() &&
232 420 : JSObject::cast(object)->GetEmbedderFieldCount() == kFieldCount;
233 : }
234 :
235 287524 : DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule,
236 : WasmCompiledModule)
237 :
238 1147 : Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
239 : int64_t maximum,
240 : Handle<FixedArray>* js_functions) {
241 : Handle<JSFunction> table_ctor(
242 2294 : isolate->native_context()->wasm_table_constructor());
243 1147 : Handle<JSObject> table_obj = isolate->factory()->NewJSObject(table_ctor);
244 : table_obj->SetEmbedderField(kWrapperTracerHeader, Smi::kZero);
245 :
246 1147 : *js_functions = isolate->factory()->NewFixedArray(initial);
247 1147 : Object* null = isolate->heap()->null_value();
248 6711 : for (int i = 0; i < static_cast<int>(initial); ++i) {
249 5564 : (*js_functions)->set(i, null);
250 : }
251 1147 : table_obj->SetEmbedderField(kFunctions, *(*js_functions));
252 1147 : Handle<Object> max = isolate->factory()->NewNumber(maximum);
253 1147 : table_obj->SetEmbedderField(kMaximum, *max);
254 :
255 1147 : Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0);
256 1147 : table_obj->SetEmbedderField(kDispatchTables, *dispatch_tables);
257 2294 : Handle<Symbol> table_sym(isolate->native_context()->wasm_table_sym());
258 2294 : Object::SetProperty(table_obj, table_sym, table_obj, STRICT).Check();
259 1147 : return Handle<WasmTableObject>::cast(table_obj);
260 : }
261 :
262 6960 : DEFINE_OBJ_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray)
263 :
264 1934 : Handle<FixedArray> WasmTableObject::AddDispatchTable(
265 : Isolate* isolate, Handle<WasmTableObject> table_obj,
266 : Handle<WasmInstanceObject> instance, int table_index,
267 : Handle<FixedArray> function_table, Handle<FixedArray> signature_table) {
268 : Handle<FixedArray> dispatch_tables(
269 : FixedArray::cast(table_obj->GetEmbedderField(kDispatchTables)), isolate);
270 : DCHECK_EQ(0, dispatch_tables->length() % 4);
271 :
272 1934 : if (instance.is_null()) return dispatch_tables;
273 : // TODO(titzer): use weak cells here to avoid leaking instances.
274 :
275 : // Grow the dispatch table and add a new triple at the end.
276 : Handle<FixedArray> new_dispatch_tables =
277 967 : isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 4);
278 :
279 967 : new_dispatch_tables->set(dispatch_tables->length() + 0, *instance);
280 : new_dispatch_tables->set(dispatch_tables->length() + 1,
281 : Smi::FromInt(table_index));
282 1934 : new_dispatch_tables->set(dispatch_tables->length() + 2, *function_table);
283 1934 : new_dispatch_tables->set(dispatch_tables->length() + 3, *signature_table);
284 :
285 : table_obj->SetEmbedderField(WasmTableObject::kDispatchTables,
286 967 : *new_dispatch_tables);
287 :
288 967 : return new_dispatch_tables;
289 : }
290 :
291 33540 : DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray)
292 :
293 9390 : uint32_t WasmTableObject::current_length() { return functions()->length(); }
294 :
295 0 : bool WasmTableObject::has_maximum_length() {
296 0 : return GetEmbedderField(kMaximum)->Number() >= 0;
297 : }
298 :
299 1155 : int64_t WasmTableObject::maximum_length() {
300 1155 : return static_cast<int64_t>(GetEmbedderField(kMaximum)->Number());
301 : }
302 :
303 21375 : WasmTableObject* WasmTableObject::cast(Object* object) {
304 : DCHECK(object && object->IsJSObject());
305 : // TODO(titzer): brand check for WasmTableObject.
306 21375 : return reinterpret_cast<WasmTableObject*>(object);
307 : }
308 :
309 255 : void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
310 : uint32_t count) {
311 : Handle<FixedArray> dispatch_tables(table->dispatch_tables());
312 : wasm::GrowDispatchTables(isolate, dispatch_tables,
313 255 : table->functions()->length(), count);
314 255 : }
315 :
316 : namespace {
317 :
318 1631 : Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
319 : Handle<JSArrayBuffer> old_buffer,
320 : uint32_t pages, uint32_t max_pages) {
321 : Address old_mem_start = nullptr;
322 : uint32_t old_size = 0;
323 1631 : if (!old_buffer.is_null()) {
324 : DCHECK(old_buffer->byte_length()->IsNumber());
325 : old_mem_start = static_cast<Address>(old_buffer->backing_store());
326 1541 : old_size = old_buffer->byte_length()->Number();
327 : }
328 : DCHECK_GE(std::numeric_limits<uint32_t>::max(),
329 : old_size + pages * WasmModule::kPageSize);
330 1631 : uint32_t new_size = old_size + pages * WasmModule::kPageSize;
331 3187 : if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
332 1556 : FLAG_wasm_max_mem_pages * WasmModule::kPageSize < new_size) {
333 : return Handle<JSArrayBuffer>::null();
334 : }
335 :
336 : // TODO(gdeepti): Change the protection here instead of allocating a new
337 : // buffer before guard regions are turned on, see issue #5886.
338 : const bool enable_guard_regions =
339 1630 : (old_buffer.is_null() && EnableGuardRegions()) ||
340 1450 : (!old_buffer.is_null() && old_buffer->has_guard_region());
341 : Handle<JSArrayBuffer> new_buffer =
342 1540 : NewArrayBuffer(isolate, new_size, enable_guard_regions);
343 1540 : if (new_buffer.is_null()) return new_buffer;
344 : Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
345 1540 : memcpy(new_mem_start, old_mem_start, old_size);
346 1540 : return new_buffer;
347 : }
348 :
349 : // May GC, because SetSpecializationMemInfoFrom may GC
350 4773 : void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
351 : Handle<JSArrayBuffer> buffer) {
352 : instance->set_memory_buffer(*buffer);
353 : WasmCompiledModule::SetSpecializationMemInfoFrom(
354 4773 : isolate->factory(), handle(instance->compiled_module()), buffer);
355 4773 : if (instance->has_debug_info()) {
356 30 : instance->debug_info()->UpdateMemory(*buffer);
357 : }
358 4773 : }
359 :
360 9546 : void UncheckedUpdateInstanceMemory(Isolate* isolate,
361 : Handle<WasmInstanceObject> instance,
362 : Address old_mem_start, uint32_t old_size) {
363 : DCHECK(instance->has_memory_buffer());
364 : Handle<JSArrayBuffer> mem_buffer(instance->memory_buffer());
365 4773 : uint32_t new_size = mem_buffer->byte_length()->Number();
366 : Address new_mem_start = static_cast<Address>(mem_buffer->backing_store());
367 : DCHECK_NOT_NULL(new_mem_start);
368 4773 : Zone specialization_zone(isolate->allocator(), ZONE_NAME);
369 9546 : CodeSpecialization code_specialization(isolate, &specialization_zone);
370 : code_specialization.RelocateMemoryReferences(old_mem_start, old_size,
371 4773 : new_mem_start, new_size);
372 9546 : code_specialization.ApplyToWholeInstance(*instance);
373 4773 : }
374 :
375 : } // namespace
376 :
377 1569 : Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
378 : Handle<JSArrayBuffer> buffer,
379 : int32_t maximum) {
380 : Handle<JSFunction> memory_ctor(
381 3138 : isolate->native_context()->wasm_memory_constructor());
382 : Handle<JSObject> memory_obj =
383 1569 : isolate->factory()->NewJSObject(memory_ctor, TENURED);
384 : memory_obj->SetEmbedderField(kWrapperTracerHeader, Smi::kZero);
385 : buffer.is_null() ? memory_obj->SetEmbedderField(
386 30 : kArrayBuffer, isolate->heap()->undefined_value())
387 3123 : : memory_obj->SetEmbedderField(kArrayBuffer, *buffer);
388 1569 : Handle<Object> max = isolate->factory()->NewNumber(maximum);
389 1569 : memory_obj->SetEmbedderField(kMaximum, *max);
390 3138 : Handle<Symbol> memory_sym(isolate->native_context()->wasm_memory_sym());
391 3138 : Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check();
392 1569 : return Handle<WasmMemoryObject>::cast(memory_obj);
393 : }
394 :
395 11675 : DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer,
396 : JSArrayBuffer)
397 7281 : DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, instances_link, kInstancesLink,
398 : WasmInstanceWrapper)
399 :
400 0 : uint32_t WasmMemoryObject::current_pages() {
401 : uint32_t byte_length;
402 0 : CHECK(buffer()->byte_length()->ToUint32(&byte_length));
403 0 : return byte_length / wasm::WasmModule::kPageSize;
404 : }
405 :
406 997 : bool WasmMemoryObject::has_maximum_pages() {
407 997 : return GetEmbedderField(kMaximum)->Number() >= 0;
408 : }
409 :
410 2512 : int32_t WasmMemoryObject::maximum_pages() {
411 2512 : return static_cast<int32_t>(GetEmbedderField(kMaximum)->Number());
412 : }
413 :
414 4275 : WasmMemoryObject* WasmMemoryObject::cast(Object* object) {
415 : DCHECK(object && object->IsJSObject());
416 : // TODO(titzer): brand check for WasmMemoryObject.
417 4275 : return reinterpret_cast<WasmMemoryObject*>(object);
418 : }
419 :
420 1742 : void WasmMemoryObject::AddInstance(Isolate* isolate,
421 : Handle<WasmInstanceObject> instance) {
422 : Handle<WasmInstanceWrapper> instance_wrapper =
423 : handle(instance->instance_wrapper());
424 1742 : if (has_instances_link()) {
425 : Handle<WasmInstanceWrapper> current_wrapper(instances_link());
426 : DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*current_wrapper));
427 : DCHECK(!current_wrapper->has_previous());
428 : instance_wrapper->set_next_wrapper(*current_wrapper);
429 : current_wrapper->set_previous_wrapper(*instance_wrapper);
430 : }
431 : set_instances_link(*instance_wrapper);
432 1742 : }
433 :
434 1024 : void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) {
435 : Handle<Object> undefined = isolate->factory()->undefined_value();
436 1024 : SetEmbedderField(kInstancesLink, *undefined);
437 1024 : }
438 :
439 : // static
440 1042 : int32_t WasmMemoryObject::Grow(Isolate* isolate,
441 : Handle<WasmMemoryObject> memory_object,
442 : uint32_t pages) {
443 : Handle<JSArrayBuffer> old_buffer;
444 : uint32_t old_size = 0;
445 : Address old_mem_start = nullptr;
446 1042 : if (memory_object->has_buffer()) {
447 : old_buffer = handle(memory_object->buffer());
448 1027 : old_size = old_buffer->byte_length()->Number();
449 : old_mem_start = static_cast<Address>(old_buffer->backing_store());
450 : }
451 : Handle<JSArrayBuffer> new_buffer;
452 : // Return current size if grow by 0.
453 1042 : if (pages == 0) {
454 : // Even for pages == 0, we need to attach a new JSArrayBuffer and neuter the
455 : // old one to be spec compliant.
456 90 : if (!old_buffer.is_null() && old_buffer->backing_store() != nullptr) {
457 : new_buffer = SetupArrayBuffer(isolate, old_buffer->backing_store(),
458 : old_size, old_buffer->is_external(),
459 135 : old_buffer->has_guard_region());
460 : memory_object->set_buffer(*new_buffer);
461 : old_buffer->set_is_neuterable(true);
462 45 : if (!old_buffer->has_guard_region()) {
463 : old_buffer->set_is_external(true);
464 42 : isolate->heap()->UnregisterArrayBuffer(*old_buffer);
465 : }
466 : // Neuter but don't free the memory because it is now being used by
467 : // new_buffer.
468 45 : old_buffer->Neuter();
469 : }
470 : DCHECK_EQ(0, old_size % WasmModule::kPageSize);
471 45 : return old_size / WasmModule::kPageSize;
472 : }
473 997 : if (!memory_object->has_instances_link()) {
474 : // Memory object does not have an instance associated with it, just grow
475 : uint32_t max_pages;
476 52 : if (memory_object->has_maximum_pages()) {
477 52 : max_pages = static_cast<uint32_t>(memory_object->maximum_pages());
478 52 : if (FLAG_wasm_max_mem_pages < max_pages) return -1;
479 : } else {
480 0 : max_pages = FLAG_wasm_max_mem_pages;
481 : }
482 52 : new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, max_pages);
483 52 : if (new_buffer.is_null()) return -1;
484 : } else {
485 : Handle<WasmInstanceWrapper> instance_wrapper(
486 : memory_object->instances_link());
487 : DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
488 : DCHECK(instance_wrapper->has_instance());
489 945 : Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
490 : DCHECK(IsWasmInstance(*instance));
491 945 : uint32_t max_pages = instance->GetMaxMemoryPages();
492 :
493 : // Grow memory object buffer and update instances associated with it.
494 945 : new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, max_pages);
495 945 : if (new_buffer.is_null()) return -1;
496 : DCHECK(!instance_wrapper->has_previous());
497 930 : SetInstanceMemory(isolate, instance, new_buffer);
498 930 : UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
499 5145 : while (instance_wrapper->has_next()) {
500 3285 : instance_wrapper = instance_wrapper->next_wrapper();
501 : DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
502 3285 : Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
503 : DCHECK(IsWasmInstance(*instance));
504 3285 : SetInstanceMemory(isolate, instance, new_buffer);
505 3285 : UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
506 : }
507 : }
508 : memory_object->set_buffer(*new_buffer);
509 : DCHECK_EQ(0, old_size % WasmModule::kPageSize);
510 982 : return old_size / WasmModule::kPageSize;
511 : }
512 :
513 1342558 : DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule,
514 : WasmCompiledModule)
515 2860 : DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer,
516 : kGlobalsArrayBuffer, JSArrayBuffer)
517 106158 : DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_buffer,
518 : kMemoryArrayBuffer, JSArrayBuffer)
519 142053 : DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject,
520 : WasmMemoryObject)
521 126213 : DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo,
522 : WasmDebugInfo)
523 34078 : DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, instance_wrapper,
524 : kWasmMemInstanceWrapper, WasmInstanceWrapper)
525 :
526 0 : WasmModuleObject* WasmInstanceObject::module_object() {
527 0 : return *compiled_module()->wasm_module();
528 : }
529 :
530 12432 : WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); }
531 :
532 1228 : Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo(
533 : Handle<WasmInstanceObject> instance) {
534 1303 : if (instance->has_debug_info()) return handle(instance->debug_info());
535 1153 : Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance);
536 : instance->set_debug_info(*new_info);
537 1153 : return new_info;
538 : }
539 :
540 320512 : WasmInstanceObject* WasmInstanceObject::cast(Object* object) {
541 : DCHECK(IsWasmInstanceObject(object));
542 320512 : return reinterpret_cast<WasmInstanceObject*>(object);
543 : }
544 :
545 51980 : bool WasmInstanceObject::IsWasmInstanceObject(Object* object) {
546 51980 : if (!object->IsJSObject()) return false;
547 :
548 : JSObject* obj = JSObject::cast(object);
549 : Isolate* isolate = obj->GetIsolate();
550 51980 : if (obj->GetEmbedderFieldCount() != kFieldCount) {
551 : return false;
552 : }
553 :
554 : Object* mem = obj->GetEmbedderField(kMemoryArrayBuffer);
555 104230 : if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) ||
556 : !WasmCompiledModule::IsWasmCompiledModule(
557 51980 : obj->GetEmbedderField(kCompiledModule))) {
558 : return false;
559 : }
560 :
561 : // All checks passed.
562 51980 : return true;
563 : }
564 :
565 87727 : Handle<WasmInstanceObject> WasmInstanceObject::New(
566 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
567 : Handle<JSFunction> instance_cons(
568 175454 : isolate->native_context()->wasm_instance_constructor());
569 : Handle<JSObject> instance_object =
570 87727 : isolate->factory()->NewJSObject(instance_cons, TENURED);
571 : instance_object->SetEmbedderField(kWrapperTracerHeader, Smi::kZero);
572 :
573 175454 : Handle<Symbol> instance_sym(isolate->native_context()->wasm_instance_sym());
574 : Object::SetProperty(instance_object, instance_sym, instance_object, STRICT)
575 175454 : .Check();
576 : Handle<WasmInstanceObject> instance(
577 : reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate);
578 :
579 87727 : instance->SetEmbedderField(kCompiledModule, *compiled_module);
580 175454 : instance->SetEmbedderField(kMemoryObject, isolate->heap()->undefined_value());
581 : Handle<WasmInstanceWrapper> instance_wrapper =
582 87727 : WasmInstanceWrapper::New(isolate, instance);
583 87727 : instance->SetEmbedderField(kWasmMemInstanceWrapper, *instance_wrapper);
584 87727 : return instance;
585 : }
586 :
587 4653 : int32_t WasmInstanceObject::GetMemorySize() {
588 4653 : if (!has_memory_buffer()) return 0;
589 4638 : uint32_t bytes = memory_buffer()->byte_length()->Number();
590 : DCHECK_EQ(0, bytes % WasmModule::kPageSize);
591 4638 : return bytes / WasmModule::kPageSize;
592 : }
593 :
594 1318 : int32_t WasmInstanceObject::GrowMemory(Isolate* isolate,
595 : Handle<WasmInstanceObject> instance,
596 : uint32_t pages) {
597 1387 : if (pages == 0) return instance->GetMemorySize();
598 1249 : if (instance->has_memory_object()) {
599 : return WasmMemoryObject::Grow(
600 615 : isolate, handle(instance->memory_object(), isolate), pages);
601 : }
602 :
603 : // No other instances to grow, grow just the one.
604 : uint32_t old_size = 0;
605 : Address old_mem_start = nullptr;
606 : Handle<JSArrayBuffer> old_buffer;
607 634 : if (instance->has_memory_buffer()) {
608 : old_buffer = handle(instance->memory_buffer(), isolate);
609 559 : old_size = old_buffer->byte_length()->Number();
610 : old_mem_start = static_cast<Address>(old_buffer->backing_store());
611 : }
612 634 : uint32_t max_pages = instance->GetMaxMemoryPages();
613 : Handle<JSArrayBuffer> buffer =
614 634 : GrowMemoryBuffer(isolate, old_buffer, pages, max_pages);
615 634 : if (buffer.is_null()) return -1;
616 558 : SetInstanceMemory(isolate, instance, buffer);
617 558 : UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
618 : DCHECK_EQ(0, old_size % WasmModule::kPageSize);
619 558 : return old_size / WasmModule::kPageSize;
620 : }
621 :
622 1579 : uint32_t WasmInstanceObject::GetMaxMemoryPages() {
623 1579 : if (has_memory_object()) {
624 945 : if (memory_object()->has_maximum_pages()) {
625 : uint32_t maximum =
626 885 : static_cast<uint32_t>(memory_object()->maximum_pages());
627 885 : if (maximum < FLAG_wasm_max_mem_pages) return maximum;
628 : }
629 : }
630 709 : uint32_t compiled_max_pages = compiled_module()->module()->max_mem_pages;
631 709 : Isolate* isolate = GetIsolate();
632 709 : auto* histogram = (compiled_module()->module()->is_wasm()
633 : ? isolate->counters()->wasm_wasm_max_mem_pages_count()
634 1418 : : isolate->counters()->wasm_asm_max_mem_pages_count());
635 709 : histogram->AddSample(compiled_max_pages);
636 709 : if (compiled_max_pages != 0) return compiled_max_pages;
637 0 : return FLAG_wasm_max_mem_pages;
638 : }
639 :
640 3171 : WasmInstanceObject* WasmExportedFunction::instance() {
641 3171 : return WasmInstanceObject::cast(GetEmbedderField(kInstance));
642 : }
643 :
644 3171 : int WasmExportedFunction::function_index() {
645 : int32_t func_index;
646 3171 : CHECK(GetEmbedderField(kIndex)->ToInt32(&func_index));
647 3171 : return func_index;
648 : }
649 :
650 3171 : WasmExportedFunction* WasmExportedFunction::cast(Object* object) {
651 : DCHECK(object && object->IsJSFunction());
652 : DCHECK_EQ(Code::JS_TO_WASM_FUNCTION,
653 : JSFunction::cast(object)->code()->kind());
654 : // TODO(titzer): brand check for WasmExportedFunction.
655 3171 : return reinterpret_cast<WasmExportedFunction*>(object);
656 : }
657 :
658 90249 : Handle<WasmExportedFunction> WasmExportedFunction::New(
659 : Isolate* isolate, Handle<WasmInstanceObject> instance,
660 : MaybeHandle<String> maybe_name, int func_index, int arity,
661 : Handle<Code> export_wrapper) {
662 : Handle<String> name;
663 90249 : if (maybe_name.is_null()) {
664 : EmbeddedVector<char, 16> buffer;
665 72767 : int length = SNPrintF(buffer, "%d", func_index);
666 : name = isolate->factory()
667 : ->NewStringFromOneByte(
668 : Vector<uint8_t>::cast(buffer.SubVector(0, length)))
669 145534 : .ToHandleChecked();
670 : } else {
671 17482 : name = maybe_name.ToHandleChecked();
672 : }
673 : DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
674 : Handle<SharedFunctionInfo> shared =
675 90249 : isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false);
676 : shared->set_length(arity);
677 : shared->set_internal_formal_parameter_count(arity);
678 : Handle<JSFunction> function = isolate->factory()->NewFunction(
679 90249 : isolate->wasm_function_map(), name, export_wrapper);
680 : function->SetEmbedderField(kWrapperTracerHeader, Smi::kZero);
681 :
682 90249 : function->set_shared(*shared);
683 :
684 90249 : function->SetEmbedderField(kInstance, *instance);
685 : function->SetEmbedderField(kIndex, Smi::FromInt(func_index));
686 90249 : return Handle<WasmExportedFunction>::cast(function);
687 : }
688 :
689 51980 : bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) {
690 51980 : if (!object->IsFixedArray()) return false;
691 : FixedArray* arr = FixedArray::cast(object);
692 51980 : if (arr->length() != kFieldCount) return false;
693 : Isolate* isolate = arr->GetIsolate();
694 51980 : if (!arr->get(kModuleWrapper)->IsForeign()) return false;
695 103960 : if (!arr->get(kModuleBytes)->IsUndefined(isolate) &&
696 : !arr->get(kModuleBytes)->IsSeqOneByteString())
697 : return false;
698 51980 : if (!arr->get(kScript)->IsScript()) return false;
699 51980 : if (!arr->get(kAsmJsOffsetTable)->IsUndefined(isolate) &&
700 : !arr->get(kAsmJsOffsetTable)->IsByteArray())
701 : return false;
702 52026 : if (!arr->get(kBreakPointInfos)->IsUndefined(isolate) &&
703 : !arr->get(kBreakPointInfos)->IsFixedArray())
704 : return false;
705 51980 : return true;
706 : }
707 :
708 878556 : WasmSharedModuleData* WasmSharedModuleData::cast(Object* object) {
709 : DCHECK(IsWasmSharedModuleData(object));
710 878556 : return reinterpret_cast<WasmSharedModuleData*>(object);
711 : }
712 :
713 231191 : wasm::WasmModule* WasmSharedModuleData::module() {
714 : // We populate the kModuleWrapper field with a Foreign holding the
715 : // address to the address of a WasmModule. This is because we can
716 : // handle both cases when the WasmModule's lifetime is managed through
717 : // a Managed<WasmModule> object, as well as cases when it's managed
718 : // by the embedder. CcTests fall into the latter case.
719 : return *(reinterpret_cast<wasm::WasmModule**>(
720 549807 : Foreign::cast(get(kModuleWrapper))->foreign_address()));
721 : }
722 :
723 389957 : DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes,
724 : SeqOneByteString);
725 78990 : DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script);
726 78 : DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table,
727 : kAsmJsOffsetTable, ByteArray);
728 95494 : DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos,
729 : kBreakPointInfos, FixedArray);
730 7232 : DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, lazy_compilation_orchestrator,
731 : kLazyCompilationOrchestrator, Foreign);
732 :
733 55551 : Handle<WasmSharedModuleData> WasmSharedModuleData::New(
734 : Isolate* isolate, Handle<Foreign> module_wrapper,
735 : Handle<SeqOneByteString> module_bytes, Handle<Script> script,
736 : Handle<ByteArray> asm_js_offset_table) {
737 : Handle<FixedArray> arr =
738 55551 : isolate->factory()->NewFixedArray(kFieldCount, TENURED);
739 : arr->set(kWrapperTracerHeader, Smi::kZero);
740 55551 : arr->set(kModuleWrapper, *module_wrapper);
741 55551 : if (!module_bytes.is_null()) {
742 55551 : arr->set(kModuleBytes, *module_bytes);
743 : }
744 55551 : if (!script.is_null()) {
745 55551 : arr->set(kScript, *script);
746 : }
747 55551 : if (!asm_js_offset_table.is_null()) {
748 3616 : arr->set(kAsmJsOffsetTable, *asm_js_offset_table);
749 : }
750 :
751 : DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*arr));
752 55551 : return Handle<WasmSharedModuleData>::cast(arr);
753 : }
754 :
755 74553 : bool WasmSharedModuleData::is_asm_js() {
756 74553 : bool asm_js = module()->is_asm_js();
757 : DCHECK_EQ(asm_js, script()->IsUserJavaScript());
758 : DCHECK_EQ(asm_js, has_asm_js_offset_table());
759 74553 : return asm_js;
760 : }
761 :
762 112 : void WasmSharedModuleData::ReinitializeAfterDeserialization(
763 : Isolate* isolate, Handle<WasmSharedModuleData> shared) {
764 : DCHECK(shared->get(kModuleWrapper)->IsUndefined(isolate));
765 : #ifdef DEBUG
766 : // No BreakpointInfo objects should survive deserialization.
767 : if (shared->has_breakpoint_infos()) {
768 : for (int i = 0, e = shared->breakpoint_infos()->length(); i < e; ++i) {
769 : DCHECK(shared->breakpoint_infos()->get(i)->IsUndefined(isolate));
770 : }
771 : }
772 : #endif
773 :
774 224 : shared->set(kBreakPointInfos, isolate->heap()->undefined_value());
775 :
776 : WasmModule* module = nullptr;
777 : {
778 : // We parse the module again directly from the module bytes, so
779 : // the underlying storage must not be moved meanwhile.
780 : DisallowHeapAllocation no_allocation;
781 : SeqOneByteString* module_bytes = shared->module_bytes();
782 : const byte* start =
783 112 : reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
784 112 : const byte* end = start + module_bytes->length();
785 : // TODO(titzer): remember the module origin in the compiled_module
786 : // For now, we assume serialized modules did not originate from asm.js.
787 : ModuleResult result =
788 224 : DecodeWasmModule(isolate, start, end, false, kWasmOrigin);
789 112 : CHECK(result.ok());
790 112 : CHECK_NOT_NULL(result.val);
791 : module = const_cast<WasmModule*>(result.val);
792 : }
793 :
794 : Handle<WasmModuleWrapper> module_wrapper =
795 112 : WasmModuleWrapper::New(isolate, module);
796 :
797 112 : shared->set(kModuleWrapper, *module_wrapper);
798 : DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
799 112 : }
800 :
801 : namespace {
802 :
803 1657 : int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) {
804 1657 : if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt;
805 745 : return BreakPointInfo::cast(break_point_info_or_undef)->source_position();
806 : }
807 :
808 461 : int FindBreakpointInfoInsertPos(Isolate* isolate,
809 : Handle<FixedArray> breakpoint_infos,
810 : int position) {
811 : // Find insert location via binary search, taking care of undefined values on
812 : // the right. Position is always greater than zero.
813 : DCHECK_LT(0, position);
814 :
815 : int left = 0; // inclusive
816 : int right = breakpoint_infos->length(); // exclusive
817 2024 : while (right - left > 1) {
818 1102 : int mid = left + (right - left) / 2;
819 : Object* mid_obj = breakpoint_infos->get(mid);
820 1102 : if (GetBreakpointPos(isolate, mid_obj) <= position) {
821 : left = mid;
822 : } else {
823 : right = mid;
824 : }
825 : }
826 :
827 461 : int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
828 461 : return left_pos < position ? left + 1 : left;
829 : }
830 :
831 : } // namespace
832 :
833 106 : void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
834 : int position,
835 : Handle<Object> break_point_object) {
836 : Isolate* isolate = shared->GetIsolate();
837 : Handle<FixedArray> breakpoint_infos;
838 106 : if (shared->has_breakpoint_infos()) {
839 : breakpoint_infos = handle(shared->breakpoint_infos(), isolate);
840 : } else {
841 46 : breakpoint_infos = isolate->factory()->NewFixedArray(4, TENURED);
842 46 : shared->set(kBreakPointInfos, *breakpoint_infos);
843 : }
844 :
845 : int insert_pos =
846 106 : FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
847 :
848 : // If a BreakPointInfo object already exists for this position, add the new
849 : // breakpoint object and return.
850 200 : if (insert_pos < breakpoint_infos->length() &&
851 94 : GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
852 : position) {
853 : Handle<BreakPointInfo> old_info(
854 : BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
855 0 : BreakPointInfo::SetBreakPoint(old_info, break_point_object);
856 106 : return;
857 : }
858 :
859 : // Enlarge break positions array if necessary.
860 : bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
861 106 : ->IsUndefined(isolate);
862 : Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
863 106 : if (need_realloc) {
864 : new_breakpoint_infos = isolate->factory()->NewFixedArray(
865 12 : 2 * breakpoint_infos->length(), TENURED);
866 12 : shared->set(kBreakPointInfos, *new_breakpoint_infos);
867 : // Copy over the entries [0, insert_pos).
868 84 : for (int i = 0; i < insert_pos; ++i)
869 72 : new_breakpoint_infos->set(i, breakpoint_infos->get(i));
870 : }
871 :
872 : // Move elements [insert_pos+1, ...] up by one.
873 212 : for (int i = insert_pos + 1; i < breakpoint_infos->length(); ++i) {
874 : Object* entry = breakpoint_infos->get(i);
875 82 : if (entry->IsUndefined(isolate)) break;
876 0 : new_breakpoint_infos->set(i + 1, entry);
877 : }
878 :
879 : // Generate new BreakpointInfo.
880 : Handle<BreakPointInfo> breakpoint_info =
881 106 : isolate->factory()->NewBreakPointInfo(position);
882 106 : BreakPointInfo::SetBreakPoint(breakpoint_info, break_point_object);
883 :
884 : // Now insert new position at insert_pos.
885 106 : new_breakpoint_infos->set(insert_pos, *breakpoint_info);
886 : }
887 :
888 47286 : void WasmSharedModuleData::SetBreakpointsOnNewInstance(
889 : Handle<WasmSharedModuleData> shared, Handle<WasmInstanceObject> instance) {
890 94572 : if (!shared->has_breakpoint_infos()) return;
891 : Isolate* isolate = shared->GetIsolate();
892 : Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
893 : isolate);
894 : Handle<WasmDebugInfo> debug_info =
895 0 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
896 :
897 : Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate);
898 : // If the array exists, it should not be empty.
899 : DCHECK_LT(0, breakpoint_infos->length());
900 :
901 0 : for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
902 : Handle<Object> obj(breakpoint_infos->get(i), isolate);
903 0 : if (obj->IsUndefined(isolate)) {
904 : for (; i < e; ++i) {
905 : DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate));
906 : }
907 : break;
908 : }
909 : Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
910 : int position = breakpoint_info->source_position();
911 :
912 : // Find the function for this breakpoint, and set the breakpoint.
913 0 : int func_index = compiled_module->GetContainingFunction(position);
914 : DCHECK_LE(0, func_index);
915 0 : WasmFunction& func = compiled_module->module()->functions[func_index];
916 0 : int offset_in_func = position - func.code_start_offset;
917 0 : WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
918 : }
919 : }
920 :
921 3616 : void WasmSharedModuleData::PrepareForLazyCompilation(
922 : Handle<WasmSharedModuleData> shared) {
923 3616 : if (shared->has_lazy_compilation_orchestrator()) return;
924 : Isolate* isolate = shared->GetIsolate();
925 3616 : LazyCompilationOrchestrator* orch = new LazyCompilationOrchestrator();
926 : Handle<Managed<LazyCompilationOrchestrator>> orch_handle =
927 3616 : Managed<LazyCompilationOrchestrator>::New(isolate, orch);
928 3616 : shared->set(WasmSharedModuleData::kLazyCompilationOrchestrator, *orch_handle);
929 : }
930 :
931 55551 : Handle<WasmCompiledModule> WasmCompiledModule::New(
932 : Isolate* isolate, Handle<WasmSharedModuleData> shared,
933 : Handle<FixedArray> code_table,
934 : MaybeHandle<FixedArray> maybe_empty_function_tables,
935 : MaybeHandle<FixedArray> maybe_signature_tables) {
936 : Handle<FixedArray> ret =
937 55551 : isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
938 : // WasmCompiledModule::cast would fail since fields are not set yet.
939 : Handle<WasmCompiledModule> compiled_module(
940 : reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
941 : compiled_module->InitId();
942 : compiled_module->set_shared(shared);
943 55551 : compiled_module->set_native_context(isolate->native_context());
944 : compiled_module->set_code_table(code_table);
945 : int function_table_count =
946 111102 : static_cast<int>(shared->module()->function_tables.size());
947 55551 : if (function_table_count > 0) {
948 : compiled_module->set_signature_tables(
949 : maybe_signature_tables.ToHandleChecked());
950 : compiled_module->set_empty_function_tables(
951 : maybe_empty_function_tables.ToHandleChecked());
952 : compiled_module->set_function_tables(
953 : maybe_empty_function_tables.ToHandleChecked());
954 : }
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 55551 : compiled_module->set_min_mem_pages(shared->module()->min_mem_pages);
960 : compiled_module->set_num_imported_functions(
961 55551 : shared->module()->num_imported_functions);
962 55551 : return compiled_module;
963 : }
964 :
965 32147 : Handle<WasmCompiledModule> WasmCompiledModule::Clone(
966 : Isolate* isolate, Handle<WasmCompiledModule> module) {
967 : Handle<FixedArray> code_copy =
968 32147 : isolate->factory()->CopyFixedArray(module->code_table());
969 : Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast(
970 32147 : isolate->factory()->CopyFixedArray(module));
971 : ret->InitId();
972 : ret->set_code_table(code_copy);
973 : ret->reset_weak_owning_instance();
974 : ret->reset_weak_next_instance();
975 : ret->reset_weak_prev_instance();
976 : ret->reset_weak_exported_functions();
977 32147 : if (ret->has_embedded_mem_start()) {
978 : WasmCompiledModule::recreate_embedded_mem_start(ret, isolate->factory(),
979 2852 : ret->embedded_mem_start());
980 : }
981 32147 : if (ret->has_globals_start()) {
982 : WasmCompiledModule::recreate_globals_start(ret, isolate->factory(),
983 1361 : ret->globals_start());
984 : }
985 32147 : if (ret->has_embedded_mem_size()) {
986 : WasmCompiledModule::recreate_embedded_mem_size(ret, isolate->factory(),
987 2852 : ret->embedded_mem_size());
988 : }
989 32147 : return ret;
990 : }
991 :
992 3510 : void WasmCompiledModule::Reset(Isolate* isolate,
993 : WasmCompiledModule* compiled_module) {
994 : DisallowHeapAllocation no_gc;
995 : TRACE("Resetting %d\n", compiled_module->instance_id());
996 : Object* undefined = *isolate->factory()->undefined_value();
997 : Object* fct_obj = compiled_module->ptr_to_code_table();
998 1755 : if (fct_obj != nullptr && fct_obj != undefined) {
999 1755 : uint32_t old_mem_size = compiled_module->mem_size();
1000 : uint32_t default_mem_size = compiled_module->default_mem_size();
1001 1755 : Address old_mem_start = compiled_module->GetEmbeddedMemStartOrNull();
1002 :
1003 : // Patch code to update memory references, global references, and function
1004 : // table references.
1005 1755 : Zone specialization_zone(isolate->allocator(), ZONE_NAME);
1006 3510 : CodeSpecialization code_specialization(isolate, &specialization_zone);
1007 :
1008 1755 : if (old_mem_size > 0 && old_mem_start != nullptr) {
1009 : code_specialization.RelocateMemoryReferences(old_mem_start, old_mem_size,
1010 1663 : nullptr, default_mem_size);
1011 : }
1012 :
1013 1755 : if (compiled_module->has_globals_start()) {
1014 : Address globals_start =
1015 85 : reinterpret_cast<Address>(compiled_module->globals_start());
1016 85 : code_specialization.RelocateGlobals(globals_start, nullptr);
1017 : compiled_module->set_globals_start(0);
1018 : }
1019 :
1020 : // Reset function tables.
1021 1755 : if (compiled_module->has_function_tables()) {
1022 : FixedArray* function_tables = compiled_module->ptr_to_function_tables();
1023 : FixedArray* empty_function_tables =
1024 : compiled_module->ptr_to_empty_function_tables();
1025 81 : if (function_tables != empty_function_tables) {
1026 : DCHECK_EQ(function_tables->length(), empty_function_tables->length());
1027 162 : for (int i = 0, e = function_tables->length(); i < e; ++i) {
1028 : code_specialization.RelocateObject(
1029 : handle(function_tables->get(i), isolate),
1030 81 : handle(empty_function_tables->get(i), isolate));
1031 : }
1032 : compiled_module->set_ptr_to_function_tables(empty_function_tables);
1033 : }
1034 : }
1035 :
1036 : FixedArray* functions = FixedArray::cast(fct_obj);
1037 9670 : for (int i = compiled_module->num_imported_functions(),
1038 : end = functions->length();
1039 : i < end; ++i) {
1040 : Code* code = Code::cast(functions->get(i));
1041 : // Skip lazy compile stubs.
1042 7910 : if (code->builtin_index() == Builtins::kWasmCompileLazy) continue;
1043 7137 : if (code->kind() != Code::WASM_FUNCTION) {
1044 : // From here on, there should only be wrappers for exported functions.
1045 : for (; i < end; ++i) {
1046 : DCHECK_EQ(Code::JS_TO_WASM_FUNCTION,
1047 : Code::cast(functions->get(i))->kind());
1048 : }
1049 : break;
1050 : }
1051 : bool changed =
1052 5387 : code_specialization.ApplyToWasmCode(code, SKIP_ICACHE_FLUSH);
1053 : // TODO(wasm): Check if this is faster than passing FLUSH_ICACHE_IF_NEEDED
1054 : // above.
1055 5387 : if (changed) {
1056 951 : Assembler::FlushICache(isolate, code->instruction_start(),
1057 1902 : code->instruction_size());
1058 : }
1059 1755 : }
1060 : }
1061 1755 : compiled_module->ResetSpecializationMemInfoIfNeeded();
1062 1755 : }
1063 :
1064 0 : void WasmCompiledModule::InitId() {
1065 : #if DEBUG
1066 : static uint32_t instance_id_counter = 0;
1067 : set(kID_instance_id, Smi::FromInt(instance_id_counter++));
1068 : TRACE("New compiled module id: %d\n", instance_id());
1069 : #endif
1070 0 : }
1071 :
1072 1755 : void WasmCompiledModule::ResetSpecializationMemInfoIfNeeded() {
1073 : DisallowHeapAllocation no_gc;
1074 1755 : if (has_embedded_mem_start()) {
1075 : set_embedded_mem_size(0);
1076 : set_embedded_mem_start(0);
1077 : }
1078 1755 : }
1079 :
1080 14467 : void WasmCompiledModule::SetSpecializationMemInfoFrom(
1081 : Factory* factory, Handle<WasmCompiledModule> compiled_module,
1082 : Handle<JSArrayBuffer> buffer) {
1083 : DCHECK(!buffer.is_null());
1084 14467 : size_t start_address = reinterpret_cast<size_t>(buffer->backing_store());
1085 14467 : uint32_t size = static_cast<uint32_t>(buffer->byte_length()->Number());
1086 14467 : if (!compiled_module->has_embedded_mem_start()) {
1087 : DCHECK(!compiled_module->has_embedded_mem_size());
1088 : WasmCompiledModule::recreate_embedded_mem_start(compiled_module, factory,
1089 5755 : start_address);
1090 : WasmCompiledModule::recreate_embedded_mem_size(compiled_module, factory,
1091 5755 : size);
1092 : } else {
1093 : compiled_module->set_embedded_mem_start(start_address);
1094 : compiled_module->set_embedded_mem_size(size);
1095 : }
1096 14467 : }
1097 :
1098 2860 : void WasmCompiledModule::SetGlobalsStartAddressFrom(
1099 : Factory* factory, Handle<WasmCompiledModule> compiled_module,
1100 : Handle<JSArrayBuffer> buffer) {
1101 : DCHECK(!buffer.is_null());
1102 2860 : size_t start_address = reinterpret_cast<size_t>(buffer->backing_store());
1103 2860 : if (!compiled_module->has_globals_start()) {
1104 : WasmCompiledModule::recreate_globals_start(compiled_module, factory,
1105 1432 : start_address);
1106 : } else {
1107 : compiled_module->set_globals_start(start_address);
1108 : }
1109 2860 : }
1110 :
1111 182051 : MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
1112 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
1113 : uint32_t offset, uint32_t size) {
1114 : // TODO(wasm): cache strings from modules if it's a performance win.
1115 : Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(),
1116 182051 : isolate);
1117 : DCHECK_GE(module_bytes->length(), offset);
1118 : DCHECK_GE(module_bytes->length() - offset, size);
1119 : // UTF8 validation happens at decode time.
1120 : DCHECK(unibrow::Utf8::Validate(
1121 : reinterpret_cast<const byte*>(module_bytes->GetCharsAddress() + offset),
1122 : size));
1123 : DCHECK_GE(kMaxInt, offset);
1124 : DCHECK_GE(kMaxInt, size);
1125 : return isolate->factory()->NewStringFromUtf8SubString(
1126 182051 : module_bytes, static_cast<int>(offset), static_cast<int>(size));
1127 : }
1128 :
1129 51980 : bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) {
1130 51980 : if (!obj->IsFixedArray()) return false;
1131 : FixedArray* arr = FixedArray::cast(obj);
1132 51980 : if (arr->length() != PropertyIndices::Count) return false;
1133 : Isolate* isolate = arr->GetIsolate();
1134 : #define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \
1135 : do { \
1136 : Object* obj = arr->get(kID_##NAME); \
1137 : if (!(TYPE_CHECK)) return false; \
1138 : } while (false);
1139 : // We're OK with undefined, generally, because maybe we don't
1140 : // have a value for that item. For example, we may not have a
1141 : // memory, or globals.
1142 : // We're not OK with the const numbers being undefined. They are
1143 : // expected to be initialized at construction.
1144 : #define WCM_CHECK_OBJECT(TYPE, NAME) \
1145 : WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE())
1146 : #define WCM_CHECK_CONST_OBJECT(TYPE, NAME) \
1147 : WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE())
1148 : #define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \
1149 : WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj))
1150 : #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME)
1151 : #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) \
1152 : WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsSmi())
1153 : #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME)
1154 : #define WCM_CHECK_SMALL_CONST_NUMBER(TYPE, NAME) \
1155 : WCM_CHECK_TYPE(NAME, obj->IsSmi())
1156 : #define WCM_CHECK_LARGE_NUMBER(TYPE, NAME) \
1157 : WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->IsMutableHeapNumber())
1158 1017476 : WCM_PROPERTY_TABLE(WCM_CHECK)
1159 : #undef WCM_CHECK
1160 :
1161 : // All checks passed.
1162 51980 : return true;
1163 : }
1164 :
1165 52742 : void WasmCompiledModule::PrintInstancesChain() {
1166 : #if DEBUG
1167 : if (!FLAG_trace_wasm_instances) return;
1168 : for (WasmCompiledModule* current = this; current != nullptr;) {
1169 : PrintF("->%d", current->instance_id());
1170 : if (!current->has_weak_next_instance()) break;
1171 : CHECK(!current->ptr_to_weak_next_instance()->cleared());
1172 : current =
1173 : WasmCompiledModule::cast(current->ptr_to_weak_next_instance()->value());
1174 : }
1175 : PrintF("\n");
1176 : #endif
1177 52742 : }
1178 :
1179 112 : void WasmCompiledModule::ReinitializeAfterDeserialization(
1180 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
1181 : // This method must only be called immediately after deserialization.
1182 : // At this point, no module wrapper exists, so the shared module data is
1183 : // incomplete.
1184 : Handle<WasmSharedModuleData> shared(
1185 : static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)),
1186 : isolate);
1187 : DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
1188 112 : WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
1189 112 : WasmCompiledModule::Reset(isolate, *compiled_module);
1190 : DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
1191 112 : }
1192 :
1193 11449 : uint32_t WasmCompiledModule::mem_size() const {
1194 : DCHECK(has_embedded_mem_size() == has_embedded_mem_start());
1195 22898 : return has_embedded_mem_start() ? embedded_mem_size() : default_mem_size();
1196 : }
1197 :
1198 0 : uint32_t WasmCompiledModule::default_mem_size() const {
1199 7511 : return min_mem_pages() * WasmModule::kPageSize;
1200 : }
1201 :
1202 2370 : MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull(
1203 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
1204 : uint32_t func_index) {
1205 : DCHECK_LT(func_index, compiled_module->module()->functions.size());
1206 4740 : WasmFunction& function = compiled_module->module()->functions[func_index];
1207 : DCHECK_IMPLIES(function.name_offset == 0, function.name_length == 0);
1208 2370 : if (!function.name_offset) return {};
1209 : return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
1210 2310 : isolate, compiled_module, function.name_offset, function.name_length);
1211 : }
1212 :
1213 609 : Handle<String> WasmCompiledModule::GetFunctionName(
1214 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
1215 : uint32_t func_index) {
1216 : MaybeHandle<String> name =
1217 609 : GetFunctionNameOrNull(isolate, compiled_module, func_index);
1218 609 : if (!name.is_null()) return name.ToHandleChecked();
1219 0 : return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
1220 : }
1221 :
1222 12496 : Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName(
1223 : uint32_t func_index) {
1224 : DCHECK_GT(module()->functions.size(), func_index);
1225 12496 : WasmFunction& function = module()->functions[func_index];
1226 12496 : SeqOneByteString* bytes = module_bytes();
1227 : DCHECK_GE(bytes->length(), function.name_offset);
1228 : DCHECK_GE(bytes->length() - function.name_offset, function.name_length);
1229 12496 : return Vector<const uint8_t>(bytes->GetCharsAddress() + function.name_offset,
1230 24992 : function.name_length);
1231 : }
1232 :
1233 37528 : int WasmCompiledModule::GetFunctionOffset(uint32_t func_index) {
1234 75056 : std::vector<WasmFunction>& functions = module()->functions;
1235 75056 : if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
1236 : DCHECK_GE(kMaxInt, functions[func_index].code_start_offset);
1237 37528 : return static_cast<int>(functions[func_index].code_start_offset);
1238 : }
1239 :
1240 624 : int WasmCompiledModule::GetContainingFunction(uint32_t byte_offset) {
1241 624 : std::vector<WasmFunction>& functions = module()->functions;
1242 :
1243 : // Binary search for a function containing the given position.
1244 : int left = 0; // inclusive
1245 624 : int right = static_cast<int>(functions.size()); // exclusive
1246 624 : if (right == 0) return false;
1247 1283 : while (right - left > 1) {
1248 659 : int mid = left + (right - left) / 2;
1249 1318 : if (functions[mid].code_start_offset <= byte_offset) {
1250 : left = mid;
1251 : } else {
1252 : right = mid;
1253 : }
1254 : }
1255 : // If the found function does not contains the given position, return -1.
1256 624 : WasmFunction& func = functions[left];
1257 1248 : if (byte_offset < func.code_start_offset ||
1258 624 : byte_offset >= func.code_end_offset) {
1259 : return -1;
1260 : }
1261 :
1262 624 : return left;
1263 : }
1264 :
1265 518 : bool WasmCompiledModule::GetPositionInfo(uint32_t position,
1266 : Script::PositionInfo* info) {
1267 518 : int func_index = GetContainingFunction(position);
1268 518 : if (func_index < 0) return false;
1269 :
1270 518 : WasmFunction& function = module()->functions[func_index];
1271 :
1272 518 : info->line = func_index;
1273 518 : info->column = position - function.code_start_offset;
1274 518 : info->line_start = function.code_start_offset;
1275 518 : info->line_end = function.code_end_offset;
1276 518 : return true;
1277 : }
1278 :
1279 : namespace {
1280 :
1281 : enum AsmJsOffsetTableEntryLayout {
1282 : kOTEByteOffset,
1283 : kOTECallPosition,
1284 : kOTENumberConvPosition,
1285 : kOTESize
1286 : };
1287 :
1288 1371 : Handle<ByteArray> GetDecodedAsmJsOffsetTable(
1289 : Handle<WasmCompiledModule> compiled_module, Isolate* isolate) {
1290 : DCHECK(compiled_module->is_asm_js());
1291 : Handle<ByteArray> offset_table(
1292 2742 : compiled_module->shared()->asm_js_offset_table(), isolate);
1293 :
1294 : // The last byte in the asm_js_offset_tables ByteArray tells whether it is
1295 : // still encoded (0) or decoded (1).
1296 : enum AsmJsTableType : int { Encoded = 0, Decoded = 1 };
1297 1371 : int table_type = offset_table->get(offset_table->length() - 1);
1298 : DCHECK(table_type == Encoded || table_type == Decoded);
1299 1371 : if (table_type == Decoded) return offset_table;
1300 :
1301 : AsmJsOffsetsResult asm_offsets;
1302 : {
1303 : DisallowHeapAllocation no_gc;
1304 78 : const byte* bytes_start = offset_table->GetDataStartAddress();
1305 78 : const byte* bytes_end = bytes_start + offset_table->length() - 1;
1306 78 : asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end);
1307 : }
1308 : // Wasm bytes must be valid and must contain asm.js offset table.
1309 : DCHECK(asm_offsets.ok());
1310 : DCHECK_GE(kMaxInt, asm_offsets.val.size());
1311 156 : int num_functions = static_cast<int>(asm_offsets.val.size());
1312 : int num_imported_functions =
1313 78 : static_cast<int>(compiled_module->module()->num_imported_functions);
1314 : DCHECK_EQ(compiled_module->module()->functions.size(),
1315 : static_cast<size_t>(num_functions) + num_imported_functions);
1316 : int num_entries = 0;
1317 334 : for (int func = 0; func < num_functions; ++func) {
1318 512 : size_t new_size = asm_offsets.val[func].size();
1319 : DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
1320 256 : num_entries += static_cast<int>(new_size);
1321 : }
1322 : // One byte to encode that this is a decoded table.
1323 : DCHECK_GE(kMaxInt,
1324 : 1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
1325 78 : int total_size = 1 + num_entries * kOTESize * kIntSize;
1326 : Handle<ByteArray> decoded_table =
1327 78 : isolate->factory()->NewByteArray(total_size, TENURED);
1328 : decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
1329 156 : compiled_module->shared()->set_asm_js_offset_table(*decoded_table);
1330 :
1331 : int idx = 0;
1332 256 : std::vector<WasmFunction>& wasm_funs = compiled_module->module()->functions;
1333 334 : for (int func = 0; func < num_functions; ++func) {
1334 256 : std::vector<AsmJsOffsetEntry>& func_asm_offsets = asm_offsets.val[func];
1335 256 : if (func_asm_offsets.empty()) continue;
1336 : int func_offset =
1337 356 : wasm_funs[num_imported_functions + func].code_start_offset;
1338 673 : for (AsmJsOffsetEntry& e : func_asm_offsets) {
1339 : // Byte offsets must be strictly monotonously increasing:
1340 : DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
1341 : decoded_table->get_int(idx - kOTESize));
1342 317 : decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
1343 317 : decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
1344 : decoded_table->set_int(idx + kOTENumberConvPosition,
1345 317 : e.source_position_number_conversion);
1346 317 : idx += kOTESize;
1347 : }
1348 : }
1349 : DCHECK_EQ(total_size, idx * kIntSize + 1);
1350 78 : return decoded_table;
1351 : }
1352 :
1353 : } // namespace
1354 :
1355 1371 : int WasmCompiledModule::GetAsmJsSourcePosition(
1356 : Handle<WasmCompiledModule> compiled_module, uint32_t func_index,
1357 : uint32_t byte_offset, bool is_at_number_conversion) {
1358 : Isolate* isolate = compiled_module->GetIsolate();
1359 : Handle<ByteArray> offset_table =
1360 1371 : GetDecodedAsmJsOffsetTable(compiled_module, isolate);
1361 :
1362 : DCHECK_LT(func_index, compiled_module->module()->functions.size());
1363 : uint32_t func_code_offset =
1364 4113 : compiled_module->module()->functions[func_index].code_start_offset;
1365 1371 : uint32_t total_offset = func_code_offset + byte_offset;
1366 :
1367 : // Binary search for the total byte offset.
1368 : int left = 0; // inclusive
1369 1371 : int right = offset_table->length() / kIntSize / kOTESize; // exclusive
1370 : DCHECK_LT(left, right);
1371 6200 : while (right - left > 1) {
1372 3458 : int mid = left + (right - left) / 2;
1373 3458 : int mid_entry = offset_table->get_int(kOTESize * mid);
1374 : DCHECK_GE(kMaxInt, mid_entry);
1375 3458 : if (static_cast<uint32_t>(mid_entry) <= total_offset) {
1376 : left = mid;
1377 : } else {
1378 : right = mid;
1379 : }
1380 : }
1381 : // There should be an entry for each position that could show up on the stack
1382 : // trace:
1383 : DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
1384 1371 : int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
1385 2742 : return offset_table->get_int(kOTESize * left + idx);
1386 : }
1387 :
1388 100 : v8::debug::WasmDisassembly WasmCompiledModule::DisassembleFunction(
1389 : int func_index) {
1390 : DisallowHeapAllocation no_gc;
1391 :
1392 200 : if (func_index < 0 ||
1393 100 : static_cast<uint32_t>(func_index) >= module()->functions.size())
1394 : return {};
1395 :
1396 100 : SeqOneByteString* module_bytes_str = module_bytes();
1397 100 : Vector<const byte> module_bytes(module_bytes_str->GetChars(),
1398 : module_bytes_str->length());
1399 :
1400 100 : std::ostringstream disassembly_os;
1401 : v8::debug::WasmDisassembly::OffsetTable offset_table;
1402 :
1403 100 : PrintWasmText(module(), module_bytes, static_cast<uint32_t>(func_index),
1404 200 : disassembly_os, &offset_table);
1405 :
1406 200 : return {disassembly_os.str(), std::move(offset_table)};
1407 : }
1408 :
1409 85 : bool WasmCompiledModule::GetPossibleBreakpoints(
1410 : const v8::debug::Location& start, const v8::debug::Location& end,
1411 : std::vector<v8::debug::BreakLocation>* locations) {
1412 : DisallowHeapAllocation no_gc;
1413 :
1414 449 : std::vector<WasmFunction>& functions = module()->functions;
1415 255 : if (start.GetLineNumber() < 0 || start.GetColumnNumber() < 0 ||
1416 170 : (!end.IsEmpty() &&
1417 170 : (end.GetLineNumber() < 0 || end.GetColumnNumber() < 0)))
1418 : return false;
1419 :
1420 : // start_func_index, start_offset and end_func_index is inclusive.
1421 : // end_offset is exclusive.
1422 : // start_offset and end_offset are module-relative byte offsets.
1423 85 : uint32_t start_func_index = start.GetLineNumber();
1424 170 : if (start_func_index >= functions.size()) return false;
1425 85 : int start_func_len = functions[start_func_index].code_end_offset -
1426 85 : functions[start_func_index].code_start_offset;
1427 85 : if (start.GetColumnNumber() > start_func_len) return false;
1428 : uint32_t start_offset =
1429 78 : functions[start_func_index].code_start_offset + start.GetColumnNumber();
1430 : uint32_t end_func_index;
1431 : uint32_t end_offset;
1432 78 : if (end.IsEmpty()) {
1433 : // Default: everything till the end of the Script.
1434 0 : end_func_index = static_cast<uint32_t>(functions.size() - 1);
1435 0 : end_offset = functions[end_func_index].code_end_offset;
1436 : } else {
1437 : // If end is specified: Use it and check for valid input.
1438 78 : end_func_index = static_cast<uint32_t>(end.GetLineNumber());
1439 :
1440 : // Special case: Stop before the start of the next function. Change to: Stop
1441 : // at the end of the function before, such that we don't disassemble the
1442 : // next function also.
1443 78 : if (end.GetColumnNumber() == 0 && end_func_index > 0) {
1444 33 : --end_func_index;
1445 66 : end_offset = functions[end_func_index].code_end_offset;
1446 : } else {
1447 90 : if (end_func_index >= functions.size()) return false;
1448 : end_offset =
1449 45 : functions[end_func_index].code_start_offset + end.GetColumnNumber();
1450 45 : if (end_offset > functions[end_func_index].code_end_offset) return false;
1451 : }
1452 : }
1453 :
1454 78 : AccountingAllocator alloc;
1455 156 : Zone tmp(&alloc, ZONE_NAME);
1456 78 : const byte* module_start = module_bytes()->GetChars();
1457 :
1458 156 : for (uint32_t func_idx = start_func_index; func_idx <= end_func_index;
1459 : ++func_idx) {
1460 78 : WasmFunction& func = functions[func_idx];
1461 78 : if (func.code_start_offset == func.code_end_offset) continue;
1462 :
1463 : BodyLocalDecls locals(&tmp);
1464 : BytecodeIterator iterator(module_start + func.code_start_offset,
1465 78 : module_start + func.code_end_offset, &locals);
1466 : DCHECK_LT(0u, locals.encoded_size);
1467 736 : for (uint32_t offset : iterator.offsets()) {
1468 345 : uint32_t total_offset = func.code_start_offset + offset;
1469 345 : if (total_offset >= end_offset) {
1470 : DCHECK_EQ(end_func_index, func_idx);
1471 : break;
1472 : }
1473 313 : if (total_offset < start_offset) continue;
1474 178 : locations->emplace_back(func_idx, offset, debug::kCommonBreakLocation);
1475 : }
1476 : }
1477 78 : return true;
1478 : }
1479 :
1480 106 : bool WasmCompiledModule::SetBreakPoint(
1481 : Handle<WasmCompiledModule> compiled_module, int* position,
1482 : Handle<Object> break_point_object) {
1483 : Isolate* isolate = compiled_module->GetIsolate();
1484 :
1485 : // Find the function for this breakpoint.
1486 106 : int func_index = compiled_module->GetContainingFunction(*position);
1487 106 : if (func_index < 0) return false;
1488 212 : WasmFunction& func = compiled_module->module()->functions[func_index];
1489 106 : int offset_in_func = *position - func.code_start_offset;
1490 :
1491 : // According to the current design, we should only be called with valid
1492 : // breakable positions.
1493 : DCHECK(IsBreakablePosition(compiled_module, func_index, offset_in_func));
1494 :
1495 : // Insert new break point into break_positions of shared module data.
1496 : WasmSharedModuleData::AddBreakpoint(compiled_module->shared(), *position,
1497 106 : break_point_object);
1498 :
1499 : // Iterate over all instances of this module and tell them to set this new
1500 : // breakpoint.
1501 184 : for (Handle<WasmInstanceObject> instance :
1502 262 : iterate_compiled_module_instance_chain(isolate, compiled_module)) {
1503 : Handle<WasmDebugInfo> debug_info =
1504 78 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
1505 78 : WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
1506 : }
1507 :
1508 106 : return true;
1509 : }
1510 :
1511 355 : MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) {
1512 124 : Isolate* isolate = GetIsolate();
1513 710 : if (!shared()->has_breakpoint_infos()) return {};
1514 :
1515 710 : Handle<FixedArray> breakpoint_infos(shared()->breakpoint_infos(), isolate);
1516 : int insert_pos =
1517 355 : FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
1518 355 : if (insert_pos >= breakpoint_infos->length()) return {};
1519 :
1520 : Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
1521 : isolate);
1522 355 : if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
1523 : Handle<BreakPointInfo> breakpoint_info =
1524 : Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
1525 209 : if (breakpoint_info->source_position() != position) return {};
1526 :
1527 : Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(),
1528 : isolate);
1529 124 : return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
1530 : }
1531 :
1532 12699 : MaybeHandle<Code> WasmCompiledModule::CompileLazy(
1533 : Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> caller,
1534 : int offset, int func_index, bool patch_caller) {
1535 25398 : isolate->set_context(*instance->compiled_module()->native_context());
1536 : Object* orch_obj =
1537 25398 : instance->compiled_module()->shared()->lazy_compilation_orchestrator();
1538 : LazyCompilationOrchestrator* orch =
1539 : Managed<LazyCompilationOrchestrator>::cast(orch_obj)->get();
1540 : return orch->CompileLazy(isolate, instance, caller, offset, func_index,
1541 12699 : patch_caller);
1542 : }
1543 :
1544 87727 : Handle<WasmInstanceWrapper> WasmInstanceWrapper::New(
1545 : Isolate* isolate, Handle<WasmInstanceObject> instance) {
1546 : Handle<FixedArray> array =
1547 87727 : isolate->factory()->NewFixedArray(kWrapperPropertyCount, TENURED);
1548 : Handle<WasmInstanceWrapper> instance_wrapper(
1549 : reinterpret_cast<WasmInstanceWrapper*>(*array), isolate);
1550 87727 : Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance);
1551 87727 : instance_wrapper->set(kWrapperInstanceObject, *cell);
1552 87727 : return instance_wrapper;
1553 : }
1554 :
1555 6497 : bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) {
1556 6497 : if (!obj->IsFixedArray()) return false;
1557 : Handle<FixedArray> array = handle(FixedArray::cast(obj));
1558 3677 : if (array->length() != kWrapperPropertyCount) return false;
1559 3677 : if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false;
1560 : Isolate* isolate = array->GetIsolate();
1561 6573 : if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) &&
1562 : !array->get(kNextInstanceWrapper)->IsFixedArray())
1563 : return false;
1564 7272 : if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) &&
1565 : !array->get(kPreviousInstanceWrapper)->IsFixedArray())
1566 : return false;
1567 3677 : return true;
1568 : }
|