current commit
261015.17 · deps: update V8 to 15.6.75.13
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@abstract
@cppObjectLayoutDefinition
extern class Context extends HeapObject {
  macro GetScopeInfo(): ScopeInfo {
    return *ContextSlot(this, ContextSlot::SCOPE_INFO_INDEX);
  }
  const length: Smi;
  elements[length]: Object;
}

@cppObjectLayoutDefinition
extern class ScriptContextTable extends HeapObject {
  const capacity: uint32;
  length: uint32;
  names_to_context_index: NameToIndexHashTable;
  objects[capacity]: Context;
}

@cppObjectLayoutDefinition
extern class ContextCell extends HeapObject {
  // TODO(victorgomes): Change the type of tagged_value to JSAny.
  tagged_value: Object;
  dependent_code: DependentCode;
  state: int32;
  @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
  double_value: float64;
}

extern enum ContextMode extends uint32 { kNoContextCells, kHasContextCells }

extern operator '.int32_value' macro LoadContextCellInt32Value(ContextCell):
    int32;
extern operator '.int32_value=' macro StoreContextCellInt32Value(
    ContextCell, int32): void;

const kContextCellConst: constexpr int32 generates 'ContextCell::kConst';
const kContextCellSmi: constexpr int32 generates 'ContextCell::kSmi';
const kContextCellInt32: constexpr int32 generates 'ContextCell::kInt32';
const kContextCellFloat64: constexpr int32 generates 'ContextCell::kFloat64';
const kContextCellDetached:
    constexpr int32 generates 'ContextCell::kDetached';

extern class AwaitContext extends Context generates 'Context';
extern class BlockContext extends Context generates 'Context';
extern class CatchContext extends Context generates 'Context';
extern class DebugEvaluateContext extends Context
    generates 'Context';
extern class EvalContext extends Context generates 'Context';
extern class ModuleContext extends Context generates 'Context';
extern class ScriptContext extends Context generates 'Context';
extern class WithContext extends Context generates 'Context';

extern class FunctionContext extends Context generates 'Context';

extern macro IsEmptyDependentCode(Object): bool;
extern macro IsUndefinedContextCell(Object): bool;
extern macro TryFloat64ToInt32(float64): int32 labels Failed;
const kInitialContextSlotValue: Smi = 0;

@export
macro AllocateSyntheticFunctionContext(
    nativeContext: NativeContext, slots: constexpr int31): FunctionContext {
  return AllocateSyntheticFunctionContext(
      nativeContext, Convert<intptr>(slots));
}

macro AllocateSyntheticFunctionContext(
    nativeContext: NativeContext, slots: intptr): FunctionContext {
  static_assert(slots >= ContextSlot::MIN_CONTEXT_SLOTS);
  const map =
      *ContextSlot(nativeContext, ContextSlot::FUNCTION_CONTEXT_MAP_INDEX);
  const result = new FunctionContext{
    map,
    length: Convert<Smi>(slots),
    elements: ...ConstantIterator<Smi>(kInitialContextSlotValue)
  };
  InitContextSlot(result, ContextSlot::SCOPE_INFO_INDEX, kEmptyScopeInfo);
  InitContextSlot(result, ContextSlot::PREVIOUS_INDEX, Undefined);
  return result;
}

macro HasContextCells(c: Context): bool {
  return c.GetScopeInfo().flags.has_context_cells;
}

extern class NativeContext extends Context;

type Slot<Container : type extends Context, T : type extends Object> extends
    intptr;

// We cannot use ContextSlot() for initialization since that one asserts the
// slot has the right type already.
macro InitContextSlot<
    ArgumentContext: type, AnnotatedContext: type, T: type, U: type>(
    context: ArgumentContext, index: Slot<AnnotatedContext, T>,
    value: U): void {
  // Make sure the arguments have the right type.
  const context: AnnotatedContext = context;
  const value: T = value;
  dcheck(TaggedEqual(context.elements[index], kInitialContextSlotValue));
  context.elements[index] = value;
}

