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/objects-inl.h"
9 #include "src/wasm/managed.h"
10 
11 namespace v8 {
12 namespace internal {
13 namespace wasm {
14 struct WasmModule;
15 }
16 
17 class WasmCompiledModule;
18 class WasmDebugInfo;
19 class WasmInstanceObject;
20 
21 #define DECLARE_CASTS(name)             \
22   static bool Is##name(Object* object); \
23   static name* cast(Object* object)
24 
25 #define DECLARE_ACCESSORS(name, type) \
26   type* get_##name();                 \
27   void set_##name(type* value)
28 
29 #define DECLARE_OPTIONAL_ACCESSORS(name, type) \
30   bool has_##name();                           \
31   type* get_##name();                          \
32   void set_##name(type* value)
33 
34 // Representation of a WebAssembly.Module JavaScript-level object.
35 class WasmModuleObject : public JSObject {
36  public:
37   // TODO(titzer): add the brand as an internal field instead of a property.
38   enum Fields { kCompiledModule, kFieldCount };
39 
40   DECLARE_CASTS(WasmModuleObject);
41 
42   WasmCompiledModule* compiled_module();
43   wasm::WasmModule* module();
44   int num_functions();
45   bool is_asm_js();
46   int GetAsmWasmSourcePosition(int func_index, int byte_offset);
47   WasmDebugInfo* debug_info();
48   void set_debug_info(WasmDebugInfo* debug_info);
49   MaybeHandle<String> GetFunctionName(Isolate* isolate, int func_index);
50 
51   static Handle<WasmModuleObject> New(
52       Isolate* isolate, Handle<WasmCompiledModule> compiled_module);
53 };
54 
55 // Representation of a WebAssembly.Table JavaScript-level object.
56 class WasmTableObject : public JSObject {
57  public:
58   // TODO(titzer): add the brand as an internal field instead of a property.
59   enum Fields { kFunctions, kMaximum, kDispatchTables, kFieldCount };
60 
61   DECLARE_CASTS(WasmTableObject);
62   DECLARE_ACCESSORS(functions, FixedArray);
63 
64   FixedArray* get_dispatch_tables();
65   uint32_t current_length();
66   uint32_t maximum_length();
67 
68   static Handle<WasmTableObject> New(Isolate* isolate, uint32_t initial,
69                                      uint32_t maximum,
70                                      Handle<FixedArray>* js_functions);
71   static bool Grow(Handle<WasmTableObject> table, uint32_t count);
72   static Handle<FixedArray> AddDispatchTable(
73       Isolate* isolate, Handle<WasmTableObject> table,
74       Handle<WasmInstanceObject> instance, int table_index,
75       Handle<FixedArray> dispatch_table);
76 };
77 
78 // Representation of a WebAssembly.Memory JavaScript-level object.
79 class WasmMemoryObject : public JSObject {
80  public:
81   // TODO(titzer): add the brand as an internal field instead of a property.
82   enum Fields : uint8_t { kArrayBuffer, kMaximum, kInstance, kFieldCount };
83 
84   DECLARE_CASTS(WasmMemoryObject);
85   DECLARE_ACCESSORS(buffer, JSArrayBuffer);
86 
87   void AddInstance(WasmInstanceObject* object);
88   uint32_t current_pages();
89   int32_t maximum_pages();  // returns < 0 if there is no maximum
90 
91   static Handle<WasmMemoryObject> New(Isolate* isolate,
92                                       Handle<JSArrayBuffer> buffer,
93                                       int maximum);
94 
95   static bool Grow(Handle<WasmMemoryObject> memory, uint32_t count);
96 };
97 
98 // Representation of a WebAssembly.Instance JavaScript-level object.
99 class WasmInstanceObject : public JSObject {
100  public:
101   // TODO(titzer): add the brand as an internal field instead of a property.
102   enum Fields {
103     kCompiledModule,
104     kMemoryObject,
105     kMemoryArrayBuffer,
106     kGlobalsArrayBuffer,
107     kDebugInfo,
108     kFieldCount
109   };
110 
111   DECLARE_CASTS(WasmInstanceObject);
112 
113   DECLARE_ACCESSORS(compiled_module, WasmCompiledModule);
114   DECLARE_OPTIONAL_ACCESSORS(globals_buffer, JSArrayBuffer);
115   DECLARE_OPTIONAL_ACCESSORS(memory_buffer, JSArrayBuffer);
116   DECLARE_OPTIONAL_ACCESSORS(memory_object, WasmMemoryObject);
117   DECLARE_OPTIONAL_ACCESSORS(debug_info, WasmDebugInfo);
118 
119   WasmModuleObject* module_object();
120   wasm::WasmModule* module();
121 
122   static Handle<WasmInstanceObject> New(
123       Isolate* isolate, Handle<WasmCompiledModule> compiled_module);
124 };
125 
126 // Representation of an exported WASM function.
127 class WasmExportedFunction : public JSFunction {
128  public:
129   enum Fields { kInstance, kIndex, kFieldCount };
130 
131   DECLARE_CASTS(WasmExportedFunction);
132 
133   WasmInstanceObject* instance();
134   int function_index();
135 
136   static Handle<WasmExportedFunction> New(Isolate* isolate,
137                                           Handle<WasmInstanceObject> instance,
138                                           Handle<String> name,
139                                           Handle<Code> export_wrapper,
140                                           int arity, int func_index);
141 };
142 
143 class WasmCompiledModule : public FixedArray {
144  public:
145   enum Fields { kFieldCount };
146 
cast(Object * fixed_array)147   static WasmCompiledModule* cast(Object* fixed_array) {
148     SLOW_DCHECK(IsWasmCompiledModule(fixed_array));
149     return reinterpret_cast<WasmCompiledModule*>(fixed_array);
150   }
151 
152 #define WCM_OBJECT_OR_WEAK(TYPE, NAME, ID)                           \
153   Handle<TYPE> NAME() const { return handle(ptr_to_##NAME()); }      \
154                                                                      \
155   MaybeHandle<TYPE> maybe_##NAME() const {                           \
156     if (has_##NAME()) return NAME();                                 \
157     return MaybeHandle<TYPE>();                                      \
158   }                                                                  \
159                                                                      \
160   TYPE* ptr_to_##NAME() const {                                      \
161     Object* obj = get(ID);                                           \
162     if (!obj->Is##TYPE()) return nullptr;                            \
163     return TYPE::cast(obj);                                          \
164   }                                                                  \
165                                                                      \
166   void set_##NAME(Handle<TYPE> value) { set_ptr_to_##NAME(*value); } \
167                                                                      \
168   void set_ptr_to_##NAME(TYPE* value) { set(ID, value); }            \
169                                                                      \
170   bool has_##NAME() const { return get(ID)->Is##TYPE(); }            \
171                                                                      \
172   void reset_##NAME() { set_undefined(ID); }
173 
174 #define WCM_OBJECT(TYPE, NAME) WCM_OBJECT_OR_WEAK(TYPE, NAME, kID_##NAME)
175 
176 #define WCM_SMALL_NUMBER(TYPE, NAME)                               \
177   TYPE NAME() const {                                              \
178     return static_cast<TYPE>(Smi::cast(get(kID_##NAME))->value()); \
179   }                                                                \
180   void set_##NAME(TYPE value) { set(kID_##NAME, Smi::FromInt(value)); }
181 
182 #define WCM_WEAK_LINK(TYPE, NAME)                        \
183   WCM_OBJECT_OR_WEAK(WeakCell, weak_##NAME, kID_##NAME); \
184                                                          \
185   Handle<TYPE> NAME() const {                            \
186     return handle(TYPE::cast(weak_##NAME()->value()));   \
187   }
188 
189 #define CORE_WCM_PROPERTY_TABLE(MACRO)                \
190   MACRO(OBJECT, FixedArray, code_table)               \
191   MACRO(OBJECT, Foreign, module_wrapper)              \
192   /* For debugging: */                                \
193   MACRO(OBJECT, SeqOneByteString, module_bytes)       \
194   MACRO(OBJECT, Script, script)                       \
195   MACRO(OBJECT, ByteArray, asm_js_offset_tables)      \
196   /* End of debugging stuff */                        \
197   MACRO(OBJECT, FixedArray, function_tables)          \
198   MACRO(OBJECT, FixedArray, empty_function_tables)    \
199   MACRO(OBJECT, JSArrayBuffer, memory)                \
200   MACRO(SMALL_NUMBER, uint32_t, min_mem_pages)        \
201   MACRO(SMALL_NUMBER, uint32_t, max_mem_pages)        \
202   MACRO(WEAK_LINK, WasmCompiledModule, next_instance) \
203   MACRO(WEAK_LINK, WasmCompiledModule, prev_instance) \
204   MACRO(WEAK_LINK, JSObject, owning_instance)         \
205   MACRO(WEAK_LINK, JSObject, wasm_module)
206 
207 #if DEBUG
208 #define DEBUG_ONLY_TABLE(MACRO) MACRO(SMALL_NUMBER, uint32_t, instance_id)
209 #else
210 #define DEBUG_ONLY_TABLE(IGNORE)
instance_id()211   uint32_t instance_id() const { return -1; }
212 #endif
213 
214 #define WCM_PROPERTY_TABLE(MACRO) \
215   CORE_WCM_PROPERTY_TABLE(MACRO)  \
216   DEBUG_ONLY_TABLE(MACRO)
217 
218  private:
219   enum PropertyIndices {
220 #define INDICES(IGNORE1, IGNORE2, NAME) kID_##NAME,
221     WCM_PROPERTY_TABLE(INDICES) Count
222 #undef INDICES
223   };
224 
225  public:
226   static Handle<WasmCompiledModule> New(
227       Isolate* isolate, Handle<Managed<wasm::WasmModule>> module_wrapper);
228 
Clone(Isolate * isolate,Handle<WasmCompiledModule> module)229   static Handle<WasmCompiledModule> Clone(Isolate* isolate,
230                                           Handle<WasmCompiledModule> module) {
231     Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast(
232         isolate->factory()->CopyFixedArray(module));
233     ret->InitId();
234     ret->reset_weak_owning_instance();
235     ret->reset_weak_next_instance();
236     ret->reset_weak_prev_instance();
237     return ret;
238   }
239 
240   uint32_t mem_size() const;
241   uint32_t default_mem_size() const;
242 
243   wasm::WasmModule* module() const;
244 
245 #define DECLARATION(KIND, TYPE, NAME) WCM_##KIND(TYPE, NAME)
246   WCM_PROPERTY_TABLE(DECLARATION)
247 #undef DECLARATION
248 
249   static bool IsWasmCompiledModule(Object* obj);
250 
251   void PrintInstancesChain();
252 
253   static void RecreateModuleWrapper(Isolate* isolate,
254                                     Handle<FixedArray> compiled_module);
255 
256   // Extract a function name from the given wasm instance.
257   // Returns a null handle if the function is unnamed or the name is not a valid
258   // UTF-8 string.
259   static MaybeHandle<String> GetFunctionName(
260       Handle<WasmCompiledModule> compiled_module, uint32_t func_index);
261 
262  private:
263   void InitId();
264 
265   DISALLOW_IMPLICIT_CONSTRUCTORS(WasmCompiledModule);
266 };
267 
268 class WasmDebugInfo : public FixedArray {
269  public:
270   enum class Fields { kFieldCount };
271 
272   static Handle<WasmDebugInfo> New(Handle<JSObject> wasm);
273 
274   static bool IsDebugInfo(Object* object);
275   static WasmDebugInfo* cast(Object* object);
276 
277   JSObject* wasm_instance();
278 
279   bool SetBreakPoint(int byte_offset);
280 
281   // Get the Script for the specified function.
282   static Script* GetFunctionScript(Handle<WasmDebugInfo> debug_info,
283                                    int func_index);
284 
285   // Disassemble the specified function from this module.
286   static Handle<String> DisassembleFunction(Handle<WasmDebugInfo> debug_info,
287                                             int func_index);
288 
289   // Get the offset table for the specified function, mapping from byte offsets
290   // to position in the disassembly.
291   // Returns an array with three entries per instruction: byte offset, line and
292   // column.
293   static Handle<FixedArray> GetFunctionOffsetTable(
294       Handle<WasmDebugInfo> debug_info, int func_index);
295 
296   // Get the asm.js source position from a byte offset.
297   // Must only be called if the associated wasm object was created from asm.js.
298   static int GetAsmJsSourcePosition(Handle<WasmDebugInfo> debug_info,
299                                     int func_index, int byte_offset);
300 };
301 
302 #undef DECLARE_ACCESSORS
303 #undef DECLARE_OPTIONAL_ACCESSORS
304 
305 }  // namespace internal
306 }  // namespace v8
307 
308 #endif  // V8_WASM_OBJECTS_H_
309