base.tq 62.2 KB
Newer Older
1
// Copyright 2018 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be:
// Context found in the LICENSE file.
4

5
#include 'src/builtins/builtins-regexp-gen.h'
6 7
#include 'src/builtins/builtins-utils-gen.h'
#include 'src/builtins/builtins.h'
8
#include 'src/codegen/code-factory.h'
9 10 11
#include 'src/heap/factory-inl.h'
#include 'src/objects/arguments.h'
#include 'src/objects/bigint.h'
12
#include 'src/objects/elements-kind.h'
13
#include 'src/objects/free-space.h'
14 15
#include 'src/objects/js-generator.h'
#include 'src/objects/js-promise.h'
Irina Yatsenko's avatar
Irina Yatsenko committed
16
#include 'src/objects/js-regexp-string-iterator.h'
17
#include 'src/objects/js-weak-refs.h'
18
#include 'src/objects/objects.h'
19
#include 'src/objects/source-text-module.h'
20
#include 'src/objects/stack-frame-info.h'
21
#include 'src/objects/synthetic-module.h'
22
#include 'src/objects/template-objects.h'
23
#include 'src/torque/runtime-support.h'
24

25 26
type void;
type never;
27

28 29 30 31
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';
32 33
type TaggedIndex extends StrongTagged
    generates 'TNode<TaggedIndex>' constexpr 'TaggedIndex';
34 35 36 37 38 39 40 41
// 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;

42
// A Smi that is greater than or equal to 0. See TaggedIsPositiveSmi.
43
type PositiveSmi extends Smi;
44

45 46 47
// The Smi value zero, which is often used as null for HeapObject types.
type Zero extends PositiveSmi;

48 49 50
// A value with the size of Tagged which may contain arbitrary data.
type Uninitialized extends Tagged;

51 52 53 54
extern macro MakeWeak(HeapObject): WeakHeapObject;
extern macro GetHeapObjectAssumeWeak(WeakHeapObject):
    HeapObject labels ClearedWeakPointer;
extern macro IsWeakOrCleared(MaybeObject): bool;
55
extern macro IsWeakReferenceToObject(MaybeObject, Object): bool;
56

57 58 59 60 61 62 63
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);
}
64

65 66
// Defined to coincide with https://tc39.es/ecma262/#sec-ispropertykey
// Doesn't include PrivateSymbol.
67
type PropertyKey = String|PublicSymbol;
68 69 70 71 72 73 74

// 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.
75
type JSPrimitive = Numeric|String|Symbol|Boolean|Null|Undefined;
76 77 78

// A user-exposed JavaScript value, as opposed to V8-internal values like
// TheHole or FixedArray.
79
type JSAny = JSReceiver|JSPrimitive;
80

81
type JSAnyNotNumber = BigInt|String|Symbol|Boolean|Null|Undefined|JSReceiver;
82 83

// This is the intersection of JSAny and HeapObject.
84
type JSAnyNotSmi = JSAnyNotNumber|HeapNumber;
85

86 87
type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
type uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t';
88 89 90
type int31 extends int32
    generates 'TNode<Int32T>' constexpr 'int31_t';
type uint31 extends uint32
91
    generates 'TNode<Uint32T>' constexpr 'uint32_t';
92
type int16 extends int31
93
    generates 'TNode<Int16T>' constexpr 'int16_t';
94
type uint16 extends uint31
95 96
    generates 'TNode<Uint16T>' constexpr 'uint16_t';
type int8 extends int16 generates 'TNode<Int8T>' constexpr 'int8_t';
97
type uint8 extends uint16
98
    generates 'TNode<Uint8T>' constexpr 'uint8_t';
99 100
type char8 extends int8 constexpr 'char';
type char16 extends uint16 constexpr 'char16_t';
101
type int64 generates 'TNode<Int64T>' constexpr 'int64_t';
102
type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t';
103
type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t';
104
type float32 generates 'TNode<Float32T>' constexpr 'float';
105 106
type float64 generates 'TNode<Float64T>' constexpr 'double';
type bool generates 'TNode<BoolT>' constexpr 'bool';
107
type bint generates 'TNode<BInt>' constexpr 'BInt';
108
type string constexpr 'const char*';
109

110 111 112
// A Smi value containing a bitfield struct as its integer data.
type SmiTagged<T : type extends uint31> extends Smi;

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
// 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};

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
// 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.
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;
149

150
type RawPtr generates 'TNode<RawPtrT>' constexpr 'void*';
151 152
type ExternalPointer
    generates 'TNode<ExternalPointerT>' constexpr 'ExternalPointer_t';
153
extern class Code extends HeapObject;
154
type BuiltinPtr extends Smi generates 'TNode<BuiltinPtr>';
155

156 157
type Number = Smi|HeapNumber;
type Numeric = Number|BigInt;
158

159 160 161 162
extern class ObjectBoilerplateDescription extends FixedArray;
extern class ClosureFeedbackCellArray extends FixedArray;
extern class ScriptContextTable extends FixedArray;

163 164
type LayoutDescriptor extends ByteArray
    generates 'TNode<LayoutDescriptor>';
165
extern class TransitionArray extends WeakFixedArray;
166

167
type InstanceType extends uint16 constexpr 'InstanceType';
168

169
type NoSharedNameSentinel extends Smi;
170

171
// Specialized types. The following three type definitions don't correspond to
172 173
// actual C++ classes, but have Is... methods that check additional constraints.

174 175 176
// A Foreign object whose raw pointer is not allowed to be null.
type NonNullForeign extends Foreign;

177
// A function built with InstantiateFunction for the public API.
178
type CallableApiObject extends JSObject;
179 180 181 182

// A JSProxy with the callable bit set.
type CallableJSProxy extends JSProxy;

183
type Callable = JSFunction|JSBoundFunction|CallableJSProxy|CallableApiObject;
184

185 186
type WriteBarrierMode
    generates 'TNode<Int32T>' constexpr 'WriteBarrierMode';
187

188
extern enum UnicodeEncoding { UTF16, UTF32 }
189

190
// Promise constants
191 192 193 194 195
extern enum PromiseState extends int31 constexpr 'Promise::PromiseState' {
  kPending,
  kFulfilled,
  kRejected
}
196

197 198
type FrameArray extends FixedArray;

Tobias Tebbi's avatar
Tobias Tebbi committed
199 200
const kTaggedSize: constexpr int31 generates 'kTaggedSize';
const kDoubleSize: constexpr int31 generates 'kDoubleSize';
201 202
const kVariableSizeSentinel:
    constexpr int31 generates 'kVariableSizeSentinel';
203