macro ContextSlot<ArgumentContext: type, AnnotatedContext: type, T: type>(
    context: ArgumentContext, index: Slot<AnnotatedContext, T>):&T {
  const context: AnnotatedContext = context;
  return torque_internal::unsafe::ReferenceCast<T>(&context.elements[index]);
}

macro NativeContextSlot<T: type>(
    context: NativeContext, index: Slot<NativeContext, T>):&T {
  return ContextSlot(context, index);
}
macro NativeContextSlot<T: type>(
    context: Context, index: Slot<NativeContext, T>):&T {
  return ContextSlot(LoadNativeContext(context), index);
}
macro NativeContextSlot<C: type, T: type>(
    implicit context: C)(index: Slot<NativeContext, T>):&T {
  return NativeContextSlot(context, index);
}

extern enum ContextSlot extends intptr constexpr 'Context::Field' {
  SCOPE_INFO_INDEX: Slot<Context, ScopeInfo>,
  // Zero is used for the NativeContext, Undefined is used for synthetic
  // function contexts.
  PREVIOUS_INDEX: Slot<Context, Context|Zero|Undefined>,

  AGGREGATE_ERROR_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,
  ARRAY_BUFFER_FUN_INDEX: Slot<NativeContext, Constructor>,
  ARRAY_BUFFER_NOINIT_FUN_INDEX: Slot<NativeContext, JSFunction>,
  ARRAY_BUFFER_MAP_INDEX: Slot<NativeContext, Map>,
  ARRAY_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,
  ARRAY_JOIN_STACK_INDEX: Slot<NativeContext, Undefined|FixedArray>,
  OBJECT_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,
  ITERATOR_RESULT_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_MAP_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_FILTER_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_TAKE_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_DROP_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_FLAT_MAP_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_CONCAT_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_ZIP_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_ZIP_KEYED_HELPER_MAP_INDEX: Slot<NativeContext, Map>,
  ITERATOR_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,
  VALID_ITERATOR_WRAPPER_MAP_INDEX: Slot<NativeContext, Map>,
  JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX: Slot<NativeContext, Map>,
  JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX: Slot<NativeContext, Map>,
  INITIAL_ARRAY_PROTOTYPE_INDEX: Slot<NativeContext, JSObject>,
  INITIAL_ARRAY_PROTOTYPE_VALIDITY_CELL_INDEX: Slot<NativeContext, Cell>,
  JS_MAP_MAP_INDEX: Slot<NativeContext, Map>,
  JS_SET_MAP_INDEX: Slot<NativeContext, Map>,
  MATH_RANDOM_CACHE_INDEX: Slot<NativeContext, Undefined|FixedDoubleArray>,
  MATH_RANDOM_STATE_INDEX: Slot<NativeContext, ByteArray>,
  MATH_RANDOM_INDEX_INDEX: Slot<NativeContext, Smi>,
  NUMBER_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,
  PROXY_REVOCABLE_RESULT_MAP_INDEX: Slot<NativeContext, Map>,
  REFLECT_APPLY_INDEX: Slot<NativeContext, Callable>,
  REGEXP_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,
  REGEXP_LAST_MATCH_INFO_INDEX: Slot<NativeContext, RegExpMatchInfo>,
  INITIAL_STRING_ITERATOR_MAP_INDEX: Slot<NativeContext, Map>,
  INITIAL_ARRAY_ITERATOR_MAP_INDEX: Slot<NativeContext, Map>,
  INITIAL_ITERATOR_PROTOTYPE_INDEX: Slot<NativeContext, JSObject>,
  SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP: Slot<NativeContext, Map>,
  STRICT_ARGUMENTS_MAP_INDEX: Slot<NativeContext, Map>,
  SLOPPY_ARGUMENTS_MAP_INDEX: Slot<NativeContext, Map>,
  FAST_ALIASED_ARGUMENTS_MAP_INDEX: Slot<NativeContext, Map>,
  FUNCTION_CONTEXT_MAP_INDEX: Slot<NativeContext, Map>,
  FUNCTION_PROTOTYPE_APPLY_INDEX: Slot<NativeContext, JSFunction>,
  STRING_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,

  UINT8_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  INT8_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  UINT16_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  INT16_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  UINT32_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  INT32_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  FLOAT16_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  FLOAT32_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  FLOAT64_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  UINT8_CLAMPED_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  BIGUINT64_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,
  BIGINT64_ARRAY_FUN_INDEX: Slot<NativeContext, JSFunction>,

  RAB_GSAB_UINT8_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_INT8_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_UINT16_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_INT16_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_UINT32_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_INT32_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_FLOAT16_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_FLOAT32_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_FLOAT64_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_UINT8_CLAMPED_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_BIGUINT64_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,
  RAB_GSAB_BIGINT64_ARRAY_MAP_INDEX: Slot<NativeContext, Map>,

  ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX: Slot<NativeContext, Map>,
  DATA_PROPERTY_DESCRIPTOR_MAP_INDEX: Slot<NativeContext, Map>,

  PROMISE_FUNCTION_INDEX: Slot<NativeContext, JSFunction>,
  PROMISE_THEN_INDEX: Slot<NativeContext, JSFunction>,
  PROMISE_PROTOTYPE_INDEX: Slot<NativeContext, JSObject>,
  STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX: Slot<NativeContext, Map>,

  PROMISE_HOOK_INIT_FUNCTION_INDEX: Slot<NativeContext, Undefined|Callable>,
  PROMISE_HOOK_BEFORE_FUNCTION_INDEX: Slot<NativeContext, Undefined|Callable>,
  PROMISE_HOOK_AFTER_FUNCTION_INDEX: Slot<NativeContext, Undefined|Callable>,
  PROMISE_HOOK_RESOLVE_FUNCTION_INDEX: Slot<NativeContext, Undefined|Callable>,

  // @if(V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA)
  CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX: Slot<NativeContext, HeapObject>,

  BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX: Slot<NativeContext, Map>,
  BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX: Slot<NativeContext, Map>,

  WRAPPED_FUNCTION_MAP_INDEX: Slot<NativeContext, Map>,

  MIN_CONTEXT_SLOTS,
  ...
}

