// 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(o); } @export macro IsAccessorPair(o: HeapObject): bool { return Is(o); } @export macro IsAllocationSite(o: HeapObject): bool { return Is(o); } @export macro IsCell(o: HeapObject): bool { return Is(o); } @export macro IsCode(o: HeapObject): bool { return Is(o); } @export macro IsCodeDataContainer(o: HeapObject): bool { return Is(o); } @export macro IsContext(o: HeapObject): bool { return Is(o); } @export macro IsCoverageInfo(o: HeapObject): bool { return Is(o); } @export macro IsDebugInfo(o: HeapObject): bool { return Is(o); } @export macro IsFixedDoubleArray(o: HeapObject): bool { return Is(o); } @export macro IsFeedbackCell(o: HeapObject): bool { return Is(o); } @export macro IsFeedbackVector(o: HeapObject): bool { return Is(o); } @export macro IsHeapNumber(o: HeapObject): bool { return Is(o); } @export macro IsNativeContext(o: HeapObject): bool { return Is(o); } @export macro IsNumber(o: Object): bool { return Is(o); } @export macro IsPrivateSymbol(o: HeapObject): bool { return Is(o); } @export macro IsPromiseCapability(o: HeapObject): bool { return Is(o); } @export macro IsPromiseFulfillReactionJobTask(o: HeapObject): bool { return Is(o); } @export macro IsPromiseReaction(o: HeapObject): bool { return Is(o); } @export macro IsPromiseRejectReactionJobTask(o: HeapObject): bool { return Is(o); } @export macro IsSharedFunctionInfo(o: HeapObject): bool { return Is(o); } @export macro IsSymbol(o: HeapObject): bool { return Is(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(o: A|Object): A labels CastError { if (!IsWeakOrCleared(o)) goto CastError; return %RawDownCast(o); } macro Cast(implicit context: Context)(o: MaybeObject): A labels CastError { typeswitch (o) { case (WeakHeapObject): { goto CastError; } case (o: Object): { return Cast(o) otherwise CastError; } } } Cast(o: MaybeObject): Undefined labels CastError { if (TaggedNotEqual(o, Undefined)) goto CastError; return %RawDownCast(o); } macro Cast(implicit context: Context)(o: Object): A labels CastError { return Cast(TaggedToHeapObject(o) otherwise CastError) otherwise CastError; } // This is required for casting MaybeObject to Object. Cast(o: Object): Smi labels CastError { return TaggedToSmi(o) otherwise CastError; } Cast(o: Object): PositiveSmi labels CastError { return TaggedToPositiveSmi(o) otherwise CastError; } Cast(o: Object): Zero labels CastError { if (TaggedEqual(o, SmiConstant(0))) return %RawDownCast(o); goto CastError; } Cast(o: Object): Number labels CastError { typeswitch (o) { case (s: Smi): { return s; } case (n: HeapNumber): { return n; } case (Object): { goto CastError; } } } Cast(o: Object): Undefined labels CastError { const o: MaybeObject = o; return Cast(o) otherwise CastError; } Cast(o: Object): Numeric labels CastError { typeswitch (o) { case (o: Number): { return o; } case (o: BigInt): { return o; } case (HeapObject): { goto CastError; } } } Cast(o: Object): TheHole labels CastError { if (o == TheHole) return %RawDownCast(o); goto CastError; } Cast(o: HeapObject): TheHole labels CastError { const o: Object = o; return Cast(o) otherwise CastError; } Cast(o: Object): True labels CastError { if (o == True) return %RawDownCast(o); goto CastError; } Cast(o: HeapObject): True labels CastError { const o: Object = o; return Cast(o) otherwise CastError; } Cast(o: Object): False labels CastError { if (o == False) return %RawDownCast(o); goto CastError; } Cast(o: HeapObject): False labels CastError { const o: Object = o; return Cast(o) otherwise CastError; } Cast(o: Object): Boolean labels CastError { typeswitch (o) { case (o: True): { return o; } case (o: False): { return o; } case (Object): { goto CastError; } } } Cast(o: HeapObject): Boolean labels CastError { const o: Object = o; return Cast(o) otherwise CastError; } // TODO(turbofan): These trivial casts for union types should be generated // automatically. Cast(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(o: Object): JSAny labels CastError { typeswitch (o) { case (o: JSPrimitive): { return o; } case (o: JSReceiver): { return o; } case (Object): { goto CastError; } } } Cast(o: Object): JSAny|TheHole labels CastError { typeswitch (o) { case (o: JSAny): { return o; } case (o: TheHole): { return o; } case (Object): { goto CastError; } } } Cast(o: Object): Number|TheHole labels CastError { typeswitch (o) { case (o: Number): { return o; } case (o: TheHole): { return o; } case (Object): { goto CastError; } } } Cast(o: Object): Context|Zero|Undefined labels CastError { typeswitch (o) { case (o: Context): { return o; } case (o: Zero): { return o; } case (o: Undefined): { return o; } case (Object): { goto CastError; } } } macro Cast(o: HeapObject): A labels CastError; Cast(o: HeapObject): HeapObject labels _CastError { return o; } Cast(o: HeapObject): Null labels CastError { if (o != Null) goto CastError; return %RawDownCast(o); } Cast(o: HeapObject): Undefined labels CastError { const o: MaybeObject = o; return Cast(o) otherwise CastError; } Cast(o: Object): EmptyFixedArray labels CastError { if (o != kEmptyFixedArray) goto CastError; return %RawDownCast(o); } Cast(o: HeapObject): EmptyFixedArray labels CastError { const o: Object = o; return Cast(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(o: HeapObject): Callable labels CastError { return HeapObjectToCallable(o) otherwise CastError; } Cast(o: HeapObject): Undefined|Callable labels CastError { if (o == Undefined) return Undefined; return HeapObjectToCallable(o) otherwise CastError; } Cast(o: HeapObject): Undefined|JSFunction labels CastError { if (o == Undefined) return Undefined; return Cast(o) otherwise CastError; } macro Cast(o: Symbol): T labels CastError; Cast(s: Symbol): PublicSymbol labels CastError { if (s.flags.is_private) goto CastError; return %RawDownCast(s); } Cast(s: Symbol): PrivateSymbol labels CastError { if (s.flags.is_private) return %RawDownCast(s); goto CastError; } Cast(o: HeapObject): PublicSymbol labels CastError { const s = Cast(o) otherwise CastError; return Cast(s) otherwise CastError; } Cast(o: HeapObject): PrivateSymbol labels CastError { const s = Cast(o) otherwise CastError; return Cast(s) otherwise CastError; } Cast(o: String): DirectString labels CastError { return TaggedToDirectString(o) otherwise CastError; } Cast(o: HeapObject): Constructor labels CastError { return HeapObjectToConstructor(o) otherwise CastError; } Cast(o: HeapObject): JSFunctionWithPrototypeSlot labels CastError { return HeapObjectToJSFunctionWithPrototypeSlot(o) otherwise CastError; } Cast(o: HeapObject): BigInt labels CastError { if (IsBigInt(o)) return %RawDownCast(o); goto CastError; } Cast(implicit context: Context)(o: HeapObject): JSRegExpResult labels CastError { if (regexp::IsRegExpResult(o)) return %RawDownCast(o); goto CastError; } Cast(implicit context: Context)(o: HeapObject): JSSloppyArgumentsObject labels CastError { const map: Map = o.map; if (IsFastAliasedArgumentsMap(map) || IsSloppyArgumentsMap(map) || IsSlowAliasedArgumentsMap(map)) { return %RawDownCast(o); } goto CastError; } Cast(implicit context: Context)(o: HeapObject): JSStrictArgumentsObject labels CastError { const map: Map = o.map; if (!IsStrictArgumentsMap(map)) goto CastError; return %RawDownCast(o); } Cast(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(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(o); } goto CastError; } Cast(implicit context: Context)(o: HeapObject): FastJSArray labels CastError { if (IsForceSlowPath()) goto CastError; if (!Is(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(o); } Cast(implicit context: Context)(o: HeapObject): FastJSArrayForRead labels CastError { if (!Is(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(o); } Cast(implicit context: Context)(o: HeapObject): FastJSArrayForCopy labels CastError { if (IsArraySpeciesProtectorCellInvalid()) goto CastError; // TODO(victorgomes): Check if we can cast from FastJSArrayForRead instead. const a = Cast(o) otherwise CastError; return %RawDownCast(a); } Cast(implicit context: Context)(o: HeapObject): FastJSArrayForConcat labels CastError { if (IsIsConcatSpreadableProtectorCellInvalid()) goto CastError; const a = Cast(o) otherwise CastError; return %RawDownCast(a); } Cast(implicit context: Context)( o: HeapObject): FastJSArrayWithNoCustomIteration labels CastError { if (IsArrayIteratorProtectorCellInvalid()) goto CastError; const a = Cast(o) otherwise CastError; return %RawDownCast(a); } Cast(implicit context: Context)( o: HeapObject): FastJSArrayForReadWithNoCustomIteration labels CastError { if (IsArrayIteratorProtectorCellInvalid()) goto CastError; const a = Cast(o) otherwise CastError; return %RawDownCast(a); } macro Cast(o: String): T labels CastError; Cast(o: HeapObject): SeqOneByteString labels CastError { return Cast(Cast(o) otherwise CastError) otherwise CastError; } Cast(o: String): SeqOneByteString labels CastError { const instanceType = o.StringInstanceType(); // Using & instead of && enables Turbofan to merge the two checks into one. if (!(instanceType.representation == StringRepresentationTag::kSeqStringTag & instanceType.is_one_byte)) { goto CastError; } return %RawDownCast(o); } Cast(o: HeapObject): SeqTwoByteString labels CastError { return Cast(Cast(o) otherwise CastError) otherwise CastError; } Cast(o: String): SeqTwoByteString labels CastError { const instanceType = o.StringInstanceType(); // Using & instead of && enables Turbofan to merge the two checks into one. if (!(instanceType.representation == StringRepresentationTag::kSeqStringTag & !instanceType.is_one_byte)) { goto CastError; } return %RawDownCast(o); } Cast(o: HeapObject): ThinString labels CastError { return Cast(Cast(o) otherwise CastError) otherwise CastError; } Cast(o: String): ThinString labels CastError { const instanceType = o.StringInstanceType(); if (instanceType.representation != StringRepresentationTag::kThinStringTag) { goto CastError; } return %RawDownCast(o); } Cast(o: HeapObject): ConsString labels CastError { return Cast(Cast(o) otherwise CastError) otherwise CastError; } Cast(o: String): ConsString labels CastError { const instanceType = o.StringInstanceType(); if (instanceType.representation != StringRepresentationTag::kConsStringTag) { goto CastError; } return %RawDownCast(o); } Cast(o: HeapObject): SlicedString labels CastError { return Cast(Cast(o) otherwise CastError) otherwise CastError; } Cast(o: String): SlicedString labels CastError { const instanceType = o.StringInstanceType(); if (instanceType.representation != StringRepresentationTag::kSlicedStringTag) { goto CastError; } return %RawDownCast(o); } Cast(o: HeapObject): ExternalOneByteString labels CastError { return Cast(Cast(o) otherwise CastError) otherwise CastError; } Cast(o: String): ExternalOneByteString labels CastError { const instanceType = o.StringInstanceType(); // Using & instead of && enables Turbofan to merge the two checks into one. if (!(instanceType.representation == StringRepresentationTag::kExternalStringTag & instanceType.is_one_byte)) { goto CastError; } return %RawDownCast(o); } Cast(o: HeapObject): ExternalTwoByteString labels CastError { return Cast(Cast(o) otherwise CastError) otherwise CastError; } Cast(o: String): ExternalTwoByteString labels CastError { const instanceType = o.StringInstanceType(); // Using & instead of && enables Turbofan to merge the two checks into one. if (!(instanceType.representation == StringRepresentationTag::kExternalStringTag & !instanceType.is_one_byte)) { goto CastError; } return %RawDownCast(o); } Cast(o: HeapObject): JSReceiver|Null labels CastError { typeswitch (o) { case (o: Null): { return o; } case (o: JSReceiver): { return o; } case (HeapObject): { goto CastError; } } } Cast(o: Object): Smi|PromiseReaction labels CastError { typeswitch (o) { case (o: Smi): { return o; } case (o: PromiseReaction): { return o; } case (Object): { goto CastError; } } } Cast(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(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(implicit context: Context)( o: Object): JSFunction|JSBoundFunction|JSWrappedFunction labels CastError { typeswitch (o) { case (o: JSFunction): { return o; } case (o: JSBoundFunction): { return o; } case (o: JSWrappedFunction): { return o; } case (Object): { goto CastError; } } } Cast(o: HeapObject): FixedArray| Undefined labels CastError { typeswitch (o) { case (o: Undefined): { return o; } case (o: FixedArray): { return o; } case (Object): { goto CastError; } } } Cast(o: HeapObject): JSProxy|Null labels CastError { typeswitch (o) { case (o: Null): { return o; } case (o: JSProxy): { return o; } case (Object): { goto CastError; } } } macro Is( implicit context: Context)(o: B): bool { Cast(o) otherwise return false; return true; } macro UnsafeCast(implicit context: Context)(o: Object): A { dcheck(Is(o)); return %RawDownCast(o); } macro UnsafeConstCast(r: const &T):&T { return %RawDownCast<&T>(r); } UnsafeCast(implicit context: Context)(o: Object): RegExpMatchInfo { dcheck(Is(o)); return %RawDownCast(o); } macro UnsafeCast(o: A|Object): A { dcheck(IsWeakOrCleared(o)); return %RawDownCast(o); } macro CastOrDefault(implicit context: Context)( x: Arg, default: Default): T|Default { return Cast(x) otherwise return default; } // This is required for casting MaybeObject to Object. Cast(o: Object): Object labels _CastError { return o; }