Tobias Tebbi's avatar
Tobias Tebbi committed
204
const kSmiTagSize: constexpr int31 generates 'kSmiTagSize';
205
const kHeapObjectTag: constexpr int31 generates 'kHeapObjectTag';
Tobias Tebbi's avatar
Tobias Tebbi committed
206
const V8_INFINITY: constexpr float64 generates 'V8_INFINITY';
207
const MINUS_V8_INFINITY: constexpr float64 generates '-V8_INFINITY';
208

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
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 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 {
259
  kAllPromisesRejected,
260 261
  kInvalidArrayBufferLength,
  kInvalidArrayLength,
262
  kInvalidIndex,
263
  kNotConstructor,
264
  kNotGeneric,
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
  kCalledNonCallable,
  kCalledOnNullOrUndefined,
  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,
295
  kTooManyElementsInPromiseCombinator,
296 297 298 299 300 301 302 303 304 305 306 307 308 309
  kToRadixFormatRange,
  kCalledOnNonObject,
  kRegExpGlobalInvokedOnNonGlobal,
  kProxyNonObject,
  kProxyRevoked,
  kProxyTrapReturnedFalsishFor,
  kProxyPrivate,
  kProxyIsExtensibleInconsistent,
  kProxyPreventExtensionsExtensible,
  kProxyTrapReturnedFalsish,
  kProxyGetPrototypeOfInvalid,
  kProxyGetPrototypeOfNonExtensible,
  kProxySetPrototypeOfNonExtensible,
  kProxyDeletePropertyNonExtensible,
310
  kWeakRefsCleanupMustBeCallable,
311 312 313 314 315 316 317 318 319 320 321
  kWasmTrapUnreachable,
  kWasmTrapMemOutOfBounds,
  kWasmTrapUnalignedAccess,
  kWasmTrapDivByZero,
  kWasmTrapDivUnrepresentable,
  kWasmTrapRemByZero,
  kWasmTrapFloatUnrepresentable,
  kWasmTrapFuncInvalid,
  kWasmTrapFuncSigMismatch,
  kWasmTrapDataSegmentDropped,
  kWasmTrapElemSegmentDropped,
322
  kWasmTrapTableOutOfBounds,
323 324 325
  kWasmTrapBrOnExnNullRef,
  kWasmTrapRethrowNullRef,
  kWasmTrapNullDereference,
326
  kWasmTrapIllegalCast,
327
  kWasmTrapArrayOutOfBounds,
328 329
  ...
}
330

331 332
const kMaxArrayIndex:
    constexpr uint32 generates 'JSArray::kMaxArrayIndex';
333 334
const kArrayBufferMaxByteLength:
    constexpr uintptr generates 'JSArrayBuffer::kMaxByteLength';
335 336
const kTypedArrayMaxLength:
    constexpr uintptr generates 'JSTypedArray::kMaxLength';
337 338
const kMaxTypedArrayInHeap:
    constexpr int31 generates 'JSTypedArray::kMaxSizeInHeap';
339 340 341 342
// 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
343
    generates 'CodeStubAssembler::MaxSafeIntegerUintPtr()';
344
const kMaxSafeInteger: constexpr float64 generates 'kMaxSafeInteger';
345
const kMaxUInt32Double: constexpr float64 generates 'kMaxUInt32Double';
346
const kSmiMaxValue: constexpr uintptr generates 'kSmiMaxValue';
347
const kSmiMax: uintptr = kSmiMaxValue;
348
// TODO(v8:8996): Use uintptr version instead and drop this one.
349
const kStringMaxLength: constexpr int31 generates 'String::kMaxLength';
350 351
const kStringMaxLengthUintptr:
    constexpr uintptr generates 'String::kMaxLength';
352 353
const kFixedArrayMaxLength:
    constexpr int31 generates 'FixedArray::kMaxLength';
354 355
const kObjectAlignmentMask: constexpr intptr
    generates 'kObjectAlignmentMask';
356 357 358 359
const kMinAddedElementsCapacity:
    constexpr int31 generates 'JSObject::kMinAddedElementsCapacity';
const kMaxCopyElements:
    constexpr int31 generates 'JSArray::kMaxCopyElements';
360 361 362 363 364 365 366 367 368 369 370 371
const kMaxRegularHeapObjectSize: constexpr int31
    generates 'kMaxRegularHeapObjectSize';

const kMaxNewSpaceFixedArrayElements: constexpr int31
    generates 'FixedArray::kMaxRegularLength';
const kSloppyArgumentsArgumentsIndex: constexpr int31
    generates 'SloppyArgumentsElements::kArgumentsIndex';
const kSloppyArgumentsContextIndex: constexpr int31
    generates 'SloppyArgumentsElements::kContextIndex';
const kSloppyArgumentsParameterMapStart: constexpr int31
    generates 'SloppyArgumentsElements::kParameterMapStart';

372
extern enum PrimitiveType { kString, kBoolean, kSymbol, kNumber }
373

374 375 376
const kNameDictionaryInitialCapacity:
    constexpr int32 generates 'NameDictionary::kInitialCapacity';

377
type TheHole extends Oddball;
378 379 380 381
type Null extends Oddball;
type Undefined extends Oddball;
type True extends Oddball;
type False extends Oddball;
382
type Exception extends Oddball;
383
type EmptyString extends String;
384
type Boolean = True|False;
385

386
type NumberOrUndefined = Number|Undefined;
387

388
extern macro EmptyStringConstant(): EmptyString;
389
extern macro FalseConstant(): False;
390
extern macro Int32FalseConstant(): bool;
391 392
extern macro Int32TrueConstant(): bool;
extern macro IteratorSymbolConstant(): PublicSymbol;
393
extern macro LengthStringConstant(): String;
394
extern macro MatchSymbolConstant(): Symbol;
395
extern macro MessageStringConstant(): String;
396
extern macro NanConstant(): NaN;
397
extern macro NameStringConstant(): String;
398
extern macro NullConstant(): Null;
399
extern macro ReturnStringConstant(): String;
400 401 402
extern macro TheHoleConstant(): TheHole;
extern macro TrueConstant(): True;
extern macro UndefinedConstant(): Undefined;
403

404
const TheHole: TheHole = TheHoleConstant();
405 406 407 408
const Null: Null = NullConstant();
const Undefined: Undefined = UndefinedConstant();
const True: True = TrueConstant();
const False: False = FalseConstant();
409
const kEmptyString: EmptyString = EmptyStringConstant();
410
const kLengthString: String = LengthStringConstant();
411
const kMessageString: String = MessageStringConstant();
412 413
const kReturnString: String = ReturnStringConstant();

414
const kNaN: NaN = NanConstant();
415
const kZero: Zero = %RawDownCast<Zero>(SmiConstant(0));
416

417 418 419
const true: constexpr bool generates 'true';
const false: constexpr bool generates 'false';

420 421
extern enum LanguageMode extends bool { kStrict, kSloppy }
type LanguageModeSmi extends Smi;
422

423 424
const SKIP_WRITE_BARRIER:
    constexpr WriteBarrierMode generates 'SKIP_WRITE_BARRIER';
425 426
const UNSAFE_SKIP_WRITE_BARRIER:
    constexpr WriteBarrierMode generates 'UNSAFE_SKIP_WRITE_BARRIER';
427

428
extern transitioning macro AllocateJSIteratorResult(implicit context: Context)(
429
    JSAny, Boolean): JSObject;
430 431
extern macro AllocateSyntheticFunctionContext(
    NativeContext, constexpr int32): Context;
432

433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
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>';

449 450
extern macro Is64(): constexpr bool;

451 452
extern macro SelectBooleanConstant(bool): Boolean;

453 454
extern macro Print(constexpr string);
extern macro Print(constexpr string, Object);
455
extern macro Comment(constexpr string);
456
extern macro StaticAssert(bool);
457 458
extern macro Print(Object);
extern macro DebugBreak();
459 460

// ES6 7.1.4 ToInteger ( argument )
461 462
transitioning macro ToIntegerImpl(implicit context: Context)(input: Object):
    Number {
463 464 465 466 467 468 469 470 471 472 473
  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);
474 475
        // ToInteger normalizes -0 to +0.
        if (value == 0.0) return SmiConstant(0);
476
        const result = ChangeFloat64ToTagged(value);
477
        assert(IsNumberNormalized(result));
478 479 480 481 482 483 484 485 486 487 488 489
        return result;
      }
      case (ho: HeapObject): {
        input = math::NonNumberToNumber(ho);
      }
    }
  }
  unreachable;
}

transitioning builtin ToInteger(implicit context: Context)(input: Object):
    Number {
490
  return ToIntegerImpl(input);
491 492 493 494 495 496 497 498 499 500
}