@export
macro LoadContextElementNoCell(c: Context, i: intptr): Object {
  return LoadContextElementNoCellImpl(c, i);
}

@export
macro LoadContextElementNoCell(c: Context, i: Smi): Object {
  return LoadContextElementNoCellImpl(c, SmiUntag(i));
}

@export
macro LoadContextElementNoCell(c: Context, i: constexpr int32): Object {
  return LoadContextElementNoCellImpl(c, i);
}

@export
macro LoadContextElement(c: Context, i: intptr): Object {
  return LoadContextElementImpl(c, i);
}

@export
macro LoadContextElement(c: Context, i: Smi): Object {
  return LoadContextElementImpl(c, SmiUntag(i));
}

@export
macro LoadContextElement(c: Context, i: constexpr int32): Object {
  return LoadContextElementImpl(c, i);
}

@export
macro StoreContextElementNoCell(c: Context, i: intptr, o: Object): void {
  StoreContextElementNoCellImpl(c, i, o);
}

@export
macro StoreContextElementNoCell(c: Context, i: Smi, o: Object): void {
  StoreContextElementNoCellImpl(c, SmiUntag(i), o);
}

@export
macro StoreContextElementNoCell(
    c: Context, i: constexpr int32, o: Object): void {
  StoreContextElementNoCellImpl(c, i, o);
}

@export
macro StoreContextElement(c: Context, i: intptr, o: Object): void {
  StoreScriptContextElementImpl(c, i, o);
}

@export
macro StoreContextElement(c: Context, i: constexpr int32, o: Object): void {
  StoreScriptContextElementImpl(c, i, o);
}

