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/. */ 6 7 #ifndef vm_FunctionFlags_h 8 #define vm_FunctionFlags_h 9 10 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_ASSERT_IF 11 #include "mozilla/Attributes.h" // MOZ_IMPLICIT 12 13 #include <stdint.h> // uint8_t, uint16_t 14 15 #include "jstypes.h" // JS_PUBLIC_API 16 17 class JS_PUBLIC_API JSAtom; 18 19 namespace js { 20 21 class FunctionFlags { 22 public: 23 enum FunctionKind : uint8_t { 24 NormalFunction = 0, 25 Arrow, // ES6 '(args) => body' syntax 26 Method, // ES6 MethodDefinition 27 ClassConstructor, 28 Getter, 29 Setter, 30 AsmJS, // An asm.js module or exported function 31 Wasm, // An exported WebAssembly function 32 FunctionKindLimit 33 }; 34 35 enum Flags : uint16_t { 36 // The general kind of a function. This is used to describe characteristics 37 // of functions that do not merit a dedicated flag bit below. 38 FUNCTION_KIND_SHIFT = 0, 39 FUNCTION_KIND_MASK = 0x0007, 40 41 // The AllocKind used was FunctionExtended and extra slots were allocated. 42 // These slots may be used by the engine or the embedding so care must be 43 // taken to avoid conflicts. 44 EXTENDED = 1 << 3, 45 46 // Set if function is a self-hosted builtin or intrinsic. An 'intrinsic' 47 // here means a native function used inside self-hosted code. In general, a 48 // self-hosted function should appear to script as though it were a native 49 // builtin. 50 SELF_HOSTED = 1 << 4, 51 52 // An interpreted function has or may-have bytecode and an environment. Only 53 // one of these flags may be used at a time. As a memory optimization, the 54 // SELFHOSTLAZY flag indicates there is no js::BaseScript at all and we must 55 // clone from the self-hosted realm in order to get bytecode. 56 BASESCRIPT = 1 << 5, 57 SELFHOSTLAZY = 1 << 6, 58 59 // Function may be called as a constructor. This corresponds in the spec as 60 // having a [[Construct]] internal method. 61 CONSTRUCTOR = 1 << 7, 62 63 // A 'Bound Function Exotic Object' created by Function.prototype.bind. 64 BOUND_FUN = 1 << 8, 65 66 // Function comes from a FunctionExpression, ArrowFunction, or Function() 67 // call (not a FunctionDeclaration or nonstandard function-statement). 68 LAMBDA = 1 << 9, 69 70 // The WASM function has a JIT entry which emulates the 71 // js::BaseScript::jitCodeRaw mechanism. 72 WASM_JIT_ENTRY = 1 << 10, 73 74 // Function had no explicit name, but a name was set by SetFunctionName at 75 // compile time or SetFunctionName at runtime. 76 HAS_INFERRED_NAME = 1 << 11, 77 78 // Function had no explicit name, but a name was guessed for it anyway. For 79 // a Bound function, tracks if atom_ already contains the "bound " prefix. 80 ATOM_EXTRA_FLAG = 1 << 12, 81 HAS_GUESSED_ATOM = ATOM_EXTRA_FLAG, 82 HAS_BOUND_FUNCTION_NAME_PREFIX = ATOM_EXTRA_FLAG, 83 84 // The 'length' or 'name property has been resolved. See fun_resolve. 85 RESOLVED_NAME = 1 << 13, 86 RESOLVED_LENGTH = 1 << 14, 87 88 // For a function used as an interpreted constructor, whether a 'new' type 89 // had constructor information cleared. 90 NEW_SCRIPT_CLEARED = 1 << 15, 91 92 // Shifted form of FunctionKinds. 93 NORMAL_KIND = NormalFunction << FUNCTION_KIND_SHIFT, 94 ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT, 95 WASM_KIND = Wasm << FUNCTION_KIND_SHIFT, 96 ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT, 97 METHOD_KIND = Method << FUNCTION_KIND_SHIFT, 98 CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT, 99 GETTER_KIND = Getter << FUNCTION_KIND_SHIFT, 100 SETTER_KIND = Setter << FUNCTION_KIND_SHIFT, 101 102 // Derived Flags combinations to use when creating functions. 103 NATIVE_FUN = NORMAL_KIND, 104 NATIVE_CTOR = CONSTRUCTOR | NORMAL_KIND, 105 ASMJS_CTOR = CONSTRUCTOR | ASMJS_KIND, 106 ASMJS_LAMBDA_CTOR = CONSTRUCTOR | LAMBDA | ASMJS_KIND, 107 WASM = WASM_KIND, 108 INTERPRETED_NORMAL = BASESCRIPT | CONSTRUCTOR | NORMAL_KIND, 109 INTERPRETED_CLASS_CTOR = BASESCRIPT | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND, 110 INTERPRETED_GENERATOR_OR_ASYNC = BASESCRIPT | NORMAL_KIND, 111 INTERPRETED_LAMBDA = BASESCRIPT | LAMBDA | CONSTRUCTOR | NORMAL_KIND, 112 INTERPRETED_LAMBDA_ARROW = BASESCRIPT | LAMBDA | ARROW_KIND, 113 INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = BASESCRIPT | LAMBDA | NORMAL_KIND, 114 INTERPRETED_GETTER = BASESCRIPT | GETTER_KIND, 115 INTERPRETED_SETTER = BASESCRIPT | SETTER_KIND, 116 INTERPRETED_METHOD = BASESCRIPT | METHOD_KIND, 117 118 // Flags that XDR ignores. See also: js::BaseScript::MutableFlags. 119 MUTABLE_FLAGS = RESOLVED_NAME | RESOLVED_LENGTH | NEW_SCRIPT_CLEARED, 120 121 // Flags preserved when cloning a function. (Exception: 122 // js::MakeDefaultConstructor produces default constructors for ECMAScript 123 // classes by cloning self-hosted functions, and then clearing their 124 // SELF_HOSTED bit, setting their CONSTRUCTOR bit, and otherwise munging 125 // them to look like they originated with the class definition.) */ 126 STABLE_ACROSS_CLONES = 127 CONSTRUCTOR | LAMBDA | SELF_HOSTED | FUNCTION_KIND_MASK 128 }; 129 130 uint16_t flags_; 131 132 public: FunctionFlags()133 FunctionFlags() : flags_() { 134 static_assert(sizeof(FunctionFlags) == sizeof(flags_), 135 "No extra members allowed is it'll grow JSFunction"); 136 static_assert(offsetof(FunctionFlags, flags_) == 0, 137 "Required for JIT flag access"); 138 } 139 FunctionFlags(uint16_t flags)140 explicit FunctionFlags(uint16_t flags) : flags_(flags) {} FunctionFlags(Flags f)141 MOZ_IMPLICIT FunctionFlags(Flags f) : flags_(f) {} 142 143 static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= 144 FUNCTION_KIND_MASK, 145 "FunctionKind doesn't fit into flags_"); 146 toRaw()147 uint16_t toRaw() const { return flags_; } 148 stableAcrossClones()149 uint16_t stableAcrossClones() const { return flags_ & STABLE_ACROSS_CLONES; } 150 151 // For flag combinations the type is int. hasFlags(uint16_t flags)152 bool hasFlags(uint16_t flags) const { return flags_ & flags; } setFlags(uint16_t flags)153 void setFlags(uint16_t flags) { flags_ |= flags; } clearFlags(uint16_t flags)154 void clearFlags(uint16_t flags) { flags_ &= ~flags; } setFlags(uint16_t flags,bool set)155 void setFlags(uint16_t flags, bool set) { 156 if (set) { 157 setFlags(flags); 158 } else { 159 clearFlags(flags); 160 } 161 } 162 kind()163 FunctionKind kind() const { 164 return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> 165 FUNCTION_KIND_SHIFT); 166 } 167 168 /* A function can be classified as either native (C++) or interpreted (JS): */ isInterpreted()169 bool isInterpreted() const { 170 return hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY); 171 } isNative()172 bool isNative() const { return !isInterpreted(); } 173 isConstructor()174 bool isConstructor() const { return hasFlags(CONSTRUCTOR); } 175 176 /* Possible attributes of a native function: */ isAsmJSNative()177 bool isAsmJSNative() const { 178 MOZ_ASSERT_IF(kind() == AsmJS, isNative()); 179 return kind() == AsmJS; 180 } isWasm()181 bool isWasm() const { 182 MOZ_ASSERT_IF(kind() == Wasm, isNative()); 183 return kind() == Wasm; 184 } isWasmWithJitEntry()185 bool isWasmWithJitEntry() const { 186 MOZ_ASSERT_IF(hasFlags(WASM_JIT_ENTRY), isWasm()); 187 return hasFlags(WASM_JIT_ENTRY); 188 } isNativeWithJitEntry()189 bool isNativeWithJitEntry() const { 190 MOZ_ASSERT_IF(isWasmWithJitEntry(), isNative()); 191 return isWasmWithJitEntry(); 192 } isBuiltinNative()193 bool isBuiltinNative() const { 194 return isNative() && !isAsmJSNative() && !isWasm(); 195 } 196 197 /* Possible attributes of an interpreted function: */ isBoundFunction()198 bool isBoundFunction() const { return hasFlags(BOUND_FUN); } hasInferredName()199 bool hasInferredName() const { return hasFlags(HAS_INFERRED_NAME); } hasGuessedAtom()200 bool hasGuessedAtom() const { 201 static_assert(HAS_GUESSED_ATOM == HAS_BOUND_FUNCTION_NAME_PREFIX, 202 "HAS_GUESSED_ATOM is unused for bound functions"); 203 bool hasGuessedAtom = hasFlags(HAS_GUESSED_ATOM); 204 bool boundFun = hasFlags(BOUND_FUN); 205 return hasGuessedAtom && !boundFun; 206 } hasBoundFunctionNamePrefix()207 bool hasBoundFunctionNamePrefix() const { 208 static_assert( 209 HAS_BOUND_FUNCTION_NAME_PREFIX == HAS_GUESSED_ATOM, 210 "HAS_BOUND_FUNCTION_NAME_PREFIX is only used for bound functions"); 211 MOZ_ASSERT(isBoundFunction()); 212 return hasFlags(HAS_BOUND_FUNCTION_NAME_PREFIX); 213 } isLambda()214 bool isLambda() const { return hasFlags(LAMBDA); } 215 isNamedLambda(bool hasName)216 bool isNamedLambda(bool hasName) const { 217 return hasName && isLambda() && !hasInferredName() && !hasGuessedAtom(); 218 } 219 220 // These methods determine which of the u.scripted.s union arms are active. 221 // For live JSFunctions the pointer values will always be non-null, but due 222 // to partial initialization the GC (and other features that scan the heap 223 // directly) may still return a null pointer. hasBaseScript()224 bool hasBaseScript() const { return hasFlags(BASESCRIPT); } hasSelfHostedLazyScript()225 bool hasSelfHostedLazyScript() const { return hasFlags(SELFHOSTLAZY); } 226 227 // Arrow functions store their lexical new.target in the first extended slot. isArrow()228 bool isArrow() const { return kind() == Arrow; } 229 // Every class-constructor is also a method. isMethod()230 bool isMethod() const { 231 return kind() == Method || kind() == ClassConstructor; 232 } isClassConstructor()233 bool isClassConstructor() const { return kind() == ClassConstructor; } 234 isGetter()235 bool isGetter() const { return kind() == Getter; } isSetter()236 bool isSetter() const { return kind() == Setter; } 237 allowSuperProperty()238 bool allowSuperProperty() const { 239 return isMethod() || isGetter() || isSetter(); 240 } 241 hasResolvedLength()242 bool hasResolvedLength() const { return hasFlags(RESOLVED_LENGTH); } hasResolvedName()243 bool hasResolvedName() const { return hasFlags(RESOLVED_NAME); } 244 isSelfHostedOrIntrinsic()245 bool isSelfHostedOrIntrinsic() const { return hasFlags(SELF_HOSTED); } isSelfHostedBuiltin()246 bool isSelfHostedBuiltin() const { 247 return isSelfHostedOrIntrinsic() && !isNative(); 248 } isIntrinsic()249 bool isIntrinsic() const { return isSelfHostedOrIntrinsic() && isNative(); } 250 setKind(FunctionKind kind)251 void setKind(FunctionKind kind) { 252 this->flags_ &= ~FUNCTION_KIND_MASK; 253 this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT; 254 } 255 256 // Make the function constructible. setIsConstructor()257 void setIsConstructor() { 258 MOZ_ASSERT(!isConstructor()); 259 MOZ_ASSERT(isSelfHostedBuiltin()); 260 setFlags(CONSTRUCTOR); 261 } 262 setIsClassConstructor()263 void setIsClassConstructor() { 264 MOZ_ASSERT(!isClassConstructor()); 265 MOZ_ASSERT(isConstructor()); 266 267 setKind(ClassConstructor); 268 } 269 setIsBoundFunction()270 void setIsBoundFunction() { 271 MOZ_ASSERT(!isBoundFunction()); 272 setFlags(BOUND_FUN); 273 } 274 setIsSelfHostedBuiltin()275 void setIsSelfHostedBuiltin() { 276 MOZ_ASSERT(isInterpreted()); 277 MOZ_ASSERT(!isSelfHostedBuiltin()); 278 setFlags(SELF_HOSTED); 279 // Self-hosted functions should not be constructable. 280 clearFlags(CONSTRUCTOR); 281 } setIsIntrinsic()282 void setIsIntrinsic() { 283 MOZ_ASSERT(isNative()); 284 MOZ_ASSERT(!isIntrinsic()); 285 setFlags(SELF_HOSTED); 286 } 287 setResolvedLength()288 void setResolvedLength() { setFlags(RESOLVED_LENGTH); } setResolvedName()289 void setResolvedName() { setFlags(RESOLVED_NAME); } 290 291 // Mark a function as having its 'new' script information cleared. wasNewScriptCleared()292 bool wasNewScriptCleared() const { return hasFlags(NEW_SCRIPT_CLEARED); } setNewScriptCleared()293 void setNewScriptCleared() { setFlags(NEW_SCRIPT_CLEARED); } 294 setInferredName()295 void setInferredName() { setFlags(HAS_INFERRED_NAME); } clearInferredName()296 void clearInferredName() { clearFlags(HAS_INFERRED_NAME); } 297 setGuessedAtom()298 void setGuessedAtom() { setFlags(HAS_GUESSED_ATOM); } 299 setPrefixedBoundFunctionName()300 void setPrefixedBoundFunctionName() { 301 setFlags(HAS_BOUND_FUNCTION_NAME_PREFIX); 302 } 303 setSelfHostedLazy()304 void setSelfHostedLazy() { setFlags(SELFHOSTLAZY); } clearSelfHostedLazy()305 void clearSelfHostedLazy() { clearFlags(SELFHOSTLAZY); } setBaseScript()306 void setBaseScript() { setFlags(BASESCRIPT); } clearBaseScript()307 void clearBaseScript() { clearFlags(BASESCRIPT); } 308 setWasmJitEntry()309 void setWasmJitEntry() { setFlags(WASM_JIT_ENTRY); } 310 isExtended()311 bool isExtended() const { return hasFlags(EXTENDED); } setIsExtended()312 void setIsExtended() { setFlags(EXTENDED); } 313 isNativeConstructor()314 bool isNativeConstructor() const { return hasFlags(NATIVE_CTOR); } 315 }; 316 317 } /* namespace js */ 318 319 #endif /* vm_FunctionFlags_h */ 320