@export
transitioning macro ToInteger_Inline(implicit context: Context)(input: Object):
    Number {
  typeswitch (input) {
    case (s: Smi): {
      return s;
    }
    case (ho: HeapObject): {
501
      return ToInteger(ho);
502 503 504 505
    }
  }
}

506 507 508 509 510 511
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;
512
extern transitioning macro ToThisString(implicit context: Context)(
513
    JSAny, String): String;
514
extern transitioning macro ToThisValue(implicit context: Context)(
515
    JSAny, constexpr PrimitiveType, constexpr string): JSAny;
516
extern transitioning macro GetProperty(implicit context: Context)(
517
    JSAny, JSAny): JSAny;
518
extern transitioning builtin SetProperty(implicit context: Context)(
519
    JSAny, JSAny, JSAny): JSAny;
520
extern transitioning builtin SetPropertyInLiteral(implicit context: Context)(
521
    JSAny, JSAny, JSAny): JSAny;
522
extern transitioning builtin DeleteProperty(implicit context: Context)(
523
    JSAny, JSAny | PrivateSymbol, LanguageModeSmi): Boolean;
524
extern transitioning builtin HasProperty(implicit context: Context)(
525
    JSAny, JSAny): Boolean;
526
extern transitioning macro HasProperty_Inline(implicit context: Context)(
527
    JSReceiver, JSAny): Boolean;
528 529
extern builtin LoadIC(
    Context, JSAny, JSAny, TaggedIndex, FeedbackVector): JSAny;
530

531 532 533 534 535 536 537 538 539 540
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;
541 542
extern macro ThrowTypeError(implicit context: Context)(
    constexpr MessageTemplate, Object, Object): never;
543 544
extern macro ThrowTypeError(implicit context: Context)(
    constexpr MessageTemplate, Object, Object, Object): never;
545 546
extern transitioning runtime ThrowTypeErrorIfStrict(implicit context: Context)(
    Smi, Object, Object): void;
547 548
extern transitioning runtime ThrowCalledNonCallable(implicit context: Context)(
    JSAny): never;
549

550 551 552
extern transitioning macro ThrowIfNotJSReceiver(implicit context: Context)(
    JSAny, constexpr MessageTemplate, constexpr string): void;

553
extern macro ArraySpeciesCreate(Context, JSAny, Number): JSReceiver;
554
extern macro ArrayCreate(implicit context: Context)(Number): JSArray;
555
extern macro BuildAppendJSArray(
556
    constexpr ElementsKind, FastJSArray, JSAny): void labels Bailout;
557

558
extern macro EnsureArrayPushable(implicit context: Context)(Map): ElementsKind
559
    labels Bailout;
560
// TODO: Reduce duplication once varargs are supported in macros.
561
extern macro Construct(implicit context: Context)(Constructor): JSReceiver;
562
extern macro Construct(implicit context: Context)(
563
    Constructor, JSAny): JSReceiver;
564
extern macro Construct(implicit context: Context)(
565
    Constructor, JSAny, JSAny): JSReceiver;
566
extern macro Construct(implicit context: Context)(
567
    Constructor, JSAny, JSAny, JSAny): JSReceiver;
568 569 570
extern macro ConstructWithTarget(implicit context: Context)(
    Constructor, JSReceiver): JSReceiver;
extern macro ConstructWithTarget(implicit context: Context)(
571
    Constructor, JSReceiver, JSAny): JSReceiver;
572
extern macro SpeciesConstructor(implicit context: Context)(
573
    JSAny, JSReceiver): JSReceiver;
574

575 576 577 578
extern macro ConstructorBuiltinsAssembler::IsDictionaryMap(Map): bool;
extern macro CodeStubAssembler::AllocateNameDictionary(constexpr int32):
    NameDictionary;

579 580
extern builtin ToObject(Context, JSAny): JSReceiver;
extern macro ToObject_Inline(Context, JSAny): JSReceiver;
581
extern macro IsNullOrUndefined(Object): bool;
582
extern macro IsString(HeapObject): bool;
583
transitioning builtin ToString(context: Context, o: JSAny): String {
Shiyu Zhang's avatar
Shiyu Zhang committed
584 585
  return ToStringImpl(context, o);
}
586
extern transitioning runtime ToStringRT(Context, JSAny): String;
Shiyu Zhang's avatar
Shiyu Zhang committed
587
extern transitioning builtin NonPrimitiveToPrimitive_String(
588
    Context, JSAny): JSPrimitive;
589
extern transitioning builtin NonPrimitiveToPrimitive_Default(
590 591 592 593 594 595 596 597 598 599 600 601 602
    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;
    }
  }
}
603

604 605 606
extern transitioning runtime NormalizeElements(Context, JSObject);
extern transitioning runtime TransitionElementsKindWithKind(
    Context, JSObject, Smi);
607

608 609 610 611
extern macro LoadBufferObject(RawPtr, constexpr int32): Object;
extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr;
extern macro LoadBufferSmi(RawPtr, constexpr int32): Smi;

612
extern runtime StringEqual(Context, String, String): Oddball;
613
extern builtin StringLessThan(Context, String, String): Boolean;
614
extern macro StringCharCodeAt(String, uintptr): int32;
615
extern runtime StringCompareSequence(Context, String, String, Number): Boolean;
616
extern macro StringFromSingleCharCode(int32): String;
617

618
extern macro StrictEqual(JSAny, JSAny): Boolean;
619
extern macro SmiLexicographicCompare(Smi, Smi): Smi;
620
extern runtime ReThrow(Context, JSAny): never;
621
extern runtime Throw(implicit context: Context)(JSAny): never;
622
extern runtime ThrowInvalidStringLength(Context): never;
623

624 625
extern operator '==' macro WordEqual(RawPtr, RawPtr): bool;
extern operator '!=' macro WordNotEqual(RawPtr, RawPtr): bool;
626 627
extern operator '+' macro RawPtrAdd(RawPtr, intptr): RawPtr;
extern operator '+' macro RawPtrAdd(intptr, RawPtr): RawPtr;
628

629
extern operator '<' macro Int32LessThan(int32, int32): bool;
630
extern operator '<' macro Uint32LessThan(uint32, uint32): bool;
631
extern operator '>' macro Int32GreaterThan(int32, int32): bool;
632
extern operator '>' macro Uint32GreaterThan(uint32, uint32): bool;
633
extern operator '<=' macro Int32LessThanOrEqual(int32, int32): bool;
634
extern operator '<=' macro Uint32LessThanOrEqual(uint32, uint32): bool;
635
extern operator '>=' macro Int32GreaterThanOrEqual(int32, int32): bool;
636
extern operator '>=' macro Uint32GreaterThanOrEqual(uint32, uint32): bool;
637

638 639 640 641 642 643
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;
644

645 646
extern operator '==' macro ElementsKindEqual(
    constexpr ElementsKind, constexpr ElementsKind): constexpr bool;
647
extern operator '==' macro ElementsKindEqual(ElementsKind, ElementsKind): bool;
648 649 650 651
operator '!=' macro ElementsKindNotEqual(
    k1: ElementsKind, k2: ElementsKind): bool {
  return !ElementsKindEqual(k1, k2);
}
652 653 654 655
extern macro IsElementsKindLessThanOrEqual(
    ElementsKind, constexpr ElementsKind): bool;
extern macro IsElementsKindGreaterThan(
    ElementsKind, constexpr ElementsKind): bool;
656 657 658
extern macro IsElementsKindInRange(
    ElementsKind, constexpr ElementsKind, constexpr ElementsKind): bool;

659
extern macro IsFastElementsKind(constexpr ElementsKind): constexpr bool;
660
extern macro IsDoubleElementsKind(constexpr ElementsKind): constexpr bool;
661

662 663 664 665
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;
666
extern macro IsTuple2Map(Map): bool;
667

