• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 #ifndef V8_WASM_OBJECTS_H_
6 #define V8_WASM_OBJECTS_H_
7 
8 #include "src/debug/debug.h"
9 #include "src/debug/interface-types.h"
10 #include "src/objects.h"
11 #include "src/trap-handler/trap-handler.h"
12 #include "src/wasm/wasm-limits.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace wasm {
17 class InterpretedFrame;
18 struct WasmModule;
19 }
20 
21 class WasmCompiledModule;
22 class WasmDebugInfo;
23 class WasmInstanceObject;
24 class WasmInstanceWrapper;
25 
26 #define DECLARE_CASTS(name)             \
27   static bool Is##name(Object* object); \
28   static name* cast(Object* object)
29 
30 #define DECLARE_GETTER(name, type) type* name()
31 
32 #define DECLARE_ACCESSORS(name, type) \
33   void set_##name(type* value);       \
34   DECLARE_GETTER(name, type)
35 
36 #define DECLARE_OPTIONAL_ACCESSORS(name, type) \
37   bool has_##name();                           \
38   DECLARE_ACCESSORS(name, type)
39 
40 #define DECLARE_OPTIONAL_GETTER(name, type) \
41   bool has_##name();                        \
42   DECLARE_GETTER(name, type)
43 
44 // Representation of a WebAssembly.Module JavaScript-level object.
45 class WasmModuleObject : public JSObject {
46  public:
47   // TODO(titzer): add the brand as an internal field instead of a property.
48   enum Fields { kCompiledModule, kFieldCount };
49 
50   DECLARE_CASTS(WasmModuleObject);
51 
52   WasmCompiledModule* compiled_module();
53 
54   static Handle<WasmModuleObject> New(
55       Isolate* isolate, Handle<WasmCompiledModule> compiled_module);
56 };
57 
58 // Representation of a WebAssembly.Table JavaScript-level object.
59 class WasmTableObject : public JSObject {
60  public:
61   // TODO(titzer): add the brand as an internal field instead of a property.
62   enum Fields { kFunctions, kMaximum, kDispatchTables, kFieldCount };
63 
64   DECLARE_CASTS(WasmTableObject);
65   DECLARE_ACCESSORS(functions, FixedArray);
66 
67   FixedArray* dispatch_tables();
68   uint32_t current_length();
69   bool has_maximum_length();
70   int64_t maximum_length();  // Returns < 0 if no maximum.
71 
72   static Handle<WasmTableObject> New(Isolate* isolate, uint32_t initial,
73                                      int64_t maximum,
74                                      Handle<FixedArray>* js_functions);
75   static void Grow(Isolate* isolate, Handle<WasmTableObject> table,
76                    uint32_t count);
77   static Handle<FixedArray> AddDispatchTable(
78       Isolate* isolate, Handle<WasmTableObject> table,
79       Handle<WasmInstanceObject> instance, int table_index,
80       Handle<FixedArray> function_table, Handle<FixedArray> signature_table);
81 };
82 
83 // Representation of a WebAssembly.Memory JavaScript-level object.
84 class WasmMemoryObject : public JSObject {
85  public:
86   // TODO(titzer): add the brand as an internal field instead of a property.
87   enum Fields : uint8_t { kArrayBuffer, kMaximum, kInstancesLink, kFieldCount };
88 
89   DECLARE_CASTS(WasmMemoryObject);
90   DECLARE_ACCESSORS(buffer, JSArrayBuffer);
91   DECLARE_OPTIONAL_ACCESSORS(instances_link, WasmInstanceWrapper);
92 
93   void AddInstance(Isolate* isolate, Handle<WasmInstanceObject> object);
94   void ResetInstancesLink(Isolate* isolate);
95   uint32_t current_pages();
96   bool has_maximum_pages();
97   int32_t maximum_pages();  // Returns < 0 if there is no maximum.
98 
99   static Handle<WasmMemoryObject> New(Isolate* isolate,
100                                       Handle<JSArrayBuffer> buffer,
101                                       int32_t maximum);
102 
103   static bool Grow(Isolate* isolate, Handle<WasmMemoryObject> memory,
104                    uint32_t count);
105 };
106 
107 // Representation of a WebAssembly.Instance JavaScript-level object.
108 class WasmInstanceObject : public JSObject {
109  public:
110   // TODO(titzer): add the brand as an internal field instead of a property.
111   enum Fields {
112     kCompiledModule,
113     kMemoryObject,
114     kMemoryArrayBuffer,
115     kGlobalsArrayBuffer,
116     kDebugInfo,
117     kWasmMemInstanceWrapper,
118     kFieldCount
119   };
120 
121   DECLARE_CASTS(WasmInstanceObject);
122 
123   DECLARE_ACCESSORS(compiled_module, WasmCompiledModule);
124   DECLARE_OPTIONAL_ACCESSORS(globals_buffer, JSArrayBuffer);
125   DECLARE_OPTIONAL_ACCESSORS(memory_buffer, JSArrayBuffer);
126   DECLARE_OPTIONAL_ACCESSORS(memory_object, WasmMemoryObject);
127   DECLARE_OPTIONAL_ACCESSORS(debug_info, WasmDebugInfo);
128   DECLARE_OPTIONAL_ACCESSORS(instance_wrapper, WasmInstanceWrapper);
129 
130   WasmModuleObject* module_object();
131   wasm::WasmModule* module();
132 
133   // Get the debug info associated with the given wasm object.
134   // If no debug info exists yet, it is created automatically.
135   static Handle<WasmDebugInfo> GetOrCreateDebugInfo(
136       Handle<WasmInstanceObject> instance);
137 
138   static Handle<WasmInstanceObject> New(
139       Isolate* isolate, Handle<WasmCompiledModule> compiled_module);
140 };
141 
142 // Representation of an exported WASM function.
143 class WasmExportedFunction : public JSFunction {
144  public:
145   enum Fields { kInstance, kIndex, kFieldCount };
146 
147   DECLARE_CASTS(WasmExportedFunction);
148 
149   WasmInstanceObject* instance();
150   int function_index();
151 
152   static Handle<WasmExportedFunction> New(Isolate* isolate,
153                                           Handle<WasmInstanceObject> instance,
154                                           MaybeHandle<String> maybe_name,
155                                           int func_index, int arity,
156                                           Handle<Code> export_wrapper);
157 };
158 
159 // Information shared by all WasmCompiledModule objects for the same module.
160 class WasmSharedModuleData : public FixedArray {
161   enum Fields {
162     kModuleWrapper,
163     kModuleBytes,
164     kScript,
165     kAsmJsOffsetTable,
166     kBreakPointInfos,
167     kFieldCount
168   };
169 
170  public:
171   DECLARE_CASTS(WasmSharedModuleData);
172 
173   DECLARE_GETTER(module, wasm::WasmModule);
174   DECLARE_OPTIONAL_ACCESSORS(module_bytes, SeqOneByteString);
175   DECLARE_GETTER(script, Script);
176   DECLARE_OPTIONAL_ACCESSORS(asm_js_offset_table, ByteArray);
177   DECLARE_OPTIONAL_GETTER(breakpoint_infos, FixedArray);
178 
179   static Handle<WasmSharedModuleData> New(
180       Isolate* isolate, Handle<Foreign> module_wrapper,
181       Handle<SeqOneByteString> module_bytes, Handle<Script> script,
182       Handle<ByteArray> asm_js_offset_table);
183 
184   // Check whether this module was generated from asm.js source.
185   bool is_asm_js();
186 
187   static void ReinitializeAfterDeserialization(Isolate*,
188                                                Handle<WasmSharedModuleData>);
189 
190   static void AddBreakpoint(Handle<WasmSharedModuleData>, int position,
191                             Handle<Object> break_point_object);
192 
193   static void SetBreakpointsOnNewInstance(Handle<WasmSharedModuleData>,
194                                           Handle<WasmInstanceObject>);
195 };
196 
197 class WasmCompiledModule : public FixedArray {
198  public:
199   enum Fields { kFieldCount };
200 
cast(Object * fixed_array)201   static WasmCompiledModule* cast(Object* fixed_array) {
202     SLOW_DCHECK(IsWasmCompiledModule(fixed_array));
203     return reinterpret_cast<WasmCompiledModule*>(fixed_array);
204   }
205 
206 #define WCM_OBJECT_OR_WEAK(TYPE, NAME, ID, TYPE_CHECK)               \
207   Handle<TYPE> NAME() const { return handle(ptr_to_##NAME()); }      \
208                                                                      \
209   MaybeHandle<TYPE> maybe_##NAME() const {                           \
210     if (has_##NAME()) return NAME();                                 \
211     return MaybeHandle<TYPE>();                                      \
212   }                                                                  \
213                                                                      \
214   TYPE* maybe_ptr_to_##NAME() const {                                \
215     Object* obj = get(ID);                                           \
216     if (!(TYPE_CHECK)) return nullptr;                               \
217     return TYPE::cast(obj);                                          \
218   }                                                                  \
219                                                                      \
220   TYPE* ptr_to_##NAME() const {                                      \
221     Object* obj = get(ID);                                           \
222     DCHECK(TYPE_CHECK);                                              \
223     return TYPE::cast(obj);                                          \
224   }                                                                  \
225                                                                      \
226   void set_##NAME(Handle<TYPE> value) { set_ptr_to_##NAME(*value); } \
227                                                                      \
228   void set_ptr_to_##NAME(TYPE* value) { set(ID, value); }            \
229                                                                      \
230   bool has_##NAME() const {                                          \
231     Object* obj = get(ID);                                           \
232     return TYPE_CHECK;                                               \
233   }                                                                  \
234                                                                      \
235   void reset_##NAME() { set_undefined(ID); }
236 
237 #define WCM_OBJECT(TYPE, NAME) \
238   WCM_OBJECT_OR_WEAK(TYPE, NAME, kID_##NAME, obj->Is##TYPE())
239 
240 #define WCM_WASM_OBJECT(TYPE, NAME) \
241   WCM_OBJECT_OR_WEAK(TYPE, NAME, kID_##NAME, TYPE::Is##TYPE(obj))
242 
243 #define WCM_SMALL_NUMBER(TYPE, NAME)                               \
244   TYPE NAME() const {                                              \
245     return static_cast<TYPE>(Smi::cast(get(kID_##NAME))->value()); \
246   }                                                                \
247   void set_##NAME(TYPE value) { set(kID_##NAME, Smi::FromInt(value)); }
248 
249 #define WCM_WEAK_LINK(TYPE, NAME)                                           \
250   WCM_OBJECT_OR_WEAK(WeakCell, weak_##NAME, kID_##NAME, obj->IsWeakCell()); \
251                                                                             \
252   Handle<TYPE> NAME() const {                                               \
253     return handle(TYPE::cast(weak_##NAME()->value()));                      \
254   }
255 
256 #define CORE_WCM_PROPERTY_TABLE(MACRO)                  \
257   MACRO(WASM_OBJECT, WasmSharedModuleData, shared)      \
258   MACRO(OBJECT, Context, native_context)                \
259   MACRO(SMALL_NUMBER, uint32_t, num_imported_functions) \
260   MACRO(OBJECT, FixedArray, code_table)                 \
261   MACRO(OBJECT, FixedArray, weak_exported_functions)    \
262   MACRO(OBJECT, FixedArray, function_tables)            \
263   MACRO(OBJECT, FixedArray, signature_tables)           \
264   MACRO(OBJECT, FixedArray, empty_function_tables)      \
265   MACRO(OBJECT, JSArrayBuffer, memory)                  \
266   MACRO(SMALL_NUMBER, uint32_t, min_mem_pages)          \
267   MACRO(SMALL_NUMBER, uint32_t, max_mem_pages)          \
268   MACRO(WEAK_LINK, WasmCompiledModule, next_instance)   \
269   MACRO(WEAK_LINK, WasmCompiledModule, prev_instance)   \
270   MACRO(WEAK_LINK, JSObject, owning_instance)           \
271   MACRO(WEAK_LINK, WasmModuleObject, wasm_module)
272 
273 #if DEBUG
274 #define DEBUG_ONLY_TABLE(MACRO) MACRO(SMALL_NUMBER, uint32_t, instance_id)
275 #else
276 #define DEBUG_ONLY_TABLE(IGNORE)
instance_id()277   uint32_t instance_id() const { return -1; }
278 #endif
279 
280 #define WCM_PROPERTY_TABLE(MACRO) \
281   CORE_WCM_PROPERTY_TABLE(MACRO)  \
282   DEBUG_ONLY_TABLE(MACRO)
283 
284  private:
285   enum PropertyIndices {
286 #define INDICES(IGNORE1, IGNORE2, NAME) kID_##NAME,
287     WCM_PROPERTY_TABLE(INDICES) Count
288 #undef INDICES
289   };
290 
291  public:
292   static Handle<WasmCompiledModule> New(Isolate* isolate,
293                                         Handle<WasmSharedModuleData> shared);
294 
Clone(Isolate * isolate,Handle<WasmCompiledModule> module)295   static Handle<WasmCompiledModule> Clone(Isolate* isolate,
296                                           Handle<WasmCompiledModule> module) {
297     Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast(
298         isolate->factory()->CopyFixedArray(module));
299     ret->InitId();
300     ret->reset_weak_owning_instance();
301     ret->reset_weak_next_instance();
302     ret->reset_weak_prev_instance();
303     ret->reset_weak_exported_functions();
304     return ret;
305   }
306 
307   uint32_t mem_size() const;
308   uint32_t default_mem_size() const;
309 
310 #define DECLARATION(KIND, TYPE, NAME) WCM_##KIND(TYPE, NAME)
311   WCM_PROPERTY_TABLE(DECLARATION)
312 #undef DECLARATION
313 
314 // Allow to call method on WasmSharedModuleData also on this object.
315 #define FORWARD_SHARED(type, name) \
316   type name() { return shared()->name(); }
317   FORWARD_SHARED(SeqOneByteString*, module_bytes)
318   FORWARD_SHARED(wasm::WasmModule*, module)
319   FORWARD_SHARED(Script*, script)
320   FORWARD_SHARED(bool, is_asm_js)
321 #undef FORWARD_SHARED
322 
323   static bool IsWasmCompiledModule(Object* obj);
324 
325   void PrintInstancesChain();
326 
327   static void ReinitializeAfterDeserialization(Isolate*,
328                                                Handle<WasmCompiledModule>);
329 
330   // Get the function name of the function identified by the given index.
331   // Returns a null handle if the function is unnamed or the name is not a valid
332   // UTF-8 string.
333   static MaybeHandle<String> GetFunctionNameOrNull(
334       Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
335       uint32_t func_index);
336 
337   // Get the function name of the function identified by the given index.
338   // Returns "<WASM UNNAMED>" if the function is unnamed or the name is not a
339   // valid UTF-8 string.
340   static Handle<String> GetFunctionName(
341       Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
342       uint32_t func_index);
343 
344   // Get the raw bytes of the function name of the function identified by the
345   // given index.
346   // Meant to be used for debugging or frame printing.
347   // Does not allocate, hence gc-safe.
348   Vector<const uint8_t> GetRawFunctionName(uint32_t func_index);
349 
350   // Return the byte offset of the function identified by the given index.
351   // The offset will be relative to the start of the module bytes.
352   // Returns -1 if the function index is invalid.
353   int GetFunctionOffset(uint32_t func_index);
354 
355   // Returns the function containing the given byte offset.
356   // Returns -1 if the byte offset is not contained in any function of this
357   // module.
358   int GetContainingFunction(uint32_t byte_offset);
359 
360   // Translate from byte offset in the module to function number and byte offset
361   // within that function, encoded as line and column in the position info.
362   // Returns true if the position is valid inside this module, false otherwise.
363   bool GetPositionInfo(uint32_t position, Script::PositionInfo* info);
364 
365   // Get the asm.js source position from a byte offset.
366   // Must only be called if the associated wasm object was created from asm.js.
367   static int GetAsmJsSourcePosition(Handle<WasmCompiledModule> compiled_module,
368                                     uint32_t func_index, uint32_t byte_offset,
369                                     bool is_at_number_conversion);
370 
371   // Compute the disassembly of a wasm function.
372   // Returns the disassembly string and a list of <byte_offset, line, column>
373   // entries, mapping wasm byte offsets to line and column in the disassembly.
374   // The list is guaranteed to be ordered by the byte_offset.
375   // Returns an empty string and empty vector if the function index is invalid.
376   debug::WasmDisassembly DisassembleFunction(int func_index);
377 
378   // Extract a portion of the wire bytes as UTF-8 string.
379   // Returns a null handle if the respective bytes do not form a valid UTF-8
380   // string.
381   static MaybeHandle<String> ExtractUtf8StringFromModuleBytes(
382       Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
383       uint32_t offset, uint32_t size);
384 
385   // Get a list of all possible breakpoints within a given range of this module.
386   bool GetPossibleBreakpoints(const debug::Location& start,
387                               const debug::Location& end,
388                               std::vector<debug::Location>* locations);
389 
390   // Set a breakpoint on the given byte position inside the given module.
391   // This will affect all live and future instances of the module.
392   // The passed position might be modified to point to the next breakable
393   // location inside the same function.
394   // If it points outside a function, or behind the last breakable location,
395   // this function returns false and does not set any breakpoint.
396   static bool SetBreakPoint(Handle<WasmCompiledModule>, int* position,
397                             Handle<Object> break_point_object);
398 
399   // Return an empty handle if no breakpoint is hit at that location, or a
400   // FixedArray with all hit breakpoint objects.
401   MaybeHandle<FixedArray> CheckBreakPoints(int position);
402 
403  private:
404   void InitId();
405 
406   DISALLOW_IMPLICIT_CONSTRUCTORS(WasmCompiledModule);
407 };
408 
409 class WasmDebugInfo : public FixedArray {
410  public:
411   enum Fields {
412     kInstance,
413     kInterpreterHandle,
414     kInterpretedFunctions,
415     kFieldCount
416   };
417 
418   static Handle<WasmDebugInfo> New(Handle<WasmInstanceObject>);
419 
420   static bool IsDebugInfo(Object*);
421   static WasmDebugInfo* cast(Object*);
422 
423   // Set a breakpoint in the given function at the given byte offset within that
424   // function. This will redirect all future calls to this function to the
425   // interpreter and will always pause at the given offset.
426   static void SetBreakpoint(Handle<WasmDebugInfo>, int func_index, int offset);
427 
428   // Make a function always execute in the interpreter without setting a
429   // breakpoints.
430   static void RedirectToInterpreter(Handle<WasmDebugInfo>, int func_index);
431 
432   void PrepareStep(StepAction);
433 
434   void RunInterpreter(int func_index, uint8_t* arg_buffer);
435 
436   // Get the stack of the wasm interpreter as pairs of <function index, byte
437   // offset>. The list is ordered bottom-to-top, i.e. caller before callee.
438   std::vector<std::pair<uint32_t, int>> GetInterpretedStack(
439       Address frame_pointer);
440 
441   std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame(
442       Address frame_pointer, int idx);
443 
444   // Returns the number of calls / function frames executed in the interpreter.
445   uint64_t NumInterpretedCalls();
446 
447   DECLARE_GETTER(wasm_instance, WasmInstanceObject);
448 };
449 
450 class WasmInstanceWrapper : public FixedArray {
451  public:
452   static Handle<WasmInstanceWrapper> New(Isolate* isolate,
453                                          Handle<WasmInstanceObject> instance);
cast(Object * fixed_array)454   static WasmInstanceWrapper* cast(Object* fixed_array) {
455     SLOW_DCHECK(IsWasmInstanceWrapper(fixed_array));
456     return reinterpret_cast<WasmInstanceWrapper*>(fixed_array);
457   }
458   static bool IsWasmInstanceWrapper(Object* obj);
has_instance()459   bool has_instance() { return get(kWrapperInstanceObject)->IsWeakCell(); }
instance_object()460   Handle<WasmInstanceObject> instance_object() {
461     Object* obj = get(kWrapperInstanceObject);
462     DCHECK(obj->IsWeakCell());
463     WeakCell* cell = WeakCell::cast(obj);
464     DCHECK(cell->value()->IsJSObject());
465     return handle(WasmInstanceObject::cast(cell->value()));
466   }
has_next()467   bool has_next() { return IsWasmInstanceWrapper(get(kNextInstanceWrapper)); }
has_previous()468   bool has_previous() {
469     return IsWasmInstanceWrapper(get(kPreviousInstanceWrapper));
470   }
set_next_wrapper(Object * obj)471   void set_next_wrapper(Object* obj) {
472     DCHECK(IsWasmInstanceWrapper(obj));
473     set(kNextInstanceWrapper, obj);
474   }
set_previous_wrapper(Object * obj)475   void set_previous_wrapper(Object* obj) {
476     DCHECK(IsWasmInstanceWrapper(obj));
477     set(kPreviousInstanceWrapper, obj);
478   }
next_wrapper()479   Handle<WasmInstanceWrapper> next_wrapper() {
480     Object* obj = get(kNextInstanceWrapper);
481     DCHECK(IsWasmInstanceWrapper(obj));
482     return handle(WasmInstanceWrapper::cast(obj));
483   }
previous_wrapper()484   Handle<WasmInstanceWrapper> previous_wrapper() {
485     Object* obj = get(kPreviousInstanceWrapper);
486     DCHECK(IsWasmInstanceWrapper(obj));
487     return handle(WasmInstanceWrapper::cast(obj));
488   }
reset_next_wrapper()489   void reset_next_wrapper() { set_undefined(kNextInstanceWrapper); }
reset_previous_wrapper()490   void reset_previous_wrapper() { set_undefined(kPreviousInstanceWrapper); }
reset()491   void reset() {
492     for (int kID = 0; kID < kWrapperPropertyCount; kID++) set_undefined(kID);
493   }
494 
495  private:
496   enum {
497     kWrapperInstanceObject,
498     kNextInstanceWrapper,
499     kPreviousInstanceWrapper,
500     kWrapperPropertyCount
501   };
502 };
503 
504 #undef DECLARE_ACCESSORS
505 #undef DECLARE_OPTIONAL_ACCESSORS
506 
507 }  // namespace internal
508 }  // namespace v8
509 
510 #endif  // V8_WASM_OBJECTS_H_
511