summaryrefslogtreecommitdiffstats
path: root/js/src/vm/FunctionFlags.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/FunctionFlags.h')
-rw-r--r--js/src/vm/FunctionFlags.h445
1 files changed, 445 insertions, 0 deletions
diff --git a/js/src/vm/FunctionFlags.h b/js/src/vm/FunctionFlags.h
new file mode 100644
index 0000000000..d927056230
--- /dev/null
+++ b/js/src/vm/FunctionFlags.h
@@ -0,0 +1,445 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_FunctionFlags_h
+#define vm_FunctionFlags_h
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_ASSERT_IF
+#include "mozilla/Attributes.h" // MOZ_IMPLICIT
+
+#include <stdint.h> // uint8_t, uint16_t
+
+#include "jstypes.h" // JS_PUBLIC_API
+
+class JS_PUBLIC_API JSAtom;
+
+namespace js {
+
+class FunctionFlags {
+ public:
+ // Syntactic characteristics of a function.
+ enum FunctionKind : uint8_t {
+ // Regular function that doesn't match any of the other kinds.
+ //
+ // This kind is used by the following scipted functions:
+ // * FunctionDeclaration
+ // * FunctionExpression
+ // * Function created from Function() call or its variants
+ //
+ // Also all native functions excluding AsmJS and Wasm use this kind.
+ NormalFunction = 0,
+
+ // ES6 '(args) => body' syntax.
+ // This kind is used only by scripted function.
+ Arrow,
+
+ // ES6 MethodDefinition syntax.
+ // This kind is used only by scripted function.
+ Method,
+
+ // Class constructor syntax, or default constructor.
+ // This kind is used only by scripted function and default constructor.
+ //
+ // WARNING: This is independent from Flags::CONSTRUCTOR.
+ ClassConstructor,
+
+ // Getter and setter syntax in objects or classes, or
+ // native getter and setter created from JSPropertySpec.
+ // This kind is used both by scripted functions and native functions.
+ Getter,
+ Setter,
+
+ // An asm.js module or exported function.
+ //
+ // This kind is used only by scripted function, and used only when the
+ // asm.js module is created.
+ //
+ // "use asm" directive itself doesn't necessarily imply this kind.
+ // e.g. arrow function with "use asm" becomes Arrow kind,
+ //
+ // See EstablishPreconditions in js/src/wasm/AsmJS.cpp
+ AsmJS,
+
+ // An exported WebAssembly function.
+ Wasm,
+
+ FunctionKindLimit
+ };
+
+ enum Flags : uint16_t {
+ // FunctionKind enum value.
+ FUNCTION_KIND_SHIFT = 0,
+ FUNCTION_KIND_MASK = 0x0007,
+
+ // The AllocKind used was FunctionExtended and extra slots were allocated.
+ // These slots may be used by the engine or the embedding so care must be
+ // taken to avoid conflicts.
+ //
+ // This flag is used both by scripted functions and native functions.
+ EXTENDED = 1 << 3,
+
+ // Set if function is a self-hosted builtin or intrinsic. An 'intrinsic'
+ // here means a native function used inside self-hosted code. In general, a
+ // self-hosted function should appear to script as though it were a native
+ // builtin.
+ SELF_HOSTED = 1 << 4,
+
+ // An interpreted function has or may-have bytecode and an environment. Only
+ // one of these flags may be used at a time. As a memory optimization, the
+ // SELFHOSTLAZY flag indicates there is no js::BaseScript at all and we must
+ // clone from the self-hosted realm in order to get bytecode.
+ BASESCRIPT = 1 << 5,
+ SELFHOSTLAZY = 1 << 6,
+
+ // Function may be called as a constructor. This corresponds in the spec as
+ // having a [[Construct]] internal method.
+ //
+ // e.g. FunctionDeclaration has this flag, but GeneratorDeclaration doesn't
+ // have this flag.
+ //
+ // This flag is used both by scripted functions and native functions.
+ //
+ // WARNING: This is independent from FunctionKind::ClassConstructor.
+ CONSTRUCTOR = 1 << 7,
+
+ // Function is either getter or setter, with "get " or "set " prefix,
+ // but JSFunction::AtomSlot contains unprefixed name, and the function name
+ // is lazily constructed on the first access.
+ LAZY_ACCESSOR_NAME = 1 << 8,
+
+ // Function comes from a FunctionExpression, ArrowFunction, or Function()
+ // call (not a FunctionDeclaration).
+ //
+ // This flag is used only by scripted functions and AsmJS.
+ LAMBDA = 1 << 9,
+
+ // The WASM function has a JIT entry which emulates the
+ // js::BaseScript::jitCodeRaw mechanism.
+ WASM_JIT_ENTRY = 1 << 10,
+
+ // Function had no explicit name, but a name was set by SetFunctionName at
+ // compile time or SetFunctionName at runtime.
+ //
+ // This flag can be used both by scripted functions and native functions.
+ HAS_INFERRED_NAME = 1 << 11,
+
+ // Function had no explicit name, but a name was guessed for it anyway.
+ //
+ // This flag is used only by scripted function.
+ HAS_GUESSED_ATOM = 1 << 12,
+
+ // The 'length' or 'name property has been resolved. See fun_resolve.
+ //
+ // These flags are used both by scripted functions and native functions.
+ RESOLVED_NAME = 1 << 13,
+ RESOLVED_LENGTH = 1 << 14,
+
+ // This function is kept only for skipping it over during delazification.
+ //
+ // This function is inside arrow function's parameter expression, and
+ // parsed twice, once before finding "=>" token, and once after finding
+ // "=>" and rewinding to the beginning of the parameters.
+ // ScriptStencil is created for both case, and the first one is kept only
+ // for delazification, to make sure delazification sees the same sequence
+ // of inner function to skip over.
+ //
+ // We call the first one "ghost".
+ // It should be kept lazy, and shouldn't be exposed to debugger.
+ //
+ // This flag is used only by scripted functions.
+ GHOST_FUNCTION = 1 << 15,
+
+ // Shifted form of FunctionKinds.
+ NORMAL_KIND = NormalFunction << FUNCTION_KIND_SHIFT,
+ ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
+ WASM_KIND = Wasm << FUNCTION_KIND_SHIFT,
+ ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
+ METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
+ CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
+ GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
+ SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
+
+ // Derived Flags combinations to use when creating functions.
+ NATIVE_FUN = NORMAL_KIND,
+ NATIVE_CTOR = CONSTRUCTOR | NORMAL_KIND,
+ NATIVE_GETTER_WITH_LAZY_NAME = LAZY_ACCESSOR_NAME | GETTER_KIND,
+ NATIVE_SETTER_WITH_LAZY_NAME = LAZY_ACCESSOR_NAME | SETTER_KIND,
+ ASMJS_CTOR = CONSTRUCTOR | ASMJS_KIND,
+ ASMJS_LAMBDA_CTOR = CONSTRUCTOR | LAMBDA | ASMJS_KIND,
+ WASM = WASM_KIND,
+ INTERPRETED_NORMAL = BASESCRIPT | CONSTRUCTOR | NORMAL_KIND,
+ INTERPRETED_CLASS_CTOR = BASESCRIPT | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
+ INTERPRETED_GENERATOR_OR_ASYNC = BASESCRIPT | NORMAL_KIND,
+ INTERPRETED_LAMBDA = BASESCRIPT | LAMBDA | CONSTRUCTOR | NORMAL_KIND,
+ INTERPRETED_LAMBDA_ARROW = BASESCRIPT | LAMBDA | ARROW_KIND,
+ INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = BASESCRIPT | LAMBDA | NORMAL_KIND,
+ INTERPRETED_GETTER = BASESCRIPT | GETTER_KIND,
+ INTERPRETED_SETTER = BASESCRIPT | SETTER_KIND,
+ INTERPRETED_METHOD = BASESCRIPT | METHOD_KIND,
+
+ // Flags that XDR ignores. See also: js::BaseScript::MutableFlags.
+ MUTABLE_FLAGS = RESOLVED_NAME | RESOLVED_LENGTH,
+
+ // Flags preserved when cloning a function.
+ STABLE_ACROSS_CLONES =
+ CONSTRUCTOR | LAMBDA | SELF_HOSTED | FUNCTION_KIND_MASK | GHOST_FUNCTION
+ };
+
+ uint16_t flags_;
+
+ public:
+ FunctionFlags() : flags_() {
+ static_assert(sizeof(FunctionFlags) == sizeof(flags_),
+ "No extra members allowed is it'll grow JSFunction");
+ static_assert(offsetof(FunctionFlags, flags_) == 0,
+ "Required for JIT flag access");
+ }
+
+ explicit FunctionFlags(uint16_t flags) : flags_(flags) {}
+ MOZ_IMPLICIT FunctionFlags(Flags f) : flags_(f) {}
+
+ static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <=
+ FUNCTION_KIND_MASK,
+ "FunctionKind doesn't fit into flags_");
+
+ uint16_t toRaw() const { return flags_; }
+
+ uint16_t stableAcrossClones() const { return flags_ & STABLE_ACROSS_CLONES; }
+
+ // For flag combinations the type is int.
+ bool hasFlags(uint16_t flags) const { return flags_ & flags; }
+ FunctionFlags& setFlags(uint16_t flags) {
+ flags_ |= flags;
+ return *this;
+ }
+ FunctionFlags& clearFlags(uint16_t flags) {
+ flags_ &= ~flags;
+ return *this;
+ }
+ FunctionFlags& setFlags(uint16_t flags, bool set) {
+ if (set) {
+ setFlags(flags);
+ } else {
+ clearFlags(flags);
+ }
+ return *this;
+ }
+
+ FunctionKind kind() const {
+ return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >>
+ FUNCTION_KIND_SHIFT);
+ }
+
+#ifdef DEBUG
+ void assertFunctionKindIntegrity() {
+ switch (kind()) {
+ case FunctionKind::NormalFunction:
+ MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
+ MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY));
+ break;
+
+ case FunctionKind::Arrow:
+ MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY));
+ MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
+ MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
+ MOZ_ASSERT(hasFlags(LAMBDA));
+ MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY));
+ break;
+ case FunctionKind::Method:
+ MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY));
+ MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
+ MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
+ MOZ_ASSERT(!hasFlags(LAMBDA));
+ MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY));
+ break;
+ case FunctionKind::ClassConstructor:
+ MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY));
+ MOZ_ASSERT(hasFlags(CONSTRUCTOR));
+ MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
+ MOZ_ASSERT(!hasFlags(LAMBDA));
+ MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY));
+ break;
+ case FunctionKind::Getter:
+ MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
+ MOZ_ASSERT(!hasFlags(LAMBDA));
+ MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY));
+ break;
+ case FunctionKind::Setter:
+ MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
+ MOZ_ASSERT(!hasFlags(LAMBDA));
+ MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY));
+ break;
+
+ case FunctionKind::AsmJS:
+ MOZ_ASSERT(!hasFlags(BASESCRIPT));
+ MOZ_ASSERT(!hasFlags(SELFHOSTLAZY));
+ MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
+ MOZ_ASSERT(!hasFlags(WASM_JIT_ENTRY));
+ break;
+ case FunctionKind::Wasm:
+ MOZ_ASSERT(!hasFlags(BASESCRIPT));
+ MOZ_ASSERT(!hasFlags(SELFHOSTLAZY));
+ MOZ_ASSERT(!hasFlags(CONSTRUCTOR));
+ MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME));
+ MOZ_ASSERT(!hasFlags(LAMBDA));
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+
+ /* A function can be classified as either native (C++) or interpreted (JS): */
+ bool isInterpreted() const {
+ return hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY);
+ }
+ bool isNativeFun() const { return !isInterpreted(); }
+
+ bool isConstructor() const { return hasFlags(CONSTRUCTOR); }
+
+ bool isNonBuiltinConstructor() const {
+ // Note: keep this in sync with branchIfNotFunctionIsNonBuiltinCtor in
+ // MacroAssembler.cpp.
+ return hasFlags(BASESCRIPT) && hasFlags(CONSTRUCTOR) &&
+ !hasFlags(SELF_HOSTED);
+ }
+
+ /* Possible attributes of a native function: */
+ bool isAsmJSNative() const {
+ MOZ_ASSERT_IF(kind() == AsmJS, isNativeFun());
+ return kind() == AsmJS;
+ }
+ bool isWasm() const {
+ MOZ_ASSERT_IF(kind() == Wasm, isNativeFun());
+ return kind() == Wasm;
+ }
+ bool isWasmWithJitEntry() const {
+ MOZ_ASSERT_IF(hasFlags(WASM_JIT_ENTRY), isWasm());
+ return hasFlags(WASM_JIT_ENTRY);
+ }
+ bool isNativeWithoutJitEntry() const {
+ MOZ_ASSERT_IF(!hasJitEntry(), isNativeFun());
+ return !hasJitEntry();
+ }
+ bool isBuiltinNative() const {
+ return isNativeFun() && !isAsmJSNative() && !isWasm();
+ }
+ bool hasJitEntry() const {
+ return hasBaseScript() || hasSelfHostedLazyScript() || isWasmWithJitEntry();
+ }
+
+ /* Possible attributes of an interpreted function: */
+ bool hasInferredName() const { return hasFlags(HAS_INFERRED_NAME); }
+ bool hasGuessedAtom() const { return hasFlags(HAS_GUESSED_ATOM); }
+ bool isLambda() const { return hasFlags(LAMBDA); }
+
+ bool isNamedLambda(bool hasName) const {
+ return hasName && isLambda() && !hasInferredName() && !hasGuessedAtom();
+ }
+
+ // These methods determine which of the u.scripted.s union arms are active.
+ // For live JSFunctions the pointer values will always be non-null, but due
+ // to partial initialization the GC (and other features that scan the heap
+ // directly) may still return a null pointer.
+ bool hasBaseScript() const { return hasFlags(BASESCRIPT); }
+ bool hasSelfHostedLazyScript() const { return hasFlags(SELFHOSTLAZY); }
+
+ // Arrow functions store their lexical new.target in the first extended slot.
+ bool isArrow() const { return kind() == Arrow; }
+ // Every class-constructor is also a method.
+ bool isMethod() const {
+ return kind() == Method || kind() == ClassConstructor;
+ }
+ bool isClassConstructor() const { return kind() == ClassConstructor; }
+
+ bool isGetter() const { return kind() == Getter; }
+ bool isSetter() const { return kind() == Setter; }
+
+ bool isAccessorWithLazyName() const { return hasFlags(LAZY_ACCESSOR_NAME); }
+
+ bool allowSuperProperty() const {
+ return isMethod() || isGetter() || isSetter();
+ }
+
+ bool hasResolvedLength() const { return hasFlags(RESOLVED_LENGTH); }
+ bool hasResolvedName() const { return hasFlags(RESOLVED_NAME); }
+
+ bool isSelfHostedOrIntrinsic() const { return hasFlags(SELF_HOSTED); }
+ bool isSelfHostedBuiltin() const {
+ return isSelfHostedOrIntrinsic() && !isNativeFun();
+ }
+ bool isIntrinsic() const {
+ return isSelfHostedOrIntrinsic() && isNativeFun();
+ }
+
+ FunctionFlags& setKind(FunctionKind kind) {
+ this->flags_ &= ~FUNCTION_KIND_MASK;
+ this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
+ return *this;
+ }
+
+ // Make the function constructible.
+ FunctionFlags& setIsConstructor() {
+ MOZ_ASSERT(!isConstructor());
+ MOZ_ASSERT(isSelfHostedBuiltin());
+ return setFlags(CONSTRUCTOR);
+ }
+
+ FunctionFlags& setIsSelfHostedBuiltin() {
+ MOZ_ASSERT(isInterpreted());
+ MOZ_ASSERT(!isSelfHostedBuiltin());
+ setFlags(SELF_HOSTED);
+ // Self-hosted functions should not be constructable.
+ return clearFlags(CONSTRUCTOR);
+ }
+ FunctionFlags& setIsIntrinsic() {
+ MOZ_ASSERT(isNativeFun());
+ MOZ_ASSERT(!isIntrinsic());
+ return setFlags(SELF_HOSTED);
+ }
+
+ FunctionFlags& setResolvedLength() { return setFlags(RESOLVED_LENGTH); }
+ FunctionFlags& setResolvedName() { return setFlags(RESOLVED_NAME); }
+
+ FunctionFlags& setInferredName() { return setFlags(HAS_INFERRED_NAME); }
+
+ FunctionFlags& setGuessedAtom() { return setFlags(HAS_GUESSED_ATOM); }
+
+ FunctionFlags& setSelfHostedLazy() { return setFlags(SELFHOSTLAZY); }
+ FunctionFlags& clearSelfHostedLazy() { return clearFlags(SELFHOSTLAZY); }
+ FunctionFlags& setBaseScript() { return setFlags(BASESCRIPT); }
+ FunctionFlags& clearBaseScript() { return clearFlags(BASESCRIPT); }
+
+ FunctionFlags& clearLazyAccessorName() {
+ return clearFlags(LAZY_ACCESSOR_NAME);
+ }
+
+ FunctionFlags& setWasmJitEntry() { return setFlags(WASM_JIT_ENTRY); }
+
+ bool isExtended() const { return hasFlags(EXTENDED); }
+ FunctionFlags& setIsExtended() { return setFlags(EXTENDED); }
+
+ bool isNativeConstructor() const { return hasFlags(NATIVE_CTOR); }
+
+ FunctionFlags& setIsGhost() { return setFlags(GHOST_FUNCTION); }
+ bool isGhost() const { return hasFlags(GHOST_FUNCTION); }
+
+ static uint16_t HasJitEntryFlags(bool isConstructing) {
+ uint16_t flags = BASESCRIPT | SELFHOSTLAZY;
+ if (!isConstructing) {
+ flags |= WASM_JIT_ENTRY;
+ }
+ return flags;
+ }
+
+ static FunctionFlags clearMutableflags(FunctionFlags flags) {
+ return FunctionFlags(flags.toRaw() & ~FunctionFlags::MUTABLE_FLAGS);
+ }
+};
+
+} /* namespace js */
+
+#endif /* vm_FunctionFlags_h */