668
extern macro SmiAbove(Smi, Smi): bool;
669

670
extern operator '==' macro WordEqual(intptr, intptr): bool;
671
extern operator '==' macro WordEqual(uintptr, uintptr): bool;
672
extern operator '!=' macro WordNotEqual(intptr, intptr): bool;
673
extern operator '!=' macro WordNotEqual(uintptr, uintptr): bool;
674
extern operator '<' macro IntPtrLessThan(intptr, intptr): bool;
675
extern operator '<' macro UintPtrLessThan(uintptr, uintptr): bool;
676
extern operator '>' macro IntPtrGreaterThan(intptr, intptr): bool;
677
extern operator '>' macro UintPtrGreaterThan(uintptr, uintptr): bool;
678
extern operator '<=' macro IntPtrLessThanOrEqual(intptr, intptr): bool;
679
extern operator '<=' macro UintPtrLessThanOrEqual(uintptr, uintptr): bool;
680
extern operator '>=' macro IntPtrGreaterThanOrEqual(intptr, intptr): bool;
681
extern operator '>=' macro UintPtrGreaterThanOrEqual(uintptr, uintptr): bool;
682 683 684 685 686
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;
687

688
extern operator '==' macro Float64Equal(float64, float64): bool;
689
extern operator '!=' macro Float64NotEqual(float64, float64): bool;
690
extern operator '>' macro Float64GreaterThan(float64, float64): bool;
691
extern operator '>=' macro Float64GreaterThanOrEqual(float64, float64): bool;
692
extern operator '<' macro Float64LessThan(float64, float64): bool;
693
extern operator '<=' macro Float64LessThanOrEqual(float64, float64): bool;
694

695
extern macro BranchIfNumberEqual(Number, Number): never
696
    labels Taken, NotTaken;
697
operator '==' macro IsNumberEqual(a: Number, b: Number): bool {
698
  BranchIfNumberEqual(a, b) otherwise return true, return false;
699
}
700
operator '!=' macro IsNumberNotEqual(a: Number, b: Number): bool {
701
  return !(a == b);
702
}
703
extern macro BranchIfNumberLessThan(Number, Number): never
704
    labels Taken, NotTaken;
705 706 707 708
operator '<' macro NumberIsLessThan(a: Number, b: Number): bool {
  BranchIfNumberLessThan(a, b) otherwise return true, return false;
}
extern macro BranchIfNumberLessThanOrEqual(Number, Number): never
709
    labels Taken, NotTaken;
710 711 712
operator '<=' macro NumberIsLessThanOrEqual(a: Number, b: Number): bool {
  BranchIfNumberLessThanOrEqual(a, b) otherwise return true, return false;
}
713

714 715 716 717 718 719
operator '>' macro NumberIsGreaterThan(a: Number, b: Number): bool {
  return b < a;
}
operator '>=' macro NumberIsGreaterThanOrEqual(a: Number, b: Number): bool {
  return b <= a;
}
720

721 722 723
extern macro BranchIfFloat64IsNaN(float64): never
    labels Taken, NotTaken;
macro Float64IsNaN(n: float64): bool {
724
  BranchIfFloat64IsNaN(n) otherwise return true, return false;
725 726
}

727
// The type of all tagged values that can safely be compared with TaggedEqual.
728
type TaggedWithIdentity =
729
    JSReceiver|FixedArrayBase|Oddball|Map|WeakCell|Context|EmptyString;
730

731 732 733
extern operator '==' macro TaggedEqual(TaggedWithIdentity, Object): bool;
extern operator '==' macro TaggedEqual(Object, TaggedWithIdentity): bool;
extern operator '==' macro TaggedEqual(
734
    TaggedWithIdentity, TaggedWithIdentity): bool;
735
extern operator '==' macro TaggedEqual(WeakHeapObject, WeakHeapObject): bool;
736 737 738
extern operator '!=' macro TaggedNotEqual(TaggedWithIdentity, Object): bool;
extern operator '!=' macro TaggedNotEqual(Object, TaggedWithIdentity): bool;
extern operator '!=' macro TaggedNotEqual(
739
    TaggedWithIdentity, TaggedWithIdentity): bool;
740
extern operator '!=' macro TaggedNotEqual(WeakHeapObject, WeakHeapObject): bool;
741 742
// Do not overload == and != if it is unclear if object identity is the right
// equality.
743 744
extern macro TaggedEqual(MaybeObject, MaybeObject): bool;
extern macro TaggedNotEqual(MaybeObject, MaybeObject): bool;
745 746 747

extern operator '+' macro SmiAdd(Smi, Smi): Smi;
extern operator '-' macro SmiSub(Smi, Smi): Smi;
748
extern operator '&' macro SmiAnd(Smi, Smi): Smi;
749 750
extern operator '|' macro SmiOr(Smi, Smi): Smi;
extern operator '<<' macro SmiShl(Smi, constexpr int31): Smi;
751
extern operator '>>' macro SmiSar(Smi, constexpr int31): Smi;
752 753

extern operator '+' macro IntPtrAdd(intptr, intptr): intptr;
754 755 756 757
extern operator '+' macro ConstexprIntPtrAdd(
    constexpr intptr, constexpr intptr): constexpr intptr;
extern operator '+' macro ConstexprUintPtrAdd(
    constexpr uintptr, constexpr uintptr): constexpr intptr;
758
extern operator '-' macro IntPtrSub(intptr, intptr): intptr;
759
extern operator '*' macro IntPtrMul(intptr, intptr): intptr;
760
extern operator '/' macro IntPtrDiv(intptr, intptr): intptr;
761
extern operator '<<' macro WordShl(intptr, intptr): intptr;
762
extern operator '>>' macro WordSar(intptr, intptr): intptr;
763
extern operator '&' macro WordAnd(intptr, intptr): intptr;
764 765 766 767
extern operator '|' macro WordOr(intptr, intptr): intptr;

extern operator '+' macro UintPtrAdd(uintptr, uintptr): uintptr;
extern operator '-' macro UintPtrSub(uintptr, uintptr): uintptr;
768
extern operator '<<' macro WordShl(uintptr, uintptr): uintptr;
Tobias Tebbi's avatar
Tobias Tebbi committed
769 770 771
extern operator '>>>' macro WordShr(uintptr, uintptr): uintptr;
extern operator '&' macro WordAnd(uintptr, uintptr): uintptr;
extern operator '|' macro WordOr(uintptr, uintptr): uintptr;
772

Tobias Tebbi's avatar
Tobias Tebbi committed
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
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(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;
793 794 795 796
extern operator '==' macro ConstexprInt32Equal(
    constexpr int32, constexpr int32): constexpr bool;
extern operator '!=' macro ConstexprInt32NotEqual(
    constexpr int32, constexpr int32): constexpr bool;
797

Tobias Tebbi's avatar
Tobias Tebbi committed
798 799 800 801 802 803 804 805 806 807 808 809 810
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 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;
811

Tobias Tebbi's avatar
Tobias Tebbi committed
812 813 814 815
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;
816

Tobias Tebbi's avatar
Tobias Tebbi committed
817 818 819 820 821 822
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);
823
}
Tobias Tebbi's avatar
Tobias Tebbi committed
824 825
macro Max(x: Number, y: Number): Number {
  return NumberMax(x, y);
826 827
}

Tobias Tebbi's avatar
Tobias Tebbi committed
828 829 830
extern macro TryIntPtrAdd(intptr, intptr): intptr labels Overflow;
extern macro TryIntPtrSub(intptr, intptr): intptr labels Overflow;
extern macro TryInt32Mul(int32, int32): int32 labels Overflow;
831

Tobias Tebbi's avatar
Tobias Tebbi committed
832 833 834 835 836 837
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;
838

