FunctionFlags.h (16262B)
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 // Syntactic characteristics of a function. 24 enum FunctionKind : uint8_t { 25 // Regular function that doesn't match any of the other kinds. 26 // 27 // This kind is used by the following scipted functions: 28 // * FunctionDeclaration 29 // * FunctionExpression 30 // * Function created from Function() call or its variants 31 // 32 // Also all native functions excluding AsmJS and Wasm use this kind. 33 NormalFunction = 0, 34 35 // ES6 '(args) => body' syntax. 36 // This kind is used only by scripted function. 37 Arrow, 38 39 // ES6 MethodDefinition syntax. 40 // This kind is used only by scripted function. 41 Method, 42 43 // Class constructor syntax, or default constructor. 44 // This kind is used only by scripted function and default constructor. 45 // 46 // WARNING: This is independent from Flags::CONSTRUCTOR. 47 ClassConstructor, 48 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. 52 Getter, 53 Setter, 54 55 // An asm.js module or exported function. 56 // 57 // This kind is used only by scripted function, and used only when the 58 // asm.js module is created. 59 // 60 // "use asm" directive itself doesn't necessarily imply this kind. 61 // e.g. arrow function with "use asm" becomes Arrow kind, 62 // 63 // See EstablishPreconditions in js/src/wasm/AsmJS.cpp 64 AsmJS, 65 66 // An exported WebAssembly function. 67 Wasm, 68 69 FunctionKindLimit 70 }; 71 72 enum Flags : uint16_t { 73 // FunctionKind enum value. 74 FUNCTION_KIND_SHIFT = 0, 75 FUNCTION_KIND_MASK = 0x0007, 76 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. 80 // 81 // This flag is used both by scripted functions and native functions. 82 EXTENDED = 1 << 3, 83 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 87 // builtin. 88 SELF_HOSTED = 1 << 4, 89 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. 94 BASESCRIPT = 1 << 5, 95 SELFHOSTLAZY = 1 << 6, 96 97 // This Native function has a JIT entry which emulates the 98 // js::BaseScript::jitCodeRaw mechanism. Used for Wasm functions and 99 // TrampolineNative builtins. 100 NATIVE_JIT_ENTRY = 1 << 7, 101 102 // Function may be called as a constructor. This corresponds in the spec as 103 // having a [[Construct]] internal method. 104 // 105 // e.g. FunctionDeclaration has this flag, but GeneratorDeclaration doesn't 106 // have this flag. 107 // 108 // This flag is used both by scripted functions and native functions. 109 // 110 // WARNING: This is independent from FunctionKind::ClassConstructor. 111 CONSTRUCTOR = 1 << 8, 112 113 // Function comes from a FunctionExpression, ArrowFunction, or Function() 114 // call (not a FunctionDeclaration). 115 // 116 // This flag is used only by scripted functions and AsmJS. 117 LAMBDA = 1 << 9, 118 119 // Function is either getter or setter, with "get " or "set " prefix, 120 // but JSFunction::AtomSlot contains unprefixed name, and the function name 121 // is lazily constructed on the first access. 122 LAZY_ACCESSOR_NAME = 1 << 10, 123 124 // Function had no explicit name, but a name was set by SetFunctionName at 125 // compile time or SetFunctionName at runtime. 126 // 127 // This flag can be used both by scripted functions and native functions. 128 HAS_INFERRED_NAME = 1 << 11, 129 130 // Function had no explicit name, but a name was guessed for it anyway. 131 // 132 // This flag is used only by scripted function. 133 HAS_GUESSED_ATOM = 1 << 12, 134 135 // The 'length' or 'name property has been resolved. See fun_resolve. 136 // 137 // These flags are used both by scripted functions and native functions. 138 RESOLVED_NAME = 1 << 13, 139 RESOLVED_LENGTH = 1 << 14, 140 141 // This function is kept only for skipping it over during delazification. 142 // 143 // This function is inside arrow function's parameter expression, and 144 // parsed twice, once before finding "=>" token, and once after finding 145 // "=>" and rewinding to the beginning of the parameters. 146 // ScriptStencil is created for both case, and the first one is kept only 147 // for delazification, to make sure delazification sees the same sequence 148 // of inner function to skip over. 149 // 150 // We call the first one "ghost". 151 // It should be kept lazy, and shouldn't be exposed to debugger. 152 // 153 // This flag is used only by scripted functions. 154 GHOST_FUNCTION = 1 << 15, 155 156 // Shifted form of FunctionKinds. 157 NORMAL_KIND = NormalFunction << FUNCTION_KIND_SHIFT, 158 ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT, 159 WASM_KIND = Wasm << FUNCTION_KIND_SHIFT, 160 ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT, 161 METHOD_KIND = Method << FUNCTION_KIND_SHIFT, 162 CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT, 163 GETTER_KIND = Getter << FUNCTION_KIND_SHIFT, 164 SETTER_KIND = Setter << FUNCTION_KIND_SHIFT, 165 166 // Derived Flags combinations to use when creating functions. 167 NATIVE_FUN = NORMAL_KIND, 168 NATIVE_CTOR = CONSTRUCTOR | NORMAL_KIND, 169 NATIVE_GETTER_WITH_LAZY_NAME = LAZY_ACCESSOR_NAME | GETTER_KIND, 170 NATIVE_SETTER_WITH_LAZY_NAME = LAZY_ACCESSOR_NAME | SETTER_KIND, 171 ASMJS_CTOR = CONSTRUCTOR | ASMJS_KIND, 172 ASMJS_LAMBDA_CTOR = CONSTRUCTOR | LAMBDA | ASMJS_KIND, 173 WASM = WASM_KIND, 174 INTERPRETED_NORMAL = BASESCRIPT | CONSTRUCTOR | NORMAL_KIND, 175 INTERPRETED_CLASS_CTOR = BASESCRIPT | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND, 176 INTERPRETED_GENERATOR_OR_ASYNC = BASESCRIPT | NORMAL_KIND, 177 INTERPRETED_LAMBDA = BASESCRIPT | LAMBDA | CONSTRUCTOR | NORMAL_KIND, 178 INTERPRETED_LAMBDA_ARROW = BASESCRIPT | LAMBDA | ARROW_KIND, 179 INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = BASESCRIPT | LAMBDA | NORMAL_KIND, 180 INTERPRETED_GETTER = BASESCRIPT | GETTER_KIND, 181 INTERPRETED_SETTER = BASESCRIPT | SETTER_KIND, 182 INTERPRETED_METHOD = BASESCRIPT | METHOD_KIND, 183 184 // Flags that XDR ignores. See also: js::BaseScript::MutableFlags. 185 MUTABLE_FLAGS = RESOLVED_NAME | RESOLVED_LENGTH, 186 187 // Flags preserved when cloning a function. 188 STABLE_ACROSS_CLONES = 189 CONSTRUCTOR | LAMBDA | SELF_HOSTED | FUNCTION_KIND_MASK | GHOST_FUNCTION 190 }; 191 192 uint16_t flags_; 193 194 public: 195 FunctionFlags() : flags_() { 196 static_assert(sizeof(FunctionFlags) == sizeof(flags_), 197 "No extra members allowed is it'll grow JSFunction"); 198 static_assert(offsetof(FunctionFlags, flags_) == 0, 199 "Required for JIT flag access"); 200 } 201 202 explicit FunctionFlags(uint16_t flags) : flags_(flags) {} 203 MOZ_IMPLICIT FunctionFlags(Flags f) : flags_(f) {} 204 205 static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= 206 FUNCTION_KIND_MASK, 207 "FunctionKind doesn't fit into flags_"); 208 209 uint16_t toRaw() const { return flags_; } 210 211 uint16_t stableAcrossClones() const { return flags_ & STABLE_ACROSS_CLONES; } 212 213 // For flag combinations the type is int. 214 bool hasFlags(uint16_t flags) const { return flags_ & flags; } 215 FunctionFlags& setFlags(uint16_t flags) { 216 flags_ |= flags; 217 return *this; 218 } 219 FunctionFlags& clearFlags(uint16_t flags) { 220 flags_ &= ~flags; 221 return *this; 222 } 223 FunctionFlags& setFlags(uint16_t flags, bool set) { 224 if (set) { 225 setFlags(flags); 226 } else { 227 clearFlags(flags); 228 } 229 return *this; 230 } 231 232 FunctionKind kind() const { 233 return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> 234 FUNCTION_KIND_SHIFT); 235 } 236 237 #ifdef DEBUG 238 void assertFunctionKindIntegrity() { 239 switch (kind()) { 240 case FunctionKind::NormalFunction: 241 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME)); 242 MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY)); 243 break; 244 245 case FunctionKind::Arrow: 246 MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY)); 247 MOZ_ASSERT(!hasFlags(CONSTRUCTOR)); 248 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME)); 249 MOZ_ASSERT(hasFlags(LAMBDA)); 250 MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY)); 251 break; 252 case FunctionKind::Method: 253 MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY)); 254 MOZ_ASSERT(!hasFlags(CONSTRUCTOR)); 255 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME)); 256 MOZ_ASSERT(!hasFlags(LAMBDA)); 257 MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY)); 258 break; 259 case FunctionKind::ClassConstructor: 260 MOZ_ASSERT(hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY)); 261 MOZ_ASSERT(hasFlags(CONSTRUCTOR)); 262 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME)); 263 MOZ_ASSERT(!hasFlags(LAMBDA)); 264 MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY)); 265 break; 266 case FunctionKind::Getter: 267 MOZ_ASSERT(!hasFlags(CONSTRUCTOR)); 268 MOZ_ASSERT(!hasFlags(LAMBDA)); 269 MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY)); 270 break; 271 case FunctionKind::Setter: 272 MOZ_ASSERT(!hasFlags(CONSTRUCTOR)); 273 MOZ_ASSERT(!hasFlags(LAMBDA)); 274 MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY)); 275 break; 276 277 case FunctionKind::AsmJS: 278 MOZ_ASSERT(!hasFlags(BASESCRIPT)); 279 MOZ_ASSERT(!hasFlags(SELFHOSTLAZY)); 280 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME)); 281 MOZ_ASSERT(!hasFlags(NATIVE_JIT_ENTRY)); 282 break; 283 case FunctionKind::Wasm: 284 MOZ_ASSERT(!hasFlags(BASESCRIPT)); 285 MOZ_ASSERT(!hasFlags(SELFHOSTLAZY)); 286 MOZ_ASSERT(!hasFlags(CONSTRUCTOR)); 287 MOZ_ASSERT(!hasFlags(LAZY_ACCESSOR_NAME)); 288 MOZ_ASSERT(!hasFlags(LAMBDA)); 289 break; 290 default: 291 break; 292 } 293 } 294 #endif 295 296 /* A function can be classified as either native (C++) or interpreted (JS): */ 297 bool isInterpreted() const { 298 return hasFlags(BASESCRIPT) || hasFlags(SELFHOSTLAZY); 299 } 300 bool isNativeFun() const { return !isInterpreted(); } 301 302 bool isConstructor() const { return hasFlags(CONSTRUCTOR); } 303 304 bool isNonBuiltinConstructor() const { 305 // Note: keep this in sync with branchIfNotFunctionIsNonBuiltinCtor in 306 // MacroAssembler.cpp. 307 return hasFlags(BASESCRIPT) && hasFlags(CONSTRUCTOR) && 308 !hasFlags(SELF_HOSTED); 309 } 310 311 /* Possible attributes of a native function: */ 312 bool isAsmJSNative() const { 313 MOZ_ASSERT_IF(kind() == AsmJS, isNativeFun()); 314 return kind() == AsmJS; 315 } 316 bool isWasm() const { 317 MOZ_ASSERT_IF(kind() == Wasm, isNativeFun()); 318 return kind() == Wasm; 319 } 320 bool isNativeWithJitEntry() const { 321 MOZ_ASSERT_IF(hasFlags(NATIVE_JIT_ENTRY), isNativeFun()); 322 return hasFlags(NATIVE_JIT_ENTRY); 323 } 324 bool isWasmWithJitEntry() const { return isWasm() && isNativeWithJitEntry(); } 325 bool isNativeWithoutJitEntry() const { 326 MOZ_ASSERT_IF(!hasJitEntry(), isNativeFun()); 327 return !hasJitEntry(); 328 } 329 bool isBuiltinNative() const { 330 return isNativeFun() && !isAsmJSNative() && !isWasm(); 331 } 332 bool hasJitEntry() const { 333 return hasBaseScript() || hasSelfHostedLazyScript() || 334 isNativeWithJitEntry(); 335 } 336 337 bool canHaveJitInfo() const { 338 // A native builtin can have a pointer to either its JitEntry or JSJitInfo, 339 // but not both. 340 return isBuiltinNative() && !isNativeWithJitEntry(); 341 } 342 343 /* Possible attributes of an interpreted function: */ 344 bool hasInferredName() const { return hasFlags(HAS_INFERRED_NAME); } 345 bool hasGuessedAtom() const { return hasFlags(HAS_GUESSED_ATOM); } 346 bool isLambda() const { return hasFlags(LAMBDA); } 347 348 bool isNamedLambda(bool hasName) const { 349 return hasName && isLambda() && !hasInferredName() && !hasGuessedAtom(); 350 } 351 352 // These methods determine which of the u.scripted.s union arms are active. 353 // For live JSFunctions the pointer values will always be non-null, but due 354 // to partial initialization the GC (and other features that scan the heap 355 // directly) may still return a null pointer. 356 bool hasBaseScript() const { return hasFlags(BASESCRIPT); } 357 bool hasSelfHostedLazyScript() const { return hasFlags(SELFHOSTLAZY); } 358 359 // Arrow functions store their lexical new.target in the first extended slot. 360 bool isArrow() const { return kind() == Arrow; } 361 // Every class-constructor is also a method. 362 bool isMethod() const { 363 return kind() == Method || kind() == ClassConstructor; 364 } 365 bool isClassConstructor() const { return kind() == ClassConstructor; } 366 367 bool isGetter() const { return kind() == Getter; } 368 bool isSetter() const { return kind() == Setter; } 369 370 bool isAccessorWithLazyName() const { return hasFlags(LAZY_ACCESSOR_NAME); } 371 372 bool allowSuperProperty() const { 373 return isMethod() || isGetter() || isSetter(); 374 } 375 376 bool hasResolvedLength() const { return hasFlags(RESOLVED_LENGTH); } 377 bool hasResolvedName() const { return hasFlags(RESOLVED_NAME); } 378 379 bool isSelfHostedOrIntrinsic() const { return hasFlags(SELF_HOSTED); } 380 bool isSelfHostedBuiltin() const { 381 return isSelfHostedOrIntrinsic() && !isNativeFun(); 382 } 383 bool isIntrinsic() const { 384 return isSelfHostedOrIntrinsic() && isNativeFun(); 385 } 386 387 FunctionFlags& setKind(FunctionKind kind) { 388 this->flags_ &= ~FUNCTION_KIND_MASK; 389 this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT; 390 return *this; 391 } 392 393 // Make the function constructible. 394 FunctionFlags& setIsConstructor() { 395 MOZ_ASSERT(!isConstructor()); 396 MOZ_ASSERT(isSelfHostedBuiltin()); 397 return setFlags(CONSTRUCTOR); 398 } 399 400 FunctionFlags& setIsSelfHostedBuiltin() { 401 MOZ_ASSERT(isInterpreted()); 402 MOZ_ASSERT(!isSelfHostedBuiltin()); 403 setFlags(SELF_HOSTED); 404 // Self-hosted functions should not be constructable. 405 return clearFlags(CONSTRUCTOR); 406 } 407 FunctionFlags& setIsIntrinsic() { 408 MOZ_ASSERT(isNativeFun()); 409 MOZ_ASSERT(!isIntrinsic()); 410 return setFlags(SELF_HOSTED); 411 } 412 413 FunctionFlags& setResolvedLength() { return setFlags(RESOLVED_LENGTH); } 414 FunctionFlags& setResolvedName() { return setFlags(RESOLVED_NAME); } 415 416 FunctionFlags& setInferredName() { return setFlags(HAS_INFERRED_NAME); } 417 418 FunctionFlags& setGuessedAtom() { return setFlags(HAS_GUESSED_ATOM); } 419 420 FunctionFlags& setSelfHostedLazy() { return setFlags(SELFHOSTLAZY); } 421 FunctionFlags& clearSelfHostedLazy() { return clearFlags(SELFHOSTLAZY); } 422 FunctionFlags& setBaseScript() { return setFlags(BASESCRIPT); } 423 FunctionFlags& clearBaseScript() { return clearFlags(BASESCRIPT); } 424 425 FunctionFlags& clearLazyAccessorName() { 426 return clearFlags(LAZY_ACCESSOR_NAME); 427 } 428 429 FunctionFlags& setNativeJitEntry() { return setFlags(NATIVE_JIT_ENTRY); } 430 431 bool isExtended() const { return hasFlags(EXTENDED); } 432 FunctionFlags& setIsExtended() { return setFlags(EXTENDED); } 433 434 bool isNativeConstructor() const { return hasFlags(NATIVE_CTOR); } 435 436 FunctionFlags& setIsGhost() { return setFlags(GHOST_FUNCTION); } 437 bool isGhost() const { return hasFlags(GHOST_FUNCTION); } 438 439 static constexpr uint16_t HasJitEntryFlags() { 440 return BASESCRIPT | SELFHOSTLAZY | NATIVE_JIT_ENTRY; 441 } 442 443 static FunctionFlags clearMutableflags(FunctionFlags flags) { 444 return FunctionFlags(flags.toRaw() & ~FunctionFlags::MUTABLE_FLAGS); 445 } 446 }; 447 448 } /* namespace js */ 449 450 #endif /* vm_FunctionFlags_h */