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 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_experimental_JitInfo_h
8 #define js_experimental_JitInfo_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
12 #include <stddef.h> // size_t
13 #include <stdint.h> // uint16_t, uint32_t
15 #include "js/CallArgs.h" // JS::CallArgs, JS::detail::CallArgsBase, JSNative
16 #include "js/RootingAPI.h" // JS::{,Mutable}Handle, JS::Rooted
17 #include "js/Value.h" // JS::Value, JSValueType
23 enum class InlinableNative
: uint16_t;
30 * A class, expected to be passed by value, which represents the CallArgs for a
33 class JSJitGetterCallArgs
: protected JS::MutableHandle
<JS::Value
> {
35 explicit JSJitGetterCallArgs(const JS::CallArgs
& args
)
36 : JS::MutableHandle
<JS::Value
>(args
.rval()) {}
38 explicit JSJitGetterCallArgs(JS::Rooted
<JS::Value
>* rooted
)
39 : JS::MutableHandle
<JS::Value
>(rooted
) {}
41 explicit JSJitGetterCallArgs(JS::MutableHandle
<JS::Value
> handle
)
42 : JS::MutableHandle
<JS::Value
>(handle
) {}
44 JS::MutableHandle
<JS::Value
> rval() { return *this; }
48 * A class, expected to be passed by value, which represents the CallArgs for a
51 class JSJitSetterCallArgs
: protected JS::MutableHandle
<JS::Value
> {
53 explicit JSJitSetterCallArgs(const JS::CallArgs
& args
)
54 : JS::MutableHandle
<JS::Value
>(args
[0]) {}
56 explicit JSJitSetterCallArgs(JS::Rooted
<JS::Value
>* rooted
)
57 : JS::MutableHandle
<JS::Value
>(rooted
) {}
59 JS::MutableHandle
<JS::Value
> operator[](unsigned i
) {
64 unsigned length() const { return 1; }
66 // Add get() or maybe hasDefined() as needed
69 struct JSJitMethodCallArgsTraits
;
72 * A class, expected to be passed by reference, which represents the CallArgs
73 * for a JSJitMethodOp.
75 class JSJitMethodCallArgs
76 : protected JS::detail::CallArgsBase
<JS::detail::NoUsedRval
> {
78 using Base
= JS::detail::CallArgsBase
<JS::detail::NoUsedRval
>;
79 friend struct JSJitMethodCallArgsTraits
;
82 explicit JSJitMethodCallArgs(const JS::CallArgs
& args
) {
84 argc_
= args
.length();
87 JS::MutableHandle
<JS::Value
> rval() const { return Base::rval(); }
89 unsigned length() const { return Base::length(); }
91 JS::MutableHandle
<JS::Value
> operator[](unsigned i
) const {
92 return Base::operator[](i
);
95 bool hasDefined(unsigned i
) const { return Base::hasDefined(i
); }
97 JSObject
& callee() const {
98 // We can't use Base::callee() because that will try to poke at
99 // this->usedRval_, which we don't have.
100 return argv_
[-2].toObject();
103 JS::Handle
<JS::Value
> get(unsigned i
) const { return Base::get(i
); }
105 bool requireAtLeast(JSContext
* cx
, const char* fnname
,
106 unsigned required
) const {
107 // Can just forward to Base, since it only needs the length and we
108 // forward that already.
109 return Base::requireAtLeast(cx
, fnname
, required
);
113 struct JSJitMethodCallArgsTraits
{
114 static constexpr size_t offsetOfArgv
= offsetof(JSJitMethodCallArgs
, argv_
);
115 static constexpr size_t offsetOfArgc
= offsetof(JSJitMethodCallArgs
, argc_
);
118 using JSJitGetterOp
= bool (*)(JSContext
*, JS::Handle
<JSObject
*>, void*,
119 JSJitGetterCallArgs
);
120 using JSJitSetterOp
= bool (*)(JSContext
*, JS::Handle
<JSObject
*>, void*,
121 JSJitSetterCallArgs
);
122 using JSJitMethodOp
= bool (*)(JSContext
*, JS::Handle
<JSObject
*>, void*,
123 const JSJitMethodCallArgs
&);
126 * This struct contains metadata passed from the DOM to the JS Engine for JIT
127 * optimizations on DOM property accessors.
129 * Eventually, this should be made available to general JSAPI users as *not*
130 * experimental and *not* a friend API, but we're not ready to do so yet.
140 IgnoresReturnValueNative
,
148 Integer
= (1 << 1), // Only 32-bit or less
149 Double
= (1 << 2), // Maybe we want to add Float sometime too
155 Numeric
= Integer
| Double
,
156 // Should "Primitive" use the WebIDL definition, which
157 // excludes string and null, or the typical JS one that includes them?
158 Primitive
= Numeric
| Boolean
| Null
| String
,
159 ObjectOrNull
= Object
| Null
,
160 Any
= ObjectOrNull
| Primitive
,
162 // Our sentinel value.
163 ArgTypeListEnd
= (1 << 31)
166 static_assert(Any
& String
, "Any must include String");
167 static_assert(Any
& Integer
, "Any must include Integer");
168 static_assert(Any
& Double
, "Any must include Double");
169 static_assert(Any
& Boolean
, "Any must include Boolean");
170 static_assert(Any
& Object
, "Any must include Object");
171 static_assert(Any
& Null
, "Any must include Null");
174 * An enum that describes what this getter/setter/method aliases. This
175 * determines what things can be hoisted past this call, and if this
176 * call is movable what it can be hoisted past.
180 * Alias nothing: a constant value, getting it can't affect any other
181 * values, nothing can affect it.
186 * Alias things that can modify the DOM but nothing else. Doing the
187 * call can't affect the behavior of any other function.
192 * Alias the world. Calling this can change arbitrary values anywhere
193 * in the system. Most things fall in this bucket.
201 bool needsOuterizedThisObject() const {
202 return type() != Getter
&& type() != Setter
;
205 bool isTypedMethodJitInfo() const { return isTypedMethod
; }
207 OpType
type() const { return OpType(type_
); }
209 AliasSet
aliasSet() const { return AliasSet(aliasSet_
); }
211 JSValueType
returnType() const { return JSValueType(returnType_
); }
214 JSJitGetterOp getter
;
215 JSJitSetterOp setter
;
216 JSJitMethodOp method
;
217 /** A DOM static method, used for Promise wrappers */
218 JSNative staticMethod
;
219 JSNative ignoresReturnValueMethod
;
222 static unsigned offsetOfIgnoresReturnValueNative() {
223 return offsetof(JSJitInfo
, ignoresReturnValueMethod
);
228 js::jit::InlinableNative inlinableNative
;
234 // Additional opcode for some InlinableNative functions.
238 // These fields are carefully packed to take up 4 bytes. If you need more
239 // bits for whatever reason, please see if you can steal bits from existing
240 // fields before adding more members to this structure.
241 static constexpr size_t OpTypeBits
= 4;
242 static constexpr size_t AliasSetBits
= 4;
243 static constexpr size_t ReturnTypeBits
= 8;
244 static constexpr size_t SlotIndexBits
= 10;
246 /** The OpType that says what sort of function we are. */
247 uint32_t type_
: OpTypeBits
;
250 * The alias set for this op. This is a _minimal_ alias set; in
251 * particular for a method it does not include whatever argument
252 * conversions might do. That's covered by argTypes and runtime
253 * analysis of the actual argument types being passed in.
255 uint32_t aliasSet_
: AliasSetBits
;
257 /** The return type tag. Might be JSVAL_TYPE_UNKNOWN. */
258 uint32_t returnType_
: ReturnTypeBits
;
260 static_assert(OpTypeCount
<= (1 << OpTypeBits
),
261 "Not enough space for OpType");
262 static_assert(AliasSetCount
<= (1 << AliasSetBits
),
263 "Not enough space for AliasSet");
264 static_assert((sizeof(JSValueType
) * 8) <= ReturnTypeBits
,
265 "Not enough space for JSValueType");
267 /** Is op fallible? False in setters. */
268 uint32_t isInfallible
: 1;
271 * Is op movable? To be movable the op must
272 * not AliasEverything, but even that might
273 * not be enough (e.g. in cases when it can
274 * throw or is explicitly not movable).
276 uint32_t isMovable
: 1;
279 * Can op be dead-code eliminated? Again, this
280 * depends on whether the op can throw, in
281 * addition to the alias set.
283 uint32_t isEliminatable
: 1;
285 // XXXbz should we have a JSValueType for the type of the member?
287 * True if this is a getter that can always
288 * get the value from a slot of the "this" object.
290 uint32_t isAlwaysInSlot
: 1;
293 * True if this is a getter that can sometimes (if the slot doesn't contain
294 * UndefinedValue()) get the value from a slot of the "this" object.
296 uint32_t isLazilyCachedInSlot
: 1;
298 /** True if this is an instance of JSTypedMethodJitInfo. */
299 uint32_t isTypedMethod
: 1;
302 * If isAlwaysInSlot or isSometimesInSlot is true,
303 * the index of the slot to get the value from.
306 uint32_t slotIndex
: SlotIndexBits
;
308 static constexpr size_t maxSlotIndex
= (1 << SlotIndexBits
) - 1;
311 static_assert(sizeof(JSJitInfo
) == (sizeof(void*) + 2 * sizeof(uint32_t)),
312 "There are several thousand instances of JSJitInfo stored in "
313 "a binary. Please don't increase its space requirements without "
314 "verifying that there is no other way forward (better packing, "
315 "smaller datatypes for fields, subclassing, etc.).");
317 struct JSTypedMethodJitInfo
{
318 // We use C-style inheritance here, rather than C++ style inheritance
319 // because not all compilers support brace-initialization for non-aggregate
320 // classes. Using C++ style inheritance and constructors instead of
321 // brace-initialization would also force the creation of static
322 // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo
323 // structures are declared. Since there can be several thousand of these
324 // structures present and we want to have roughly equivalent performance
325 // across a range of compilers, we do things manually.
328 const JSJitInfo::ArgType
* const argTypes
; /* For a method, a list of sets of
329 types that the function
330 expects. This can be used,
331 for example, to figure out
332 when argument coercions can
333 have side-effects. */
336 #endif // js_experimental_JitInfo_h