Tobias Tebbi's avatar
Tobias Tebbi committed
839 840 841 842
extern macro SmiMax(Smi, Smi): Smi;
extern macro SmiMin(Smi, Smi): Smi;
extern macro SmiMul(Smi, Smi): Number;
extern macro SmiMod(Smi, Smi): Number;
843

Tobias Tebbi's avatar
Tobias Tebbi committed
844 845 846
extern macro IntPtrMax(intptr, intptr): intptr;
extern macro IntPtrMin(intptr, intptr): intptr;
extern macro UintPtrMin(uintptr, uintptr): uintptr;
847

Tobias Tebbi's avatar
Tobias Tebbi committed
848 849 850
extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool;
extern operator '!' macro Word32BinaryNot(bool): bool;
extern operator '!' macro IsFalse(Boolean): bool;
851

Tobias Tebbi's avatar
Tobias Tebbi committed
852 853
extern operator '.instanceType' macro LoadInstanceType(HeapObject):
    InstanceType;
854

Tobias Tebbi's avatar
Tobias Tebbi committed
855 856 857
operator '.length_uintptr' macro LoadJSArrayLengthAsUintPtr(array: JSArray):
    uintptr {
  return Convert<uintptr>(array.length);
858 859
}

Tobias Tebbi's avatar
Tobias Tebbi committed
860 861 862
extern operator '.length_intptr' macro LoadStringLengthAsWord(String): intptr;
operator '.length_uintptr' macro LoadStringLengthAsUintPtr(s: String): uintptr {
  return Unsigned(s.length_intptr);
863
}
Tobias Tebbi's avatar
Tobias Tebbi committed
864 865
extern operator '.length_uint32' macro LoadStringLengthAsWord32(String): uint32;
extern operator '.length_smi' macro LoadStringLengthAsSmi(String): Smi;
866

Tobias Tebbi's avatar
Tobias Tebbi committed
867 868 869 870 871
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);
872 873
}

Tobias Tebbi's avatar
Tobias Tebbi committed
874 875 876
operator '==' macro PromiseStateEquals(
    s1: PromiseState, s2: PromiseState): bool {
  return Word32Equal(s1, s2);
877 878
}

Tobias Tebbi's avatar
Tobias Tebbi committed
879 880 881 882
extern macro TaggedIsSmi(Object): bool;
extern macro TaggedIsNotSmi(Object): bool;
extern macro TaggedIsPositiveSmi(Object): bool;
extern macro IsValidPositiveSmi(intptr): bool;
883

Tobias Tebbi's avatar
Tobias Tebbi committed
884
extern macro IsInteger(HeapNumber): bool;
885

886
extern macro AllocateHeapNumberWithValue(float64): HeapNumber;
887 888
extern macro ChangeInt32ToTagged(int32): Number;
extern macro ChangeUint32ToTagged(uint32): Number;
889 890
extern macro ChangeUintPtrToFloat64(uintptr): float64;
extern macro ChangeUintPtrToTagged(uintptr): Number;
891
extern macro Unsigned(int32): uint32;
892 893
extern macro Unsigned(int16): uint16;
extern macro Unsigned(int8): uint8;
894
extern macro Unsigned(intptr): uintptr;
895 896
extern macro Unsigned(RawPtr): uintptr;
extern macro Signed(uint32): int32;
897 898
extern macro Signed(uint16): int16;
extern macro Signed(uint8): int8;
899
extern macro Signed(uintptr): intptr;
900
extern macro Signed(RawPtr): intptr;
901 902 903
extern macro TruncateIntPtrToInt32(intptr): int32;
extern macro SmiTag(intptr): Smi;
extern macro SmiFromInt32(int32): Smi;
904
extern macro SmiFromUint32(uint32): Smi;
905
extern macro SmiFromIntPtr(intptr): Smi;
906
extern macro SmiUntag(Smi): intptr;
907 908 909
macro SmiUntag<T: type>(value: SmiTagged<T>): T {
  return %RawDownCast<T>(Unsigned(SmiToInt32(Convert<Smi>(value))));
}
910 911 912
macro SmiTag<T : type extends uint31>(value: T): SmiTagged<T> {
  return %RawDownCast<SmiTagged<T>>(SmiFromUint32(value));
}
913
extern macro SmiToInt32(Smi): int32;
914 915 916 917
extern macro TaggedIndexToIntPtr(TaggedIndex): intptr;
extern macro IntPtrToTaggedIndex(intptr): TaggedIndex;
extern macro TaggedIndexToSmi(TaggedIndex): Smi;
extern macro SmiToTaggedIndex(Smi): TaggedIndex;
918
extern macro RoundIntPtrToFloat64(intptr): float64;
919 920
extern macro ChangeFloat32ToFloat64(float32): float64;
extern macro ChangeNumberToFloat64(Number): float64;
921 922 923
extern macro ChangeTaggedNonSmiToInt32(implicit context: Context)(JSAnyNotSmi):
    int32;
extern macro ChangeTaggedToFloat64(implicit context: Context)(JSAny): float64;
924
extern macro ChangeFloat64ToTagged(float64): Number;
925
extern macro ChangeFloat64ToUintPtr(float64): uintptr;
926
extern macro ChangeFloat64ToIntPtr(float64): intptr;
927
extern macro ChangeInt32ToFloat64(int32): float64;
928
extern macro ChangeInt32ToIntPtr(int32): intptr;   // Sign-extends.
929
extern macro ChangeUint32ToWord(uint32): uintptr;  // Doesn't sign-extend.
930
extern macro LoadNativeContext(Context): NativeContext;
931
extern macro TruncateFloat64ToFloat32(float64): float32;
932
extern macro TruncateHeapNumberValueToWord32(HeapNumber): int32;
933 934
extern macro LoadJSArrayElementsMap(constexpr ElementsKind, NativeContext): Map;
extern macro LoadJSArrayElementsMap(ElementsKind, NativeContext): Map;
935 936
extern macro NumberConstant(constexpr float64): Number;
extern macro NumberConstant(constexpr int32): Number;
937
extern macro NumberConstant(constexpr uint32): Number;
938 939
extern macro IntPtrConstant(constexpr int31): intptr;
extern macro IntPtrConstant(constexpr int32): intptr;
940
extern macro Int32Constant(constexpr int31): int31;
941
extern macro Int32Constant(constexpr int32): int32;
942
extern macro Float64Constant(constexpr int31): float64;
943
extern macro Float64Constant(constexpr float64): float64;
944
extern macro SmiConstant(constexpr int31): Smi;
945
extern macro SmiConstant(constexpr Smi): Smi;
946
extern macro SmiConstant(constexpr MessageTemplate): Smi;
947 948
extern macro SmiConstant(constexpr bool): Smi;
extern macro SmiConstant(constexpr uint32): Smi;
949
extern macro BoolConstant(constexpr bool): bool;
950
extern macro StringConstant(constexpr string): String;
951
extern macro IntPtrConstant(constexpr ContextSlot): ContextSlot;
952
extern macro IntPtrConstant(constexpr intptr): intptr;
953
extern macro PointerConstant(constexpr RawPtr): RawPtr;
954
extern macro SingleCharacterStringConstant(constexpr string): String;
955
extern macro Float64SilenceNaN(float64): float64;
956

957
extern macro BitcastWordToTaggedSigned(intptr): Smi;
958
extern macro BitcastWordToTaggedSigned(uintptr): Smi;
959
extern macro BitcastWordToTagged(intptr): Object;
960 961
extern macro BitcastWordToTagged(uintptr): Object;
extern macro BitcastTaggedToWord(Tagged): intptr;
962
extern macro BitcastTaggedToWordForTagAndSmiBits(Tagged): intptr;
963