macro LoadContextElementNoCellImpl(c: Context, i: intptr): Object {
  const val = c.elements[i];
  dcheck(Is<TdzHole>(val) || !Is<ContextCell>(val));
  return val;
}

macro StoreContextElementNoCellImpl(c: Context, i: intptr, o: Object): void {
  dcheck(Is<TdzHole>(c.elements[i]) || !Is<ContextCell>(c.elements[i]));
  c.elements[i] = o;
}

builtin LoadFromContextCell(_n: Object, c: Object, i: Smi): Object {
  const context = UnsafeCast<Context>(c);
  const index = SmiUntag(i);
  return LoadContextElementImpl(context, index);
}

builtin StoreCurrentContextElementBaseline(o: Object, i: Smi): JSAny {
  const context = internal::LoadContextFromBaseline();
  const index = SmiUntag(i);
  StoreScriptContextElementImpl(context, index, o);
  return Undefined;
}

builtin StoreContextElementBaseline(
    c: Object, o: Object, i: Smi, d: TaggedIndex): JSAny {
  let context = UnsafeCast<Context>(c);
  let depth = TaggedIndexToIntPtr(d);
  while (depth > 0) {
    --depth;
    context =
        UnsafeCast<Context>(context.elements[ContextSlot::PREVIOUS_INDEX]);
  }

  const index = SmiUntag(i);
  StoreScriptContextElementImpl(context, index, o);
  return Undefined;
}

builtin DetachContextCell(
    theContext: Object, newValue: JSAny, i: intptr): Object {
  // We should only call this builtin if the slot contains a context cell.
  const c = UnsafeCast<Context>(theContext);
  const cell = Cast<ContextCell>(c.elements[i]) otherwise unreachable;
  if (IsUndefinedContextCell(cell)) {
    c.elements[i] = newValue;
    return Undefined;
  }
  NotifyContextCellStateWillChange(cell);
  cell.tagged_value = kZero;
  c.elements[i] = newValue;
  cell.state = kContextCellDetached;
  return Undefined;
}

namespace runtime {
extern runtime NotifyContextCellStateWillChange(NoContext, ContextCell): JSAny;
}  // namespace runtime

macro NotifyContextCellStateWillChange(cell: ContextCell): void {
  if (!IsEmptyDependentCode(cell.dependent_code)) deferred {
      runtime::NotifyContextCellStateWillChange(kNoContext, cell);
    }
}

macro TransitionContextCellToUntagged(
    heapNumber: HeapNumber, cell: ContextCell,
    currentState: constexpr int32): void {
  try {
    const int32Value = TryFloat64ToInt32(heapNumber.value) otherwise NotInt32;
    cell.int32_value = int32Value;
    cell.state = kContextCellInt32;
  } label NotInt32 {
    if constexpr (currentState == kContextCellInt32) {
      // For states kConst and kSmi, we notify the change before calling
      // TransitionContextCellToUntagged.
      NotifyContextCellStateWillChange(cell);
    }
    cell.double_value = heapNumber.value;
    cell.state = kContextCellFloat64;
  }
}

