• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5extern macro IsBigInt(HeapObject): bool;
6extern macro IsConstructor(HeapObject): bool;
7extern macro IsCustomElementsReceiverInstanceType(int32): bool;
8extern macro IsExtensibleMap(Map): bool;
9extern macro IsNumberNormalized(Number): bool;
10extern macro IsSafeInteger(Object): bool;
11
12@export
13macro IsAccessorInfo(o: HeapObject): bool {
14  return Is<AccessorInfo>(o);
15}
16
17@export
18macro IsAccessorPair(o: HeapObject): bool {
19  return Is<AccessorPair>(o);
20}
21
22@export
23macro IsAllocationSite(o: HeapObject): bool {
24  return Is<AllocationSite>(o);
25}
26
27@export
28macro IsCell(o: HeapObject): bool {
29  return Is<Cell>(o);
30}
31
32@export
33macro IsCode(o: HeapObject): bool {
34  return Is<Code>(o);
35}
36
37@export
38macro IsCodeDataContainer(o: HeapObject): bool {
39  return Is<CodeDataContainer>(o);
40}
41
42@export
43macro IsContext(o: HeapObject): bool {
44  return Is<Context>(o);
45}
46
47@export
48macro IsCoverageInfo(o: HeapObject): bool {
49  return Is<CoverageInfo>(o);
50}
51
52@export
53macro IsDebugInfo(o: HeapObject): bool {
54  return Is<DebugInfo>(o);
55}
56
57@export
58macro IsFixedDoubleArray(o: HeapObject): bool {
59  return Is<FixedDoubleArray>(o);
60}
61
62@export
63macro IsFeedbackCell(o: HeapObject): bool {
64  return Is<FeedbackCell>(o);
65}
66
67@export
68macro IsFeedbackVector(o: HeapObject): bool {
69  return Is<FeedbackVector>(o);
70}
71
72@export
73macro IsHeapNumber(o: HeapObject): bool {
74  return Is<HeapNumber>(o);
75}
76
77@export
78macro IsNativeContext(o: HeapObject): bool {
79  return Is<NativeContext>(o);
80}
81
82@export
83macro IsNumber(o: Object): bool {
84  return Is<Number>(o);
85}
86
87@export
88macro IsPrivateSymbol(o: HeapObject): bool {
89  return Is<PrivateSymbol>(o);
90}
91
92@export
93macro IsPromiseCapability(o: HeapObject): bool {
94  return Is<PromiseCapability>(o);
95}
96
97@export
98macro IsPromiseFulfillReactionJobTask(o: HeapObject): bool {
99  return Is<PromiseFulfillReactionJobTask>(o);
100}
101
102@export
103macro IsPromiseReaction(o: HeapObject): bool {
104  return Is<PromiseReaction>(o);
105}
106
107@export
108macro IsPromiseRejectReactionJobTask(o: HeapObject): bool {
109  return Is<PromiseRejectReactionJobTask>(o);
110}
111
112@export
113macro IsSharedFunctionInfo(o: HeapObject): bool {
114  return Is<SharedFunctionInfo>(o);
115}
116
117@export
118macro IsSymbol(o: HeapObject): bool {
119  return Is<Symbol>(o);
120}
121
122extern macro TaggedToHeapObject(Object): HeapObject
123    labels CastError;
124extern macro TaggedToSmi(Object): Smi
125    labels CastError;
126extern macro TaggedToPositiveSmi(Object): PositiveSmi
127    labels CastError;
128extern macro TaggedToDirectString(Object): DirectString
129    labels CastError;
130extern macro HeapObjectToCallable(HeapObject): Callable
131    labels CastError;
132extern macro HeapObjectToConstructor(HeapObject): Constructor
133    labels CastError;
134extern macro HeapObjectToJSFunctionWithPrototypeSlot(HeapObject):
135    JSFunctionWithPrototypeSlot
136    labels CastError;
137
138macro Cast<A : type extends WeakHeapObject>(o: A|Object): A labels CastError {
139  if (!IsWeakOrCleared(o)) goto CastError;
140  return %RawDownCast<A>(o);
141}
142
143macro Cast<A : type extends Object>(implicit context: Context)(o: MaybeObject):
144    A labels CastError {
145  typeswitch (o) {
146    case (WeakHeapObject): {
147      goto CastError;
148    }
149    case (o: Object): {
150      return Cast<A>(o) otherwise CastError;
151    }
152  }
153}
154
155Cast<Undefined>(o: MaybeObject): Undefined labels CastError {
156  if (TaggedNotEqual(o, Undefined)) goto CastError;
157  return %RawDownCast<Undefined>(o);
158}
159
160macro Cast<A : type extends Object>(implicit context: Context)(o: Object): A
161    labels CastError {
162  return Cast<A>(TaggedToHeapObject(o) otherwise CastError)
163      otherwise CastError;
164}
165
166// This is required for casting MaybeObject to Object.
167Cast<Smi>(o: Object): Smi
168    labels CastError {
169  return TaggedToSmi(o) otherwise CastError;
170}
171
172Cast<PositiveSmi>(o: Object): PositiveSmi
173    labels CastError {
174  return TaggedToPositiveSmi(o) otherwise CastError;
175}
176
177Cast<Zero>(o: Object): Zero labels CastError {
178  if (TaggedEqual(o, SmiConstant(0))) return %RawDownCast<Zero>(o);
179  goto CastError;
180}
181
182Cast<Number>(o: Object): Number
183    labels CastError {
184  typeswitch (o) {
185    case (s: Smi): {
186      return s;
187    }
188    case (n: HeapNumber): {
189      return n;
190    }
191    case (Object): {
192      goto CastError;
193    }
194  }
195}
196
197Cast<Undefined>(o: Object): Undefined
198    labels CastError {
199  const o: MaybeObject = o;
200  return Cast<Undefined>(o) otherwise CastError;
201}
202
203Cast<Numeric>(o: Object): Numeric labels CastError {
204  typeswitch (o) {
205    case (o: Number): {
206      return o;
207    }
208    case (o: BigInt): {
209      return o;
210    }
211    case (HeapObject): {
212      goto CastError;
213    }
214  }
215}
216
217Cast<TheHole>(o: Object): TheHole labels CastError {
218  if (o == TheHole) return %RawDownCast<TheHole>(o);
219  goto CastError;
220}
221
222Cast<TheHole>(o: HeapObject): TheHole labels CastError {
223  const o: Object = o;
224  return Cast<TheHole>(o) otherwise CastError;
225}
226
227Cast<True>(o: Object): True labels CastError {
228  if (o == True) return %RawDownCast<True>(o);
229  goto CastError;
230}
231
232Cast<True>(o: HeapObject): True labels CastError {
233  const o: Object = o;
234  return Cast<True>(o) otherwise CastError;
235}
236
237Cast<False>(o: Object): False labels CastError {
238  if (o == False) return %RawDownCast<False>(o);
239  goto CastError;
240}
241
242Cast<False>(o: HeapObject): False labels CastError {
243  const o: Object = o;
244  return Cast<False>(o) otherwise CastError;
245}
246
247Cast<Boolean>(o: Object): Boolean labels CastError {
248  typeswitch (o) {
249    case (o: True): {
250      return o;
251    }
252    case (o: False): {
253      return o;
254    }
255    case (Object): {
256      goto CastError;
257    }
258  }
259}
260
261Cast<Boolean>(o: HeapObject): Boolean labels CastError {
262  const o: Object = o;
263  return Cast<Boolean>(o) otherwise CastError;
264}
265
266// TODO(turbofan): These trivial casts for union types should be generated
267// automatically.
268
269Cast<JSPrimitive>(o: Object): JSPrimitive labels CastError {
270  typeswitch (o) {
271    case (o: Numeric): {
272      return o;
273    }
274    case (o: String): {
275      return o;
276    }
277    case (o: Symbol): {
278      return o;
279    }
280    case (o: Boolean): {
281      return o;
282    }
283    case (o: Undefined): {
284      return o;
285    }
286    case (o: Null): {
287      return o;
288    }
289    case (Object): {
290      goto CastError;
291    }
292  }
293}
294
295Cast<JSAny>(o: Object): JSAny labels CastError {
296  typeswitch (o) {
297    case (o: JSPrimitive): {
298      return o;
299    }
300    case (o: JSReceiver): {
301      return o;
302    }
303    case (Object): {
304      goto CastError;
305    }
306  }
307}
308
309Cast<JSAny|TheHole>(o: Object): JSAny|TheHole labels CastError {
310  typeswitch (o) {
311    case (o: JSAny): {
312      return o;
313    }
314    case (o: TheHole): {
315      return o;
316    }
317    case (Object): {
318      goto CastError;
319    }
320  }
321}
322
323Cast<Number|TheHole>(o: Object): Number|TheHole labels CastError {
324  typeswitch (o) {
325    case (o: Number): {
326      return o;
327    }
328    case (o: TheHole): {
329      return o;
330    }
331    case (Object): {
332      goto CastError;
333    }
334  }
335}
336
337Cast<Context|Zero|Undefined>(o: Object): Context|Zero|Undefined
338    labels CastError {
339  typeswitch (o) {
340    case (o: Context): {
341      return o;
342    }
343    case (o: Zero): {
344      return o;
345    }
346    case (o: Undefined): {
347      return o;
348    }
349    case (Object): {
350      goto CastError;
351    }
352  }
353}
354
355macro Cast<A : type extends HeapObject>(o: HeapObject): A
356    labels CastError;
357
358Cast<HeapObject>(o: HeapObject): HeapObject
359labels _CastError {
360  return o;
361}
362
363Cast<Null>(o: HeapObject): Null
364    labels CastError {
365  if (o != Null) goto CastError;
366  return %RawDownCast<Null>(o);
367}
368
369Cast<Undefined>(o: HeapObject): Undefined
370    labels CastError {
371  const o: MaybeObject = o;
372  return Cast<Undefined>(o) otherwise CastError;
373}
374
375Cast<EmptyFixedArray>(o: Object): EmptyFixedArray
376    labels CastError {
377  if (o != kEmptyFixedArray) goto CastError;
378  return %RawDownCast<EmptyFixedArray>(o);
379}
380Cast<EmptyFixedArray>(o: HeapObject): EmptyFixedArray
381    labels CastError {
382  const o: Object = o;
383  return Cast<EmptyFixedArray>(o) otherwise CastError;
384}
385
386Cast<(FixedDoubleArray | EmptyFixedArray)>(o: HeapObject): FixedDoubleArray|
387    EmptyFixedArray labels CastError {
388  typeswitch (o) {
389    case (o: EmptyFixedArray): {
390      return o;
391    }
392    case (o: FixedDoubleArray): {
393      return o;
394    }
395    case (HeapObject): {
396      goto CastError;
397    }
398  }
399}
400
401Cast<Callable>(o: HeapObject): Callable
402    labels CastError {
403  return HeapObjectToCallable(o) otherwise CastError;
404}
405
406Cast<Undefined|Callable>(o: HeapObject): Undefined|Callable
407    labels CastError {
408  if (o == Undefined) return Undefined;
409  return HeapObjectToCallable(o) otherwise CastError;
410}
411
412Cast<Undefined|JSFunction>(o: HeapObject): Undefined|JSFunction
413    labels CastError {
414  if (o == Undefined) return Undefined;
415  return Cast<JSFunction>(o) otherwise CastError;
416}
417
418macro Cast<T : type extends Symbol>(o: Symbol): T labels CastError;
419Cast<PublicSymbol>(s: Symbol): PublicSymbol labels CastError {
420  if (s.flags.is_private) goto CastError;
421  return %RawDownCast<PublicSymbol>(s);
422}
423Cast<PrivateSymbol>(s: Symbol): PrivateSymbol labels CastError {
424  if (s.flags.is_private) return %RawDownCast<PrivateSymbol>(s);
425  goto CastError;
426}
427Cast<PublicSymbol>(o: HeapObject): PublicSymbol labels CastError {
428  const s = Cast<Symbol>(o) otherwise CastError;
429  return Cast<PublicSymbol>(s) otherwise CastError;
430}
431Cast<PrivateSymbol>(o: HeapObject): PrivateSymbol labels CastError {
432  const s = Cast<Symbol>(o) otherwise CastError;
433  return Cast<PrivateSymbol>(s) otherwise CastError;
434}
435
436Cast<DirectString>(o: String): DirectString
437    labels CastError {
438  return TaggedToDirectString(o) otherwise CastError;
439}
440
441Cast<Constructor>(o: HeapObject): Constructor
442    labels CastError {
443  return HeapObjectToConstructor(o) otherwise CastError;
444}
445
446Cast<JSFunctionWithPrototypeSlot>(o: HeapObject): JSFunctionWithPrototypeSlot
447    labels CastError {
448  return HeapObjectToJSFunctionWithPrototypeSlot(o) otherwise CastError;
449}
450
451Cast<BigInt>(o: HeapObject): BigInt labels CastError {
452  if (IsBigInt(o)) return %RawDownCast<BigInt>(o);
453  goto CastError;
454}
455
456Cast<JSRegExpResult>(implicit context: Context)(o: HeapObject): JSRegExpResult
457    labels CastError {
458  if (regexp::IsRegExpResult(o)) return %RawDownCast<JSRegExpResult>(o);
459  goto CastError;
460}
461
462Cast<JSSloppyArgumentsObject>(implicit context: Context)(o: HeapObject):
463    JSSloppyArgumentsObject
464    labels CastError {
465  const map: Map = o.map;
466  if (IsFastAliasedArgumentsMap(map) || IsSloppyArgumentsMap(map) ||
467      IsSlowAliasedArgumentsMap(map)) {
468    return %RawDownCast<JSSloppyArgumentsObject>(o);
469  }
470  goto CastError;
471}
472
473Cast<JSStrictArgumentsObject>(implicit context: Context)(o: HeapObject):
474    JSStrictArgumentsObject
475    labels CastError {
476  const map: Map = o.map;
477  if (!IsStrictArgumentsMap(map)) goto CastError;
478  return %RawDownCast<JSStrictArgumentsObject>(o);
479}
480
481Cast<JSArgumentsObjectWithLength>(implicit context: Context)(o: HeapObject):
482    JSArgumentsObjectWithLength
483    labels CastError {
484  typeswitch (o) {
485    case (o: JSStrictArgumentsObject): {
486      return o;
487    }
488    case (o: JSSloppyArgumentsObject): {
489      return o;
490    }
491    case (HeapObject): {
492      goto CastError;
493    }
494  }
495}
496
497Cast<FastJSRegExp>(implicit context: Context)(o: HeapObject): FastJSRegExp
498    labels CastError {
499  // TODO(jgruber): Remove or redesign this. There is no single 'fast' regexp,
500  // the conditions to make a regexp object fast differ based on the callsite.
501  // For now, run the strict variant since replace (the only current callsite)
502  // accesses flag getters.
503  if (regexp::IsFastRegExpStrict(o)) {
504    return %RawDownCast<FastJSRegExp>(o);
505  }
506  goto CastError;
507}
508
509Cast<FastJSArray>(implicit context: Context)(o: HeapObject): FastJSArray
510    labels CastError {
511  if (IsForceSlowPath()) goto CastError;
512
513  if (!Is<JSArray>(o)) goto CastError;
514
515  // Bailout if receiver has slow elements.
516  const map: Map = o.map;
517  const elementsKind: ElementsKind = LoadMapElementsKind(map);
518  if (!IsFastElementsKind(elementsKind)) goto CastError;
519
520  // Verify that our prototype is the initial array prototype.
521  if (!IsPrototypeInitialArrayPrototype(map)) goto CastError;
522
523  if (IsNoElementsProtectorCellInvalid()) goto CastError;
524  return %RawDownCast<FastJSArray>(o);
525}
526
527Cast<FastJSArrayForRead>(implicit context: Context)(o: HeapObject):
528    FastJSArrayForRead
529    labels CastError {
530  if (!Is<JSArray>(o)) goto CastError;
531
532  // Bailout if receiver has slow elements.
533  const map: Map = o.map;
534  const elementsKind: ElementsKind = LoadMapElementsKind(map);
535  if (!IsElementsKindLessThanOrEqual(
536          elementsKind, ElementsKind::LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND))
537    goto CastError;
538
539  // Verify that our prototype is the initial array prototype.
540  if (!IsPrototypeInitialArrayPrototype(map)) goto CastError;
541
542  if (IsNoElementsProtectorCellInvalid()) goto CastError;
543  return %RawDownCast<FastJSArrayForRead>(o);
544}
545
546Cast<FastJSArrayForCopy>(implicit context: Context)(o: HeapObject):
547    FastJSArrayForCopy
548    labels CastError {
549  if (IsArraySpeciesProtectorCellInvalid()) goto CastError;
550  // TODO(victorgomes): Check if we can cast from FastJSArrayForRead instead.
551  const a = Cast<FastJSArray>(o) otherwise CastError;
552  return %RawDownCast<FastJSArrayForCopy>(a);
553}
554
555Cast<FastJSArrayForConcat>(implicit context: Context)(o: HeapObject):
556    FastJSArrayForConcat
557    labels CastError {
558  if (IsIsConcatSpreadableProtectorCellInvalid()) goto CastError;
559  const a = Cast<FastJSArrayForCopy>(o) otherwise CastError;
560  return %RawDownCast<FastJSArrayForConcat>(a);
561}
562
563Cast<FastJSArrayWithNoCustomIteration>(implicit context: Context)(
564    o: HeapObject): FastJSArrayWithNoCustomIteration
565    labels CastError {
566  if (IsArrayIteratorProtectorCellInvalid()) goto CastError;
567  const a = Cast<FastJSArray>(o) otherwise CastError;
568  return %RawDownCast<FastJSArrayWithNoCustomIteration>(a);
569}
570
571Cast<FastJSArrayForReadWithNoCustomIteration>(implicit context: Context)(
572    o: HeapObject): FastJSArrayForReadWithNoCustomIteration
573    labels CastError {
574  if (IsArrayIteratorProtectorCellInvalid()) goto CastError;
575  const a = Cast<FastJSArrayForRead>(o) otherwise CastError;
576  return %RawDownCast<FastJSArrayForReadWithNoCustomIteration>(a);
577}
578
579macro Cast<T: type>(o: String): T labels CastError;
580
581Cast<SeqOneByteString>(o: HeapObject): SeqOneByteString labels CastError {
582  return Cast<SeqOneByteString>(Cast<String>(o) otherwise CastError)
583      otherwise CastError;
584}
585
586Cast<SeqOneByteString>(o: String): SeqOneByteString labels CastError {
587  const instanceType = o.StringInstanceType();
588  // Using & instead of && enables Turbofan to merge the two checks into one.
589  if (!(instanceType.representation == StringRepresentationTag::kSeqStringTag &
590        instanceType.is_one_byte)) {
591    goto CastError;
592  }
593  return %RawDownCast<SeqOneByteString>(o);
594}
595
596Cast<SeqTwoByteString>(o: HeapObject): SeqTwoByteString labels CastError {
597  return Cast<SeqTwoByteString>(Cast<String>(o) otherwise CastError)
598      otherwise CastError;
599}
600
601Cast<SeqTwoByteString>(o: String): SeqTwoByteString labels CastError {
602  const instanceType = o.StringInstanceType();
603  // Using & instead of && enables Turbofan to merge the two checks into one.
604  if (!(instanceType.representation == StringRepresentationTag::kSeqStringTag &
605        !instanceType.is_one_byte)) {
606    goto CastError;
607  }
608  return %RawDownCast<SeqTwoByteString>(o);
609}
610
611Cast<ThinString>(o: HeapObject): ThinString labels CastError {
612  return Cast<ThinString>(Cast<String>(o) otherwise CastError)
613      otherwise CastError;
614}
615
616Cast<ThinString>(o: String): ThinString labels CastError {
617  const instanceType = o.StringInstanceType();
618  if (instanceType.representation != StringRepresentationTag::kThinStringTag) {
619    goto CastError;
620  }
621  return %RawDownCast<ThinString>(o);
622}
623
624Cast<ConsString>(o: HeapObject): ConsString labels CastError {
625  return Cast<ConsString>(Cast<String>(o) otherwise CastError)
626      otherwise CastError;
627}
628
629Cast<ConsString>(o: String): ConsString labels CastError {
630  const instanceType = o.StringInstanceType();
631  if (instanceType.representation != StringRepresentationTag::kConsStringTag) {
632    goto CastError;
633  }
634  return %RawDownCast<ConsString>(o);
635}
636
637Cast<SlicedString>(o: HeapObject): SlicedString labels CastError {
638  return Cast<SlicedString>(Cast<String>(o) otherwise CastError)
639      otherwise CastError;
640}
641
642Cast<SlicedString>(o: String): SlicedString labels CastError {
643  const instanceType = o.StringInstanceType();
644  if (instanceType.representation !=
645      StringRepresentationTag::kSlicedStringTag) {
646    goto CastError;
647  }
648  return %RawDownCast<SlicedString>(o);
649}
650
651Cast<ExternalOneByteString>(o: HeapObject):
652    ExternalOneByteString labels CastError {
653  return Cast<ExternalOneByteString>(Cast<String>(o) otherwise CastError)
654      otherwise CastError;
655}
656
657Cast<ExternalOneByteString>(o: String): ExternalOneByteString labels CastError {
658  const instanceType = o.StringInstanceType();
659  // Using & instead of && enables Turbofan to merge the two checks into one.
660  if (!(instanceType.representation ==
661            StringRepresentationTag::kExternalStringTag &
662        instanceType.is_one_byte)) {
663    goto CastError;
664  }
665  return %RawDownCast<ExternalOneByteString>(o);
666}
667
668Cast<ExternalTwoByteString>(o: HeapObject):
669    ExternalTwoByteString labels CastError {
670  return Cast<ExternalTwoByteString>(Cast<String>(o) otherwise CastError)
671      otherwise CastError;
672}
673
674Cast<ExternalTwoByteString>(o: String): ExternalTwoByteString labels CastError {
675  const instanceType = o.StringInstanceType();
676  // Using & instead of && enables Turbofan to merge the two checks into one.
677  if (!(instanceType.representation ==
678            StringRepresentationTag::kExternalStringTag &
679        !instanceType.is_one_byte)) {
680    goto CastError;
681  }
682  return %RawDownCast<ExternalTwoByteString>(o);
683}
684
685Cast<JSReceiver|Null>(o: HeapObject): JSReceiver|Null
686    labels CastError {
687  typeswitch (o) {
688    case (o: Null): {
689      return o;
690    }
691    case (o: JSReceiver): {
692      return o;
693    }
694    case (HeapObject): {
695      goto CastError;
696    }
697  }
698}
699
700Cast<Smi|PromiseReaction>(o: Object): Smi|PromiseReaction labels CastError {
701  typeswitch (o) {
702    case (o: Smi): {
703      return o;
704    }
705    case (o: PromiseReaction): {
706      return o;
707    }
708    case (Object): {
709      goto CastError;
710    }
711  }
712}
713
714Cast<String|Callable>(implicit context: Context)(o: Object): String|
715    Callable labels CastError {
716  typeswitch (o) {
717    case (o: String): {
718      return o;
719    }
720    case (o: Callable): {
721      return o;
722    }
723    case (Object): {
724      goto CastError;
725    }
726  }
727}
728
729Cast<Zero|PromiseReaction>(implicit context: Context)(o: Object): Zero|
730    PromiseReaction labels CastError {
731  typeswitch (o) {
732    case (o: Zero): {
733      return o;
734    }
735    case (o: PromiseReaction): {
736      return o;
737    }
738    case (Object): {
739      goto CastError;
740    }
741  }
742}
743
744Cast<JSFunction|JSBoundFunction|JSWrappedFunction>(implicit context: Context)(
745    o: Object): JSFunction|JSBoundFunction|JSWrappedFunction labels CastError {
746  typeswitch (o) {
747    case (o: JSFunction): {
748      return o;
749    }
750    case (o: JSBoundFunction): {
751      return o;
752    }
753    case (o: JSWrappedFunction): {
754      return o;
755    }
756    case (Object): {
757      goto CastError;
758    }
759  }
760}
761
762Cast<FixedArray|Undefined>(o: HeapObject): FixedArray|
763    Undefined labels CastError {
764  typeswitch (o) {
765    case (o: Undefined): {
766      return o;
767    }
768    case (o: FixedArray): {
769      return o;
770    }
771    case (Object): {
772      goto CastError;
773    }
774  }
775}
776
777Cast<JSProxy|Null>(o: HeapObject): JSProxy|Null labels CastError {
778  typeswitch (o) {
779    case (o: Null): {
780      return o;
781    }
782    case (o: JSProxy): {
783      return o;
784    }
785    case (Object): {
786      goto CastError;
787    }
788  }
789}
790
791macro Is<A : type extends Object, B : type extends Object>(
792    implicit context: Context)(o: B): bool {
793  Cast<A>(o) otherwise return false;
794  return true;
795}
796
797macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object):
798    A {
799  dcheck(Is<A>(o));
800  return %RawDownCast<A>(o);
801}
802
803macro UnsafeConstCast<T: type>(r: const &T):&T {
804  return %RawDownCast<&T>(r);
805}
806
807UnsafeCast<RegExpMatchInfo>(implicit context: Context)(o: Object):
808    RegExpMatchInfo {
809  dcheck(Is<FixedArray>(o));
810  return %RawDownCast<RegExpMatchInfo>(o);
811}
812
813macro UnsafeCast<A : type extends WeakHeapObject>(o: A|Object): A {
814  dcheck(IsWeakOrCleared(o));
815  return %RawDownCast<A>(o);
816}
817
818macro
819CastOrDefault<T: type, Arg: type, Default: type>(implicit context: Context)(
820    x: Arg, default: Default): T|Default {
821  return Cast<T>(x) otherwise return default;
822}
823
824// This is required for casting MaybeObject to Object.
825Cast<Object>(o: Object): Object
826labels _CastError {
827  return o;
828}
829