• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/base/iterator.h"
9 #include "src/debug/debug-interface.h"
10 #include "src/objects-inl.h"
11 #include "src/wasm/module-decoder.h"
12 #include "src/wasm/wasm-module.h"
13 #include "src/wasm/wasm-text.h"
14 
15 #define TRACE(...)                                      \
16   do {                                                  \
17     if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
18   } while (false)
19 
20 #define TRACE_CHAIN(instance)        \
21   do {                               \
22     instance->PrintInstancesChain(); \
23   } while (false)
24 
25 using namespace v8::internal;
26 using namespace v8::internal::wasm;
27 
28 #define DEFINE_GETTER0(getter, Container, name, field, type) \
29   type* Container::name() { return type::cast(getter(field)); }
30 
31 #define DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \
32   DEFINE_GETTER0(getter, Container, name, field, type)                  \
33   void Container::set_##name(type* value) { return setter(field, value); }
34 
35 #define DEFINE_OPTIONAL_ACCESSORS0(getter, setter, Container, name, field, \
36                                    type)                                   \
37   DEFINE_ACCESSORS0(getter, setter, Container, name, field, type)          \
38   bool Container::has_##name() {                                           \
39     return !getter(field)->IsUndefined(GetIsolate());                      \
40   }
41 
42 #define DEFINE_OPTIONAL_GETTER0(getter, Container, name, field, type) \
43   DEFINE_GETTER0(getter, Container, name, field, type)                \
44   bool Container::has_##name() {                                      \
45     return !getter(field)->IsUndefined(GetIsolate());                 \
46   }
47 
48 #define DEFINE_GETTER0(getter, Container, name, field, type) \
49   type* Container::name() { return type::cast(getter(field)); }
50 
51 #define DEFINE_OBJ_GETTER(Container, name, field, type) \
52   DEFINE_GETTER0(GetInternalField, Container, name, field, type)
53 #define DEFINE_OBJ_ACCESSORS(Container, name, field, type)               \
54   DEFINE_ACCESSORS0(GetInternalField, SetInternalField, Container, name, \
55                     field, type)
56 #define DEFINE_OPTIONAL_OBJ_ACCESSORS(Container, name, field, type)         \
57   DEFINE_OPTIONAL_ACCESSORS0(GetInternalField, SetInternalField, Container, \
58                              name, field, type)
59 #define DEFINE_ARR_GETTER(Container, name, field, type) \
60   DEFINE_GETTER0(get, Container, name, field, type)
61 #define DEFINE_ARR_ACCESSORS(Container, name, field, type) \
62   DEFINE_ACCESSORS0(get, set, Container, name, field, type)
63 #define DEFINE_OPTIONAL_ARR_ACCESSORS(Container, name, field, type) \
64   DEFINE_OPTIONAL_ACCESSORS0(get, set, Container, name, field, type)
65 #define DEFINE_OPTIONAL_ARR_GETTER(Container, name, field, type) \
66   DEFINE_OPTIONAL_GETTER0(get, Container, name, field, type)
67 
68 namespace {
69 
SafeUint32(Object * value)70 uint32_t SafeUint32(Object* value) {
71   if (value->IsSmi()) {
72     int32_t val = Smi::cast(value)->value();
73     CHECK_GE(val, 0);
74     return static_cast<uint32_t>(val);
75   }
76   DCHECK(value->IsHeapNumber());
77   HeapNumber* num = HeapNumber::cast(value);
78   CHECK_GE(num->value(), 0.0);
79   CHECK_LE(num->value(), kMaxUInt32);
80   return static_cast<uint32_t>(num->value());
81 }
82 
SafeInt32(Object * value)83 int32_t SafeInt32(Object* value) {
84   if (value->IsSmi()) {
85     return Smi::cast(value)->value();
86   }
87   DCHECK(value->IsHeapNumber());
88   HeapNumber* num = HeapNumber::cast(value);
89   CHECK_GE(num->value(), Smi::kMinValue);
90   CHECK_LE(num->value(), Smi::kMaxValue);
91   return static_cast<int32_t>(num->value());
92 }
93 
94 // An iterator that returns first the module itself, then all modules linked via
95 // next, then all linked via prev.
96 class CompiledModulesIterator
97     : public std::iterator<std::input_iterator_tag,
98                            Handle<WasmCompiledModule>> {
99  public:
CompiledModulesIterator(Isolate * isolate,Handle<WasmCompiledModule> start_module,bool at_end)100   CompiledModulesIterator(Isolate* isolate,
101                           Handle<WasmCompiledModule> start_module, bool at_end)
102       : isolate_(isolate),
103         start_module_(start_module),
104         current_(at_end ? Handle<WasmCompiledModule>::null() : start_module) {}
105 
operator *() const106   Handle<WasmCompiledModule> operator*() const {
107     DCHECK(!current_.is_null());
108     return current_;
109   }
110 
operator ++()111   void operator++() { Advance(); }
112 
operator !=(const CompiledModulesIterator & other)113   bool operator!=(const CompiledModulesIterator& other) {
114     DCHECK(start_module_.is_identical_to(other.start_module_));
115     return !current_.is_identical_to(other.current_);
116   }
117 
118  private:
Advance()119   void Advance() {
120     DCHECK(!current_.is_null());
121     if (!is_backwards_) {
122       if (current_->has_weak_next_instance()) {
123         WeakCell* weak_next = current_->ptr_to_weak_next_instance();
124         if (!weak_next->cleared()) {
125           current_ =
126               handle(WasmCompiledModule::cast(weak_next->value()), isolate_);
127           return;
128         }
129       }
130       // No more modules in next-links, now try the previous-links.
131       is_backwards_ = true;
132       current_ = start_module_;
133     }
134     if (current_->has_weak_prev_instance()) {
135       WeakCell* weak_prev = current_->ptr_to_weak_prev_instance();
136       if (!weak_prev->cleared()) {
137         current_ =
138             handle(WasmCompiledModule::cast(weak_prev->value()), isolate_);
139         return;
140       }
141     }
142     current_ = Handle<WasmCompiledModule>::null();
143   }
144 
145   friend class CompiledModuleInstancesIterator;
146   Isolate* isolate_;
147   Handle<WasmCompiledModule> start_module_;
148   Handle<WasmCompiledModule> current_;
149   bool is_backwards_ = false;
150 };
151 
152 // An iterator based on the CompiledModulesIterator, but it returns all live
153 // instances, not the WasmCompiledModules itself.
154 class CompiledModuleInstancesIterator
155     : public std::iterator<std::input_iterator_tag,
156                            Handle<WasmInstanceObject>> {
157  public:
CompiledModuleInstancesIterator(Isolate * isolate,Handle<WasmCompiledModule> start_module,bool at_end)158   CompiledModuleInstancesIterator(Isolate* isolate,
159                                   Handle<WasmCompiledModule> start_module,
160                                   bool at_end)
161       : it(isolate, start_module, at_end) {
162     while (NeedToAdvance()) ++it;
163   }
164 
operator *()165   Handle<WasmInstanceObject> operator*() {
166     return handle(
167         WasmInstanceObject::cast((*it)->weak_owning_instance()->value()),
168         it.isolate_);
169   }
170 
operator ++()171   void operator++() {
172     do {
173       ++it;
174     } while (NeedToAdvance());
175   }
176 
operator !=(const CompiledModuleInstancesIterator & other)177   bool operator!=(const CompiledModuleInstancesIterator& other) {
178     return it != other.it;
179   }
180 
181  private:
NeedToAdvance()182   bool NeedToAdvance() {
183     return !it.current_.is_null() &&
184            (!it.current_->has_weak_owning_instance() ||
185             it.current_->ptr_to_weak_owning_instance()->cleared());
186   }
187   CompiledModulesIterator it;
188 };
189 
190 v8::base::iterator_range<CompiledModuleInstancesIterator>
iterate_compiled_module_instance_chain(Isolate * isolate,Handle<WasmCompiledModule> compiled_module)191 iterate_compiled_module_instance_chain(
192     Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
193   return {CompiledModuleInstancesIterator(isolate, compiled_module, false),
194           CompiledModuleInstancesIterator(isolate, compiled_module, true)};
195 }
196 
197 #ifdef DEBUG
IsBreakablePosition(Handle<WasmCompiledModule> compiled_module,int func_index,int offset_in_func)198 bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module,
199                          int func_index, int offset_in_func) {
200   DisallowHeapAllocation no_gc;
201   AccountingAllocator alloc;
202   Zone tmp(&alloc, ZONE_NAME);
203   BodyLocalDecls locals(&tmp);
204   const byte* module_start = compiled_module->module_bytes()->GetChars();
205   WasmFunction& func = compiled_module->module()->functions[func_index];
206   BytecodeIterator iterator(module_start + func.code_start_offset,
207                             module_start + func.code_end_offset, &locals);
208   DCHECK_LT(0, locals.encoded_size);
209   for (uint32_t offset : iterator.offsets()) {
210     if (offset > static_cast<uint32_t>(offset_in_func)) break;
211     if (offset == static_cast<uint32_t>(offset_in_func)) return true;
212   }
213   return false;
214 }
215 #endif  // DEBUG
216 
217 }  // namespace
218 
New(Isolate * isolate,Handle<WasmCompiledModule> compiled_module)219 Handle<WasmModuleObject> WasmModuleObject::New(
220     Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
221   ModuleOrigin origin = compiled_module->module()->origin;
222 
223   Handle<JSObject> module_object;
224   if (origin == ModuleOrigin::kWasmOrigin) {
225     Handle<JSFunction> module_cons(
226         isolate->native_context()->wasm_module_constructor());
227     module_object = isolate->factory()->NewJSObject(module_cons);
228     Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym());
229     Object::SetProperty(module_object, module_sym, module_object, STRICT)
230         .Check();
231   } else {
232     DCHECK(origin == ModuleOrigin::kAsmJsOrigin);
233     Handle<Map> map = isolate->factory()->NewMap(
234         JS_OBJECT_TYPE,
235         JSObject::kHeaderSize + WasmModuleObject::kFieldCount * kPointerSize);
236     module_object = isolate->factory()->NewJSObjectFromMap(map, TENURED);
237   }
238   module_object->SetInternalField(WasmModuleObject::kCompiledModule,
239                                   *compiled_module);
240   Handle<WeakCell> link_to_module =
241       isolate->factory()->NewWeakCell(module_object);
242   compiled_module->set_weak_wasm_module(link_to_module);
243   return Handle<WasmModuleObject>::cast(module_object);
244 }
245 
cast(Object * object)246 WasmModuleObject* WasmModuleObject::cast(Object* object) {
247   DCHECK(object->IsJSObject());
248   // TODO(titzer): brand check for WasmModuleObject.
249   return reinterpret_cast<WasmModuleObject*>(object);
250 }
251 
IsWasmModuleObject(Object * object)252 bool WasmModuleObject::IsWasmModuleObject(Object* object) {
253   return object->IsJSObject() &&
254          JSObject::cast(object)->GetInternalFieldCount() == kFieldCount;
255 }
256 
DEFINE_OBJ_GETTER(WasmModuleObject,compiled_module,kCompiledModule,WasmCompiledModule)257 DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule,
258                   WasmCompiledModule)
259 
260 Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
261                                              int64_t maximum,
262                                              Handle<FixedArray>* js_functions) {
263   Handle<JSFunction> table_ctor(
264       isolate->native_context()->wasm_table_constructor());
265   Handle<JSObject> table_obj = isolate->factory()->NewJSObject(table_ctor);
266   *js_functions = isolate->factory()->NewFixedArray(initial);
267   Object* null = isolate->heap()->null_value();
268   for (int i = 0; i < static_cast<int>(initial); ++i) {
269     (*js_functions)->set(i, null);
270   }
271   table_obj->SetInternalField(kFunctions, *(*js_functions));
272   Handle<Object> max = isolate->factory()->NewNumber(maximum);
273   table_obj->SetInternalField(kMaximum, *max);
274 
275   Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0);
276   table_obj->SetInternalField(kDispatchTables, *dispatch_tables);
277   Handle<Symbol> table_sym(isolate->native_context()->wasm_table_sym());
278   Object::SetProperty(table_obj, table_sym, table_obj, STRICT).Check();
279   return Handle<WasmTableObject>::cast(table_obj);
280 }
281 
DEFINE_OBJ_GETTER(WasmTableObject,dispatch_tables,kDispatchTables,FixedArray)282 DEFINE_OBJ_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray)
283 
284 Handle<FixedArray> WasmTableObject::AddDispatchTable(
285     Isolate* isolate, Handle<WasmTableObject> table_obj,
286     Handle<WasmInstanceObject> instance, int table_index,
287     Handle<FixedArray> function_table, Handle<FixedArray> signature_table) {
288   Handle<FixedArray> dispatch_tables(
289       FixedArray::cast(table_obj->GetInternalField(kDispatchTables)), isolate);
290   DCHECK_EQ(0, dispatch_tables->length() % 4);
291 
292   if (instance.is_null()) return dispatch_tables;
293   // TODO(titzer): use weak cells here to avoid leaking instances.
294 
295   // Grow the dispatch table and add a new triple at the end.
296   Handle<FixedArray> new_dispatch_tables =
297       isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 4);
298 
299   new_dispatch_tables->set(dispatch_tables->length() + 0, *instance);
300   new_dispatch_tables->set(dispatch_tables->length() + 1,
301                            Smi::FromInt(table_index));
302   new_dispatch_tables->set(dispatch_tables->length() + 2, *function_table);
303   new_dispatch_tables->set(dispatch_tables->length() + 3, *signature_table);
304 
305   table_obj->SetInternalField(WasmTableObject::kDispatchTables,
306                               *new_dispatch_tables);
307 
308   return new_dispatch_tables;
309 }
310 
DEFINE_OBJ_ACCESSORS(WasmTableObject,functions,kFunctions,FixedArray)311 DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray)
312 
313 uint32_t WasmTableObject::current_length() { return functions()->length(); }
314 
has_maximum_length()315 bool WasmTableObject::has_maximum_length() {
316   return GetInternalField(kMaximum)->Number() >= 0;
317 }
318 
maximum_length()319 int64_t WasmTableObject::maximum_length() {
320   return static_cast<int64_t>(GetInternalField(kMaximum)->Number());
321 }
322 
cast(Object * object)323 WasmTableObject* WasmTableObject::cast(Object* object) {
324   DCHECK(object && object->IsJSObject());
325   // TODO(titzer): brand check for WasmTableObject.
326   return reinterpret_cast<WasmTableObject*>(object);
327 }
328 
Grow(Isolate * isolate,Handle<WasmTableObject> table,uint32_t count)329 void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
330                            uint32_t count) {
331   Handle<FixedArray> dispatch_tables(table->dispatch_tables());
332   wasm::GrowDispatchTables(isolate, dispatch_tables,
333                            table->functions()->length(), count);
334 }
335 
New(Isolate * isolate,Handle<JSArrayBuffer> buffer,int32_t maximum)336 Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
337                                                Handle<JSArrayBuffer> buffer,
338                                                int32_t maximum) {
339   Handle<JSFunction> memory_ctor(
340       isolate->native_context()->wasm_memory_constructor());
341   Handle<JSObject> memory_obj =
342       isolate->factory()->NewJSObject(memory_ctor, TENURED);
343   memory_obj->SetInternalField(kArrayBuffer, *buffer);
344   Handle<Object> max = isolate->factory()->NewNumber(maximum);
345   memory_obj->SetInternalField(kMaximum, *max);
346   Handle<Symbol> memory_sym(isolate->native_context()->wasm_memory_sym());
347   Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check();
348   return Handle<WasmMemoryObject>::cast(memory_obj);
349 }
350 
DEFINE_OBJ_ACCESSORS(WasmMemoryObject,buffer,kArrayBuffer,JSArrayBuffer)351 DEFINE_OBJ_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer)
352 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, instances_link, kInstancesLink,
353                               WasmInstanceWrapper)
354 
355 uint32_t WasmMemoryObject::current_pages() {
356   return SafeUint32(buffer()->byte_length()) / wasm::WasmModule::kPageSize;
357 }
358 
has_maximum_pages()359 bool WasmMemoryObject::has_maximum_pages() {
360   return GetInternalField(kMaximum)->Number() >= 0;
361 }
362 
maximum_pages()363 int32_t WasmMemoryObject::maximum_pages() {
364   return static_cast<int32_t>(GetInternalField(kMaximum)->Number());
365 }
366 
cast(Object * object)367 WasmMemoryObject* WasmMemoryObject::cast(Object* object) {
368   DCHECK(object && object->IsJSObject());
369   // TODO(titzer): brand check for WasmMemoryObject.
370   return reinterpret_cast<WasmMemoryObject*>(object);
371 }
372 
AddInstance(Isolate * isolate,Handle<WasmInstanceObject> instance)373 void WasmMemoryObject::AddInstance(Isolate* isolate,
374                                    Handle<WasmInstanceObject> instance) {
375   Handle<WasmInstanceWrapper> instance_wrapper =
376       handle(instance->instance_wrapper());
377   if (has_instances_link()) {
378     Handle<WasmInstanceWrapper> current_wrapper(instances_link());
379     DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*current_wrapper));
380     DCHECK(!current_wrapper->has_previous());
381     instance_wrapper->set_next_wrapper(*current_wrapper);
382     current_wrapper->set_previous_wrapper(*instance_wrapper);
383   }
384   set_instances_link(*instance_wrapper);
385 }
386 
ResetInstancesLink(Isolate * isolate)387 void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) {
388   Handle<Object> undefined = isolate->factory()->undefined_value();
389   SetInternalField(kInstancesLink, *undefined);
390 }
391 
DEFINE_OBJ_ACCESSORS(WasmInstanceObject,compiled_module,kCompiledModule,WasmCompiledModule)392 DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule,
393                      WasmCompiledModule)
394 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer,
395                               kGlobalsArrayBuffer, JSArrayBuffer)
396 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_buffer,
397                               kMemoryArrayBuffer, JSArrayBuffer)
398 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject,
399                               WasmMemoryObject)
400 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo,
401                               WasmDebugInfo)
402 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, instance_wrapper,
403                               kWasmMemInstanceWrapper, WasmInstanceWrapper)
404 
405 WasmModuleObject* WasmInstanceObject::module_object() {
406   return *compiled_module()->wasm_module();
407 }
408 
module()409 WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); }
410 
GetOrCreateDebugInfo(Handle<WasmInstanceObject> instance)411 Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo(
412     Handle<WasmInstanceObject> instance) {
413   if (instance->has_debug_info()) return handle(instance->debug_info());
414   Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance);
415   instance->set_debug_info(*new_info);
416   return new_info;
417 }
418 
cast(Object * object)419 WasmInstanceObject* WasmInstanceObject::cast(Object* object) {
420   DCHECK(IsWasmInstanceObject(object));
421   return reinterpret_cast<WasmInstanceObject*>(object);
422 }
423 
IsWasmInstanceObject(Object * object)424 bool WasmInstanceObject::IsWasmInstanceObject(Object* object) {
425   if (!object->IsJSObject()) return false;
426 
427   JSObject* obj = JSObject::cast(object);
428   Isolate* isolate = obj->GetIsolate();
429   if (obj->GetInternalFieldCount() != kFieldCount) {
430     return false;
431   }
432 
433   Object* mem = obj->GetInternalField(kMemoryArrayBuffer);
434   if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) ||
435       !WasmCompiledModule::IsWasmCompiledModule(
436           obj->GetInternalField(kCompiledModule))) {
437     return false;
438   }
439 
440   // All checks passed.
441   return true;
442 }
443 
New(Isolate * isolate,Handle<WasmCompiledModule> compiled_module)444 Handle<WasmInstanceObject> WasmInstanceObject::New(
445     Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
446   Handle<JSFunction> instance_cons(
447       isolate->native_context()->wasm_instance_constructor());
448   Handle<JSObject> instance_object =
449       isolate->factory()->NewJSObject(instance_cons, TENURED);
450   Handle<Symbol> instance_sym(isolate->native_context()->wasm_instance_sym());
451   Object::SetProperty(instance_object, instance_sym, instance_object, STRICT)
452       .Check();
453   Handle<WasmInstanceObject> instance(
454       reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate);
455 
456   instance->SetInternalField(kCompiledModule, *compiled_module);
457   instance->SetInternalField(kMemoryObject, isolate->heap()->undefined_value());
458   Handle<WasmInstanceWrapper> instance_wrapper =
459       WasmInstanceWrapper::New(isolate, instance);
460   instance->SetInternalField(kWasmMemInstanceWrapper, *instance_wrapper);
461   return instance;
462 }
463 
instance()464 WasmInstanceObject* WasmExportedFunction::instance() {
465   return WasmInstanceObject::cast(GetInternalField(kInstance));
466 }
467 
function_index()468 int WasmExportedFunction::function_index() {
469   return SafeInt32(GetInternalField(kIndex));
470 }
471 
cast(Object * object)472 WasmExportedFunction* WasmExportedFunction::cast(Object* object) {
473   DCHECK(object && object->IsJSFunction());
474   DCHECK_EQ(Code::JS_TO_WASM_FUNCTION,
475             JSFunction::cast(object)->code()->kind());
476   // TODO(titzer): brand check for WasmExportedFunction.
477   return reinterpret_cast<WasmExportedFunction*>(object);
478 }
479 
New(Isolate * isolate,Handle<WasmInstanceObject> instance,MaybeHandle<String> maybe_name,int func_index,int arity,Handle<Code> export_wrapper)480 Handle<WasmExportedFunction> WasmExportedFunction::New(
481     Isolate* isolate, Handle<WasmInstanceObject> instance,
482     MaybeHandle<String> maybe_name, int func_index, int arity,
483     Handle<Code> export_wrapper) {
484   Handle<String> name;
485   if (maybe_name.is_null()) {
486     EmbeddedVector<char, 16> buffer;
487     int length = SNPrintF(buffer, "%d", func_index);
488     name = isolate->factory()
489                ->NewStringFromAscii(
490                    Vector<const char>::cast(buffer.SubVector(0, length)))
491                .ToHandleChecked();
492   } else {
493     name = maybe_name.ToHandleChecked();
494   }
495   DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
496   Handle<SharedFunctionInfo> shared =
497       isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false);
498   shared->set_length(arity);
499   shared->set_internal_formal_parameter_count(arity);
500   Handle<JSFunction> function = isolate->factory()->NewFunction(
501       isolate->wasm_function_map(), name, export_wrapper);
502   function->set_shared(*shared);
503 
504   function->SetInternalField(kInstance, *instance);
505   function->SetInternalField(kIndex, Smi::FromInt(func_index));
506   return Handle<WasmExportedFunction>::cast(function);
507 }
508 
IsWasmSharedModuleData(Object * object)509 bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) {
510   if (!object->IsFixedArray()) return false;
511   FixedArray* arr = FixedArray::cast(object);
512   if (arr->length() != kFieldCount) return false;
513   Isolate* isolate = arr->GetIsolate();
514   if (!arr->get(kModuleWrapper)->IsForeign()) return false;
515   if (!arr->get(kModuleBytes)->IsUndefined(isolate) &&
516       !arr->get(kModuleBytes)->IsSeqOneByteString())
517     return false;
518   if (!arr->get(kScript)->IsScript()) return false;
519   if (!arr->get(kAsmJsOffsetTable)->IsUndefined(isolate) &&
520       !arr->get(kAsmJsOffsetTable)->IsByteArray())
521     return false;
522   if (!arr->get(kBreakPointInfos)->IsUndefined(isolate) &&
523       !arr->get(kBreakPointInfos)->IsFixedArray())
524     return false;
525   return true;
526 }
527 
cast(Object * object)528 WasmSharedModuleData* WasmSharedModuleData::cast(Object* object) {
529   DCHECK(IsWasmSharedModuleData(object));
530   return reinterpret_cast<WasmSharedModuleData*>(object);
531 }
532 
module()533 wasm::WasmModule* WasmSharedModuleData::module() {
534   // We populate the kModuleWrapper field with a Foreign holding the
535   // address to the address of a WasmModule. This is because we can
536   // handle both cases when the WasmModule's lifetime is managed through
537   // a Managed<WasmModule> object, as well as cases when it's managed
538   // by the embedder. CcTests fall into the latter case.
539   return *(reinterpret_cast<wasm::WasmModule**>(
540       Foreign::cast(get(kModuleWrapper))->foreign_address()));
541 }
542 
543 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes,
544                               SeqOneByteString);
545 DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script);
546 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table,
547                               kAsmJsOffsetTable, ByteArray);
548 DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos,
549                            kBreakPointInfos, FixedArray);
550 
New(Isolate * isolate,Handle<Foreign> module_wrapper,Handle<SeqOneByteString> module_bytes,Handle<Script> script,Handle<ByteArray> asm_js_offset_table)551 Handle<WasmSharedModuleData> WasmSharedModuleData::New(
552     Isolate* isolate, Handle<Foreign> module_wrapper,
553     Handle<SeqOneByteString> module_bytes, Handle<Script> script,
554     Handle<ByteArray> asm_js_offset_table) {
555   Handle<FixedArray> arr =
556       isolate->factory()->NewFixedArray(kFieldCount, TENURED);
557 
558   arr->set(kModuleWrapper, *module_wrapper);
559   if (!module_bytes.is_null()) {
560     arr->set(kModuleBytes, *module_bytes);
561   }
562   if (!script.is_null()) {
563     arr->set(kScript, *script);
564   }
565   if (!asm_js_offset_table.is_null()) {
566     arr->set(kAsmJsOffsetTable, *asm_js_offset_table);
567   }
568 
569   DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*arr));
570   return Handle<WasmSharedModuleData>::cast(arr);
571 }
572 
is_asm_js()573 bool WasmSharedModuleData::is_asm_js() {
574   bool asm_js = module()->origin == wasm::ModuleOrigin::kAsmJsOrigin;
575   DCHECK_EQ(asm_js, script()->type() == Script::TYPE_NORMAL);
576   DCHECK_EQ(asm_js, has_asm_js_offset_table());
577   return asm_js;
578 }
579 
ReinitializeAfterDeserialization(Isolate * isolate,Handle<WasmSharedModuleData> shared)580 void WasmSharedModuleData::ReinitializeAfterDeserialization(
581     Isolate* isolate, Handle<WasmSharedModuleData> shared) {
582   DCHECK(shared->get(kModuleWrapper)->IsUndefined(isolate));
583 #ifdef DEBUG
584   // No BreakpointInfo objects should survive deserialization.
585   if (shared->has_breakpoint_infos()) {
586     for (int i = 0, e = shared->breakpoint_infos()->length(); i < e; ++i) {
587       DCHECK(shared->breakpoint_infos()->get(i)->IsUndefined(isolate));
588     }
589   }
590 #endif
591 
592   shared->set(kBreakPointInfos, isolate->heap()->undefined_value());
593 
594   WasmModule* module = nullptr;
595   {
596     // We parse the module again directly from the module bytes, so
597     // the underlying storage must not be moved meanwhile.
598     DisallowHeapAllocation no_allocation;
599     SeqOneByteString* module_bytes = shared->module_bytes();
600     const byte* start =
601         reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
602     const byte* end = start + module_bytes->length();
603     // TODO(titzer): remember the module origin in the compiled_module
604     // For now, we assume serialized modules did not originate from asm.js.
605     ModuleResult result =
606         DecodeWasmModule(isolate, start, end, false, kWasmOrigin);
607     CHECK(result.ok());
608     CHECK_NOT_NULL(result.val);
609     module = const_cast<WasmModule*>(result.val);
610   }
611 
612   Handle<WasmModuleWrapper> module_wrapper =
613       WasmModuleWrapper::New(isolate, module);
614 
615   shared->set(kModuleWrapper, *module_wrapper);
616   DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
617 }
618 
619 namespace {
620 
GetBreakpointPos(Isolate * isolate,Object * break_point_info_or_undef)621 int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) {
622   if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt;
623   return BreakPointInfo::cast(break_point_info_or_undef)->source_position();
624 }
625 
FindBreakpointInfoInsertPos(Isolate * isolate,Handle<FixedArray> breakpoint_infos,int position)626 int FindBreakpointInfoInsertPos(Isolate* isolate,
627                                 Handle<FixedArray> breakpoint_infos,
628                                 int position) {
629   // Find insert location via binary search, taking care of undefined values on
630   // the right. Position is always greater than zero.
631   DCHECK_LT(0, position);
632 
633   int left = 0;                            // inclusive
634   int right = breakpoint_infos->length();  // exclusive
635   while (right - left > 1) {
636     int mid = left + (right - left) / 2;
637     Object* mid_obj = breakpoint_infos->get(mid);
638     if (GetBreakpointPos(isolate, mid_obj) <= position) {
639       left = mid;
640     } else {
641       right = mid;
642     }
643   }
644 
645   int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
646   return left_pos < position ? left + 1 : left;
647 }
648 
649 }  // namespace
650 
AddBreakpoint(Handle<WasmSharedModuleData> shared,int position,Handle<Object> break_point_object)651 void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
652                                          int position,
653                                          Handle<Object> break_point_object) {
654   Isolate* isolate = shared->GetIsolate();
655   Handle<FixedArray> breakpoint_infos;
656   if (shared->has_breakpoint_infos()) {
657     breakpoint_infos = handle(shared->breakpoint_infos(), isolate);
658   } else {
659     breakpoint_infos = isolate->factory()->NewFixedArray(4, TENURED);
660     shared->set(kBreakPointInfos, *breakpoint_infos);
661   }
662 
663   int insert_pos =
664       FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
665 
666   // If a BreakPointInfo object already exists for this position, add the new
667   // breakpoint object and return.
668   if (insert_pos < breakpoint_infos->length() &&
669       GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
670           position) {
671     Handle<BreakPointInfo> old_info(
672         BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
673     BreakPointInfo::SetBreakPoint(old_info, break_point_object);
674     return;
675   }
676 
677   // Enlarge break positions array if necessary.
678   bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
679                            ->IsUndefined(isolate);
680   Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
681   if (need_realloc) {
682     new_breakpoint_infos = isolate->factory()->NewFixedArray(
683         2 * breakpoint_infos->length(), TENURED);
684     shared->set(kBreakPointInfos, *new_breakpoint_infos);
685     // Copy over the entries [0, insert_pos).
686     for (int i = 0; i < insert_pos; ++i)
687       new_breakpoint_infos->set(i, breakpoint_infos->get(i));
688   }
689 
690   // Move elements [insert_pos+1, ...] up by one.
691   for (int i = insert_pos + 1; i < breakpoint_infos->length(); ++i) {
692     Object* entry = breakpoint_infos->get(i);
693     if (entry->IsUndefined(isolate)) break;
694     new_breakpoint_infos->set(i + 1, entry);
695   }
696 
697   // Generate new BreakpointInfo.
698   Handle<BreakPointInfo> breakpoint_info =
699       isolate->factory()->NewBreakPointInfo(position);
700   BreakPointInfo::SetBreakPoint(breakpoint_info, break_point_object);
701 
702   // Now insert new position at insert_pos.
703   new_breakpoint_infos->set(insert_pos, *breakpoint_info);
704 }
705 
SetBreakpointsOnNewInstance(Handle<WasmSharedModuleData> shared,Handle<WasmInstanceObject> instance)706 void WasmSharedModuleData::SetBreakpointsOnNewInstance(
707     Handle<WasmSharedModuleData> shared, Handle<WasmInstanceObject> instance) {
708   if (!shared->has_breakpoint_infos()) return;
709   Isolate* isolate = shared->GetIsolate();
710   Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
711                                              isolate);
712   Handle<WasmDebugInfo> debug_info =
713       WasmInstanceObject::GetOrCreateDebugInfo(instance);
714 
715   Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate);
716   // If the array exists, it should not be empty.
717   DCHECK_LT(0, breakpoint_infos->length());
718 
719   for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
720     Handle<Object> obj(breakpoint_infos->get(i), isolate);
721     if (obj->IsUndefined(isolate)) {
722       for (; i < e; ++i) {
723         DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate));
724       }
725       break;
726     }
727     Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
728     int position = breakpoint_info->source_position();
729 
730     // Find the function for this breakpoint, and set the breakpoint.
731     int func_index = compiled_module->GetContainingFunction(position);
732     DCHECK_LE(0, func_index);
733     WasmFunction& func = compiled_module->module()->functions[func_index];
734     int offset_in_func = position - func.code_start_offset;
735     WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
736   }
737 }
738 
New(Isolate * isolate,Handle<WasmSharedModuleData> shared)739 Handle<WasmCompiledModule> WasmCompiledModule::New(
740     Isolate* isolate, Handle<WasmSharedModuleData> shared) {
741   Handle<FixedArray> ret =
742       isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
743   // WasmCompiledModule::cast would fail since fields are not set yet.
744   Handle<WasmCompiledModule> compiled_module(
745       reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
746   compiled_module->InitId();
747   compiled_module->set_num_imported_functions(0);
748   compiled_module->set_shared(shared);
749   compiled_module->set_native_context(isolate->native_context());
750   return compiled_module;
751 }
752 
InitId()753 void WasmCompiledModule::InitId() {
754 #if DEBUG
755   static uint32_t instance_id_counter = 0;
756   set(kID_instance_id, Smi::FromInt(instance_id_counter++));
757   TRACE("New compiled module id: %d\n", instance_id());
758 #endif
759 }
760 
ExtractUtf8StringFromModuleBytes(Isolate * isolate,Handle<WasmCompiledModule> compiled_module,uint32_t offset,uint32_t size)761 MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
762     Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
763     uint32_t offset, uint32_t size) {
764   // TODO(wasm): cache strings from modules if it's a performance win.
765   Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(),
766                                         isolate);
767   DCHECK_GE(module_bytes->length(), offset);
768   DCHECK_GE(module_bytes->length() - offset, size);
769   Address raw = module_bytes->GetCharsAddress() + offset;
770   if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
771     return {};  // UTF8 decoding error for name.
772   DCHECK_GE(kMaxInt, offset);
773   DCHECK_GE(kMaxInt, size);
774   return isolate->factory()->NewStringFromUtf8SubString(
775       module_bytes, static_cast<int>(offset), static_cast<int>(size));
776 }
777 
IsWasmCompiledModule(Object * obj)778 bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) {
779   if (!obj->IsFixedArray()) return false;
780   FixedArray* arr = FixedArray::cast(obj);
781   if (arr->length() != PropertyIndices::Count) return false;
782   Isolate* isolate = arr->GetIsolate();
783 #define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \
784   do {                                   \
785     Object* obj = arr->get(kID_##NAME);  \
786     if (!(TYPE_CHECK)) return false;     \
787   } while (false);
788 #define WCM_CHECK_OBJECT(TYPE, NAME) \
789   WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE())
790 #define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \
791   WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj))
792 #define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME)
793 #define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) WCM_CHECK_TYPE(NAME, obj->IsSmi())
794 #define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME)
795   WCM_PROPERTY_TABLE(WCM_CHECK)
796 #undef WCM_CHECK
797 
798   // All checks passed.
799   return true;
800 }
801 
PrintInstancesChain()802 void WasmCompiledModule::PrintInstancesChain() {
803 #if DEBUG
804   if (!FLAG_trace_wasm_instances) return;
805   for (WasmCompiledModule* current = this; current != nullptr;) {
806     PrintF("->%d", current->instance_id());
807     if (!current->has_weak_next_instance()) break;
808     CHECK(!current->ptr_to_weak_next_instance()->cleared());
809     current =
810         WasmCompiledModule::cast(current->ptr_to_weak_next_instance()->value());
811   }
812   PrintF("\n");
813 #endif
814 }
815 
ReinitializeAfterDeserialization(Isolate * isolate,Handle<WasmCompiledModule> compiled_module)816 void WasmCompiledModule::ReinitializeAfterDeserialization(
817     Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
818   // This method must only be called immediately after deserialization.
819   // At this point, no module wrapper exists, so the shared module data is
820   // incomplete.
821   Handle<WasmSharedModuleData> shared(
822       static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)),
823       isolate);
824   DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
825   WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
826   DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
827 }
828 
mem_size() const829 uint32_t WasmCompiledModule::mem_size() const {
830   return has_memory() ? memory()->byte_length()->Number() : default_mem_size();
831 }
832 
default_mem_size() const833 uint32_t WasmCompiledModule::default_mem_size() const {
834   return min_mem_pages() * WasmModule::kPageSize;
835 }
836 
GetFunctionNameOrNull(Isolate * isolate,Handle<WasmCompiledModule> compiled_module,uint32_t func_index)837 MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull(
838     Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
839     uint32_t func_index) {
840   DCHECK_LT(func_index, compiled_module->module()->functions.size());
841   WasmFunction& function = compiled_module->module()->functions[func_index];
842   return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
843       isolate, compiled_module, function.name_offset, function.name_length);
844 }
845 
GetFunctionName(Isolate * isolate,Handle<WasmCompiledModule> compiled_module,uint32_t func_index)846 Handle<String> WasmCompiledModule::GetFunctionName(
847     Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
848     uint32_t func_index) {
849   MaybeHandle<String> name =
850       GetFunctionNameOrNull(isolate, compiled_module, func_index);
851   if (!name.is_null()) return name.ToHandleChecked();
852   return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
853 }
854 
GetRawFunctionName(uint32_t func_index)855 Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName(
856     uint32_t func_index) {
857   DCHECK_GT(module()->functions.size(), func_index);
858   WasmFunction& function = module()->functions[func_index];
859   SeqOneByteString* bytes = module_bytes();
860   DCHECK_GE(bytes->length(), function.name_offset);
861   DCHECK_GE(bytes->length() - function.name_offset, function.name_length);
862   return Vector<const uint8_t>(bytes->GetCharsAddress() + function.name_offset,
863                                function.name_length);
864 }
865 
GetFunctionOffset(uint32_t func_index)866 int WasmCompiledModule::GetFunctionOffset(uint32_t func_index) {
867   std::vector<WasmFunction>& functions = module()->functions;
868   if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
869   DCHECK_GE(kMaxInt, functions[func_index].code_start_offset);
870   return static_cast<int>(functions[func_index].code_start_offset);
871 }
872 
GetContainingFunction(uint32_t byte_offset)873 int WasmCompiledModule::GetContainingFunction(uint32_t byte_offset) {
874   std::vector<WasmFunction>& functions = module()->functions;
875 
876   // Binary search for a function containing the given position.
877   int left = 0;                                    // inclusive
878   int right = static_cast<int>(functions.size());  // exclusive
879   if (right == 0) return false;
880   while (right - left > 1) {
881     int mid = left + (right - left) / 2;
882     if (functions[mid].code_start_offset <= byte_offset) {
883       left = mid;
884     } else {
885       right = mid;
886     }
887   }
888   // If the found function does not contains the given position, return -1.
889   WasmFunction& func = functions[left];
890   if (byte_offset < func.code_start_offset ||
891       byte_offset >= func.code_end_offset) {
892     return -1;
893   }
894 
895   return left;
896 }
897 
GetPositionInfo(uint32_t position,Script::PositionInfo * info)898 bool WasmCompiledModule::GetPositionInfo(uint32_t position,
899                                          Script::PositionInfo* info) {
900   int func_index = GetContainingFunction(position);
901   if (func_index < 0) return false;
902 
903   WasmFunction& function = module()->functions[func_index];
904 
905   info->line = func_index;
906   info->column = position - function.code_start_offset;
907   info->line_start = function.code_start_offset;
908   info->line_end = function.code_end_offset;
909   return true;
910 }
911 
912 namespace {
913 
914 enum AsmJsOffsetTableEntryLayout {
915   kOTEByteOffset,
916   kOTECallPosition,
917   kOTENumberConvPosition,
918   kOTESize
919 };
920 
GetDecodedAsmJsOffsetTable(Handle<WasmCompiledModule> compiled_module,Isolate * isolate)921 Handle<ByteArray> GetDecodedAsmJsOffsetTable(
922     Handle<WasmCompiledModule> compiled_module, Isolate* isolate) {
923   DCHECK(compiled_module->is_asm_js());
924   Handle<ByteArray> offset_table(
925       compiled_module->shared()->asm_js_offset_table(), isolate);
926 
927   // The last byte in the asm_js_offset_tables ByteArray tells whether it is
928   // still encoded (0) or decoded (1).
929   enum AsmJsTableType : int { Encoded = 0, Decoded = 1 };
930   int table_type = offset_table->get(offset_table->length() - 1);
931   DCHECK(table_type == Encoded || table_type == Decoded);
932   if (table_type == Decoded) return offset_table;
933 
934   AsmJsOffsetsResult asm_offsets;
935   {
936     DisallowHeapAllocation no_gc;
937     const byte* bytes_start = offset_table->GetDataStartAddress();
938     const byte* bytes_end = bytes_start + offset_table->length() - 1;
939     asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end);
940   }
941   // Wasm bytes must be valid and must contain asm.js offset table.
942   DCHECK(asm_offsets.ok());
943   DCHECK_GE(kMaxInt, asm_offsets.val.size());
944   int num_functions = static_cast<int>(asm_offsets.val.size());
945   int num_imported_functions =
946       static_cast<int>(compiled_module->module()->num_imported_functions);
947   DCHECK_EQ(compiled_module->module()->functions.size(),
948             static_cast<size_t>(num_functions) + num_imported_functions);
949   int num_entries = 0;
950   for (int func = 0; func < num_functions; ++func) {
951     size_t new_size = asm_offsets.val[func].size();
952     DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
953     num_entries += static_cast<int>(new_size);
954   }
955   // One byte to encode that this is a decoded table.
956   DCHECK_GE(kMaxInt,
957             1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
958   int total_size = 1 + num_entries * kOTESize * kIntSize;
959   Handle<ByteArray> decoded_table =
960       isolate->factory()->NewByteArray(total_size, TENURED);
961   decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
962   compiled_module->shared()->set_asm_js_offset_table(*decoded_table);
963 
964   int idx = 0;
965   std::vector<WasmFunction>& wasm_funs = compiled_module->module()->functions;
966   for (int func = 0; func < num_functions; ++func) {
967     std::vector<AsmJsOffsetEntry>& func_asm_offsets = asm_offsets.val[func];
968     if (func_asm_offsets.empty()) continue;
969     int func_offset =
970         wasm_funs[num_imported_functions + func].code_start_offset;
971     for (AsmJsOffsetEntry& e : func_asm_offsets) {
972       // Byte offsets must be strictly monotonously increasing:
973       DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
974                                   decoded_table->get_int(idx - kOTESize));
975       decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
976       decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
977       decoded_table->set_int(idx + kOTENumberConvPosition,
978                              e.source_position_number_conversion);
979       idx += kOTESize;
980     }
981   }
982   DCHECK_EQ(total_size, idx * kIntSize + 1);
983   return decoded_table;
984 }
985 
986 }  // namespace
987 
GetAsmJsSourcePosition(Handle<WasmCompiledModule> compiled_module,uint32_t func_index,uint32_t byte_offset,bool is_at_number_conversion)988 int WasmCompiledModule::GetAsmJsSourcePosition(
989     Handle<WasmCompiledModule> compiled_module, uint32_t func_index,
990     uint32_t byte_offset, bool is_at_number_conversion) {
991   Isolate* isolate = compiled_module->GetIsolate();
992   Handle<ByteArray> offset_table =
993       GetDecodedAsmJsOffsetTable(compiled_module, isolate);
994 
995   DCHECK_LT(func_index, compiled_module->module()->functions.size());
996   uint32_t func_code_offset =
997       compiled_module->module()->functions[func_index].code_start_offset;
998   uint32_t total_offset = func_code_offset + byte_offset;
999 
1000   // Binary search for the total byte offset.
1001   int left = 0;                                              // inclusive
1002   int right = offset_table->length() / kIntSize / kOTESize;  // exclusive
1003   DCHECK_LT(left, right);
1004   while (right - left > 1) {
1005     int mid = left + (right - left) / 2;
1006     int mid_entry = offset_table->get_int(kOTESize * mid);
1007     DCHECK_GE(kMaxInt, mid_entry);
1008     if (static_cast<uint32_t>(mid_entry) <= total_offset) {
1009       left = mid;
1010     } else {
1011       right = mid;
1012     }
1013   }
1014   // There should be an entry for each position that could show up on the stack
1015   // trace:
1016   DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
1017   int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
1018   return offset_table->get_int(kOTESize * left + idx);
1019 }
1020 
DisassembleFunction(int func_index)1021 v8::debug::WasmDisassembly WasmCompiledModule::DisassembleFunction(
1022     int func_index) {
1023   DisallowHeapAllocation no_gc;
1024 
1025   if (func_index < 0 ||
1026       static_cast<uint32_t>(func_index) >= module()->functions.size())
1027     return {};
1028 
1029   SeqOneByteString* module_bytes_str = module_bytes();
1030   Vector<const byte> module_bytes(module_bytes_str->GetChars(),
1031                                   module_bytes_str->length());
1032 
1033   std::ostringstream disassembly_os;
1034   v8::debug::WasmDisassembly::OffsetTable offset_table;
1035 
1036   PrintWasmText(module(), module_bytes, static_cast<uint32_t>(func_index),
1037                 disassembly_os, &offset_table);
1038 
1039   return {disassembly_os.str(), std::move(offset_table)};
1040 }
1041 
GetPossibleBreakpoints(const v8::debug::Location & start,const v8::debug::Location & end,std::vector<v8::debug::Location> * locations)1042 bool WasmCompiledModule::GetPossibleBreakpoints(
1043     const v8::debug::Location& start, const v8::debug::Location& end,
1044     std::vector<v8::debug::Location>* locations) {
1045   DisallowHeapAllocation no_gc;
1046 
1047   std::vector<WasmFunction>& functions = module()->functions;
1048   if (start.GetLineNumber() < 0 || start.GetColumnNumber() < 0 ||
1049       (!end.IsEmpty() &&
1050        (end.GetLineNumber() < 0 || end.GetColumnNumber() < 0)))
1051     return false;
1052 
1053   // start_func_index, start_offset and end_func_index is inclusive.
1054   // end_offset is exclusive.
1055   // start_offset and end_offset are module-relative byte offsets.
1056   uint32_t start_func_index = start.GetLineNumber();
1057   if (start_func_index >= functions.size()) return false;
1058   int start_func_len = functions[start_func_index].code_end_offset -
1059                        functions[start_func_index].code_start_offset;
1060   if (start.GetColumnNumber() > start_func_len) return false;
1061   uint32_t start_offset =
1062       functions[start_func_index].code_start_offset + start.GetColumnNumber();
1063   uint32_t end_func_index;
1064   uint32_t end_offset;
1065   if (end.IsEmpty()) {
1066     // Default: everything till the end of the Script.
1067     end_func_index = static_cast<uint32_t>(functions.size() - 1);
1068     end_offset = functions[end_func_index].code_end_offset;
1069   } else {
1070     // If end is specified: Use it and check for valid input.
1071     end_func_index = static_cast<uint32_t>(end.GetLineNumber());
1072 
1073     // Special case: Stop before the start of the next function. Change to: Stop
1074     // at the end of the function before, such that we don't disassemble the
1075     // next function also.
1076     if (end.GetColumnNumber() == 0 && end_func_index > 0) {
1077       --end_func_index;
1078       end_offset = functions[end_func_index].code_end_offset;
1079     } else {
1080       if (end_func_index >= functions.size()) return false;
1081       end_offset =
1082           functions[end_func_index].code_start_offset + end.GetColumnNumber();
1083       if (end_offset > functions[end_func_index].code_end_offset) return false;
1084     }
1085   }
1086 
1087   AccountingAllocator alloc;
1088   Zone tmp(&alloc, ZONE_NAME);
1089   const byte* module_start = module_bytes()->GetChars();
1090 
1091   for (uint32_t func_idx = start_func_index; func_idx <= end_func_index;
1092        ++func_idx) {
1093     WasmFunction& func = functions[func_idx];
1094     if (func.code_start_offset == func.code_end_offset) continue;
1095 
1096     BodyLocalDecls locals(&tmp);
1097     BytecodeIterator iterator(module_start + func.code_start_offset,
1098                               module_start + func.code_end_offset, &locals);
1099     DCHECK_LT(0u, locals.encoded_size);
1100     for (uint32_t offset : iterator.offsets()) {
1101       uint32_t total_offset = func.code_start_offset + offset;
1102       if (total_offset >= end_offset) {
1103         DCHECK_EQ(end_func_index, func_idx);
1104         break;
1105       }
1106       if (total_offset < start_offset) continue;
1107       locations->push_back(v8::debug::Location(func_idx, offset));
1108     }
1109   }
1110   return true;
1111 }
1112 
SetBreakPoint(Handle<WasmCompiledModule> compiled_module,int * position,Handle<Object> break_point_object)1113 bool WasmCompiledModule::SetBreakPoint(
1114     Handle<WasmCompiledModule> compiled_module, int* position,
1115     Handle<Object> break_point_object) {
1116   Isolate* isolate = compiled_module->GetIsolate();
1117 
1118   // Find the function for this breakpoint.
1119   int func_index = compiled_module->GetContainingFunction(*position);
1120   if (func_index < 0) return false;
1121   WasmFunction& func = compiled_module->module()->functions[func_index];
1122   int offset_in_func = *position - func.code_start_offset;
1123 
1124   // According to the current design, we should only be called with valid
1125   // breakable positions.
1126   DCHECK(IsBreakablePosition(compiled_module, func_index, offset_in_func));
1127 
1128   // Insert new break point into break_positions of shared module data.
1129   WasmSharedModuleData::AddBreakpoint(compiled_module->shared(), *position,
1130                                       break_point_object);
1131 
1132   // Iterate over all instances of this module and tell them to set this new
1133   // breakpoint.
1134   for (Handle<WasmInstanceObject> instance :
1135        iterate_compiled_module_instance_chain(isolate, compiled_module)) {
1136     Handle<WasmDebugInfo> debug_info =
1137         WasmInstanceObject::GetOrCreateDebugInfo(instance);
1138     WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
1139   }
1140 
1141   return true;
1142 }
1143 
CheckBreakPoints(int position)1144 MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) {
1145   Isolate* isolate = GetIsolate();
1146   if (!shared()->has_breakpoint_infos()) return {};
1147 
1148   Handle<FixedArray> breakpoint_infos(shared()->breakpoint_infos(), isolate);
1149   int insert_pos =
1150       FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
1151   if (insert_pos >= breakpoint_infos->length()) return {};
1152 
1153   Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
1154                                        isolate);
1155   if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
1156   Handle<BreakPointInfo> breakpoint_info =
1157       Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
1158   if (breakpoint_info->source_position() != position) return {};
1159 
1160   Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(),
1161                                     isolate);
1162   return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
1163 }
1164 
New(Isolate * isolate,Handle<WasmInstanceObject> instance)1165 Handle<WasmInstanceWrapper> WasmInstanceWrapper::New(
1166     Isolate* isolate, Handle<WasmInstanceObject> instance) {
1167   Handle<FixedArray> array =
1168       isolate->factory()->NewFixedArray(kWrapperPropertyCount, TENURED);
1169   Handle<WasmInstanceWrapper> instance_wrapper(
1170       reinterpret_cast<WasmInstanceWrapper*>(*array), isolate);
1171   Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance);
1172   instance_wrapper->set(kWrapperInstanceObject, *cell);
1173   return instance_wrapper;
1174 }
1175 
IsWasmInstanceWrapper(Object * obj)1176 bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) {
1177   if (!obj->IsFixedArray()) return false;
1178   Handle<FixedArray> array = handle(FixedArray::cast(obj));
1179   if (array->length() != kWrapperPropertyCount) return false;
1180   if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false;
1181   Isolate* isolate = array->GetIsolate();
1182   if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) &&
1183       !array->get(kNextInstanceWrapper)->IsFixedArray())
1184     return false;
1185   if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) &&
1186       !array->get(kPreviousInstanceWrapper)->IsFixedArray())
1187     return false;
1188   return true;
1189 }
1190