macro StoreScriptContextElementImpl(
    c: Context, index: intptr, newValue: Object): void {
  const oldValue = c.elements[index];

  if (oldValue == TdzHole && HasContextCells(c)) {
    // Setting the initial value.
    c.elements[index] = AllocateContextCell(newValue);
    return;
  }

  if (!Is<ContextCell>(oldValue)) {
    c.elements[index] = newValue;
    return;
  }

  if (IsUndefinedContextCell(oldValue)) {
    if (newValue == Undefined) return;
    if (newValue == TdzHole) {
      c.elements[index] = newValue;
      return;
    }
    c.elements[index] = AllocateContextCell(newValue);
    return;
  }

  const cell = Cast<ContextCell>(oldValue) otherwise unreachable;
  if (cell.state == kContextCellConst) {
    const constValue = cell.tagged_value;
    // If we are assigning the same value, the property won't change.
    if (TaggedEqual(constValue, newValue)) {
      return;
    }
    // If both values are HeapNumbers with the same double value, the property
    // won't change either.
    if (Is<HeapNumber>(constValue) && Is<HeapNumber>(newValue)) {
      const oldNumber = Cast<HeapNumber>(constValue) otherwise unreachable;
      const newNumber = Cast<HeapNumber>(newValue) otherwise unreachable;
      if (oldNumber.value == newNumber.value && oldNumber.value != 0) {
        return;
      }
    }
    NotifyContextCellStateWillChange(cell);
    typeswitch (newValue) {
      case (smiNumber: Smi): {
        cell.state = kContextCellSmi;
        cell.tagged_value = smiNumber;
      }
      case (heapNumber: HeapNumber): {
        TransitionContextCellToUntagged(heapNumber, cell, kContextCellConst);
        cell.tagged_value = kZero;
      }
      case (Object): {
        c.elements[index] = newValue;
        cell.tagged_value = kZero;
        cell.state = kContextCellDetached;
      }
    }
    return;
  }

  if (cell.state == kContextCellSmi) {
    typeswitch (newValue) {
      case (smiNumber: Smi): {
        cell.tagged_value = smiNumber;
      }
      case (heapNumber: HeapNumber): {
        NotifyContextCellStateWillChange(cell);
        TransitionContextCellToUntagged(heapNumber, cell, kContextCellSmi);
        cell.tagged_value = kZero;
      }
      case (Object): {
        NotifyContextCellStateWillChange(cell);
        c.elements[index] = newValue;
        cell.tagged_value = kZero;
        cell.state = kContextCellDetached;
      }
    }
    return;
  }

  if (cell.state == kContextCellInt32) {
    typeswitch (newValue) {
      case (smiNumber: Smi): {
        cell.int32_value = SmiToInt32(smiNumber);
      }
      case (heapNumber: HeapNumber): {
        TransitionContextCellToUntagged(heapNumber, cell, kContextCellInt32);
      }
      case (Object): {
        NotifyContextCellStateWillChange(cell);
        c.elements[index] = newValue;
        cell.state = kContextCellDetached;
      }
    }
    return;
  }

  dcheck(cell.state == kContextCellFloat64);
  typeswitch (newValue) {
    case (smiNumber: Smi): {
      cell.double_value = SmiToFloat64(smiNumber);
    }
    case (heapNumber: HeapNumber): {
      cell.double_value = heapNumber.value;
    }
    case (Object): {
      NotifyContextCellStateWillChange(cell);
      c.elements[index] = newValue;
      cell.state = kContextCellDetached;
    }
  }
}

macro LoadContextElementImpl(c: Context, i: intptr): Object {
  const val = c.elements[i];
  const cell = Cast<ContextCell>(val) otherwise return val;
  dcheck(HasContextCells(c));
  dcheck(kContextCellConst == 0);
  dcheck(kContextCellSmi == 1);
  if (cell.state <= kContextCellSmi) {
    return cell.tagged_value;
  } else if (cell.state == kContextCellInt32) {
    const intValue = Convert<intptr>(cell.int32_value);
    if (Convert<uintptr>(intValue) <= kSmiMaxValue) {
      return Convert<Smi>(intValue);
    }
    return AllocateHeapNumberWithValue(ChangeInt32ToFloat64(cell.int32_value));
  } else {
    dcheck(cell.state == kContextCellFloat64);
    // TODO(victorgomes): and in this case tagged_value could have contained the
    // HeapNumber from which this double_value value was initialized.
    return AllocateHeapNumberWithValue(cell.double_value);
  }
}

// A dummy used instead of a context constant for runtime calls that don't need
// a context.
type NoContext extends Smi;
extern macro NoContextConstant(): NoContext;
const kNoContext: NoContext = NoContextConstant();