// 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
extern class Context extends HeapObject {
  macro GetScopeInfo(): ScopeInfo {
    return *ContextSlot(this, ContextSlot::SCOPE_INFO_INDEX);
  }
  const length: Smi;
  elements[length]: Object;
}

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

extern class FunctionContext extends Context generates 'TNode<Context>';

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

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) {
  // Make sure the arguments have the right type.
  const context: AnnotatedContext = context;
  const value: T = value;
  assert(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>,
  JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX: Slot<NativeContext, Map>,
  JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX: Slot<NativeContext, Map>,
  MATH_RANDOM_CACHE_INDEX: Slot<NativeContext, FixedDoubleArray>,
  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>,
  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>,

  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>,

  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>,

  MIN_CONTEXT_SLOTS,
  ...
}

@export
macro LoadContextElement(c: Context, i: intptr): Object {
  return c.elements[i];
}

@export
macro LoadContextElement(c: Context, i: Smi): Object {
  return c.elements[i];
}

@export
macro LoadContextElement(c: Context, i: constexpr int32): Object {
  return c.elements[i];
}

@export
macro StoreContextElement(c: Context, i: intptr, o: Object) {
  c.elements[i] = o;
}

@export
macro StoreContextElement(c: Context, i: Smi, o: Object) {
  c.elements[i] = o;
}

@export
macro StoreContextElement(c: Context, i: constexpr int32, o: Object) {
  c.elements[i] = o;
}

// 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();
