/src/mozilla-central/js/src/wasm/WasmJS.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
3 | | * |
4 | | * Copyright 2016 Mozilla Foundation |
5 | | * |
6 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | | * you may not use this file except in compliance with the License. |
8 | | * You may obtain a copy of the License at |
9 | | * |
10 | | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | | * |
12 | | * Unless required by applicable law or agreed to in writing, software |
13 | | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | | * See the License for the specific language governing permissions and |
16 | | * limitations under the License. |
17 | | */ |
18 | | |
19 | | #ifndef wasm_js_h |
20 | | #define wasm_js_h |
21 | | |
22 | | #include "gc/Policy.h" |
23 | | #include "vm/NativeObject.h" |
24 | | #include "wasm/WasmTypes.h" |
25 | | |
26 | | namespace js { |
27 | | |
28 | | class GlobalObject; |
29 | | class StructTypeDescr; |
30 | | class TypedArrayObject; |
31 | | class WasmFunctionScope; |
32 | | class WasmInstanceScope; |
33 | | class SharedArrayRawBuffer; |
34 | | |
35 | | namespace wasm { |
36 | | |
37 | | // Return whether WebAssembly can be compiled on this platform. |
38 | | // This must be checked and must be true to call any of the top-level wasm |
39 | | // eval/compile methods. |
40 | | |
41 | | bool |
42 | | HasCompilerSupport(JSContext* cx); |
43 | | |
44 | | // Return whether WebAssembly is supported on this platform. This determines |
45 | | // whether the WebAssembly object is exposed to JS and takes into account |
46 | | // configuration options that disable various modes. |
47 | | |
48 | | bool |
49 | | HasSupport(JSContext* cx); |
50 | | |
51 | | // Return whether WebAssembly streaming/caching is supported on this platform. |
52 | | // This takes into account prefs and necessary embedding callbacks. |
53 | | |
54 | | bool |
55 | | HasStreamingSupport(JSContext* cx); |
56 | | |
57 | | bool |
58 | | HasCachingSupport(JSContext* cx); |
59 | | |
60 | | // Compiles the given binary wasm module given the ArrayBufferObject |
61 | | // and links the module's imports with the given import object. |
62 | | |
63 | | MOZ_MUST_USE bool |
64 | | Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj, |
65 | | MutableHandleWasmInstanceObject instanceObj); |
66 | | |
67 | | // These accessors can be used to probe JS values for being an exported wasm |
68 | | // function. |
69 | | |
70 | | extern bool |
71 | | IsExportedFunction(JSFunction* fun); |
72 | | |
73 | | extern bool |
74 | | IsExportedWasmFunction(JSFunction* fun); |
75 | | |
76 | | extern bool |
77 | | IsExportedFunction(const Value& v, MutableHandleFunction f); |
78 | | |
79 | | extern Instance& |
80 | | ExportedFunctionToInstance(JSFunction* fun); |
81 | | |
82 | | extern WasmInstanceObject* |
83 | | ExportedFunctionToInstanceObject(JSFunction* fun); |
84 | | |
85 | | extern uint32_t |
86 | | ExportedFunctionToFuncIndex(JSFunction* fun); |
87 | | |
88 | | extern bool |
89 | | IsSharedWasmMemoryObject(JSObject* obj); |
90 | | |
91 | | } // namespace wasm |
92 | | |
93 | | // The class of the WebAssembly global namespace object. |
94 | | |
95 | | extern const Class WebAssemblyClass; |
96 | | |
97 | | JSObject* |
98 | | InitWebAssemblyClass(JSContext* cx, Handle<GlobalObject*> global); |
99 | | |
100 | | // The class of WebAssembly.Module. Each WasmModuleObject owns a |
101 | | // wasm::Module. These objects are used both as content-facing JS objects and as |
102 | | // internal implementation details of asm.js. |
103 | | |
104 | | class WasmModuleObject : public NativeObject |
105 | | { |
106 | | static const unsigned MODULE_SLOT = 0; |
107 | | static const ClassOps classOps_; |
108 | | static void finalize(FreeOp* fop, JSObject* obj); |
109 | | static bool imports(JSContext* cx, unsigned argc, Value* vp); |
110 | | static bool exports(JSContext* cx, unsigned argc, Value* vp); |
111 | | static bool customSections(JSContext* cx, unsigned argc, Value* vp); |
112 | | |
113 | | public: |
114 | | static const unsigned RESERVED_SLOTS = 1; |
115 | | static const Class class_; |
116 | | static const JSPropertySpec properties[]; |
117 | | static const JSFunctionSpec methods[]; |
118 | | static const JSFunctionSpec static_methods[]; |
119 | | static bool construct(JSContext*, unsigned, Value*); |
120 | | |
121 | | static WasmModuleObject* create(JSContext* cx, |
122 | | const wasm::Module& module, |
123 | | HandleObject proto = nullptr); |
124 | | const wasm::Module& module() const; |
125 | | }; |
126 | | |
127 | | // The class of WebAssembly.Global. This wraps a storage location, and there is |
128 | | // a per-agent one-to-one relationship between the WasmGlobalObject and the |
129 | | // storage location (the Cell) it wraps: if a module re-exports an imported |
130 | | // global, the imported and exported WasmGlobalObjects are the same, and if a |
131 | | // module exports a global twice, the two exported WasmGlobalObjects are the |
132 | | // same. |
133 | | |
134 | | class WasmGlobalObject : public NativeObject |
135 | | { |
136 | | static const unsigned TYPE_SLOT = 0; |
137 | | static const unsigned MUTABLE_SLOT = 1; |
138 | | static const unsigned CELL_SLOT = 2; |
139 | | |
140 | | static const ClassOps classOps_; |
141 | | static void finalize(FreeOp*, JSObject* obj); |
142 | | static void trace(JSTracer* trc, JSObject* obj); |
143 | | |
144 | | static bool valueGetterImpl(JSContext* cx, const CallArgs& args); |
145 | | static bool valueGetter(JSContext* cx, unsigned argc, Value* vp); |
146 | | static bool valueSetterImpl(JSContext* cx, const CallArgs& args); |
147 | | static bool valueSetter(JSContext* cx, unsigned argc, Value* vp); |
148 | | |
149 | | public: |
150 | | // For exposed globals the Cell holds the value of the global; the |
151 | | // instance's global area holds a pointer to the Cell. |
152 | | union Cell { |
153 | | int32_t i32; |
154 | | int64_t i64; |
155 | | float f32; |
156 | | double f64; |
157 | | JSObject* ptr; |
158 | 0 | Cell() : i64(0) {} |
159 | 0 | ~Cell() {} |
160 | | }; |
161 | | |
162 | | static const unsigned RESERVED_SLOTS = 3; |
163 | | static const Class class_; |
164 | | static const JSPropertySpec properties[]; |
165 | | static const JSFunctionSpec methods[]; |
166 | | static const JSFunctionSpec static_methods[]; |
167 | | static bool construct(JSContext*, unsigned, Value*); |
168 | | |
169 | | static WasmGlobalObject* create(JSContext* cx, wasm::HandleVal value, bool isMutable); |
170 | 0 | bool isNewborn() { return getReservedSlot(CELL_SLOT).isUndefined(); } |
171 | | |
172 | | wasm::ValType type() const; |
173 | | void val(wasm::MutableHandleVal outval) const; |
174 | | bool isMutable() const; |
175 | | // value() will MOZ_CRASH if the type is int64 |
176 | | Value value(JSContext* cx) const; |
177 | | Cell* cell() const; |
178 | | }; |
179 | | |
180 | | // The class of WebAssembly.Instance. Each WasmInstanceObject owns a |
181 | | // wasm::Instance. These objects are used both as content-facing JS objects and |
182 | | // as internal implementation details of asm.js. |
183 | | |
184 | | class WasmInstanceObject : public NativeObject |
185 | | { |
186 | | static const unsigned INSTANCE_SLOT = 0; |
187 | | static const unsigned EXPORTS_OBJ_SLOT = 1; |
188 | | static const unsigned EXPORTS_SLOT = 2; |
189 | | static const unsigned SCOPES_SLOT = 3; |
190 | | static const unsigned INSTANCE_SCOPE_SLOT = 4; |
191 | | static const unsigned GLOBALS_SLOT = 5; |
192 | | |
193 | | static const ClassOps classOps_; |
194 | | static bool exportsGetterImpl(JSContext* cx, const CallArgs& args); |
195 | | static bool exportsGetter(JSContext* cx, unsigned argc, Value* vp); |
196 | | bool isNewborn() const; |
197 | | static void finalize(FreeOp* fop, JSObject* obj); |
198 | | static void trace(JSTracer* trc, JSObject* obj); |
199 | | |
200 | | // ExportMap maps from function index to exported function object. |
201 | | // This allows the instance to lazily create exported function |
202 | | // objects on demand (instead up-front for all table elements) while |
203 | | // correctly preserving observable function object identity. |
204 | | using ExportMap = GCHashMap<uint32_t, |
205 | | HeapPtr<JSFunction*>, |
206 | | DefaultHasher<uint32_t>, |
207 | | SystemAllocPolicy>; |
208 | | ExportMap& exports() const; |
209 | | |
210 | | // WeakScopeMap maps from function index to js::Scope. This maps is weak |
211 | | // to avoid holding scope objects alive. The scopes are normally created |
212 | | // during debugging. |
213 | | using ScopeMap = JS::WeakCache<GCHashMap<uint32_t, |
214 | | ReadBarriered<WasmFunctionScope*>, |
215 | | DefaultHasher<uint32_t>, |
216 | | SystemAllocPolicy>>; |
217 | | ScopeMap& scopes() const; |
218 | | |
219 | | public: |
220 | | static const unsigned RESERVED_SLOTS = 6; |
221 | | static const Class class_; |
222 | | static const JSPropertySpec properties[]; |
223 | | static const JSFunctionSpec methods[]; |
224 | | static const JSFunctionSpec static_methods[]; |
225 | | static bool construct(JSContext*, unsigned, Value*); |
226 | | |
227 | | static WasmInstanceObject* create(JSContext* cx, |
228 | | RefPtr<const wasm::Code> code, |
229 | | const wasm::DataSegmentVector& dataSegments, |
230 | | const wasm::ElemSegmentVector& elemSegments, |
231 | | wasm::UniqueTlsData tlsData, |
232 | | HandleWasmMemoryObject memory, |
233 | | Vector<RefPtr<wasm::Table>, 0, SystemAllocPolicy>&& tables, |
234 | | GCVector<HeapPtr<StructTypeDescr*>, 0, SystemAllocPolicy>&& structTypeDescrs, |
235 | | Handle<FunctionVector> funcImports, |
236 | | const wasm::GlobalDescVector& globals, |
237 | | wasm::HandleValVector globalImportValues, |
238 | | const WasmGlobalObjectVector& globalObjs, |
239 | | HandleObject proto, |
240 | | UniquePtr<wasm::DebugState> maybeDebug); |
241 | | void initExportsObj(JSObject& exportsObj); |
242 | | |
243 | | wasm::Instance& instance() const; |
244 | | JSObject& exportsObj() const; |
245 | | |
246 | | static bool getExportedFunction(JSContext* cx, |
247 | | HandleWasmInstanceObject instanceObj, |
248 | | uint32_t funcIndex, |
249 | | MutableHandleFunction fun); |
250 | | |
251 | | const wasm::CodeRange& getExportedFunctionCodeRange(JSFunction* fun, wasm::Tier tier); |
252 | | |
253 | | static WasmInstanceScope* getScope(JSContext* cx, HandleWasmInstanceObject instanceObj); |
254 | | static WasmFunctionScope* getFunctionScope(JSContext* cx, |
255 | | HandleWasmInstanceObject instanceObj, |
256 | | uint32_t funcIndex); |
257 | | |
258 | | WasmGlobalObjectVector& indirectGlobals() const; |
259 | | }; |
260 | | |
261 | | // The class of WebAssembly.Memory. A WasmMemoryObject references an ArrayBuffer |
262 | | // or SharedArrayBuffer object which owns the actual memory. |
263 | | |
264 | | class WasmMemoryObject : public NativeObject |
265 | | { |
266 | | static const unsigned BUFFER_SLOT = 0; |
267 | | static const unsigned OBSERVERS_SLOT = 1; |
268 | | static const ClassOps classOps_; |
269 | | static void finalize(FreeOp* fop, JSObject* obj); |
270 | | static bool bufferGetterImpl(JSContext* cx, const CallArgs& args); |
271 | | static bool bufferGetter(JSContext* cx, unsigned argc, Value* vp); |
272 | | static bool growImpl(JSContext* cx, const CallArgs& args); |
273 | | static bool grow(JSContext* cx, unsigned argc, Value* vp); |
274 | | static uint32_t growShared(HandleWasmMemoryObject memory, uint32_t delta); |
275 | | |
276 | | using InstanceSet = JS::WeakCache<GCHashSet<ReadBarrieredWasmInstanceObject, |
277 | | MovableCellHasher<ReadBarrieredWasmInstanceObject>, |
278 | | SystemAllocPolicy>>; |
279 | | bool hasObservers() const; |
280 | | InstanceSet& observers() const; |
281 | | InstanceSet* getOrCreateObservers(JSContext* cx); |
282 | | |
283 | | public: |
284 | | static const unsigned RESERVED_SLOTS = 2; |
285 | | static const Class class_; |
286 | | static const JSPropertySpec properties[]; |
287 | | static const JSFunctionSpec methods[]; |
288 | | static const JSFunctionSpec static_methods[]; |
289 | | static bool construct(JSContext*, unsigned, Value*); |
290 | | |
291 | | static WasmMemoryObject* create(JSContext* cx, |
292 | | Handle<ArrayBufferObjectMaybeShared*> buffer, |
293 | | HandleObject proto); |
294 | | |
295 | | // `buffer()` returns the current buffer object always. If the buffer |
296 | | // represents shared memory then `buffer().byteLength()` never changes, and |
297 | | // in particular it may be a smaller value than that returned from |
298 | | // `volatileMemoryLength()` below. |
299 | | // |
300 | | // Generally, you do not want to call `buffer().byteLength()`, but to call |
301 | | // `volatileMemoryLength()`, instead. |
302 | | ArrayBufferObjectMaybeShared& buffer() const; |
303 | | |
304 | | // The current length of the memory. In the case of shared memory, the |
305 | | // length can change at any time. Also note that this will acquire a lock |
306 | | // for shared memory, so do not call this from a signal handler. |
307 | | uint32_t volatileMemoryLength() const; |
308 | | |
309 | | bool isShared() const; |
310 | | bool movingGrowable() const; |
311 | | |
312 | | // If isShared() is true then obtain the underlying buffer object. |
313 | | SharedArrayRawBuffer* sharedArrayRawBuffer() const; |
314 | | |
315 | | bool addMovingGrowObserver(JSContext* cx, WasmInstanceObject* instance); |
316 | | static uint32_t grow(HandleWasmMemoryObject memory, uint32_t delta, JSContext* cx); |
317 | | }; |
318 | | |
319 | | // The class of WebAssembly.Table. A WasmTableObject holds a refcount on a |
320 | | // wasm::Table, allowing a Table to be shared between multiple Instances |
321 | | // (eventually between multiple threads). |
322 | | |
323 | | class WasmTableObject : public NativeObject |
324 | | { |
325 | | static const unsigned TABLE_SLOT = 0; |
326 | | static const ClassOps classOps_; |
327 | | bool isNewborn() const; |
328 | | static void finalize(FreeOp* fop, JSObject* obj); |
329 | | static void trace(JSTracer* trc, JSObject* obj); |
330 | | static bool lengthGetterImpl(JSContext* cx, const CallArgs& args); |
331 | | static bool lengthGetter(JSContext* cx, unsigned argc, Value* vp); |
332 | | static bool getImpl(JSContext* cx, const CallArgs& args); |
333 | | static bool get(JSContext* cx, unsigned argc, Value* vp); |
334 | | static bool setImpl(JSContext* cx, const CallArgs& args); |
335 | | static bool set(JSContext* cx, unsigned argc, Value* vp); |
336 | | static bool growImpl(JSContext* cx, const CallArgs& args); |
337 | | static bool grow(JSContext* cx, unsigned argc, Value* vp); |
338 | | |
339 | | public: |
340 | | static const unsigned RESERVED_SLOTS = 1; |
341 | | static const Class class_; |
342 | | static const JSPropertySpec properties[]; |
343 | | static const JSFunctionSpec methods[]; |
344 | | static const JSFunctionSpec static_methods[]; |
345 | | static bool construct(JSContext*, unsigned, Value*); |
346 | | |
347 | | // Note that, after creation, a WasmTableObject's table() is not initialized |
348 | | // and must be initialized before use. |
349 | | |
350 | | static WasmTableObject* create(JSContext* cx, const wasm::Limits& limits); |
351 | | wasm::Table& table() const; |
352 | | }; |
353 | | |
354 | | } // namespace js |
355 | | |
356 | | #endif // wasm_js_h |