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 vm_FunctionFlags_h
8 #define vm_FunctionFlags_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_ASSERT_IF
11 #include "mozilla/Attributes.h" // MOZ_IMPLICIT
13 #include <stdint.h> // uint8_t, uint16_t
15 #include "jstypes.h" // JS_PUBLIC_API
17 class JS_PUBLIC_API JSAtom
;
23 // Syntactic characteristics of a function.
24 enum FunctionKind
: uint8_t {
25 // Regular function that doesn't match any of the other kinds.
27 // This kind is used by the following scipted functions:
28 // * FunctionDeclaration
29 // * FunctionExpression
30 // * Function created from Function() call or its variants
32 // Also all native functions excluding AsmJS and Wasm use this kind.
35 // ES6 '(args) => body' syntax.
36 // This kind is used only by scripted function.
39 // ES6 MethodDefinition syntax.
40 // This kind is used only by scripted function.
43 // Class constructor syntax, or default constructor.
44 // This kind is used only by scripted function and default constructor.
46 // WARNING: This is independent from Flags::CONSTRUCTOR.
49 // Getter and setter syntax in objects or classes, or
50 // native getter and setter created from JSPropertySpec.
51 // This kind is used both by scripted functions and native functions.
55 // An asm.js module or exported function.
57 // This kind is used only by scripted function, and used only when the
58 // asm.js module is created.
60 // "use asm" directive itself doesn't necessarily imply this kind.
61 // e.g. arrow function with "use asm" becomes Arrow kind,
63 // See EstablishPreconditions in js/src/wasm/AsmJS.cpp
66 // An exported WebAssembly function.
72 enum Flags
: uint16_t {
73 // FunctionKind enum value.
74 FUNCTION_KIND_SHIFT
= 0,
75 FUNCTION_KIND_MASK
= 0x0007,
77 // The AllocKind used was FunctionExtended and extra slots were allocated.
78 // These slots may be used by the engine or the embedding so care must be
79 // taken to avoid conflicts.
81 // This flag is used both by scripted functions and native functions.
84 // Set if function is a self-hosted builtin or intrinsic. An 'intrinsic'
85 // here means a native function used inside self-hosted code. In general, a
86 // self-hosted function should appear to script as though it were a native
90 // An interpreted function has or may-have bytecode and an environment. Only
91 // one of these flags may be used at a time. As a memory optimization, the
92 // SELFHOSTLAZY flag indicates there is no js::BaseScript at all and we must
93 // clone from the self-hosted realm in order to get bytecode.
95 SELFHOSTLAZY
= 1 << 6,
97 // Function may be called as a constructor. This corresponds in the spec as
98 // having a [[Construct]] internal method.
100 // e.g. FunctionDeclaration has this flag, but GeneratorDeclaration doesn't
103 // This flag is used both by scripted functions and native functions.
105 // WARNING: This is independent from FunctionKind::ClassConstructor.
106 CONSTRUCTOR
= 1 << 7,
108 // Function is either getter or setter, with "get " or "set " prefix,
109 // but JSFunction::AtomSlot contains unprefixed name, and the function name
110 // is lazily constructed on the first access.
111 LAZY_ACCESSOR_NAME
= 1 << 8,
113 // Function comes from a FunctionExpression, ArrowFunction, or Function()
114 // call (not a FunctionDeclaration).
116 // This flag is used only by scripted functions and AsmJS.
119 // The WASM function has a JIT entry which emulates the
120 // js::BaseScript::jitCodeRaw mechanism.
121 WASM_JIT_ENTRY
= 1 << 10,
123 // Function had no explicit name, but a name was set by SetFunctionName at
124 // compile time or SetFunctionName at runtime.
126 // This flag can be used both by scripted functions and native functions.
127 HAS_INFERRED_NAME
= 1 << 11,
129 // Function had no explicit name, but a name was guessed for it anyway.
131 // This flag is used only by scripted function.
132 HAS_GUESSED_ATOM
= 1 << 12,
134 // The 'length' or 'name property has been resolved. See fun_resolve.
136 // These flags are used both by scripted functions and native functions.
137 RESOLVED_NAME
= 1 << 13,
138 RESOLVED_LENGTH
= 1 << 14,
140 // This function is kept only for skipping it over during delazification.
142 // This function is inside arrow function's parameter expression, and
143 // parsed twice, once before finding "=>" token, and once after finding
144 // "=>" and rewinding to the beginning of the parameters.
145 // ScriptStencil is created for both case, and the first one is kept only
146 // for delazification, to make sure delazification sees the same sequence
147 // of inner function to skip over.
149 // We call the first one "ghost".
150 // It should be kept lazy, and shouldn't be exposed to debugger.
152 // This flag is used only by scripted functions.
153 GHOST_FUNCTION
= 1 << 15,
155 // Shifted form of FunctionKinds.
156 NORMAL_KIND
= NormalFunction
<< FUNCTION_KIND_SHIFT
,
157 ASMJS_KIND
= AsmJS
<< FUNCTION_KIND_SHIFT
,
158 WASM_KIND
= Wasm
<< FUNCTION_KIND_SHIFT
,
159 ARROW_KIND
= Arrow
<< FUNCTION_KIND_SHIFT
,
160 METHOD_KIND
= Method
<< FUNCTION_KIND_SHIFT
,
161 CLASSCONSTRUCTOR_KIND
= ClassConstructor
<< FUNCTION_KIND_SHIFT
,
162 GETTER_KIND
= Getter
<< FUNCTION_KIND_SHIFT
,
163 SETTER_KIND
= Setter
<< FUNCTION_KIND_SHIFT
,
165 // Derived Flags combinations to use when creating functions.
166 NATIVE_FUN
= NORMAL_KIND
,
167 NATIVE_CTOR
= CONSTRUCTOR
| NORMAL_KIND
,
168 NATIVE_GETTER_WITH_LAZY_NAME
= LAZY_ACCESSOR_NAME
| GETTER_KIND
,
169 NATIVE_SETTER_WITH_LAZY_NAME
= LAZY_ACCESSOR_NAME
| SETTER_KIND
,
170 ASMJS_CTOR
= CONSTRUCTOR
| ASMJS_KIND
,
171 ASMJS_LAMBDA_CTOR
= CONSTRUCTOR
| LAMBDA
| ASMJS_KIND
,
173 INTERPRETED_NORMAL
= BASESCRIPT
| CONSTRUCTOR
| NORMAL_KIND
,
174 INTERPRETED_CLASS_CTOR
= BASESCRIPT
| CONSTRUCTOR
| CLASSCONSTRUCTOR_KIND
,
175 INTERPRETED_GENERATOR_OR_ASYNC
= BASESCRIPT
| NORMAL_KIND
,
176 INTERPRETED_LAMBDA
= BASESCRIPT
| LAMBDA
| CONSTRUCTOR
| NORMAL_KIND
,
177 INTERPRETED_LAMBDA_ARROW
= BASESCRIPT
| LAMBDA
| ARROW_KIND
,
178 INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC
= BASESCRIPT
| LAMBDA
| NORMAL_KIND
,
179 INTERPRETED_GETTER
= BASESCRIPT
| GETTER_KIND
,
180 INTERPRETED_SETTER
= BASESCRIPT
| SETTER_KIND
,
181 INTERPRETED_METHOD
= BASESCRIPT
| METHOD_KIND
,
183 // Flags that XDR ignores. See also: js::BaseScript::MutableFlags.
184 MUTABLE_FLAGS
= RESOLVED_NAME
| RESOLVED_LENGTH
,
186 // Flags preserved when cloning a function.
187 STABLE_ACROSS_CLONES
=
188 CONSTRUCTOR
| LAMBDA
| SELF_HOSTED
| FUNCTION_KIND_MASK
| GHOST_FUNCTION
194 FunctionFlags() : flags_() {
195 static_assert(sizeof(FunctionFlags
) == sizeof(flags_
),
196 "No extra members allowed is it'll grow JSFunction");
197 static_assert(offsetof(FunctionFlags
, flags_
) == 0,
198 "Required for JIT flag access");
201 explicit FunctionFlags(uint16_t flags
) : flags_(flags
) {}
202 MOZ_IMPLICIT
FunctionFlags(Flags f
) : flags_(f
) {}
204 static_assert(((FunctionKindLimit
- 1) << FUNCTION_KIND_SHIFT
) <=
206 "FunctionKind doesn't fit into flags_");
208 uint16_t toRaw() const { return flags_
; }
210 uint16_t stableAcrossClones() const { return flags_
& STABLE_ACROSS_CLONES
; }
212 // For flag combinations the type is int.
213 bool hasFlags(uint16_t flags
) const { return flags_
& flags
; }
214 FunctionFlags
& setFlags(uint16_t flags
) {
218 FunctionFlags
& clearFlags(uint16_t flags
) {
222 FunctionFlags
& setFlags(uint16_t flags
, bool set
) {
231 FunctionKind
kind() const {
232 return static_cast<FunctionKind
>((flags_
& FUNCTION_KIND_MASK
) >>
233 FUNCTION_KIND_SHIFT
);
237 void assertFunctionKindIntegrity() {
239 case FunctionKind::NormalFunction
:
240 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME
));
241 MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY
));
244 case FunctionKind::Arrow
:
245 MOZ_ASSERT(hasFlags(BASESCRIPT
) || hasFlags(SELFHOSTLAZY
));
246 MOZ_ASSERT(!hasFlags(CONSTRUCTOR
));
247 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME
));
248 MOZ_ASSERT(hasFlags(LAMBDA
));
249 MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY
));
251 case FunctionKind::Method
:
252 MOZ_ASSERT(hasFlags(BASESCRIPT
) || hasFlags(SELFHOSTLAZY
));
253 MOZ_ASSERT(!hasFlags(CONSTRUCTOR
));
254 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME
));
255 MOZ_ASSERT(!hasFlags(LAMBDA
));
256 MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY
));
258 case FunctionKind::ClassConstructor
:
259 MOZ_ASSERT(hasFlags(BASESCRIPT
) || hasFlags(SELFHOSTLAZY
));
260 MOZ_ASSERT(hasFlags(CONSTRUCTOR
));
261 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME
));
262 MOZ_ASSERT(!hasFlags(LAMBDA
));
263 MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY
));
265 case FunctionKind::Getter
:
266 MOZ_ASSERT(!hasFlags(CONSTRUCTOR
));
267 MOZ_ASSERT(!hasFlags(LAMBDA
));
268 MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY
));
270 case FunctionKind::Setter
:
271 MOZ_ASSERT(!hasFlags(CONSTRUCTOR
));
272 MOZ_ASSERT(!hasFlags(LAMBDA
));
273 MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY
));
276 case FunctionKind::AsmJS
:
277 MOZ_ASSERT(!hasFlags(BASESCRIPT
));
278 MOZ_ASSERT(!hasFlags(SELFHOSTLAZY
));
279 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME
));
280 MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY
));
282 case FunctionKind::Wasm
:
283 MOZ_ASSERT(!hasFlags(BASESCRIPT
));
284 MOZ_ASSERT(!hasFlags(SELFHOSTLAZY
));
285 MOZ_ASSERT(!hasFlags(CONSTRUCTOR
));
286 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME
));
287 MOZ_ASSERT(!hasFlags(LAMBDA
));
295 /* A function can be classified as either native (C++) or interpreted (JS): */
296 bool isInterpreted() const {
297 return hasFlags(BASESCRIPT
) || hasFlags(SELFHOSTLAZY
);
299 bool isNativeFun() const { return !isInterpreted(); }
301 bool isConstructor() const { return hasFlags(CONSTRUCTOR
); }
303 bool isNonBuiltinConstructor() const {
304 // Note: keep this in sync with branchIfNotFunctionIsNonBuiltinCtor in
305 // MacroAssembler.cpp.
306 return hasFlags(BASESCRIPT
) && hasFlags(CONSTRUCTOR
) &&
307 !hasFlags(SELF_HOSTED
);
310 /* Possible attributes of a native function: */
311 bool isAsmJSNative() const {
312 MOZ_ASSERT_IF(kind() == AsmJS
, isNativeFun());
313 return kind() == AsmJS
;
315 bool isWasm() const {
316 MOZ_ASSERT_IF(kind() == Wasm
, isNativeFun());
317 return kind() == Wasm
;
319 bool isWasmWithJitEntry() const {
320 MOZ_ASSERT_IF(hasFlags(WASM_JIT_ENTRY
), isWasm());
321 return hasFlags(WASM_JIT_ENTRY
);
323 bool isNativeWithoutJitEntry() const {
324 MOZ_ASSERT_IF(!hasJitEntry(), isNativeFun());
325 return !hasJitEntry();
327 bool isBuiltinNative() const {
328 return isNativeFun() && !isAsmJSNative() && !isWasm();
330 bool hasJitEntry() const {
331 return hasBaseScript() || hasSelfHostedLazyScript() || isWasmWithJitEntry();
334 /* Possible attributes of an interpreted function: */
335 bool hasInferredName() const { return hasFlags(HAS_INFERRED_NAME
); }
336 bool hasGuessedAtom() const { return hasFlags(HAS_GUESSED_ATOM
); }
337 bool isLambda() const { return hasFlags(LAMBDA
); }
339 bool isNamedLambda(bool hasName
) const {
340 return hasName
&& isLambda() && !hasInferredName() && !hasGuessedAtom();
343 // These methods determine which of the u.scripted.s union arms are active.
344 // For live JSFunctions the pointer values will always be non-null, but due
345 // to partial initialization the GC (and other features that scan the heap
346 // directly) may still return a null pointer.
347 bool hasBaseScript() const { return hasFlags(BASESCRIPT
); }
348 bool hasSelfHostedLazyScript() const { return hasFlags(SELFHOSTLAZY
); }
350 // Arrow functions store their lexical new.target in the first extended slot.
351 bool isArrow() const { return kind() == Arrow
; }
352 // Every class-constructor is also a method.
353 bool isMethod() const {
354 return kind() == Method
|| kind() == ClassConstructor
;
356 bool isClassConstructor() const { return kind() == ClassConstructor
; }
358 bool isGetter() const { return kind() == Getter
; }
359 bool isSetter() const { return kind() == Setter
; }
361 bool isAccessorWithLazyName() const { return hasFlags(LAZY_ACCESSOR_NAME
); }
363 bool allowSuperProperty() const {
364 return isMethod() || isGetter() || isSetter();
367 bool hasResolvedLength() const { return hasFlags(RESOLVED_LENGTH
); }
368 bool hasResolvedName() const { return hasFlags(RESOLVED_NAME
); }
370 bool isSelfHostedOrIntrinsic() const { return hasFlags(SELF_HOSTED
); }
371 bool isSelfHostedBuiltin() const {
372 return isSelfHostedOrIntrinsic() && !isNativeFun();
374 bool isIntrinsic() const {
375 return isSelfHostedOrIntrinsic() && isNativeFun();
378 FunctionFlags
& setKind(FunctionKind kind
) {
379 this->flags_
&= ~FUNCTION_KIND_MASK
;
380 this->flags_
|= static_cast<uint16_t>(kind
) << FUNCTION_KIND_SHIFT
;
384 // Make the function constructible.
385 FunctionFlags
& setIsConstructor() {
386 MOZ_ASSERT(!isConstructor());
387 MOZ_ASSERT(isSelfHostedBuiltin());
388 return setFlags(CONSTRUCTOR
);
391 FunctionFlags
& setIsSelfHostedBuiltin() {
392 MOZ_ASSERT(isInterpreted());
393 MOZ_ASSERT(!isSelfHostedBuiltin());
394 setFlags(SELF_HOSTED
);
395 // Self-hosted functions should not be constructable.
396 return clearFlags(CONSTRUCTOR
);
398 FunctionFlags
& setIsIntrinsic() {
399 MOZ_ASSERT(isNativeFun());
400 MOZ_ASSERT(!isIntrinsic());
401 return setFlags(SELF_HOSTED
);
404 FunctionFlags
& setResolvedLength() { return setFlags(RESOLVED_LENGTH
); }
405 FunctionFlags
& setResolvedName() { return setFlags(RESOLVED_NAME
); }
407 FunctionFlags
& setInferredName() { return setFlags(HAS_INFERRED_NAME
); }
409 FunctionFlags
& setGuessedAtom() { return setFlags(HAS_GUESSED_ATOM
); }
411 FunctionFlags
& setSelfHostedLazy() { return setFlags(SELFHOSTLAZY
); }
412 FunctionFlags
& clearSelfHostedLazy() { return clearFlags(SELFHOSTLAZY
); }
413 FunctionFlags
& setBaseScript() { return setFlags(BASESCRIPT
); }
414 FunctionFlags
& clearBaseScript() { return clearFlags(BASESCRIPT
); }
416 FunctionFlags
& clearLazyAccessorName() {
417 return clearFlags(LAZY_ACCESSOR_NAME
);
420 FunctionFlags
& setWasmJitEntry() { return setFlags(WASM_JIT_ENTRY
); }
422 bool isExtended() const { return hasFlags(EXTENDED
); }
423 FunctionFlags
& setIsExtended() { return setFlags(EXTENDED
); }
425 bool isNativeConstructor() const { return hasFlags(NATIVE_CTOR
); }
427 FunctionFlags
& setIsGhost() { return setFlags(GHOST_FUNCTION
); }
428 bool isGhost() const { return hasFlags(GHOST_FUNCTION
); }
430 static uint16_t HasJitEntryFlags(bool isConstructing
) {
431 uint16_t flags
= BASESCRIPT
| SELFHOSTLAZY
;
432 if (!isConstructing
) {
433 flags
|= WASM_JIT_ENTRY
;
438 static FunctionFlags
clearMutableflags(FunctionFlags flags
) {
439 return FunctionFlags(flags
.toRaw() & ~FunctionFlags::MUTABLE_FLAGS
);
445 #endif /* vm_FunctionFlags_h */