964 965
macro Is<A : type extends Object, B : type extends Object>(
    implicit context: Context)(o: B): bool {
966 967
  Cast<A>(o) otherwise return false;
  return true;
968 969
}

970 971
macro UnsafeCast<A : type extends Object>(implicit context: Context)(o: Object):
    A {
972
  assert(Is<A>(o));
973
  return %RawDownCast<A>(o);
974 975
}

976 977 978 979
macro UnsafeConstCast<T: type>(r: const &T):&T {
  return %RawDownCast<&T>(r);
}

980
extern macro FixedArrayMapConstant(): Map;
981
extern macro FixedDoubleArrayMapConstant(): Map;
982 983
extern macro FixedCOWArrayMapConstant(): Map;
extern macro EmptyByteArrayConstant(): ByteArray;
984
extern macro EmptyFixedArrayConstant(): EmptyFixedArray;
985
extern macro PromiseCapabilityMapConstant(): Map;
986 987
extern macro OneByteStringMapConstant(): Map;
extern macro StringMapConstant(): Map;
988
extern macro SloppyArgumentsElementsMapConstant(): Map;
989 990

const kFixedArrayMap: Map = FixedArrayMapConstant();
991
const kFixedDoubleArrayMap: Map = FixedDoubleArrayMapConstant();
992 993
const kCOWMap: Map = FixedCOWArrayMapConstant();
const kEmptyByteArray: ByteArray = EmptyByteArrayConstant();
994
const kEmptyFixedArray: EmptyFixedArray = EmptyFixedArrayConstant();
995
const kPromiseCapabilityMap: Map = PromiseCapabilityMapConstant();
996 997 998 999
// The map of a non-internalized internal SeqOneByteString.
const kOneByteStringMap: Map = OneByteStringMapConstant();
// The map of a non-internalized internal SeqTwoByteString.
const kStringMap: Map = StringMapConstant();
1000
const kSloppyArgumentsElementsMap: Map = SloppyArgumentsElementsMapConstant();
1001

1002 1003
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
    bool;
1004
extern macro IsNoElementsProtectorCellInvalid(): bool;
1005
extern macro IsArrayIteratorProtectorCellInvalid(): bool;
1006 1007 1008
extern macro IsArraySpeciesProtectorCellInvalid(): bool;
extern macro IsTypedArraySpeciesProtectorCellInvalid(): bool;
extern macro IsPromiseSpeciesProtectorCellInvalid(): bool;
1009
extern macro IsMockArrayBufferAllocatorFlag(): bool;
1010 1011
extern macro IsPrototypeTypedArrayPrototype(implicit context: Context)(Map):
    bool;
1012

1013
extern operator '.data_ptr' macro LoadJSTypedArrayDataPtr(JSTypedArray): RawPtr;
1014

1015
extern operator '.elements_kind' macro LoadMapElementsKind(Map): ElementsKind;
1016 1017
extern operator '.elements_kind' macro LoadElementsKind(JSTypedArray):
    ElementsKind;
1018

1019
extern operator '.length' macro LoadFastJSArrayLength(FastJSArray): Smi;
1020 1021 1022 1023 1024
operator '.length=' macro StoreFastJSArrayLength(
    array: FastJSArray, length: Smi) {
  const array: JSArray = array;
  array.length = length;
}
1025

1026
extern macro GetNumberDictionaryNumberOfElements(NumberDictionary): Smi;
1027

1028 1029
extern macro LoadConstructorOrBackPointer(Map): Object;

1030
extern macro BasicLoadNumberDictionaryElement(NumberDictionary, intptr): JSAny
1031
    labels NotData, IfHole;
1032

1033
extern macro IsFastElementsKind(ElementsKind): bool;
1034
extern macro IsDoubleElementsKind(ElementsKind): bool;
1035 1036
extern macro IsFastSmiOrTaggedElementsKind(ElementsKind): bool;
extern macro IsFastSmiElementsKind(ElementsKind): bool;
1037
extern macro IsHoleyFastElementsKind(ElementsKind): bool;
1038

1039
macro FastHoleyElementsKind(kind: ElementsKind): ElementsKind {
1040 1041 1042 1043
  if (kind == ElementsKind::PACKED_SMI_ELEMENTS) {
    return ElementsKind::HOLEY_SMI_ELEMENTS;
  } else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) {
    return ElementsKind::HOLEY_DOUBLE_ELEMENTS;
1044
  }
1045 1046
  assert(kind == ElementsKind::PACKED_ELEMENTS);
  return ElementsKind::HOLEY_ELEMENTS;
1047 1048
}

1049
macro AllowDoubleElements(kind: ElementsKind): ElementsKind {
1050 1051 1052 1053
  if (kind == ElementsKind::PACKED_SMI_ELEMENTS) {
    return ElementsKind::PACKED_DOUBLE_ELEMENTS;
  } else if (kind == ElementsKind::HOLEY_SMI_ELEMENTS) {
    return ElementsKind::HOLEY_DOUBLE_ELEMENTS;
1054 1055 1056 1057 1058
  }
  return kind;
}

macro AllowNonNumberElements(kind: ElementsKind): ElementsKind {
1059 1060 1061 1062 1063 1064 1065 1066
  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;
1067 1068 1069 1070
  }
  return kind;
}

1071 1072
macro GetObjectFunction(implicit context: Context)(): JSFunction {
  return UnsafeCast<JSFunction>(
1073
      LoadNativeContext(context)[NativeContextSlot::OBJECT_FUNCTION_INDEX]);
1074
}
1075 1076 1077 1078
macro GetArrayFunction(implicit context: Context)(): JSFunction {
  return UnsafeCast<JSFunction>(
      LoadNativeContext(context)[NativeContextSlot::ARRAY_FUNCTION_INDEX]);
}
1079 1080
macro GetArrayBufferFunction(implicit context: Context)(): Constructor {
  return UnsafeCast<Constructor>(
1081
      LoadNativeContext(context)[NativeContextSlot::ARRAY_BUFFER_FUN_INDEX]);
1082
}
1083
macro GetArrayBufferNoInitFunction(implicit context: Context)(): JSFunction {
1084 1085
  return UnsafeCast<JSFunction>(LoadNativeContext(
      context)[NativeContextSlot::ARRAY_BUFFER_NOINIT_FUN_INDEX]);
1086
}
1087
macro GetFastPackedElementsJSArrayMap(implicit context: Context)(): Map {
1088 1089
  return UnsafeCast<Map>(LoadNativeContext(
      context)[NativeContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX]);
1090
}
1091
macro GetFastPackedSmiElementsJSArrayMap(implicit context: Context)(): Map {
1092 1093
  return UnsafeCast<Map>(LoadNativeContext(
      context)[NativeContextSlot::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX]);
1094
}
1095
macro GetProxyRevocableResultMap(implicit context: Context)(): Map {
1096 1097
  return UnsafeCast<Map>(LoadNativeContext(
      context)[NativeContextSlot::PROXY_REVOCABLE_RESULT_MAP_INDEX]);
1098
}
1099
macro GetIteratorResultMap(implicit context: Context)(): Map {
1100 1101
  return UnsafeCast<Map>(
      LoadNativeContext(context)[NativeContextSlot::ITERATOR_RESULT_MAP_INDEX]);
1102
}
1103
macro GetInitialStringIteratorMap(implicit context: Context)(): Map {
1104 1105
  return UnsafeCast<Map>(LoadNativeContext(
      context)[NativeContextSlot::INITIAL_STRING_ITERATOR_MAP_INDEX]);
1106
}
1107
macro GetReflectApply(implicit context: Context)(): Callable {
1108 1109
  return UnsafeCast<Callable>(
      LoadNativeContext(context)[NativeContextSlot::REFLECT_APPLY_INDEX]);
1110 1111
}
macro GetRegExpLastMatchInfo(implicit context: Context)(): RegExpMatchInfo {
1112 1113
  return %RawDownCast<RegExpMatchInfo>(LoadNativeContext(
      context)[NativeContextSlot::REGEXP_LAST_MATCH_INFO_INDEX]);
1114
}
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
macro GetStrictArgumentsMap(implicit context: Context)(): Map {
  return UnsafeCast<Map>(LoadNativeContext(
      context)[NativeContextSlot::STRICT_ARGUMENTS_MAP_INDEX]);
}
macro GetSloppyArgumentsMap(implicit context: Context)(): Map {
  return UnsafeCast<Map>(LoadNativeContext(
      context)[NativeContextSlot::SLOPPY_ARGUMENTS_MAP_INDEX]);
}
macro GetFastAliasedArgumentsMap(implicit context: Context)(): Map {
  return UnsafeCast<Map>(LoadNativeContext(
      context)[NativeContextSlot::FAST_ALIASED_ARGUMENTS_MAP_INDEX]);
}
1127

