| // Copyright 2019 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| extern macro IsBigInt(HeapObject): bool; |
| extern macro IsConstructor(HeapObject): bool; |
| extern macro IsCustomElementsReceiverInstanceType(int32): bool; |
| extern macro IsExtensibleMap(Map): bool; |
| extern macro IsNumberNormalized(Number): bool; |
| extern macro IsSafeInteger(Object): bool; |
| |
| @export |
| macro IsAccessorInfo(o: HeapObject): bool { |
| return Is<AccessorInfo>(o); |
| } |
| |
| @export |
| macro IsAccessorPair(o: HeapObject): bool { |
| return Is<AccessorPair>(o); |
| } |
| |
| @export |
| macro IsAllocationSite(o: HeapObject): bool { |
| return Is<AllocationSite>(o); |
| } |
| |
| @export |
| macro IsCell(o: HeapObject): bool { |
| return Is<Cell>(o); |
| } |
| |
| @export |
| macro IsCode(o: HeapObject): bool { |
| return Is<Code>(o); |
| } |
| |
| @export |
| macro IsContext(o: HeapObject): bool { |
| return Is<Context>(o); |
| } |
| |
| @export |
| macro IsCoverageInfo(o: HeapObject): bool { |
| return Is<CoverageInfo>(o); |
| } |
| |
| @export |
| macro IsDebugInfo(o: HeapObject): bool { |
| return Is<DebugInfo>(o); |
| } |
| |
| @export |
| macro IsFixedDoubleArray(o: HeapObject): bool { |
| return Is<FixedDoubleArray>(o); |
| } |
| |
| @export |
| macro IsFeedbackCell(o: HeapObject): bool { |
| return Is<FeedbackCell>(o); |
| } |
| |
| @export |
| macro IsFeedbackVector(o: HeapObject): bool { |
| return Is<FeedbackVector>(o); |
| } |
| |
| @export |
| macro IsHeapNumber(o: HeapObject): bool { |
| return Is<HeapNumber>(o); |
| } |
| |
| @export |
| macro IsNativeContext(o: HeapObject): bool { |
| return Is<NativeContext>(o); |
| } |
| |
| @export |
| macro IsNumber(o: Object): bool { |
| return Is<Number>(o); |
| } |
| |
| @export |
| macro IsPrivateSymbol(o: HeapObject): bool { |
| return Is<PrivateSymbol>(o); |
| } |
| |
| @export |
| macro IsPromiseCapability(o: HeapObject): bool { |
| return Is<PromiseCapability>(o); |
| } |
| |
| @export |
| macro IsPromiseFulfillReactionJobTask(o: HeapObject): bool { |
| return Is<PromiseFulfillReactionJobTask>(o); |
| } |
| |
| @export |
| macro IsPromiseReaction(o: HeapObject): bool { |
| return Is<PromiseReaction>(o); |
| } |
| |
| @export |
| macro IsPromiseRejectReactionJobTask(o: HeapObject): bool { |
| return Is<PromiseRejectReactionJobTask>(o); |
| } |
| |
| @export |
| macro IsSharedFunctionInfo(o: HeapObject): bool { |
| return Is<SharedFunctionInfo>(o); |
| } |
| |
| @export |
| macro IsSymbol(o: HeapObject): bool { |
| return Is<Symbol>(o); |
| } |
| |
| extern macro TaggedToHeapObject(Object): HeapObject |
| labels CastError; |
| extern macro TaggedToSmi(Object): Smi |
| labels CastError; |
| extern macro TaggedToPositiveSmi(Object): PositiveSmi |
| labels CastError; |
| extern macro TaggedToDirectString(Object): DirectString |
| labels CastError; |
| extern macro HeapObjectToCallable(HeapObject): Callable |
| labels CastError; |
| extern macro HeapObjectToConstructor(HeapObject): Constructor |
| labels CastError; |
| extern macro HeapObjectToJSFunctionWithPrototypeSlot(HeapObject): |
| JSFunctionWithPrototypeSlot |
| labels CastError; |
| |
| macro Cast<A : type extends WeakHeapObject>(o: A|Object): A labels CastError { |
| if (!IsWeakOrCleared(o)) goto CastError; |
| return %RawDownCast<A>(o); |
| } |
| |
| macro Cast<A : type extends Object>(implicit context: Context)(o: MaybeObject): |
| A labels CastError { |
| typeswitch (o) { |
| case (WeakHeapObject): { |
| goto CastError; |
| } |
| case (o: Object): { |
| return Cast<A>(o) otherwise CastError; |
| } |
| } |
| } |
| |
| Cast<Undefined>(o: MaybeObject): Undefined labels CastError { |
| if (TaggedNotEqual(o, Undefined)) goto CastError; |
| return %RawDownCast<Undefined>(o); |
| } |
| |
| macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A |
| labels CastError { |
| return Cast<A>(TaggedToHeapObject(o) otherwise CastError) |
| otherwise CastError; |
| } |
| |
| // This is required for casting MaybeObject to Object. |
| Cast<Smi>(o: Object): Smi |
| labels CastError { |
| return TaggedToSmi(o) otherwise CastError; |
| } |
| |
| Cast<PositiveSmi>(o: Object): PositiveSmi |
| labels CastError { |
| return TaggedToPositiveSmi(o) otherwise CastError; |
| } |
| |
| Cast<Zero>(o: Object): Zero labels CastError { |
| if (TaggedEqual(o, SmiConstant(0))) return %RawDownCast<Zero>(o); |
| goto CastError; |
| } |
| |
| Cast<Number>(o: Object): Number |
| labels CastError { |
| typeswitch (o) { |
| case (s: Smi): { |
| return s; |
| } |
| case (n: HeapNumber): { |
| return n; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<Undefined>(o: Object): Undefined |
| labels CastError { |
| const o: MaybeObject = o; |
| return Cast<Undefined>(o) otherwise CastError; |
| } |
| |
| Cast<Numeric>(o: Object): Numeric labels CastError { |
| typeswitch (o) { |
| case (o: Number): { |
| return o; |
| } |
| case (o: BigInt): { |
| return o; |
| } |
| case (HeapObject): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<TheHole>(o: Object): TheHole labels CastError { |
| if (o == TheHole) return %RawDownCast<TheHole>(o); |
| goto CastError; |
| } |
| |
| Cast<TheHole>(o: HeapObject): TheHole labels CastError { |
| const o: Object = o; |
| return Cast<TheHole>(o) otherwise CastError; |
| } |
| |
| Cast<True>(o: Object): True labels CastError { |
| if (o == True) return %RawDownCast<True>(o); |
| goto CastError; |
| } |
| |
| Cast<True>(o: HeapObject): True labels CastError { |
| const o: Object = o; |
| return Cast<True>(o) otherwise CastError; |
| } |
| |
| Cast<False>(o: Object): False labels CastError { |
| if (o == False) return %RawDownCast<False>(o); |
| goto CastError; |
| } |
| |
| Cast<False>(o: HeapObject): False labels CastError { |
| const o: Object = o; |
| return Cast<False>(o) otherwise CastError; |
| } |
| |
| Cast<Boolean>(o: Object): Boolean labels CastError { |
| typeswitch (o) { |
| case (o: True): { |
| return o; |
| } |
| case (o: False): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<Boolean>(o: HeapObject): Boolean labels CastError { |
| const o: Object = o; |
| return Cast<Boolean>(o) otherwise CastError; |
| } |
| |
| // TODO(tebbi): These trivial casts for union types should be generated |
| // automatically. |
| |
| Cast<JSPrimitive>(o: Object): JSPrimitive labels CastError { |
| typeswitch (o) { |
| case (o: Numeric): { |
| return o; |
| } |
| case (o: String): { |
| return o; |
| } |
| case (o: Symbol): { |
| return o; |
| } |
| case (o: Boolean): { |
| return o; |
| } |
| case (o: Undefined): { |
| return o; |
| } |
| case (o: Null): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<JSAny>(o: Object): JSAny labels CastError { |
| typeswitch (o) { |
| case (o: JSPrimitive): { |
| return o; |
| } |
| case (o: JSReceiver): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<JSAny|TheHole>(o: Object): JSAny|TheHole labels CastError { |
| typeswitch (o) { |
| case (o: JSAny): { |
| return o; |
| } |
| case (o: TheHole): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<Number|TheHole>(o: Object): Number|TheHole labels CastError { |
| typeswitch (o) { |
| case (o: Number): { |
| return o; |
| } |
| case (o: TheHole): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| macro Cast<A : type extends HeapObject>(o: HeapObject): A |
| labels CastError; |
| |
| Cast<HeapObject>(o: HeapObject): HeapObject |
| labels _CastError { |
| return o; |
| } |
| |
| Cast<Null>(o: HeapObject): Null |
| labels CastError { |
| if (o != Null) goto CastError; |
| return %RawDownCast<Null>(o); |
| } |
| |
| Cast<Undefined>(o: HeapObject): Undefined |
| labels CastError { |
| const o: MaybeObject = o; |
| return Cast<Undefined>(o) otherwise CastError; |
| } |
| |
| Cast<EmptyFixedArray>(o: Object): EmptyFixedArray |
| labels CastError { |
| if (o != kEmptyFixedArray) goto CastError; |
| return %RawDownCast<EmptyFixedArray>(o); |
| } |
| Cast<EmptyFixedArray>(o: HeapObject): EmptyFixedArray |
| labels CastError { |
| const o: Object = o; |
| return Cast<EmptyFixedArray>(o) otherwise CastError; |
| } |
| |
| Cast<(FixedDoubleArray | EmptyFixedArray)>(o: HeapObject): FixedDoubleArray| |
| EmptyFixedArray labels CastError { |
| typeswitch (o) { |
| case (o: EmptyFixedArray): { |
| return o; |
| } |
| case (o: FixedDoubleArray): { |
| return o; |
| } |
| case (HeapObject): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<Callable>(o: HeapObject): Callable |
| labels CastError { |
| return HeapObjectToCallable(o) otherwise CastError; |
| } |
| |
| Cast<Undefined|Callable>(o: HeapObject): Undefined|Callable |
| labels CastError { |
| if (o == Undefined) return Undefined; |
| return HeapObjectToCallable(o) otherwise CastError; |
| } |
| |
| macro Cast<T : type extends Symbol>(o: Symbol): T labels CastError; |
| Cast<PublicSymbol>(s: Symbol): PublicSymbol labels CastError { |
| if (s.flags.is_private) goto CastError; |
| return %RawDownCast<PublicSymbol>(s); |
| } |
| Cast<PrivateSymbol>(s: Symbol): PrivateSymbol labels CastError { |
| if (s.flags.is_private) return %RawDownCast<PrivateSymbol>(s); |
| goto CastError; |
| } |
| Cast<PublicSymbol>(o: HeapObject): PublicSymbol labels CastError { |
| const s = Cast<Symbol>(o) otherwise CastError; |
| return Cast<PublicSymbol>(s) otherwise CastError; |
| } |
| Cast<PrivateSymbol>(o: HeapObject): PrivateSymbol labels CastError { |
| const s = Cast<Symbol>(o) otherwise CastError; |
| return Cast<PrivateSymbol>(s) otherwise CastError; |
| } |
| |
| Cast<DirectString>(o: HeapObject): DirectString |
| labels CastError { |
| return TaggedToDirectString(o) otherwise CastError; |
| } |
| |
| Cast<Constructor>(o: HeapObject): Constructor |
| labels CastError { |
| return HeapObjectToConstructor(o) otherwise CastError; |
| } |
| |
| Cast<JSFunctionWithPrototypeSlot>(o: HeapObject): JSFunctionWithPrototypeSlot |
| labels CastError { |
| return HeapObjectToJSFunctionWithPrototypeSlot(o) otherwise CastError; |
| } |
| |
| Cast<BigInt>(o: HeapObject): BigInt labels CastError { |
| if (IsBigInt(o)) return %RawDownCast<BigInt>(o); |
| goto CastError; |
| } |
| |
| Cast<JSRegExpResult>(implicit context: Context)(o: HeapObject): JSRegExpResult |
| labels CastError { |
| if (regexp::IsRegExpResult(o)) return %RawDownCast<JSRegExpResult>(o); |
| goto CastError; |
| } |
| |
| Cast<JSSloppyArgumentsObject>(implicit context: Context)(o: HeapObject): |
| JSSloppyArgumentsObject |
| labels CastError { |
| const map: Map = o.map; |
| if (IsFastAliasedArgumentsMap(map) || IsSloppyArgumentsMap(map) || |
| IsSlowAliasedArgumentsMap(map)) { |
| return %RawDownCast<JSSloppyArgumentsObject>(o); |
| } |
| goto CastError; |
| } |
| |
| Cast<JSStrictArgumentsObject>(implicit context: Context)(o: HeapObject): |
| JSStrictArgumentsObject |
| labels CastError { |
| const map: Map = o.map; |
| if (!IsStrictArgumentsMap(map)) goto CastError; |
| return %RawDownCast<JSStrictArgumentsObject>(o); |
| } |
| |
| Cast<JSArgumentsObjectWithLength>(implicit context: Context)(o: HeapObject): |
| JSArgumentsObjectWithLength |
| labels CastError { |
| typeswitch (o) { |
| case (o: JSStrictArgumentsObject): { |
| return o; |
| } |
| case (o: JSSloppyArgumentsObject): { |
| return o; |
| } |
| case (HeapObject): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<FastJSRegExp>(implicit context: Context)(o: HeapObject): FastJSRegExp |
| labels CastError { |
| // TODO(jgruber): Remove or redesign this. There is no single 'fast' regexp, |
| // the conditions to make a regexp object fast differ based on the callsite. |
| // For now, run the strict variant since replace (the only current callsite) |
| // accesses flag getters. |
| if (regexp::IsFastRegExpStrict(o)) { |
| return %RawDownCast<FastJSRegExp>(o); |
| } |
| goto CastError; |
| } |
| |
| Cast<FastJSArray>(implicit context: Context)(o: HeapObject): FastJSArray |
| labels CastError { |
| if (IsForceSlowPath()) goto CastError; |
| |
| if (!Is<JSArray>(o)) goto CastError; |
| |
| // Bailout if receiver has slow elements. |
| const map: Map = o.map; |
| const elementsKind: ElementsKind = LoadMapElementsKind(map); |
| if (!IsFastElementsKind(elementsKind)) goto CastError; |
| |
| // Verify that our prototype is the initial array prototype. |
| if (!IsPrototypeInitialArrayPrototype(map)) goto CastError; |
| |
| if (IsNoElementsProtectorCellInvalid()) goto CastError; |
| return %RawDownCast<FastJSArray>(o); |
| } |
| |
| Cast<FastJSArrayForRead>(implicit context: Context)(o: HeapObject): |
| FastJSArrayForRead |
| labels CastError { |
| if (!Is<JSArray>(o)) goto CastError; |
| |
| // Bailout if receiver has slow elements. |
| const map: Map = o.map; |
| const elementsKind: ElementsKind = LoadMapElementsKind(map); |
| if (!IsElementsKindLessThanOrEqual( |
| elementsKind, ElementsKind::LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND)) |
| goto CastError; |
| |
| // Verify that our prototype is the initial array prototype. |
| if (!IsPrototypeInitialArrayPrototype(map)) goto CastError; |
| |
| if (IsNoElementsProtectorCellInvalid()) goto CastError; |
| return %RawDownCast<FastJSArrayForRead>(o); |
| } |
| |
| Cast<FastJSArrayForCopy>(implicit context: Context)(o: HeapObject): |
| FastJSArrayForCopy |
| labels CastError { |
| if (IsArraySpeciesProtectorCellInvalid()) goto CastError; |
| const a = Cast<FastJSArray>(o) otherwise CastError; |
| return %RawDownCast<FastJSArrayForCopy>(a); |
| } |
| |
| Cast<FastJSArrayWithNoCustomIteration>(implicit context: Context)( |
| o: HeapObject): FastJSArrayWithNoCustomIteration |
| labels CastError { |
| if (IsArrayIteratorProtectorCellInvalid()) goto CastError; |
| const a = Cast<FastJSArray>(o) otherwise CastError; |
| return %RawDownCast<FastJSArrayWithNoCustomIteration>(a); |
| } |
| |
| Cast<FastJSArrayForReadWithNoCustomIteration>(implicit context: Context)( |
| o: HeapObject): FastJSArrayForReadWithNoCustomIteration |
| labels CastError { |
| if (IsArrayIteratorProtectorCellInvalid()) goto CastError; |
| const a = Cast<FastJSArrayForRead>(o) otherwise CastError; |
| return %RawDownCast<FastJSArrayForReadWithNoCustomIteration>(a); |
| } |
| |
| Cast<SeqOneByteString>(o: HeapObject): SeqOneByteString labels CastError { |
| if (!IsSeqOneByteString(o)) goto CastError; |
| return %RawDownCast<SeqOneByteString>(o); |
| } |
| |
| Cast<JSReceiver|Null>(o: HeapObject): JSReceiver|Null |
| labels CastError { |
| typeswitch (o) { |
| case (o: Null): { |
| return o; |
| } |
| case (o: JSReceiver): { |
| return o; |
| } |
| case (HeapObject): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<Smi|PromiseReaction>(o: Object): Smi|PromiseReaction labels CastError { |
| typeswitch (o) { |
| case (o: Smi): { |
| return o; |
| } |
| case (o: PromiseReaction): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<String|Callable>(implicit context: Context)(o: Object): String| |
| Callable labels CastError { |
| typeswitch (o) { |
| case (o: String): { |
| return o; |
| } |
| case (o: Callable): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<Zero|PromiseReaction>(implicit context: Context)(o: Object): Zero| |
| PromiseReaction labels CastError { |
| typeswitch (o) { |
| case (o: Zero): { |
| return o; |
| } |
| case (o: PromiseReaction): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<JSFunction|JSBoundFunction>(implicit context: Context)(o: Object): |
| JSFunction|JSBoundFunction labels CastError { |
| typeswitch (o) { |
| case (o: JSFunction): { |
| return o; |
| } |
| case (o: JSBoundFunction): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<FixedArray|Undefined>(o: HeapObject): FixedArray| |
| Undefined labels CastError { |
| typeswitch (o) { |
| case (o: Undefined): { |
| return o; |
| } |
| case (o: FixedArray): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| Cast<JSProxy|Null>(o: HeapObject): JSProxy|Null labels CastError { |
| typeswitch (o) { |
| case (o: Null): { |
| return o; |
| } |
| case (o: JSProxy): { |
| return o; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| macro Is<A : type extends Object, B : type extends Object>( |
| implicit context: Context)(o: B): bool { |
| Cast<A>(o) otherwise return false; |
| return true; |
| } |
| |
| macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object): |
| A { |
| assert(Is<A>(o)); |
| return %RawDownCast<A>(o); |
| } |
| |
| macro UnsafeConstCast<T: type>(r: const &T):&T { |
| return %RawDownCast<&T>(r); |
| } |
| |
| UnsafeCast<RegExpMatchInfo>(implicit context: Context)(o: Object): |
| RegExpMatchInfo { |
| assert(Is<FixedArray>(o)); |
| return %RawDownCast<RegExpMatchInfo>(o); |
| } |
| |
| macro UnsafeCast<A : type extends WeakHeapObject>(o: A|Object): A { |
| assert(IsWeakOrCleared(o)); |
| return %RawDownCast<A>(o); |
| } |
| |
| macro |
| CastOrDefault<T: type, Arg: type, Default: type>(implicit context: Context)( |
| x: Arg, default: Default): T|Default { |
| return Cast<T>(x) otherwise return default; |
| } |
| |
| // This is required for casting MaybeObject to Object. |
| Cast<Object>(o: Object): Object |
| labels _CastError { |
| return o; |
| } |