// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be: // Context found in the LICENSE file. #include 'src/builtins/builtins-regexp-gen.h' #include 'src/builtins/builtins-utils-gen.h' #include 'src/builtins/builtins.h' #include 'src/codegen/code-factory.h' #include 'src/heap/factory-inl.h' #include 'src/objects/arguments.h' #include 'src/objects/bigint.h' #include 'src/objects/elements-kind.h' #include 'src/objects/free-space.h' #include 'src/objects/js-function.h' #include 'src/objects/js-generator.h' #include 'src/objects/js-promise.h' #include 'src/objects/js-regexp-string-iterator.h' #include 'src/objects/js-weak-refs.h' #include 'src/objects/objects.h' #include 'src/objects/source-text-module.h' #include 'src/objects/stack-frame-info.h' #include 'src/objects/synthetic-module.h' #include 'src/objects/template-objects.h' #include 'src/torque/runtime-support.h' type void; type never; type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject'; type StrongTagged extends Tagged generates 'TNode<Object>' constexpr 'Object'; type Smi extends StrongTagged generates 'TNode<Smi>' constexpr 'Smi'; type TaggedIndex extends StrongTagged generates 'TNode<TaggedIndex>' constexpr 'TaggedIndex'; // A possibly cleared weak pointer with a bit pattern that distinguishes it from // strong HeapObject pointers and Smi values. type WeakHeapObject extends Tagged; type Weak<T : type extends HeapObject> extends WeakHeapObject; type Object = Smi|HeapObject; type MaybeObject = Smi|HeapObject|WeakHeapObject; // A Smi that is greater than or equal to 0. See TaggedIsPositiveSmi. type PositiveSmi extends Smi; // The Smi value zero, which is often used as null for HeapObject types. type Zero extends PositiveSmi; // A tagged value represented by an all-zero bitpattern. type TaggedZeroPattern extends TaggedIndex; // A value with the size of Tagged which may contain arbitrary data. type Uninitialized extends Tagged; extern macro MakeWeak(HeapObject): WeakHeapObject; extern macro GetHeapObjectAssumeWeak(MaybeObject): HeapObject labels IfCleared; extern macro GetHeapObjectIfStrong(MaybeObject): HeapObject labels IfNotStrong; extern macro IsWeakOrCleared(MaybeObject): bool; extern macro IsWeakReferenceToObject(MaybeObject, Object): bool; extern macro IsStrong(MaybeObject): bool; macro StrongToWeak<T: type>(x: T): Weak<T> { return %RawDownCast<Weak<T>>(MakeWeak(x)); } macro WeakToStrong<T: type>(x: Weak<T>): T labels ClearedWeakPointer { const x = GetHeapObjectAssumeWeak(x) otherwise ClearedWeakPointer; return %RawDownCast<T>(x); } // Defined to coincide with https://tc39.es/ecma262/#sec-ispropertykey // Doesn't include PrivateSymbol. type PropertyKey = String|PublicSymbol; // TODO(turbofan): PrivateSymbol is only exposed to JavaScript through the // debugger API. We should reconsider this and try not to expose it at all. Then // JSAny would not need to contain it. // A JavaScript primitive value as defined in // https://tc39.es/ecma262/#sec-primitive-value. type JSPrimitive = Numeric|String|Symbol|Boolean|Null|Undefined; // A user-exposed JavaScript value, as opposed to V8-internal values like // TheHole or FixedArray. type JSAny = JSReceiver|JSPrimitive; type JSAnyNotNumeric = String|Symbol|Boolean|Null|Undefined|JSReceiver; type JSAnyNotNumber = BigInt|JSAnyNotNumeric; // This is the intersection of JSAny and HeapObject. type JSAnyNotSmi = JSAnyNotNumber|HeapNumber; type int32 generates 'TNode<Int32T>' constexpr 'int32_t'; type uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t'; type int31 extends int32 generates 'TNode<Int32T>' constexpr 'int31_t'; type uint31 extends uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t'; type int16 extends int31 generates 'TNode<Int16T>' constexpr 'int16_t'; type uint16 extends uint31 generates 'TNode<Uint16T>' constexpr 'uint16_t'; type int8 extends int16 generates 'TNode<Int8T>' constexpr 'int8_t'; type uint8 extends uint16 generates 'TNode<Uint8T>' constexpr 'uint8_t'; type char8 extends uint8 constexpr 'char'; type char16 extends uint16 constexpr 'char16_t'; type int64 generates 'TNode<Int64T>' constexpr 'int64_t'; type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t'; type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t'; type float32 generates 'TNode<Float32T>' constexpr 'float'; type float64 generates 'TNode<Float64T>' constexpr 'double'; type bool generates 'TNode<BoolT>' constexpr 'bool'; type bint generates 'TNode<BInt>' constexpr 'BInt'; type string constexpr 'const char*'; // A Smi value containing a bitfield struct as its integer data. @useParentTypeChecker type SmiTagged<T : type extends uint31> extends Smi; // WARNING: The memory representation (i.e., in class fields and arrays) of // float64_or_hole is just a float64 that may be the hole-representing // signalling NaN bit-pattern. So it's memory size is that of float64 and // loading and storing float64_or_hole emits special code. struct float64_or_hole { macro Value(): float64 labels IfHole { if (this.is_hole) { goto IfHole; } return this.value; } macro ValueUnsafeAssumeNotHole(): float64 { assert(!this.is_hole); return this.value; } is_hole: bool; value: float64; } const kDoubleHole: float64_or_hole = float64_or_hole{is_hole: true, value: 0}; @doNotGenerateCast @abstract extern class JSPrototype extends JSObject generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSObjectPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSRegExpPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSPromisePrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSTypedArrayPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSSetPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSIteratorPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSArrayIteratorPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSMapIteratorPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSSetIteratorPrototype extends JSPrototype generates 'TNode<JSObject>'; @doNotGenerateCast extern class JSStringIteratorPrototype extends JSPrototype generates 'TNode<JSObject>'; // The HashTable inheritance hierarchy doesn't actually look like this in C++ // because it uses some class templates that we can't yet (and may never) // express in Torque, but this is the expected organization of instance types. @doNotGenerateCast extern class HashTable extends FixedArray generates 'TNode<FixedArray>'; extern class OrderedHashMap extends HashTable; extern class OrderedHashSet extends HashTable; extern class OrderedNameDictionary extends HashTable; extern class NameDictionary extends HashTable; extern class GlobalDictionary extends HashTable; extern class SimpleNumberDictionary extends HashTable; extern class EphemeronHashTable extends HashTable; type ObjectHashTable extends HashTable generates 'TNode<ObjectHashTable>'; extern class NumberDictionary extends HashTable; type RawPtr generates 'TNode<RawPtrT>' constexpr 'Address'; type RawPtr<To: type> extends RawPtr; type ExternalPointer generates 'TNode<ExternalPointerT>' constexpr 'ExternalPointer_t'; extern class Code extends HeapObject; type BuiltinPtr extends Smi generates 'TNode<BuiltinPtr>'; type Number = Smi|HeapNumber; type Numeric = Number|BigInt; extern class ObjectBoilerplateDescription extends FixedArray; extern class ClosureFeedbackCellArray extends FixedArray; extern class ScriptContextTable extends FixedArray; type LayoutDescriptor extends ByteArray generates 'TNode<LayoutDescriptor>'; extern class TransitionArray extends WeakFixedArray; extern operator '.length_intptr' macro LoadAndUntagWeakFixedArrayLength( WeakFixedArray): intptr; type InstanceType extends uint16 constexpr 'InstanceType'; type NoSharedNameSentinel extends Smi; // Specialized types. The following three type definitions don't correspond to // actual C++ classes, but have Is... methods that check additional constraints. // A Foreign object whose raw pointer is not allowed to be null. type NonNullForeign extends Foreign; // A function built with InstantiateFunction for the public API. type CallableApiObject extends JSObject; // A JSProxy with the callable bit set. type CallableJSProxy extends JSProxy; type Callable = JSFunction|JSBoundFunction|CallableJSProxy|CallableApiObject; type WriteBarrierMode generates 'TNode<Int32T>' constexpr 'WriteBarrierMode'; extern enum UnicodeEncoding { UTF16, UTF32 } // Promise constants extern enum PromiseState extends int31 constexpr 'Promise::PromiseState' { kPending, kFulfilled, kRejected } type FrameArray extends FixedArray; const kTaggedSize: constexpr int31 generates 'kTaggedSize'; const kDoubleSize: constexpr int31 generates 'kDoubleSize'; const kVariableSizeSentinel: constexpr int31 generates 'kVariableSizeSentinel'; const kSmiTagSize: constexpr int31 generates 'kSmiTagSize'; const kHeapObjectTag: constexpr int31 generates 'kHeapObjectTag'; const V8_INFINITY: constexpr float64 generates 'V8_INFINITY'; const MINUS_V8_INFINITY: constexpr float64 generates '-V8_INFINITY'; extern enum ElementsKind extends int32 { NO_ELEMENTS, PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS, HOLEY_ELEMENTS, PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS, LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND, DICTIONARY_ELEMENTS, UINT8_ELEMENTS, INT8_ELEMENTS, UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS, INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS, UINT8_CLAMPED_ELEMENTS, BIGUINT64_ELEMENTS, BIGINT64_ELEMENTS, ... } extern enum AllocationFlag extends int32 constexpr 'CodeStubAssembler::AllocationFlag' { kNone, kDoubleAlignment, kPretenured, kAllowLargeObjectAllocation } extern enum SlackTrackingMode constexpr 'CodeStubAssembler::SlackTrackingMode' { kWithSlackTracking, kNoSlackTracking } extern enum ExtractFixedArrayFlag constexpr 'CodeStubAssembler::ExtractFixedArrayFlag' { kFixedDoubleArrays, kAllFixedArrays, kFixedArrays, ... } const kBigIntMaxLength: constexpr intptr generates 'BigInt::kMaxLength'; extern enum MessageTemplate { kAllPromisesRejected, kInvalidArrayBufferLength, kInvalidArrayLength, kInvalidIndex, kNotConstructor, kNotGeneric, kCalledNonCallable, kCalledOnNullOrUndefined, kCannotConvertToPrimitive, kProtoObjectOrNull, kInvalidOffset, kInvalidTypedArrayLength, kIteratorSymbolNonCallable, kIteratorValueNotAnObject, kNotIterable, kReduceNoInitial, kFirstArgumentNotRegExp, kBigIntMixedTypes, kTypedArrayTooShort, kTypedArrayTooLargeToSort, kInvalidCountValue, kConstructorNotFunction, kSymbolToString, kPropertyNotFunction, kBigIntTooBig, kNotTypedArray, kDetachedOperation, kBadSortComparisonFunction, kIncompatibleMethodReceiver, kInvalidDataViewAccessorOffset, kTypedArraySetOffsetOutOfBounds, kInvalidArgument, kInvalidRegExpExecResult, kRegExpNonRegExp, kRegExpNonObject, kPromiseNonCallable, kNotAPromise, kResolverNotAFunction, kTooManyElementsInPromiseCombinator, kToRadixFormatRange, kCalledOnNonObject, kRegExpGlobalInvokedOnNonGlobal, kProxyNonObject, kProxyRevoked, kProxyTrapReturnedFalsishFor, kProxyPrivate, kProxyIsExtensibleInconsistent, kProxyPreventExtensionsExtensible, kProxyTrapReturnedFalsish, kProxyGetPrototypeOfInvalid, kProxyGetPrototypeOfNonExtensible, kProxySetPrototypeOfNonExtensible, kProxyDeletePropertyNonExtensible, kUndefinedOrNullToObject, kWeakRefsCleanupMustBeCallable, kWasmTrapUnreachable, kWasmTrapMemOutOfBounds, kWasmTrapUnalignedAccess, kWasmTrapDivByZero, kWasmTrapDivUnrepresentable, kWasmTrapRemByZero, kWasmTrapFloatUnrepresentable, kWasmTrapFuncSigMismatch, kWasmTrapDataSegmentDropped, kWasmTrapElemSegmentDropped, kWasmTrapTableOutOfBounds, kWasmTrapRethrowNull, kWasmTrapNullDereference, kWasmTrapIllegalCast, kWasmTrapArrayOutOfBounds, kWeakRefsRegisterTargetAndHoldingsMustNotBeSame, kWeakRefsRegisterTargetMustBeObject, kWeakRefsUnregisterTokenMustBeObject, kWeakRefsWeakRefConstructorTargetMustBeObject, ... } extern enum PropertyAttributes extends int31 { NONE, READ_ONLY, DONT_ENUM, DONT_DELETE, ALL_ATTRIBUTES_MASK, FROZEN, ... } const kMaxArrayIndex: constexpr uint32 generates 'JSArray::kMaxArrayIndex'; const kArrayBufferMaxByteLength: constexpr uintptr generates 'JSArrayBuffer::kMaxByteLength'; const kTypedArrayMaxLength: constexpr uintptr generates 'JSTypedArray::kMaxLength'; const kMaxTypedArrayInHeap: constexpr int31 generates 'JSTypedArray::kMaxSizeInHeap'; // CSA does not support 64-bit types on 32-bit platforms so as a workaround the // kMaxSafeIntegerUint64 is defined as uintptr and allowed to be used only // inside if constexpr (Is64()) i.e. on 64-bit architectures. const kMaxSafeIntegerUint64: constexpr uintptr generates 'CodeStubAssembler::MaxSafeIntegerUintPtr()'; const kMaxSafeInteger: constexpr float64 generates 'kMaxSafeInteger'; const kMaxUInt32Double: constexpr float64 generates 'kMaxUInt32Double'; const kSmiMaxValue: constexpr uintptr generates 'kSmiMaxValue'; const kSmiMax: uintptr = kSmiMaxValue; // TODO(v8:8996): Use uintptr version instead and drop this one. const kStringMaxLength: constexpr int31 generates 'String::kMaxLength'; const kStringMaxLengthUintptr: constexpr uintptr generates 'String::kMaxLength'; const kFixedArrayMaxLength: constexpr int31 generates 'FixedArray::kMaxLength'; const kFixedDoubleArrayMaxLength: constexpr int31 generates 'FixedDoubleArray::kMaxLength'; const kObjectAlignmentMask: constexpr intptr generates 'kObjectAlignmentMask'; const kMinAddedElementsCapacity: constexpr int31 generates 'JSObject::kMinAddedElementsCapacity'; const kMaxCopyElements: constexpr int31 generates 'JSArray::kMaxCopyElements'; const kMaxRegularHeapObjectSize: constexpr int31 generates 'kMaxRegularHeapObjectSize'; const kMaxNewSpaceFixedArrayElements: constexpr int31 generates 'FixedArray::kMaxRegularLength'; extern enum PrimitiveType { kString, kBoolean, kSymbol, kNumber } const kNameDictionaryInitialCapacity: constexpr int32 generates 'NameDictionary::kInitialCapacity'; const kOrderedNameDictionaryInitialCapacity: constexpr int32 generates 'OrderedNameDictionary::kInitialCapacity'; const kWasmArrayHeaderSize: constexpr int32 generates 'WasmArray::kHeaderSize'; const kDictModePrototypes: constexpr bool generates 'V8_DICT_MODE_PROTOTYPES_BOOL'; type TheHole extends Oddball; type Null extends Oddball; type Undefined extends Oddball; type True extends Oddball; type False extends Oddball; type Exception extends Oddball; type EmptyString extends String; type Boolean = True|False; type NumberOrUndefined = Number|Undefined; extern macro DefaultStringConstant(): String; extern macro EmptyStringConstant(): EmptyString; extern macro ErrorsStringConstant(): String; extern macro FalseConstant(): False; extern macro Int32FalseConstant(): bool; extern macro Int32TrueConstant(): bool; extern macro IteratorSymbolConstant(): PublicSymbol; extern macro LengthStringConstant(): String; extern macro MatchSymbolConstant(): Symbol; extern macro MessageStringConstant(): String; extern macro NanConstant(): NaN; extern macro NameStringConstant(): String; extern macro NullConstant(): Null; extern macro NumberStringConstant(): String; extern macro ReturnStringConstant(): String; extern macro StringStringConstant(): String; extern macro TheHoleConstant(): TheHole; extern macro ToPrimitiveSymbolConstant(): PublicSymbol; extern macro ToStringStringConstant(): String; extern macro TrueConstant(): True; extern macro UndefinedConstant(): Undefined; extern macro ValueOfStringConstant(): String; extern macro WasmWrappedObjectSymbolConstant(): Symbol; const TheHole: TheHole = TheHoleConstant(); const Null: Null = NullConstant(); const Undefined: Undefined = UndefinedConstant(); const True: True = TrueConstant(); const False: False = FalseConstant(); const kEmptyString: EmptyString = EmptyStringConstant(); const kLengthString: String = LengthStringConstant(); const kMessageString: String = MessageStringConstant(); const kReturnString: String = ReturnStringConstant(); const kNaN: NaN = NanConstant(); const kZero: Zero = %RawDownCast<Zero>(SmiConstant(0)); const kZeroBitPattern: TaggedZeroPattern = %RawDownCast<TaggedZeroPattern>( Convert<Tagged>(BitcastWordToTaggedSigned(Convert<intptr>(0)))); const true: constexpr bool generates 'true'; const false: constexpr bool generates 'false'; extern enum LanguageMode extends bool { kStrict, kSloppy } type LanguageModeSmi extends Smi; const SKIP_WRITE_BARRIER: constexpr WriteBarrierMode generates 'SKIP_WRITE_BARRIER'; const UNSAFE_SKIP_WRITE_BARRIER: constexpr WriteBarrierMode generates 'UNSAFE_SKIP_WRITE_BARRIER'; extern transitioning macro AllocateJSIteratorResult(implicit context: Context)( JSAny, Boolean): JSObject; extern class Filler extends HeapObject generates 'TNode<HeapObject>'; // Various logical subclasses of JSObject, which have their own instance types // but not their own class definitions: // Like JSObject, but created from API function. @apiExposedInstanceTypeValue(0x420) extern class JSApiObject extends JSObject generates 'TNode<JSObject>'; // Like JSApiObject, but requires access checks and/or has interceptors. @apiExposedInstanceTypeValue(0x410) extern class JSSpecialApiObject extends JSSpecialObject generates 'TNode<JSSpecialObject>'; extern class JSContextExtensionObject extends JSObject generates 'TNode<JSObject>'; extern class JSError extends JSObject generates 'TNode<JSObject>'; extern macro Is64(): constexpr bool; extern macro SelectBooleanConstant(bool): Boolean; extern macro Print(constexpr string); extern macro Print(constexpr string, Object); extern macro Comment(constexpr string); extern macro Print(Object); extern macro DebugBreak(); // ES6 7.1.4 ToInteger ( argument ) transitioning macro ToIntegerImpl(implicit context: Context)(input: JSAny): Number { let input = input; while (true) { typeswitch (input) { case (s: Smi): { return s; } case (hn: HeapNumber): { let value = Convert<float64>(hn); if (Float64IsNaN(value)) return SmiConstant(0); value = math::Float64Trunc(value); // ToInteger normalizes -0 to +0. if (value == 0.0) return SmiConstant(0); const result = ChangeFloat64ToTagged(value); assert(IsNumberNormalized(result)); return result; } case (a: JSAnyNotNumber): { input = conversion::NonNumberToNumber(a); } } } unreachable; } transitioning builtin ToInteger(implicit context: Context)(input: JSAny): Number { return ToIntegerImpl(input); } @export transitioning macro ToInteger_Inline(implicit context: Context)(input: JSAny): Number { typeswitch (input) { case (s: Smi): { return s; } case (JSAny): { return ToInteger(input); } } } extern enum BigIntHandling extends int32 constexpr 'CodeStubAssembler::BigIntHandling' { kConvertToNumber, kThrow } extern transitioning macro ToNumber(implicit context: Context)( JSAny, constexpr BigIntHandling): Number; extern transitioning macro ToLength_Inline(implicit context: Context)(JSAny): Number; extern transitioning macro ToNumber_Inline(implicit context: Context)(JSAny): Number; extern transitioning macro ToString_Inline(implicit context: Context)(JSAny): String; extern transitioning macro ToThisString(implicit context: Context)( JSAny, String): String; extern transitioning macro ToThisValue(implicit context: Context)( JSAny, constexpr PrimitiveType, constexpr string): JSAny; extern transitioning macro GetProperty(implicit context: Context)( JSAny, JSAny): JSAny; extern transitioning builtin SetProperty(implicit context: Context)( JSAny, JSAny, JSAny): JSAny; extern transitioning builtin SetPropertyIgnoreAttributes( implicit context: Context)(JSObject, String, JSAny, Smi): JSAny; extern transitioning builtin SetPropertyInLiteral(implicit context: Context)( JSAny, JSAny, JSAny): JSAny; extern transitioning builtin DeleteProperty(implicit context: Context)( JSAny, JSAny | PrivateSymbol, LanguageModeSmi): Boolean; extern transitioning builtin HasProperty(implicit context: Context)( JSAny, JSAny): Boolean; extern transitioning macro HasProperty_Inline(implicit context: Context)( JSReceiver, JSAny): Boolean; extern builtin LoadIC( Context, JSAny, JSAny, TaggedIndex, FeedbackVector): JSAny; extern macro SetPropertyStrict(Context, Object, Object, Object): Object; extern macro ThrowRangeError(implicit context: Context)( constexpr MessageTemplate): never; extern macro ThrowRangeError(implicit context: Context)( constexpr MessageTemplate, Object): never; extern macro ThrowTypeError(implicit context: Context)( constexpr MessageTemplate): never; extern macro ThrowTypeError(implicit context: Context)( constexpr MessageTemplate, constexpr string): never; extern macro ThrowTypeError(implicit context: Context)( constexpr MessageTemplate, Object): never; extern macro ThrowTypeError(implicit context: Context)( constexpr MessageTemplate, Object, Object): never; extern macro ThrowTypeError(implicit context: Context)( constexpr MessageTemplate, Object, Object, Object): never; extern transitioning runtime ThrowTypeErrorIfStrict(implicit context: Context)( Smi, Object, Object): void; extern transitioning runtime ThrowCalledNonCallable(implicit context: Context)( JSAny): never; extern transitioning macro ThrowIfNotJSReceiver(implicit context: Context)( JSAny, constexpr MessageTemplate, constexpr string): void; extern macro ArraySpeciesCreate(Context, JSAny, Number): JSReceiver; extern macro ArrayCreate(implicit context: Context)(Number): JSArray; extern macro BuildAppendJSArray( constexpr ElementsKind, FastJSArray, JSAny): void labels Bailout; extern macro EnsureArrayPushable(implicit context: Context)(Map): ElementsKind labels Bailout; // TODO: Reduce duplication once varargs are supported in macros. extern macro Construct(implicit context: Context)(Constructor): JSReceiver; extern macro Construct(implicit context: Context)( Constructor, JSAny): JSReceiver; extern macro Construct(implicit context: Context)( Constructor, JSAny, JSAny): JSReceiver; extern macro Construct(implicit context: Context)( Constructor, JSAny, JSAny, JSAny): JSReceiver; extern macro ConstructWithTarget(implicit context: Context)( Constructor, JSReceiver): JSReceiver; extern macro ConstructWithTarget(implicit context: Context)( Constructor, JSReceiver, JSAny): JSReceiver; extern macro SpeciesConstructor(implicit context: Context)( JSAny, JSReceiver): JSReceiver; extern macro ConstructorBuiltinsAssembler::IsDictionaryMap(Map): bool; extern macro CodeStubAssembler::AllocateNameDictionary(constexpr int32): NameDictionary; extern macro CodeStubAssembler::AllocateOrderedNameDictionary(constexpr int32): OrderedNameDictionary; extern builtin ToObject(Context, JSAny): JSReceiver; extern macro ToObject_Inline(Context, JSAny): JSReceiver; extern macro IsUndefined(Object): bool; extern macro IsNullOrUndefined(Object): bool; extern macro IsString(HeapObject): bool; extern transitioning builtin NonPrimitiveToPrimitive_String( Context, JSAny): JSPrimitive; extern transitioning builtin NonPrimitiveToPrimitive_Default( Context, JSAny): JSPrimitive; transitioning macro ToPrimitiveDefault(implicit context: Context)(v: JSAny): JSPrimitive { typeswitch (v) { case (v: JSReceiver): { return NonPrimitiveToPrimitive_Default(context, v); } case (v: JSPrimitive): { return v; } } } extern transitioning runtime NormalizeElements(Context, JSObject); extern transitioning runtime TransitionElementsKindWithKind( Context, JSObject, Smi); extern macro LoadBufferObject(RawPtr, constexpr int32): Object; extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr; extern macro LoadBufferSmi(RawPtr, constexpr int32): Smi; extern macro LoadBufferIntptr(RawPtr, constexpr int32): intptr; extern runtime StringEqual(Context, String, String): Oddball; extern builtin StringLessThan(Context, String, String): Boolean; extern macro StringCharCodeAt(String, uintptr): char16; extern macro StringFromSingleCharCode(char8): String; extern macro StringFromSingleCharCode(char16): String; extern macro NumberToString(Number): String; extern macro StringToNumber(String): Number; extern transitioning macro NonNumberToNumber(implicit context: Context)( JSAnyNotNumber): Number; extern transitioning macro NonNumberToNumeric(implicit context: Context)( JSAnyNotNumber): Numeric; extern macro Equal(JSAny, JSAny, Context): Boolean; macro Equal(implicit context: Context)(left: JSAny, right: JSAny): Boolean { return Equal(left, right); } extern macro StrictEqual(JSAny, JSAny): Boolean; extern macro SmiLexicographicCompare(Smi, Smi): Smi; extern runtime ReThrow(Context, JSAny): never; extern runtime Throw(implicit context: Context)(JSAny): never; extern runtime ThrowInvalidStringLength(Context): never; extern operator '==' macro WordEqual(RawPtr, RawPtr): bool; extern operator '!=' macro WordNotEqual(RawPtr, RawPtr): bool; extern operator '+' macro RawPtrAdd(RawPtr, intptr): RawPtr; extern operator '+' macro RawPtrAdd(intptr, RawPtr): RawPtr; extern operator '<' macro Int32LessThan(int32, int32): bool; extern operator '<' macro Uint32LessThan(uint32, uint32): bool; extern operator '>' macro Int32GreaterThan(int32, int32): bool; extern operator '>' macro Uint32GreaterThan(uint32, uint32): bool; extern operator '<=' macro Int32LessThanOrEqual(int32, int32): bool; extern operator '<=' macro Uint32LessThanOrEqual(uint32, uint32): bool; extern operator '>=' macro Int32GreaterThanOrEqual(int32, int32): bool; extern operator '>=' macro Uint32GreaterThanOrEqual(uint32, uint32): bool; extern operator '==' macro SmiEqual(Smi, Smi): bool; extern operator '!=' macro SmiNotEqual(Smi, Smi): bool; extern operator '<' macro SmiLessThan(Smi, Smi): bool; extern operator '<=' macro SmiLessThanOrEqual(Smi, Smi): bool; extern operator '>' macro SmiGreaterThan(Smi, Smi): bool; extern operator '>=' macro SmiGreaterThanOrEqual(Smi, Smi): bool; extern operator '==' macro ElementsKindEqual( constexpr ElementsKind, constexpr ElementsKind): constexpr bool; extern operator '==' macro ElementsKindEqual(ElementsKind, ElementsKind): bool; operator '!=' macro ElementsKindNotEqual( k1: ElementsKind, k2: ElementsKind): bool { return !ElementsKindEqual(k1, k2); } extern macro IsElementsKindLessThanOrEqual( ElementsKind, constexpr ElementsKind): bool; extern macro IsElementsKindGreaterThan( ElementsKind, constexpr ElementsKind): bool; extern macro IsElementsKindInRange( ElementsKind, constexpr ElementsKind, constexpr ElementsKind): bool; extern macro IsFastElementsKind(constexpr ElementsKind): constexpr bool; extern macro IsDoubleElementsKind(constexpr ElementsKind): constexpr bool; extern macro IsFastAliasedArgumentsMap(implicit context: Context)(Map): bool; extern macro IsSlowAliasedArgumentsMap(implicit context: Context)(Map): bool; extern macro IsSloppyArgumentsMap(implicit context: Context)(Map): bool; extern macro IsStrictArgumentsMap(implicit context: Context)(Map): bool; extern macro IsTuple2Map(Map): bool; extern macro SmiAbove(Smi, Smi): bool; extern operator '==' macro WordEqual(intptr, intptr): bool; extern operator '==' macro WordEqual(uintptr, uintptr): bool; extern operator '!=' macro WordNotEqual(intptr, intptr): bool; extern operator '!=' macro WordNotEqual(uintptr, uintptr): bool; extern operator '<' macro IntPtrLessThan(intptr, intptr): bool; extern operator '<' macro UintPtrLessThan(uintptr, uintptr): bool; extern operator '>' macro IntPtrGreaterThan(intptr, intptr): bool; extern operator '>' macro UintPtrGreaterThan(uintptr, uintptr): bool; extern operator '<=' macro IntPtrLessThanOrEqual(intptr, intptr): bool; extern operator '<=' macro UintPtrLessThanOrEqual(uintptr, uintptr): bool; extern operator '>=' macro IntPtrGreaterThanOrEqual(intptr, intptr): bool; extern operator '>=' macro UintPtrGreaterThanOrEqual(uintptr, uintptr): bool; extern operator '~' macro WordNot(intptr): intptr; extern operator '~' macro WordNot(uintptr): uintptr; extern operator '~' macro ConstexprWordNot(constexpr intptr): constexpr intptr; extern operator '~' macro ConstexprWordNot(constexpr uintptr): constexpr uintptr; extern operator '==' macro Float64Equal(float64, float64): bool; extern operator '!=' macro Float64NotEqual(float64, float64): bool; extern operator '>' macro Float64GreaterThan(float64, float64): bool; extern operator '>=' macro Float64GreaterThanOrEqual(float64, float64): bool; extern operator '<' macro Float64LessThan(float64, float64): bool; extern operator '<=' macro Float64LessThanOrEqual(float64, float64): bool; extern macro BranchIfNumberEqual(Number, Number): never labels Taken, NotTaken; operator '==' macro IsNumberEqual(a: Number, b: Number): bool { BranchIfNumberEqual(a, b) otherwise return true, return false; } operator '!=' macro IsNumberNotEqual(a: Number, b: Number): bool { return !(a == b); } extern macro BranchIfNumberLessThan(Number, Number): never labels Taken, NotTaken; operator '<' macro NumberIsLessThan(a: Number, b: Number): bool { BranchIfNumberLessThan(a, b) otherwise return true, return false; } extern macro BranchIfNumberLessThanOrEqual(Number, Number): never labels Taken, NotTaken; operator '<=' macro NumberIsLessThanOrEqual(a: Number, b: Number): bool { BranchIfNumberLessThanOrEqual(a, b) otherwise return true, return false; } operator '>' macro NumberIsGreaterThan(a: Number, b: Number): bool { return b < a; } operator '>=' macro NumberIsGreaterThanOrEqual(a: Number, b: Number): bool { return b <= a; } extern macro BranchIfFloat64IsNaN(float64): never labels Taken, NotTaken; macro Float64IsNaN(n: float64): bool { BranchIfFloat64IsNaN(n) otherwise return true, return false; } // The type of all tagged values that can safely be compared with TaggedEqual. type TaggedWithIdentity = JSReceiver|FixedArrayBase|Oddball|Map|WeakCell|Context|EmptyString; extern operator '==' macro TaggedEqual(TaggedWithIdentity, Object): bool; extern operator '==' macro TaggedEqual(Object, TaggedWithIdentity): bool; extern operator '==' macro TaggedEqual( TaggedWithIdentity, TaggedWithIdentity): bool; extern operator '==' macro TaggedEqual(WeakHeapObject, WeakHeapObject): bool; extern operator '!=' macro TaggedNotEqual(TaggedWithIdentity, Object): bool; extern operator '!=' macro TaggedNotEqual(Object, TaggedWithIdentity): bool; extern operator '!=' macro TaggedNotEqual( TaggedWithIdentity, TaggedWithIdentity): bool; extern operator '!=' macro TaggedNotEqual(WeakHeapObject, WeakHeapObject): bool; // Do not overload == and != if it is unclear if object identity is the right // equality. extern macro TaggedEqual(MaybeObject, MaybeObject): bool; extern macro TaggedNotEqual(MaybeObject, MaybeObject): bool; extern operator '+' macro SmiAdd(Smi, Smi): Smi; extern operator '-' macro SmiSub(Smi, Smi): Smi; extern operator '&' macro SmiAnd(Smi, Smi): Smi; extern operator '|' macro SmiOr(Smi, Smi): Smi; extern operator '<<' macro SmiShl(Smi, constexpr int31): Smi; extern operator '>>' macro SmiSar(Smi, constexpr int31): Smi; extern operator '+' macro IntPtrAdd(intptr, intptr): intptr; extern operator '+' macro ConstexprIntPtrAdd( constexpr intptr, constexpr intptr): constexpr intptr; extern operator '+' macro ConstexprUintPtrAdd( constexpr uintptr, constexpr uintptr): constexpr intptr; extern operator '-' macro IntPtrSub(intptr, intptr): intptr; extern operator '*' macro IntPtrMul(intptr, intptr): intptr; extern operator '/' macro IntPtrDiv(intptr, intptr): intptr; extern operator '<<' macro WordShl(intptr, intptr): intptr; extern operator '>>' macro WordSar(intptr, intptr): intptr; extern operator '&' macro WordAnd(intptr, intptr): intptr; extern operator '|' macro WordOr(intptr, intptr): intptr; extern operator '+' macro UintPtrAdd(uintptr, uintptr): uintptr; extern operator '-' macro UintPtrSub(uintptr, uintptr): uintptr; extern operator '<<' macro WordShl(uintptr, uintptr): uintptr; extern operator '>>>' macro WordShr(uintptr, uintptr): uintptr; extern operator '&' macro WordAnd(uintptr, uintptr): uintptr; extern operator '|' macro WordOr(uintptr, uintptr): uintptr; extern operator '+' macro Int32Add(int32, int32): int32; extern operator '+' macro ConstexprUint32Add( constexpr uint32, constexpr int32): constexpr uint32; extern operator '+' macro ConstexprInt31Add( constexpr int31, constexpr int31): constexpr int31; extern operator '*' macro ConstexprInt31Mul( constexpr int31, constexpr int31): constexpr int31; extern operator '-' macro Int32Sub(int16, int16): int32; extern operator '-' macro Int32Sub(uint16, uint16): int32; extern operator '-' macro Int32Sub(int32, int32): int32; extern operator '*' macro Int32Mul(int32, int32): int32; extern operator '/' macro Int32Div(int32, int32): int32; extern operator '%' macro Int32Mod(int32, int32): int32; extern operator '&' macro Word32And(int32, int32): int32; extern operator '&' macro Word32And(uint32, uint32): uint32; extern operator '==' macro ConstexprInt31Equal(constexpr int31, constexpr int31): constexpr bool; extern operator '!=' macro ConstexprInt31NotEqual(constexpr int31, constexpr int31): constexpr bool; extern operator '==' macro ConstexprUint32Equal(constexpr uint32, constexpr uint32): constexpr bool; extern operator '!=' macro ConstexprUint32NotEqual(constexpr uint32, constexpr uint32): constexpr bool; extern operator '>=' macro ConstexprInt31GreaterThanEqual( constexpr int31, constexpr int31): constexpr bool; extern operator '==' macro ConstexprInt32Equal( constexpr int32, constexpr int32): constexpr bool; extern operator '!=' macro ConstexprInt32NotEqual( constexpr int32, constexpr int32): constexpr bool; extern operator '==' macro Word32Equal(int32, int32): bool; extern operator '==' macro Word32Equal(uint32, uint32): bool; extern operator '!=' macro Word32NotEqual(int32, int32): bool; extern operator '!=' macro Word32NotEqual(uint32, uint32): bool; extern operator '>>>' macro Word32Shr(uint32, uint32): uint32; extern operator '>>' macro Word32Sar(int32, int32): int32; extern operator '<<' macro Word32Shl(int32, int32): int32; extern operator '<<' macro Word32Shl(uint32, uint32): uint32; extern operator '|' macro Word32Or(int32, int32): int32; extern operator '|' macro Word32Or(uint32, uint32): uint32; extern operator '&' macro Word32And(bool, bool): bool; extern operator '|' macro Word32Or(bool, bool): bool; extern operator '==' macro Word32Equal(bool, bool): bool; extern operator '!=' macro Word32NotEqual(bool, bool): bool; extern operator '|' macro ConstexprWord32Or( constexpr int32, constexpr int32): constexpr int32; extern operator '+' macro Float64Add(float64, float64): float64; extern operator '-' macro Float64Sub(float64, float64): float64; extern operator '*' macro Float64Mul(float64, float64): float64; extern operator '/' macro Float64Div(float64, float64): float64; extern operator '%' macro Float64Mod(float64, float64): float64; extern operator '+' macro NumberAdd(Number, Number): Number; extern operator '-' macro NumberSub(Number, Number): Number; extern macro NumberMin(Number, Number): Number; extern macro NumberMax(Number, Number): Number; macro Min(x: Number, y: Number): Number { return NumberMin(x, y); } macro Max(x: Number, y: Number): Number { return NumberMax(x, y); } extern macro TryIntPtrAdd(intptr, intptr): intptr labels Overflow; extern macro TryIntPtrSub(intptr, intptr): intptr labels Overflow; extern macro TryInt32Mul(int32, int32): int32 labels Overflow; extern operator '<' macro ConstexprUintPtrLessThan( constexpr uintptr, constexpr uintptr): constexpr bool; extern operator '<<' macro ConstexprUintPtrShl( constexpr uintptr, constexpr int31): constexpr uintptr; extern operator '>>>' macro ConstexprUintPtrShr( constexpr uintptr, constexpr int31): constexpr uintptr; extern macro SmiMax(Smi, Smi): Smi; extern macro SmiMin(Smi, Smi): Smi; extern macro SmiMul(Smi, Smi): Number; extern macro SmiMod(Smi, Smi): Number; extern macro IntPtrMax(intptr, intptr): intptr; extern macro IntPtrMin(intptr, intptr): intptr; extern macro UintPtrMin(uintptr, uintptr): uintptr; extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool; extern operator '!' macro Word32BinaryNot(bool): bool; extern operator '!' macro IsFalse(Boolean): bool; extern operator '==' macro ConstexprInt31Equal( constexpr InstanceType, constexpr InstanceType): constexpr bool; extern operator '-' macro ConstexprUint32Sub( constexpr InstanceType, constexpr InstanceType): constexpr int32; extern operator '.instanceType' macro LoadInstanceType(HeapObject): InstanceType; operator '.length_uintptr' macro LoadJSArrayLengthAsUintPtr(array: JSArray): uintptr { return Convert<uintptr>(array.length); } extern operator '.length_intptr' macro LoadStringLengthAsWord(String): intptr; operator '.length_uintptr' macro LoadStringLengthAsUintPtr(s: String): uintptr { return Unsigned(s.length_intptr); } extern operator '.length_uint32' macro LoadStringLengthAsWord32(String): uint32; extern operator '.length_smi' macro LoadStringLengthAsSmi(String): Smi; extern builtin StringAdd_CheckNone(implicit context: Context)( String, String): String; operator '+' macro StringAdd(implicit context: Context)( a: String, b: String): String { return StringAdd_CheckNone(a, b); } operator '==' macro PromiseStateEquals( s1: PromiseState, s2: PromiseState): bool { return Word32Equal(s1, s2); } extern macro TaggedIsSmi(Object): bool; extern macro TaggedIsNotSmi(Object): bool; extern macro TaggedIsPositiveSmi(Object): bool; extern macro IsValidPositiveSmi(intptr): bool; extern macro IsInteger(JSAny): bool; extern macro IsInteger(HeapNumber): bool; extern macro AllocateHeapNumberWithValue(float64): HeapNumber; extern macro ChangeInt32ToTagged(int32): Number; extern macro ChangeUint32ToTagged(uint32): Number; extern macro ChangeUintPtrToFloat64(uintptr): float64; extern macro ChangeUintPtrToTagged(uintptr): Number; extern macro Unsigned(int32): uint32; extern macro Unsigned(int16): uint16; extern macro Unsigned(int8): uint8; extern macro Unsigned(intptr): uintptr; extern macro Unsigned(RawPtr): uintptr; extern macro Signed(uint32): int32; extern macro Signed(uint16): int16; extern macro Signed(uint8): int8; extern macro Signed(uintptr): intptr; extern macro Signed(RawPtr): intptr; extern macro TruncateIntPtrToInt32(intptr): int32; extern macro SmiTag(intptr): Smi; extern macro SmiFromInt32(int32): Smi; extern macro SmiFromUint32(uint32): Smi; extern macro SmiFromIntPtr(intptr): Smi; extern macro SmiUntag(Smi): intptr; macro SmiUntag<T: type>(value: SmiTagged<T>): T { return %RawDownCast<T>(Unsigned(SmiToInt32(Convert<Smi>(value)))); } macro SmiTag<T : type extends uint31>(value: T): SmiTagged<T> { return %RawDownCast<SmiTagged<T>>(SmiFromUint32(value)); } extern macro SmiToInt32(Smi): int32; extern macro SmiToFloat64(Smi): float64; extern macro TaggedIndexToIntPtr(TaggedIndex): intptr; extern macro IntPtrToTaggedIndex(intptr): TaggedIndex; extern macro TaggedIndexToSmi(TaggedIndex): Smi; extern macro SmiToTaggedIndex(Smi): TaggedIndex; extern macro RoundIntPtrToFloat64(intptr): float64; extern macro ChangeFloat32ToFloat64(float32): float64; extern macro ChangeNumberToFloat64(Number): float64; extern macro ChangeNumberToUint32(Number): uint32; extern macro ChangeTaggedNonSmiToInt32(implicit context: Context)(JSAnyNotSmi): int32; extern macro ChangeTaggedToFloat64(implicit context: Context)(JSAny): float64; extern macro ChangeFloat64ToTagged(float64): Number; extern macro ChangeFloat64ToUintPtr(float64): uintptr; extern macro ChangeFloat64ToIntPtr(float64): intptr; extern macro ChangeInt32ToFloat64(int32): float64; extern macro ChangeInt32ToIntPtr(int32): intptr; // Sign-extends. extern macro ChangeUint32ToWord(uint32): uintptr; // Doesn't sign-extend. extern macro LoadNativeContext(Context): NativeContext; extern macro TruncateFloat64ToFloat32(float64): float32; extern macro TruncateHeapNumberValueToWord32(HeapNumber): int32; extern macro LoadJSArrayElementsMap(constexpr ElementsKind, NativeContext): Map; extern macro LoadJSArrayElementsMap(ElementsKind, NativeContext): Map; extern macro NumberConstant(constexpr float64): Number; extern macro NumberConstant(constexpr int32): Number; extern macro NumberConstant(constexpr uint32): Number; extern macro IntPtrConstant(constexpr int31): intptr; extern macro IntPtrConstant(constexpr int32): intptr; extern macro Uint16Constant(constexpr uint16): uint16; extern macro Int32Constant(constexpr int31): int31; extern macro Int32Constant(constexpr int32): int32; extern macro Float64Constant(constexpr int31): float64; extern macro Float64Constant(constexpr float64): float64; extern macro SmiConstant(constexpr int31): Smi; extern macro SmiConstant(constexpr Smi): Smi; extern macro SmiConstant(constexpr MessageTemplate): Smi; extern macro SmiConstant(constexpr bool): Smi; extern macro SmiConstant(constexpr uint32): Smi; extern macro BoolConstant(constexpr bool): bool; extern macro StringConstant(constexpr string): String; extern macro IntPtrConstant(constexpr ContextSlot): ContextSlot; extern macro IntPtrConstant(constexpr intptr): intptr; extern macro PointerConstant(constexpr RawPtr): RawPtr; extern macro SingleCharacterStringConstant(constexpr string): String; extern macro Float64SilenceNaN(float64): float64; extern macro BitcastWordToTaggedSigned(intptr): Smi; extern macro BitcastWordToTaggedSigned(uintptr): Smi; extern macro BitcastWordToTagged(intptr): Object; extern macro BitcastWordToTagged(uintptr): Object; extern macro BitcastTaggedToWord(Tagged): intptr; extern macro BitcastTaggedToWordForTagAndSmiBits(Tagged): intptr; extern macro FixedArrayMapConstant(): Map; extern macro FixedDoubleArrayMapConstant(): Map; extern macro FixedCOWArrayMapConstant(): Map; extern macro EmptyByteArrayConstant(): ByteArray; extern macro EmptyFixedArrayConstant(): EmptyFixedArray; extern macro PromiseCapabilityMapConstant(): Map; extern macro OneByteStringMapConstant(): Map; extern macro StringMapConstant(): Map; const kFixedArrayMap: Map = FixedArrayMapConstant(); const kFixedDoubleArrayMap: Map = FixedDoubleArrayMapConstant(); const kCOWMap: Map = FixedCOWArrayMapConstant(); const kEmptyByteArray: ByteArray = EmptyByteArrayConstant(); const kEmptyFixedArray: EmptyFixedArray = EmptyFixedArrayConstant(); const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant(); // The map of a non-internalized internal SeqOneByteString. const kOneByteStringMap: Map = OneByteStringMapConstant(); // The map of a non-internalized internal SeqTwoByteString. const kStringMap: Map = StringMapConstant(); macro OutOfBounds<T: type, X: type>(index: T, length: X): bool { return UintPtrGreaterThanOrEqual( Convert<uintptr>(Convert<intptr>(index)), Convert<uintptr>(Convert<intptr>(length))); } extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map): bool; extern macro IsNoElementsProtectorCellInvalid(): bool; extern macro IsArrayIteratorProtectorCellInvalid(): bool; extern macro IsArraySpeciesProtectorCellInvalid(): bool; extern macro IsTypedArraySpeciesProtectorCellInvalid(): bool; extern macro IsPromiseSpeciesProtectorCellInvalid(): bool; extern macro IsMockArrayBufferAllocatorFlag(): bool; extern macro HasBuiltinSubclassingFlag(): bool; extern macro IsPrototypeTypedArrayPrototype(implicit context: Context)(Map): bool; extern operator '.data_ptr' macro LoadJSTypedArrayDataPtr(JSTypedArray): RawPtr; extern operator '.elements_kind' macro LoadMapElementsKind(Map): ElementsKind; extern operator '.elements_kind' macro LoadElementsKind(JSTypedArray): ElementsKind; extern operator '.length' macro LoadFastJSArrayLength(FastJSArray): Smi; operator '.length=' macro StoreFastJSArrayLength( array: FastJSArray, length: Smi) { const array: JSArray = array; array.length = length; } extern macro GetNumberDictionaryNumberOfElements(NumberDictionary): Smi; extern macro LoadConstructorOrBackPointer(Map): Object; extern macro BasicLoadNumberDictionaryElement(NumberDictionary, intptr): JSAny labels NotData, IfHole; extern macro IsFastElementsKind(ElementsKind): bool; extern macro IsDoubleElementsKind(ElementsKind): bool; extern macro IsFastSmiOrTaggedElementsKind(ElementsKind): bool; extern macro IsFastSmiElementsKind(ElementsKind): bool; extern macro IsHoleyFastElementsKind(ElementsKind): bool; macro FastHoleyElementsKind(kind: ElementsKind): ElementsKind { if (kind == ElementsKind::PACKED_SMI_ELEMENTS) { return ElementsKind::HOLEY_SMI_ELEMENTS; } else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) { return ElementsKind::HOLEY_DOUBLE_ELEMENTS; } assert(kind == ElementsKind::PACKED_ELEMENTS); return ElementsKind::HOLEY_ELEMENTS; } macro AllowDoubleElements(kind: ElementsKind): ElementsKind { if (kind == ElementsKind::PACKED_SMI_ELEMENTS) { return ElementsKind::PACKED_DOUBLE_ELEMENTS; } else if (kind == ElementsKind::HOLEY_SMI_ELEMENTS) { return ElementsKind::HOLEY_DOUBLE_ELEMENTS; } return kind; } macro AllowNonNumberElements(kind: ElementsKind): ElementsKind { if (kind == ElementsKind::PACKED_SMI_ELEMENTS) { return ElementsKind::PACKED_ELEMENTS; } else if (kind == ElementsKind::HOLEY_SMI_ELEMENTS) { return ElementsKind::HOLEY_ELEMENTS; } else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) { return ElementsKind::PACKED_ELEMENTS; } else if (kind == ElementsKind::HOLEY_DOUBLE_ELEMENTS) { return ElementsKind::HOLEY_ELEMENTS; } return kind; } macro GetObjectFunction(implicit context: Context)(): JSFunction { return *NativeContextSlot(ContextSlot::OBJECT_FUNCTION_INDEX); } macro GetArrayFunction(implicit context: Context)(): JSFunction { return *NativeContextSlot(ContextSlot::ARRAY_FUNCTION_INDEX); } macro GetArrayBufferFunction(implicit context: Context)(): Constructor { return *NativeContextSlot(ContextSlot::ARRAY_BUFFER_FUN_INDEX); } macro GetArrayBufferNoInitFunction(implicit context: Context)(): JSFunction { return *NativeContextSlot(ContextSlot::ARRAY_BUFFER_NOINIT_FUN_INDEX); } macro GetFastPackedElementsJSArrayMap(implicit context: Context)(): Map { return *NativeContextSlot(ContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX); } macro GetFastPackedSmiElementsJSArrayMap(implicit context: Context)(): Map { return *NativeContextSlot( ContextSlot::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX); } macro GetProxyRevocableResultMap(implicit context: Context)(): Map { return *NativeContextSlot(ContextSlot::PROXY_REVOCABLE_RESULT_MAP_INDEX); } macro GetIteratorResultMap(implicit context: Context)(): Map { return *NativeContextSlot(ContextSlot::ITERATOR_RESULT_MAP_INDEX); } macro GetInitialStringIteratorMap(implicit context: Context)(): Map { return *NativeContextSlot(ContextSlot::INITIAL_STRING_ITERATOR_MAP_INDEX); } macro GetReflectApply(implicit context: Context)(): Callable { return *NativeContextSlot(ContextSlot::REFLECT_APPLY_INDEX); } macro GetRegExpLastMatchInfo(implicit context: Context)(): RegExpMatchInfo { return *NativeContextSlot(ContextSlot::REGEXP_LAST_MATCH_INFO_INDEX); } macro GetStrictArgumentsMap(implicit context: Context)(): Map { return *NativeContextSlot(ContextSlot::STRICT_ARGUMENTS_MAP_INDEX); } macro GetSloppyArgumentsMap(implicit context: Context)(): Map { return *NativeContextSlot(ContextSlot::SLOPPY_ARGUMENTS_MAP_INDEX); } macro GetFastAliasedArgumentsMap(implicit context: Context)(): Map { return *NativeContextSlot(ContextSlot::FAST_ALIASED_ARGUMENTS_MAP_INDEX); } macro GetWeakCellMap(implicit context: Context)(): Map { return %GetClassMapConstant<WeakCell>(); } // Call(Context, Target, Receiver, ...Args) // TODO(joshualitt): Assuming the context parameter is for throwing when Target // is non-callable, then we should make it an implicit // parameter. extern transitioning macro Call(Context, JSAny, JSAny): JSAny; extern transitioning macro Call(Context, JSAny, JSAny, JSAny): JSAny; extern transitioning macro Call(Context, JSAny, JSAny, JSAny, JSAny): JSAny; extern transitioning macro Call( Context, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny; extern transitioning macro Call( Context, JSAny, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny; extern transitioning macro Call( Context, JSAny, JSAny, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny; extern macro TransitionElementsKind( JSObject, Map, constexpr ElementsKind, constexpr ElementsKind): void labels Bailout; extern macro PerformStackCheck(implicit context: Context)(): void; extern macro Typeof(JSAny): String; // Return true iff number is NaN. macro NumberIsNaN(number: Number): bool { typeswitch (number) { case (Smi): { return false; } case (hn: HeapNumber): { const value: float64 = Convert<float64>(hn); return value != value; } } } extern macro GotoIfForceSlowPath() labels Taken; macro IsForceSlowPath(): bool { GotoIfForceSlowPath() otherwise return true; return false; } extern macro BranchIfToBooleanIsTrue(JSAny): never labels Taken, NotTaken; extern macro BranchIfToBooleanIsFalse(JSAny): never labels Taken, NotTaken; macro ToBoolean(obj: JSAny): bool { BranchIfToBooleanIsTrue(obj) otherwise return true, return false; } @export macro RequireObjectCoercible(implicit context: Context)( value: JSAny, name: constexpr string): JSAny { if (IsNullOrUndefined(value)) { ThrowTypeError(MessageTemplate::kCalledOnNullOrUndefined, name); } return value; } extern macro BranchIfSameValue(JSAny, JSAny): never labels Taken, NotTaken; macro SameValue(a: JSAny, b: JSAny): bool { BranchIfSameValue(a, b) otherwise return true, return false; } // Does "if (index1 + index2 > limit) goto IfOverflow" in an uintptr overflow // friendly way where index1 and index2 are in [0, kMaxSafeInteger] range. macro CheckIntegerIndexAdditionOverflow( index1: uintptr, index2: uintptr, limit: uintptr) labels IfOverflow { if constexpr (Is64()) { assert(index1 <= kMaxSafeIntegerUint64); assert(index2 <= kMaxSafeIntegerUint64); // Given that both index1 and index2 are in a safe integer range the // addition can't overflow. if (index1 + index2 > limit) goto IfOverflow; } else { // Uintptr range is "smaller" than [0, kMaxSafeInteger] range, so // "index1 + index2" may overflow, so we check the condition in the // following way "if (index1 > limit - index2) goto IfOverflow" and check // that "limit - index2" does not underflow. const index1Limit = limit - index2; if (index1 > index1Limit) goto IfOverflow; // Handle potential index1Limit underflow. if (index1Limit > limit) goto IfOverflow; } } // TODO(turbofan): Define enum here once they appear in Torque. // // The value is a SafeInteger that fits into uintptr range, so no bounds checks // are necessary. const kModeValueIsSafeIntegerUintPtr: constexpr int31 = 0; // The value is a SafeInteger that may not fit into uintptr range, so only // uintptr bounds check is necessary. const kModeValueIsSafeInteger: constexpr int31 = 1; // The value is can be whatever non-NaN number, all checks are necessary. const kModeValueIsAnyNumber: constexpr int31 = 2; macro TryNumberToUintPtr(valueNumber: Number, kMode: constexpr int31): uintptr labels IfLessThanZero, IfUIntPtrOverflow, IfSafeIntegerOverflow { typeswitch (valueNumber) { case (valueSmi: Smi): { if (kMode == kModeValueIsAnyNumber) { if (valueSmi < 0) goto IfLessThanZero; } else { assert(valueSmi >= 0); } const value: uintptr = Unsigned(Convert<intptr>(valueSmi)); // Positive Smi values definitely fit into both [0, kMaxSafeInteger] and // [0, kMaxUintPtr] ranges. return value; } case (valueHeapNumber: HeapNumber): { assert(IsNumberNormalized(valueHeapNumber)); const valueDouble: float64 = Convert<float64>(valueHeapNumber); // NaNs must be handled outside. assert(!Float64IsNaN(valueDouble)); if (kMode == kModeValueIsAnyNumber) { if (valueDouble < 0) goto IfLessThanZero; } else { assert(valueDouble >= 0); } if constexpr (Is64()) { // On 64-bit architectures uintptr range is bigger than safe integer // range. if (kMode == kModeValueIsAnyNumber) { if (valueDouble > kMaxSafeInteger) goto IfSafeIntegerOverflow; } else { assert(valueDouble <= kMaxSafeInteger); } } else { // On 32-bit architectures uintptr range is smaller than safe integer // range. if (kMode == kModeValueIsAnyNumber || kMode == kModeValueIsSafeInteger) { if (valueDouble > kMaxUInt32Double) goto IfUIntPtrOverflow; } else { assert(valueDouble <= kMaxUInt32Double); } } return ChangeFloat64ToUintPtr(valueDouble); } } } @export macro ChangeUintPtrNumberToUintPtr(value: Number): uintptr { try { return TryNumberToUintPtr(value, kModeValueIsSafeIntegerUintPtr) otherwise InvalidValue, InvalidValue, InvalidValue; } label InvalidValue { unreachable; } } @export macro ChangeSafeIntegerNumberToUintPtr(value: Number): uintptr labels IfUIntPtrOverflow { try { return TryNumberToUintPtr(value, kModeValueIsSafeInteger) otherwise InvalidValue, IfUIntPtrOverflow, InvalidValue; } label InvalidValue { unreachable; } } transitioning macro ToUintPtr(implicit context: Context)(value: JSAny): uintptr labels IfLessThanZero, IfUIntPtrOverflow, IfSafeIntegerOverflow { if (value == Undefined) return 0; const indexNumber = ToInteger_Inline(value); return TryNumberToUintPtr(indexNumber, kModeValueIsAnyNumber) otherwise IfLessThanZero, IfUIntPtrOverflow, IfSafeIntegerOverflow; } // https://tc39.github.io/ecma262/#sec-toindex // Unlike ToIndex from the spec this implementation triggers IfRangeError if // the result is bigger than min(kMaxUIntPtr, kMaxSafeInteger). // We can do this because all callers do a range checks against uintptr length // anyway and throw a RangeError in case of out-of-bounds index. @export transitioning macro ToIndex(implicit context: Context)(value: JSAny): uintptr labels IfRangeError { if (value == Undefined) return 0; const indexNumber = ToInteger_Inline(value); // Less than 0 case, uintptr range overflow and safe integer range overflow // imply IfRangeError. return TryNumberToUintPtr(indexNumber, kModeValueIsAnyNumber) otherwise IfRangeError, IfRangeError, IfRangeError; } transitioning macro GetLengthProperty(implicit context: Context)(o: JSAny): Number { try { typeswitch (o) { case (a: JSArray): { return a.length; } case (a: JSStrictArgumentsObject): { goto ToLength(a.length); } case (a: JSSloppyArgumentsObject): { goto ToLength(a.length); } case (JSAny): deferred { goto ToLength(GetProperty(o, kLengthString)); } } } label ToLength(length: JSAny) deferred { return ToLength_Inline(length); } } transitioning macro GetMethod(implicit context: Context)( o: JSAny, name: AnyName): Callable labels IfNullOrUndefined, IfMethodNotCallable(JSAny) { const value = GetProperty(o, name); // TODO(v8:9933): Consider checking for null/undefined after checking for // callable because the latter seems to be more common. if (value == Undefined || value == Null) goto IfNullOrUndefined; return Cast<Callable>(value) otherwise goto IfMethodNotCallable(value); } transitioning macro GetMethod(implicit context: Context)( o: JSAny, name: String): Callable labels IfNullOrUndefined { try { return GetMethod(o, name) otherwise IfNullOrUndefined, IfMethodNotCallable; } label IfMethodNotCallable(value: JSAny) deferred { ThrowTypeError(MessageTemplate::kPropertyNotFunction, value, name, o); } } transitioning macro GetMethod(implicit context: Context)( o: JSAny, name: constexpr string): Callable labels IfNullOrUndefined { return GetMethod(o, StringConstant(name)) otherwise IfNullOrUndefined; } transitioning macro GetMethod(implicit context: Context)( o: JSAny, symbol: Symbol): Callable labels IfNullOrUndefined { const value = GetProperty(o, symbol); if (value == Undefined || value == Null) goto IfNullOrUndefined; return Cast<Callable>(value) otherwise ThrowTypeError( MessageTemplate::kPropertyNotFunction, value, symbol, o); } extern macro IsOneByteStringInstanceType(InstanceType): bool; // After converting an index to an integer, calculate a relative index: // return index < 0 ? max(length + index, 0) : min(index, length) @export transitioning macro ConvertToRelativeIndex(implicit context: Context)( index: JSAny, length: uintptr): uintptr { const indexNumber: Number = ToInteger_Inline(index); return ConvertToRelativeIndex(indexNumber, length); } // Calculate a relative index: // return index < 0 ? max(length + index, 0) : min(index, length) @export macro ConvertToRelativeIndex(indexNumber: Number, length: uintptr): uintptr { typeswitch (indexNumber) { case (indexSmi: Smi): { const indexIntPtr: intptr = Convert<intptr>(indexSmi); // The logic is implemented using unsigned types. if (indexIntPtr < 0) { const relativeIndex: uintptr = Unsigned(indexIntPtr) + length; return relativeIndex < length ? relativeIndex : 0; } else { const relativeIndex: uintptr = Unsigned(indexIntPtr); return relativeIndex < length ? relativeIndex : length; } } case (indexHeapNumber: HeapNumber): { assert(IsNumberNormalized(indexHeapNumber)); const indexDouble: float64 = Convert<float64>(indexHeapNumber); // NaNs must already be handled by ConvertToRelativeIndex() version // above accepting JSAny indices. assert(!Float64IsNaN(indexDouble)); const lengthDouble: float64 = Convert<float64>(length); assert(lengthDouble <= kMaxSafeInteger); if (indexDouble < 0) { const relativeIndex: float64 = lengthDouble + indexDouble; return relativeIndex > 0 ? ChangeFloat64ToUintPtr(relativeIndex) : 0; } else { return ChangeFloat64ToUintPtr( indexDouble < lengthDouble ? indexDouble : lengthDouble); } } } } // After converting an index to a signed integer, clamps it to the provided // range [0, limit]: // return min(max(index, 0), limit) @export transitioning macro ClampToIndexRange(implicit context: Context)( index: JSAny, limit: uintptr): uintptr { const indexNumber: Number = ToInteger_Inline(index); return ClampToIndexRange(indexNumber, limit); } // Clamps given signed indexNumber to the provided range [0, limit]: // return min(max(index, 0), limit) @export macro ClampToIndexRange(indexNumber: Number, limit: uintptr): uintptr { typeswitch (indexNumber) { case (indexSmi: Smi): { if (indexSmi < 0) return 0; const index: uintptr = Unsigned(Convert<intptr>(indexSmi)); if (index >= limit) return limit; return index; } case (indexHeapNumber: HeapNumber): { assert(IsNumberNormalized(indexHeapNumber)); const indexDouble: float64 = Convert<float64>(indexHeapNumber); // NaNs must already be handled by ClampToIndexRange() version // above accepting JSAny indices. assert(!Float64IsNaN(indexDouble)); if (indexDouble <= 0) return 0; const maxIndexDouble: float64 = Convert<float64>(limit); assert(maxIndexDouble <= kMaxSafeInteger); if (indexDouble >= maxIndexDouble) return limit; return ChangeFloat64ToUintPtr(indexDouble); } } } extern builtin ObjectToString(Context, JSAny): String; extern builtin StringRepeat(Context, String, Number): String; @export struct KeyValuePair { key: JSAny; value: JSAny; } // Macro definitions for compatibility that expose functionality to the CSA // using "legacy" APIs. In Torque code, these should not be used. @export macro IsFastJSArray(o: Object, context: Context): bool { // Long-term, it's likely not a good idea to have this slow-path test here, // since it fundamentally breaks the type system. if (IsForceSlowPath()) return false; return Is<FastJSArray>(o); } @export macro BranchIfFastJSArray(o: Object, context: Context): never labels True, False { if (IsFastJSArray(o, context)) { goto True; } else { goto False; } } @export macro BranchIfFastJSArrayForRead(o: Object, context: Context): never labels True, False { // Long-term, it's likely not a good idea to have this slow-path test here, // since it fundamentally breaks the type system. if (IsForceSlowPath()) goto False; if (Is<FastJSArrayForRead>(o)) { goto True; } else { goto False; } } @export macro IsFastJSArrayWithNoCustomIteration(context: Context, o: Object): bool { return Is<FastJSArrayWithNoCustomIteration>(o); } @export macro IsFastJSArrayForReadWithNoCustomIteration(context: Context, o: Object): bool { return Is<FastJSArrayForReadWithNoCustomIteration>(o); } extern transitioning runtime CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, JSAny); extern transitioning runtime SetOwnPropertyIgnoreAttributes( implicit context: Context)(JSObject, String, JSAny, Smi); namespace runtime { extern runtime GetDerivedMap(Context, JSFunction, JSReceiver): Map; } extern macro IsDeprecatedMap(Map): bool; transitioning builtin FastCreateDataProperty(implicit context: Context)( receiver: JSReceiver, key: JSAny, value: JSAny): Object { try { const array = Cast<FastJSArray>(receiver) otherwise Slow; const index: Smi = Cast<Smi>(key) otherwise goto Slow; if (index < 0 || index > array.length) goto Slow; const isAppend = index == array.length; if (isAppend) { // Fast append only works on fast elements kind and with writable length. const kind = EnsureArrayPushable(array.map) otherwise Slow; array::EnsureWriteableFastElements(array); // We may have to transition a. // For now, if transition is required, jump away to slow. if (IsFastSmiElementsKind(kind)) { BuildAppendJSArray(ElementsKind::HOLEY_SMI_ELEMENTS, array, value) otherwise Slow; } else if (IsDoubleElementsKind(kind)) { BuildAppendJSArray(ElementsKind::HOLEY_DOUBLE_ELEMENTS, array, value) otherwise Slow; } else { assert(IsFastSmiOrTaggedElementsKind(kind)); BuildAppendJSArray(ElementsKind::HOLEY_ELEMENTS, array, value) otherwise Slow; } } else { // Non-appending element store. const kind = array.map.elements_kind; array::EnsureWriteableFastElements(array); // We may have to transition a. // For now, if transition is required, jump away to slow. if (IsFastSmiElementsKind(kind)) { const smiValue = Cast<Smi>(value) otherwise Slow; const elements = Cast<FixedArray>(array.elements) otherwise unreachable; elements[index] = smiValue; } else if (IsDoubleElementsKind(kind)) { const numberValue = Cast<Number>(value) otherwise Slow; const doubleElements = Cast<FixedDoubleArray>(array.elements) otherwise unreachable; doubleElements[index] = numberValue; } else { assert(IsFastSmiOrTaggedElementsKind(kind)); const elements = Cast<FixedArray>(array.elements) otherwise unreachable; elements[index] = value; } } } label Slow { CreateDataProperty(receiver, key, value); } return Undefined; } macro VerifiedUnreachable(): never { static_assert(false); unreachable; } macro Float64IsSomeInfinity(value: float64): bool { if (value == V8_INFINITY) { return true; } return value == (Convert<float64>(0) - V8_INFINITY); } @export macro IsIntegerOrSomeInfinity(o: Object): bool { typeswitch (o) { case (Smi): { return true; } case (hn: HeapNumber): { if (Float64IsSomeInfinity(Convert<float64>(hn))) { return true; } return IsInteger(hn); } case (Object): { return false; } } } builtin CheckNumberInRange(implicit context: Context)( value: Number, min: Number, max: Number, nodeId: Smi): Undefined { if (IsIntegerOrSomeInfinity(value) && min <= value && value <= max) { return Undefined; } else { Print('Range type assertion failed! (value/min/max/nodeId)'); Print(value); Print(min); Print(max); Print(nodeId); unreachable; } } // Assert that the objects satisfy SameValue or are both the hole. builtin CheckSameObject(implicit context: Context)( lhs: Object, rhs: Object): Undefined { typeswitch (lhs) { case (TheHole): { if (rhs == TheHole) return Undefined; } case (a: JSAny): { typeswitch (rhs) { case (b: JSAny): { if (SameValue(a, b)) return Undefined; } case (Object): { } } } case (Object): { } } Print('Distinct or unexpected values in CheckSameObject'); unreachable; } macro ReplaceTheHoleWithUndefined(o: JSAny|TheHole): JSAny { typeswitch (o) { case (TheHole): { return Undefined; } case (a: JSAny): { return a; } } } extern macro DecodeScopeInfoHasContextExtension(intptr): intptr; struct ConstantIterator<T: type> { macro Empty(): bool { return false; } macro Next(): T labels _NoMore { return this.value; } value: T; } macro ConstantIterator<T: type>(value: T): ConstantIterator<T> { return ConstantIterator{value}; } extern macro FeedbackIteratorEntrySize(): intptr; extern macro FeedbackIteratorHandlerOffset(): intptr; extern operator '[]' macro LoadWeakFixedArrayElement( WeakFixedArray, intptr): MaybeObject;