1128 1129 1130 1131 1132 1133 1134
// 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;
1135
extern transitioning macro Call(
1136
    Context, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny;
1137
extern transitioning macro Call(
1138
    Context, JSAny, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny;
1139
extern transitioning macro Call(
1140
    Context, JSAny, JSAny, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny;
1141

1142
extern macro TransitionElementsKind(
1143 1144
    JSObject, Map, constexpr ElementsKind,
    constexpr ElementsKind): void labels Bailout;
1145
extern macro PerformStackCheck(implicit context: Context)(): void;
1146

1147
extern macro Typeof(JSAny): String;
1148

1149 1150
// Return true iff number is NaN.
macro NumberIsNaN(number: Number): bool {
1151 1152
  typeswitch (number) {
    case (Smi): {
1153
      return false;
1154 1155
    }
    case (hn: HeapNumber): {
1156
      const value: float64 = Convert<float64>(hn);
1157 1158
      return value != value;
    }
1159
  }
1160
}
1161

1162
extern macro GotoIfForceSlowPath() labels Taken;
1163 1164 1165 1166 1167
macro IsForceSlowPath(): bool {
  GotoIfForceSlowPath() otherwise return true;
  return false;
}

1168
extern macro BranchIfToBooleanIsTrue(JSAny): never
1169
    labels Taken, NotTaken;
1170
extern macro BranchIfToBooleanIsFalse(JSAny): never
1171
    labels Taken, NotTaken;
1172

1173
macro ToBoolean(obj: JSAny): bool {
1174
  BranchIfToBooleanIsTrue(obj) otherwise return true, return false;
1175
}
1176

1177 1178
@export
macro RequireObjectCoercible(implicit context: Context)(
1179
    value: JSAny, name: constexpr string): JSAny {
1180
  if (IsNullOrUndefined(value)) {
1181
    ThrowTypeError(MessageTemplate::kCalledOnNullOrUndefined, name);
1182 1183 1184 1185
  }
  return value;
}

1186 1187
extern macro BranchIfSameValue(JSAny, JSAny): never labels Taken, NotTaken;
macro SameValue(a: JSAny, b: JSAny): bool {
1188 1189
  BranchIfSameValue(a, b) otherwise return true, return false;
}
1190

1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
// 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;
  }
}

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
// 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));
1234 1235
      // Positive Smi values definitely fit into both [0, kMaxSafeInteger] and
      // [0, kMaxUintPtr] ranges.
1236
      return value;
1237
    }
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
    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);
      }
1248

1249
      if constexpr (Is64()) {
1250 1251 1252 1253 1254 1255 1256
        // On 64-bit architectures uintptr range is bigger than safe integer
        // range.
        if (kMode == kModeValueIsAnyNumber) {
          if (valueDouble > kMaxSafeInteger) goto IfSafeIntegerOverflow;
        } else {
          assert(valueDouble <= kMaxSafeInteger);
        }
1257
      } else {
1258 1259 1260 1261 1262 1263 1264 1265
        // 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);
        }
1266
      }
1267
      return ChangeFloat64ToUintPtr(valueDouble);
1268 1269
    }
  }
1270
}
1271

1272 1273 1274 1275 1276
@export
macro ChangeUintPtrNumberToUintPtr(value: Number): uintptr {
  try {
    return TryNumberToUintPtr(value, kModeValueIsSafeIntegerUintPtr)
        otherwise InvalidValue, InvalidValue, InvalidValue;
1277
  } label InvalidValue {
1278 1279 1280 1281
    unreachable;
  }
}

1282
@export
1283 1284 1285 1286 1287
macro ChangeSafeIntegerNumberToUintPtr(value: Number):
    uintptr labels IfUIntPtrOverflow {
  try {
    return TryNumberToUintPtr(value, kModeValueIsSafeInteger)
        otherwise InvalidValue, IfUIntPtrOverflow, InvalidValue;
1288
  } label InvalidValue {
1289 1290 1291 1292
    unreachable;
  }
}

1293 1294 1295
transitioning macro ToUintPtr(implicit context: Context)(value: JSAny):
    uintptr labels IfLessThanZero, IfUIntPtrOverflow, IfSafeIntegerOverflow {
  if (value == Undefined) return 0;
1296
  const indexNumber = ToInteger_Inline(value);
1297 1298 1299 1300
  return TryNumberToUintPtr(indexNumber, kModeValueIsAnyNumber)
      otherwise IfLessThanZero, IfUIntPtrOverflow, IfSafeIntegerOverflow;
}

1301 1302 1303 1304 1305 1306 1307 1308 1309
// 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;
1310
  const indexNumber = ToInteger_Inline(value);
1311 1312 1313 1314 1315 1316
  // Less than 0 case, uintptr range overflow and safe integer range overflow
  // imply IfRangeError.
  return TryNumberToUintPtr(indexNumber, kModeValueIsAnyNumber)
      otherwise IfRangeError, IfRangeError, IfRangeError;
}

1317
transitioning macro GetLengthProperty(implicit context: Context)(o: JSAny):
1318
    Number {
1319
  try {
1320 1321 1322 1323
    typeswitch (o) {
      case (a: JSArray): {
        return a.length;
      }
1324 1325 1326 1327
      case (a: JSStrictArgumentsObject): {
        goto ToLength(a.length);
      }
      case (a: JSSloppyArgumentsObject): {
1328
        goto ToLength(a.length);
1329
      }
1330
      case (JSAny): deferred {
1331 1332 1333
        goto ToLength(GetProperty(o, kLengthString));
      }
    }
1334
  } label ToLength(length: JSAny) deferred {
1335
    return ToLength_Inline(length);
1336 1337
  }
}
1338

1339
transitioning macro GetMethod(implicit context: Context)(
1340 1341
    o: JSAny, name: AnyName): Callable labels IfNullOrUndefined,
    IfMethodNotCallable(JSAny) {
1342
  const value = GetProperty(o, name);
1343 1344
  // TODO(v8:9933): Consider checking for null/undefined after checking for
  // callable because the latter seems to be more common.
1345 1346
  if (value == Undefined || value == Null) goto IfNullOrUndefined;
  return Cast<Callable>(value)
1347 1348 1349 1350 1351 1352 1353
      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;
1354
  } label IfMethodNotCallable(value: JSAny) deferred {
1355
    ThrowTypeError(MessageTemplate::kPropertyNotFunction, value, name, o);
1356 1357 1358 1359 1360 1361
  }
}

transitioning macro GetMethod(implicit context: Context)(
    o: JSAny, name: constexpr string): Callable labels IfNullOrUndefined {
  return GetMethod(o, StringConstant(name)) otherwise IfNullOrUndefined;
1362 1363
}

