blob: 7d74f08a3110b1bdf5528d17694b57da3b53e959 [file]
// 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<TheHole>(val) || !Is<ContextCell>(val));
return val;
}
macro StoreContextElementNoCellImpl(c: Context, i: intptr, o: Object): void {
dcheck(Is<TheHole>(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 == TheHole && 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 == TheHole) {
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();