Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
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
*
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 "gc/ZoneAllocator.h"
24
#include "vm/NativeObject.h"
25
#include "wasm/WasmTypes.h"
26
27
namespace js {
28
29
class ArrayBufferObjectMaybeShared;
30
class StructTypeDescr;
31
class TypedArrayObject;
32
class WasmFunctionScope;
33
class WasmInstanceScope;
34
class SharedArrayRawBuffer;
35
36
namespace wasm {
37
38
// Return whether WebAssembly can be compiled on this platform.
39
// This must be checked and must be true to call any of the top-level wasm
40
// eval/compile methods.
41
42
bool HasCompilerSupport(JSContext* cx);
43
44
// Return whether WebAssembly has support for an optimized compiler backend.
45
46
bool HasOptimizedCompilerTier(JSContext* cx);
47
48
// Return whether WebAssembly is supported on this platform. This determines
49
// whether the WebAssembly object is exposed to JS and takes into account
50
// configuration options that disable various modes.
51
52
bool HasSupport(JSContext* cx);
53
54
// Return whether WebAssembly streaming/caching is supported on this platform.
55
// This takes into account prefs and necessary embedding callbacks.
56
57
bool HasStreamingSupport(JSContext* cx);
58
59
bool HasCachingSupport(JSContext* cx);
60
61
// Returns true if WebAssembly as configured by compile-time flags and run-time
62
// options can support reference types and stack walking.
63
64
bool HasReftypesSupport(JSContext* cx);
65
66
// Returns true if WebAssembly as configured by compile-time flags and run-time
67
// options can support (ref T) types and structure types, etc (evolving).
68
69
bool HasGcSupport(JSContext* cx);
70
71
// Returns true if WebAssembly as configured by compile-time flags and run-time
72
// options can support multi-value block and function returns (evolving).
73
74
bool HasMultiValueSupport(JSContext* cx);
75
76
// Returns true if WebAssembly as configured by compile-time flags and run-time
77
// options can support I64 to BigInt conversion.
78
79
bool HasI64BigIntSupport(JSContext* cx);
80
81
// Compiles the given binary wasm module given the ArrayBufferObject
82
// and links the module's imports with the given import object.
83
84
MOZ_MUST_USE bool Eval(JSContext* cx, Handle<TypedArrayObject*> code,
85
HandleObject importObj,
86
MutableHandleWasmInstanceObject instanceObj);
87
88
// Extracts the various imports from the given import object into the given
89
// ImportValues structure while checking the imports against the given module.
90
// The resulting structure can be passed to WasmModule::instantiate.
91
92
struct ImportValues;
93
MOZ_MUST_USE bool GetImports(JSContext* cx, const Module& module,
94
HandleObject importObj, ImportValues* imports);
95
96
// For testing cross-process (de)serialization, this pair of functions are
97
// responsible for, in the child process, compiling the given wasm bytecode
98
// to a wasm::Module that is serialized into the given byte array, and, in
99
// the parent process, deserializing the given byte array into a
100
// WebAssembly.Module object.
101
102
MOZ_MUST_USE bool CompileAndSerialize(const ShareableBytes& bytecode,
103
Bytes* serialized);
104
105
MOZ_MUST_USE bool DeserializeModule(JSContext* cx, const Bytes& serialized,
106
MutableHandleObject module);
107
108
// A WebAssembly "Exported Function" is the spec name for the JS function
109
// objects created to wrap wasm functions. This predicate returns false
110
// for asm.js functions which are semantically just normal JS functions
111
// (even if they are implemented via wasm under the hood). The accessor
112
// functions for extracting the instance and func-index of a wasm function
113
// can be used for both wasm and asm.js, however.
114
115
bool IsWasmExportedFunction(JSFunction* fun);
116
bool CheckFuncRefValue(JSContext* cx, HandleValue v, MutableHandleFunction fun);
117
118
Instance& ExportedFunctionToInstance(JSFunction* fun);
119
WasmInstanceObject* ExportedFunctionToInstanceObject(JSFunction* fun);
120
uint32_t ExportedFunctionToFuncIndex(JSFunction* fun);
121
122
bool IsSharedWasmMemoryObject(JSObject* obj);
123
124
} // namespace wasm
125
126
// The class of the WebAssembly global namespace object.
127
128
extern const JSClass WebAssemblyClass;
129
130
// The class of WebAssembly.Module. Each WasmModuleObject owns a
131
// wasm::Module. These objects are used both as content-facing JS objects and as
132
// internal implementation details of asm.js.
133
134
class WasmModuleObject : public NativeObject {
135
static const unsigned MODULE_SLOT = 0;
136
static const JSClassOps classOps_;
137
static const ClassSpec classSpec_;
138
static void finalize(JSFreeOp* fop, JSObject* obj);
139
static bool imports(JSContext* cx, unsigned argc, Value* vp);
140
static bool exports(JSContext* cx, unsigned argc, Value* vp);
141
static bool customSections(JSContext* cx, unsigned argc, Value* vp);
142
143
public:
144
static const unsigned RESERVED_SLOTS = 1;
145
static const JSClass class_;
146
static const JSClass& protoClass_;
147
static const JSPropertySpec properties[];
148
static const JSFunctionSpec methods[];
149
static const JSFunctionSpec static_methods[];
150
static bool construct(JSContext*, unsigned, Value*);
151
152
static WasmModuleObject* create(JSContext* cx, const wasm::Module& module,
153
HandleObject proto = nullptr);
154
const wasm::Module& module() const;
155
};
156
157
// The class of WebAssembly.Global. This wraps a storage location, and there is
158
// a per-agent one-to-one relationship between the WasmGlobalObject and the
159
// storage location (the Cell) it wraps: if a module re-exports an imported
160
// global, the imported and exported WasmGlobalObjects are the same, and if a
161
// module exports a global twice, the two exported WasmGlobalObjects are the
162
// same.
163
164
// TODO/AnyRef-boxing: With boxed immediates and strings, JSObject* is no longer
165
// the most appropriate representation for Cell::anyref.
166
STATIC_ASSERT_ANYREF_IS_JSOBJECT;
167
168
class WasmGlobalObject : public NativeObject {
169
static const unsigned TYPE_SLOT = 0;
170
static const unsigned MUTABLE_SLOT = 1;
171
static const unsigned CELL_SLOT = 2;
172
173
static const JSClassOps classOps_;
174
static const ClassSpec classSpec_;
175
static void finalize(JSFreeOp*, JSObject* obj);
176
static void trace(JSTracer* trc, JSObject* obj);
177
178
static bool valueGetterImpl(JSContext* cx, const CallArgs& args);
179
static bool valueGetter(JSContext* cx, unsigned argc, Value* vp);
180
static bool valueSetterImpl(JSContext* cx, const CallArgs& args);
181
static bool valueSetter(JSContext* cx, unsigned argc, Value* vp);
182
183
public:
184
// For exposed globals the Cell holds the value of the global; the
185
// instance's global area holds a pointer to the Cell.
186
union Cell {
187
int32_t i32;
188
int64_t i64;
189
float f32;
190
double f64;
191
wasm::AnyRef ref;
192
Cell() : i64(0) {}
193
~Cell() {}
194
};
195
196
static const unsigned RESERVED_SLOTS = 3;
197
static const JSClass class_;
198
static const JSClass& protoClass_;
199
static const JSPropertySpec properties[];
200
static const JSFunctionSpec methods[];
201
static const JSFunctionSpec static_methods[];
202
static bool construct(JSContext*, unsigned, Value*);
203
204
static WasmGlobalObject* create(JSContext* cx, wasm::HandleVal value,
205
bool isMutable);
206
bool isNewborn() { return getReservedSlot(CELL_SLOT).isUndefined(); }
207
208
wasm::ValType type() const;
209
void val(wasm::MutableHandleVal outval) const;
210
bool isMutable() const;
211
bool value(JSContext* cx, MutableHandleValue out);
212
Cell* cell() const;
213
};
214
215
// The class of WebAssembly.Instance. Each WasmInstanceObject owns a
216
// wasm::Instance. These objects are used both as content-facing JS objects and
217
// as internal implementation details of asm.js.
218
219
class WasmInstanceObject : public NativeObject {
220
static const unsigned INSTANCE_SLOT = 0;
221
static const unsigned EXPORTS_OBJ_SLOT = 1;
222
static const unsigned EXPORTS_SLOT = 2;
223
static const unsigned SCOPES_SLOT = 3;
224
static const unsigned INSTANCE_SCOPE_SLOT = 4;
225
static const unsigned GLOBALS_SLOT = 5;
226
227
static const JSClassOps classOps_;
228
static const ClassSpec classSpec_;
229
static bool exportsGetterImpl(JSContext* cx, const CallArgs& args);
230
static bool exportsGetter(JSContext* cx, unsigned argc, Value* vp);
231
bool isNewborn() const;
232
static void finalize(JSFreeOp* fop, JSObject* obj);
233
static void trace(JSTracer* trc, JSObject* obj);
234
235
// ExportMap maps from function index to exported function object.
236
// This allows the instance to lazily create exported function
237
// objects on demand (instead up-front for all table elements) while
238
// correctly preserving observable function object identity.
239
using ExportMap = GCHashMap<uint32_t, HeapPtr<JSFunction*>,
240
DefaultHasher<uint32_t>, ZoneAllocPolicy>;
241
ExportMap& exports() const;
242
243
// WeakScopeMap maps from function index to js::Scope. This maps is weak
244
// to avoid holding scope objects alive. The scopes are normally created
245
// during debugging.
246
using ScopeMap =
247
JS::WeakCache<GCHashMap<uint32_t, WeakHeapPtr<WasmFunctionScope*>,
248
DefaultHasher<uint32_t>, ZoneAllocPolicy>>;
249
ScopeMap& scopes() const;
250
251
public:
252
static const unsigned RESERVED_SLOTS = 6;
253
static const JSClass class_;
254
static const JSClass& protoClass_;
255
static const JSPropertySpec properties[];
256
static const JSFunctionSpec methods[];
257
static const JSFunctionSpec static_methods[];
258
static bool construct(JSContext*, unsigned, Value*);
259
260
static WasmInstanceObject* create(
261
JSContext* cx, RefPtr<const wasm::Code> code,
262
const wasm::DataSegmentVector& dataSegments,
263
const wasm::ElemSegmentVector& elemSegments, wasm::UniqueTlsData tlsData,
264
HandleWasmMemoryObject memory,
265
Vector<RefPtr<wasm::Table>, 0, SystemAllocPolicy>&& tables,
266
GCVector<HeapPtr<StructTypeDescr*>, 0, SystemAllocPolicy>&&
267
structTypeDescrs,
268
const JSFunctionVector& funcImports,
269
const wasm::GlobalDescVector& globals,
270
const wasm::ValVector& globalImportValues,
271
const WasmGlobalObjectVector& globalObjs, HandleObject proto,
272
UniquePtr<wasm::DebugState> maybeDebug);
273
void initExportsObj(JSObject& exportsObj);
274
275
wasm::Instance& instance() const;
276
JSObject& exportsObj() const;
277
278
static bool getExportedFunction(JSContext* cx,
279
HandleWasmInstanceObject instanceObj,
280
uint32_t funcIndex,
281
MutableHandleFunction fun);
282
283
const wasm::CodeRange& getExportedFunctionCodeRange(JSFunction* fun,
284
wasm::Tier tier);
285
286
static WasmInstanceScope* getScope(JSContext* cx,
287
HandleWasmInstanceObject instanceObj);
288
static WasmFunctionScope* getFunctionScope(
289
JSContext* cx, HandleWasmInstanceObject instanceObj, uint32_t funcIndex);
290
291
using GlobalObjectVector =
292
GCVector<HeapPtr<WasmGlobalObject*>, 0, ZoneAllocPolicy>;
293
GlobalObjectVector& indirectGlobals() const;
294
};
295
296
// The class of WebAssembly.Memory. A WasmMemoryObject references an ArrayBuffer
297
// or SharedArrayBuffer object which owns the actual memory.
298
299
class WasmMemoryObject : public NativeObject {
300
static const unsigned BUFFER_SLOT = 0;
301
static const unsigned OBSERVERS_SLOT = 1;
302
static const JSClassOps classOps_;
303
static const ClassSpec classSpec_;
304
static void finalize(JSFreeOp* fop, JSObject* obj);
305
static bool bufferGetterImpl(JSContext* cx, const CallArgs& args);
306
static bool bufferGetter(JSContext* cx, unsigned argc, Value* vp);
307
static bool growImpl(JSContext* cx, const CallArgs& args);
308
static bool grow(JSContext* cx, unsigned argc, Value* vp);
309
static uint32_t growShared(HandleWasmMemoryObject memory, uint32_t delta);
310
311
using InstanceSet =
312
JS::WeakCache<GCHashSet<WeakHeapPtrWasmInstanceObject,
313
MovableCellHasher<WeakHeapPtrWasmInstanceObject>,
314
ZoneAllocPolicy>>;
315
bool hasObservers() const;
316
InstanceSet& observers() const;
317
InstanceSet* getOrCreateObservers(JSContext* cx);
318
319
public:
320
static const unsigned RESERVED_SLOTS = 2;
321
static const JSClass class_;
322
static const JSClass& protoClass_;
323
static const JSPropertySpec properties[];
324
static const JSFunctionSpec methods[];
325
static const JSFunctionSpec static_methods[];
326
static bool construct(JSContext*, unsigned, Value*);
327
328
static WasmMemoryObject* create(JSContext* cx,
329
Handle<ArrayBufferObjectMaybeShared*> buffer,
330
HandleObject proto);
331
332
// `buffer()` returns the current buffer object always. If the buffer
333
// represents shared memory then `buffer().byteLength()` never changes, and
334
// in particular it may be a smaller value than that returned from
335
// `volatileMemoryLength()` below.
336
//
337
// Generally, you do not want to call `buffer().byteLength()`, but to call
338
// `volatileMemoryLength()`, instead.
339
ArrayBufferObjectMaybeShared& buffer() const;
340
341
// The current length of the memory. In the case of shared memory, the
342
// length can change at any time. Also note that this will acquire a lock
343
// for shared memory, so do not call this from a signal handler.
344
uint32_t volatileMemoryLength() const;
345
346
bool isShared() const;
347
bool isHuge() const;
348
bool movingGrowable() const;
349
uint32_t boundsCheckLimit() const;
350
351
// If isShared() is true then obtain the underlying buffer object.
352
SharedArrayRawBuffer* sharedArrayRawBuffer() const;
353
354
bool addMovingGrowObserver(JSContext* cx, WasmInstanceObject* instance);
355
static uint32_t grow(HandleWasmMemoryObject memory, uint32_t delta,
356
JSContext* cx);
357
};
358
359
// The class of WebAssembly.Table. A WasmTableObject holds a refcount on a
360
// wasm::Table, allowing a Table to be shared between multiple Instances
361
// (eventually between multiple threads).
362
363
class WasmTableObject : public NativeObject {
364
static const unsigned TABLE_SLOT = 0;
365
static const JSClassOps classOps_;
366
static const ClassSpec classSpec_;
367
bool isNewborn() const;
368
static void finalize(JSFreeOp* fop, JSObject* obj);
369
static void trace(JSTracer* trc, JSObject* obj);
370
static bool lengthGetterImpl(JSContext* cx, const CallArgs& args);
371
static bool lengthGetter(JSContext* cx, unsigned argc, Value* vp);
372
static bool getImpl(JSContext* cx, const CallArgs& args);
373
static bool get(JSContext* cx, unsigned argc, Value* vp);
374
static bool setImpl(JSContext* cx, const CallArgs& args);
375
static bool set(JSContext* cx, unsigned argc, Value* vp);
376
static bool growImpl(JSContext* cx, const CallArgs& args);
377
static bool grow(JSContext* cx, unsigned argc, Value* vp);
378
379
public:
380
static const unsigned RESERVED_SLOTS = 1;
381
static const JSClass class_;
382
static const JSClass& protoClass_;
383
static const JSPropertySpec properties[];
384
static const JSFunctionSpec methods[];
385
static const JSFunctionSpec static_methods[];
386
static bool construct(JSContext*, unsigned, Value*);
387
388
// Note that, after creation, a WasmTableObject's table() is not initialized
389
// and must be initialized before use.
390
391
static WasmTableObject* create(JSContext* cx, const wasm::Limits& limits,
392
wasm::TableKind tableKind);
393
wasm::Table& table() const;
394
};
395
396
} // namespace js
397
398
#endif // wasm_js_h