1364 1365 1366 1367 1368
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)
1369 1370
      otherwise ThrowTypeError(
      MessageTemplate::kPropertyNotFunction, value, symbol, o);
1371 1372
}

1373
extern macro NumberToString(Number): String;
1374
extern macro IsOneByteStringInstanceType(InstanceType): bool;
1375 1376 1377 1378 1379

// 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)(
1380
    index: JSAny, length: uintptr): uintptr {
1381
  const indexNumber: Number = ToInteger_Inline(index);
1382 1383 1384 1385 1386 1387
  return ConvertToRelativeIndex(indexNumber, length);
}

// Calculate a relative index:
// return index < 0 ? max(length + index, 0) : min(index, length)
@export
1388
macro ConvertToRelativeIndex(indexNumber: Number, length: uintptr): uintptr {
1389 1390 1391 1392 1393 1394
  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;
1395
        return relativeIndex < length ? relativeIndex : 0;
1396 1397 1398

      } else {
        const relativeIndex: uintptr = Unsigned(indexIntPtr);
1399
        return relativeIndex < length ? relativeIndex : length;
1400 1401 1402
      }
    }
    case (indexHeapNumber: HeapNumber): {
1403
      assert(IsNumberNormalized(indexHeapNumber));
1404 1405 1406
      const indexDouble: float64 = Convert<float64>(indexHeapNumber);
      // NaNs must already be handled by ConvertToRelativeIndex() version
      // above accepting JSAny indices.
1407
      assert(!Float64IsNaN(indexDouble));
1408 1409 1410 1411
      const lengthDouble: float64 = Convert<float64>(length);
      assert(lengthDouble <= kMaxSafeInteger);
      if (indexDouble < 0) {
        const relativeIndex: float64 = lengthDouble + indexDouble;
1412
        return relativeIndex > 0 ? ChangeFloat64ToUintPtr(relativeIndex) : 0;
1413 1414

      } else {
1415 1416
        return ChangeFloat64ToUintPtr(
            indexDouble < lengthDouble ? indexDouble : lengthDouble);
1417 1418 1419 1420
      }
    }
  }
}
1421

1422 1423 1424 1425 1426 1427
// 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 {
1428
  const indexNumber: Number = ToInteger_Inline(index);
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
  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): {
1444
      assert(IsNumberNormalized(indexHeapNumber));
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
      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);
    }
  }
}

1460
extern builtin ObjectToString(Context, JSAny): String;
1461
extern builtin StringRepeat(Context, String, Number): String;
1462

1463
@export
1464
struct KeyValuePair {
1465 1466
  key: JSAny;
  value: JSAny;
1467
}
1468 1469 1470

// Macro definitions for compatibility that expose functionality to the CSA
// using "legacy" APIs. In Torque code, these should not be used.
1471
@export
1472
macro IsFastJSArray(o: Object, context: Context): bool {
1473 1474 1475
  // 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;
1476 1477 1478
  return Is<FastJSArray>(o);
}

1479 1480 1481
@export
macro BranchIfFastJSArray(o: Object, context: Context): never labels True,
    False {
1482 1483 1484 1485 1486
  if (IsFastJSArray(o, context)) {
    goto True;
  } else {
    goto False;
  }
1487 1488
}

1489 1490 1491
@export
macro BranchIfFastJSArrayForRead(o: Object, context: Context):
    never labels True, False {
1492 1493
  // Long-term, it's likely not a good idea to have this slow-path test here,
  // since it fundamentally breaks the type system.
1494 1495 1496 1497 1498 1499
  if (IsForceSlowPath()) goto False;
  if (Is<FastJSArrayForRead>(o)) {
    goto True;
  } else {
    goto False;
  }
1500 1501
}

1502
@export
1503 1504 1505
macro IsFastJSArrayWithNoCustomIteration(context: Context, o: Object): bool {
  return Is<FastJSArrayWithNoCustomIteration>(o);
}
1506

1507 1508 1509 1510 1511 1512
@export
macro IsFastJSArrayForReadWithNoCustomIteration(context: Context, o: Object):
    bool {
  return Is<FastJSArrayForReadWithNoCustomIteration>(o);
}

1513
extern transitioning runtime
1514
CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, JSAny);
1515

1516
namespace runtime {
1517 1518
extern runtime
GetDerivedMap(Context, JSFunction, JSReceiver): Map;
1519 1520
}

1521
transitioning builtin FastCreateDataProperty(implicit context: Context)(
1522
    receiver: JSReceiver, key: JSAny, value: JSAny): Object {
1523
  try {
1524
    const array = Cast<FastJSArray>(receiver) otherwise Slow;
1525 1526 1527
    const index: Smi = Cast<Smi>(key) otherwise goto Slow;
    if (index < 0 || index > array.length) goto Slow;
    const isAppend = index == array.length;
1528 1529 1530 1531 1532 1533 1534 1535 1536

    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)) {
1537 1538
        BuildAppendJSArray(ElementsKind::HOLEY_SMI_ELEMENTS, array, value)
            otherwise Slow;
1539
      } else if (IsDoubleElementsKind(kind)) {
1540
        BuildAppendJSArray(ElementsKind::HOLEY_DOUBLE_ELEMENTS, array, value)
1541 1542
            otherwise Slow;
      } else {
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
        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;
1560 1561 1562 1563
        const doubleElements = Cast<FixedDoubleArray>(array.elements)
            otherwise unreachable;
        doubleElements[index] = numberValue;
      } else {
1564
        assert(IsFastSmiOrTaggedElementsKind(kind));
1565 1566 1567 1568
        const elements = Cast<FixedArray>(array.elements) otherwise unreachable;
        elements[index] = value;
      }
    }
1569
  } label Slow {
1570 1571 1572 1573
    CreateDataProperty(receiver, key, value);
  }
  return Undefined;
}
Shiyu Zhang's avatar
Shiyu Zhang committed
1574

1575
@export
1576 1577
transitioning macro ToStringImpl(context: Context, o: JSAny): String {
  let result: JSAny = o;
Shiyu Zhang's avatar
Shiyu Zhang committed
1578 1579 1580 1581 1582
  while (true) {
    typeswitch (result) {
      case (num: Number): {
        return NumberToString(num);
      }
1583 1584 1585
      case (str: String): {
        return str;
      }
Shiyu Zhang's avatar
Shiyu Zhang committed
1586 1587 1588 1589 1590 1591 1592
      case (oddball: Oddball): {
        return oddball.to_string;
      }
      case (JSReceiver): {
        result = NonPrimitiveToPrimitive_String(context, result);
        continue;
      }
1593
      case (Symbol): {
1594
        ThrowTypeError(MessageTemplate::kSymbolToString);
1595
      }
1596
      case (JSAny): {
Shiyu Zhang's avatar
Shiyu Zhang committed
1597 1598 1599 1600
        return ToStringRT(context, o);
      }
    }
  }
1601
  unreachable;
Shiyu Zhang's avatar
Shiyu Zhang committed
1602
}
1603 1604 1605 1606 1607

macro VerifiedUnreachable(): never {
  StaticAssert(false);
  unreachable;
}
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645

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;
  }
}
1646

1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669
// 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;
}

1670
macro ReplaceTheHoleWithUndefined(o: JSAny|TheHole): JSAny {
1671 1672 1673 1674 1675 1676 1677 1678 1679
  typeswitch (o) {
    case (TheHole): {
      return Undefined;
    }
    case (a: JSAny): {
      return a;
    }
  }
}
1680 1681

extern macro DecodeScopeInfoHasContextExtension(intptr): intptr;
1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695

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};
}