blob: 760783cbb81ce41eac6ed6369a9f28d456226ffb [file] [log] [blame]
// 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 'ObjectPtr';
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 value with the size of Tagged which may contain arbitrary data.
type Uninitialized extends Tagged;
extern macro MakeWeak(HeapObject): WeakHeapObject;
extern macro GetHeapObjectAssumeWeak(WeakHeapObject):
HeapObject labels ClearedWeakPointer;
extern macro IsWeakOrCleared(MaybeObject): bool;
extern macro IsWeakReferenceToObject(MaybeObject, Object): 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(tebbi): 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 int8 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.
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};
// 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 StringTable 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 'void*';
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;
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,
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,
kWasmTrapFuncInvalid,
kWasmTrapFuncSigMismatch,
kWasmTrapDataSegmentDropped,
kWasmTrapElemSegmentDropped,
kWasmTrapTableOutOfBounds,
kWasmTrapBrOnExnNull,
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';
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 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 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 builtin ToObject(Context, JSAny): JSReceiver;
extern macro ToObject_Inline(Context, JSAny): JSReceiver;
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 runtime StringEqual(Context, String, String): Oddball;
extern builtin StringLessThan(Context, String, String): Boolean;
extern macro StringCharCodeAt(String, uintptr): int32;
extern runtime StringCompareSequence(Context, String, String, Number): Boolean;
extern macro StringFromSingleCharCode(int32): 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
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();
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 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(tebbi): 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;
}
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): Undefined {
if (IsIntegerOrSomeInfinity(value) && min <= value && value <= max) {
return Undefined;
} else {
Print('Range type assertion failed! (value/min/max)');
Print(value);
Print(min);
Print(max);
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};
}