/*
 * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef SHARE_INTERPRETER_ABSTRACTINTERPRETER_HPP
#define SHARE_INTERPRETER_ABSTRACTINTERPRETER_HPP

#include "asm/macroAssembler.hpp"
#include "classfile/vmIntrinsics.hpp"
#include "code/stubs.hpp"
#include "interpreter/bytecodes.hpp"
#include "oops/method.hpp"
#include "runtime/frame.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/vmThread.hpp"

// This file contains the platform-independent parts
// of the abstract interpreter and the abstract interpreter generator.

// Organization of the interpreter(s). There exists two different interpreters in hotpot
// an assembly language version (aka template interpreter) and a high level language version
// (aka c++ interpreter). The division of labor is as follows:

// Template Interpreter          Zero Interpreter       Functionality
//
// templateTable*                bytecodeInterpreter*   actual interpretation of bytecodes
//
// templateInterpreter*          zeroInterpreter*       generation of assembly code that creates
//                                                      and manages interpreter runtime frames.
//

class InterpreterMacroAssembler;

class AbstractInterpreter: AllStatic {
  friend class VMStructs;
  friend class ZeroInterpreterGenerator;
  friend class TemplateInterpreterGenerator;
 public:
  enum MethodKind {
    zerolocals,                                                 // method needs locals initialization
    zerolocals_synchronized,                                    // method needs locals initialization & is synchronized
    native,                                                     // native method
    native_synchronized,                                        // native method & is synchronized
    empty,                                                      // empty method (code: _return)
    getter,                                                     // getter method
    setter,                                                     // setter method
    abstract,                                                   // abstract method (throws an AbstractMethodException)
    method_handle_invoke_FIRST,                                 // java.lang.invoke.MethodHandles::invokeExact, etc.
    method_handle_invoke_LAST                                   = (method_handle_invoke_FIRST
                                                                   + (static_cast<int>(vmIntrinsics::LAST_MH_SIG_POLY)
                                                                      - static_cast<int>(vmIntrinsics::FIRST_MH_SIG_POLY))),
    java_lang_math_sin,                                         // implementation of java.lang.Math.sin   (x)
    java_lang_math_cos,                                         // implementation of java.lang.Math.cos   (x)
    java_lang_math_tan,                                         // implementation of java.lang.Math.tan   (x)
    java_lang_math_tanh,                                        // implementation of java.lang.Math.tanh  (x)
    java_lang_math_cbrt,                                        // implementation of java.lang.Math.cbrt  (x)
    java_lang_math_abs,                                         // implementation of java.lang.Math.abs   (x)
    java_lang_math_sqrt,                                        // implementation of java.lang.Math.sqrt  (x)
    java_lang_math_sqrt_strict,                                 // implementation of java.lang.StrictMath.sqrt(x)
    java_lang_math_log,                                         // implementation of java.lang.Math.log   (x)
    java_lang_math_log10,                                       // implementation of java.lang.Math.log10 (x)
    java_lang_math_pow,                                         // implementation of java.lang.Math.pow   (x,y)
    java_lang_math_exp,                                         // implementation of java.lang.Math.exp   (x)
    java_lang_math_fmaF,                                        // implementation of java.lang.Math.fma   (x, y, z)
    java_lang_math_fmaD,                                        // implementation of java.lang.Math.fma   (x, y, z)
    java_lang_ref_reference_get,                                // implementation of java.lang.ref.Reference.get()
    java_util_zip_CRC32_update,                                 // implementation of java.util.zip.CRC32.update()
    java_util_zip_CRC32_updateBytes,                            // implementation of java.util.zip.CRC32.updateBytes()
    java_util_zip_CRC32_updateByteBuffer,                       // implementation of java.util.zip.CRC32.updateByteBuffer()
    java_util_zip_CRC32C_updateBytes,                           // implementation of java.util.zip.CRC32C.updateBytes(crc, b[], off, end)
    java_util_zip_CRC32C_updateDirectByteBuffer,                // implementation of java.util.zip.CRC32C.updateDirectByteBuffer(crc, address, off, end)
    java_lang_Float_float16ToFloat,                             // implementation of java.lang.Float.float16ToFloat()
    java_lang_Float_floatToFloat16,                             // implementation of java.lang.Float.floatToFloat16()
    java_lang_Thread_currentThread,                             // implementation of java.lang.Thread.currentThread()
    number_of_method_entries,
    invalid = -1
  };

  // Conversion from the part of the above enum to vmIntrinsics::_invokeExact, etc.
  static vmIntrinsics::ID method_handle_intrinsic(MethodKind kind) {
    if (kind >= method_handle_invoke_FIRST && kind <= method_handle_invoke_LAST)
      return vmIntrinsics::ID_from(static_cast<int>(vmIntrinsics::FIRST_MH_SIG_POLY) + (kind - method_handle_invoke_FIRST));
    else
      return vmIntrinsics::_none;
  }

  // Conversion from the above enum to vmIntrinsics::ID
  static vmIntrinsics::ID method_intrinsic(MethodKind kind);

  enum SomeConstants {
    number_of_result_handlers = 10                              // number of result handlers for native calls
  };

 protected:
  static StubQueue* _code;                                      // the interpreter code (codelets)

  static bool       _notice_safepoints;                         // true if safepoints are activated

  // method entry points
  static address    _entry_table[number_of_method_entries];     // entry points for a given method
  static address    _native_abi_to_tosca[number_of_result_handlers];  // for native method result handlers
  static address    _slow_signature_handler;                              // the native method generic (slow) signature handler

  static address    _rethrow_exception_entry;                   // rethrows an activation in previous frame

  static bool       _should_print_instructions;                 // only with PrintInterpreter and when printing all InterpreterCodelet

  friend class      AbstractInterpreterGenerator;
  friend class      InterpreterMacroAssembler;

 public:
  // Initialization/debugging
  static void       initialize();
  static StubQueue* code()                                      { return _code; }
  static bool       should_print_instructions()                 { return _should_print_instructions; }


  // Method activation
  static MethodKind method_kind(const methodHandle& m);
  static address    entry_for_kind(MethodKind k)                { assert(0 <= k && k < number_of_method_entries, "illegal kind"); return _entry_table[k]; }
  static address    entry_for_method(const methodHandle& m)     { return entry_for_kind(method_kind(m)); }

  // used for bootstrapping method handles:
  static void       set_entry_for_kind(MethodKind k, address e);

  static void       print_method_kind(MethodKind kind)          PRODUCT_RETURN;

  // These should never be compiled since the interpreter will prefer
  // the compiled version to the intrinsic version.
  static bool       can_be_compiled(const methodHandle& m) {
    switch (m->intrinsic_id()) {
      case vmIntrinsics::_dsin  : // fall thru
      case vmIntrinsics::_dcos  : // fall thru
      case vmIntrinsics::_dtan  : // fall thru
      case vmIntrinsics::_dtanh : // fall thru
      case vmIntrinsics::_dcbrt : // fall thru
      case vmIntrinsics::_dabs  : // fall thru
      case vmIntrinsics::_dsqrt : // fall thru
      case vmIntrinsics::_dsqrt_strict : // fall thru
      case vmIntrinsics::_dlog  : // fall thru
      case vmIntrinsics::_dlog10: // fall thru
      case vmIntrinsics::_dpow  : // fall thru
      case vmIntrinsics::_dexp  : // fall thru
      case vmIntrinsics::_fmaD  : // fall thru
      case vmIntrinsics::_fmaF  : // fall thru
      case vmIntrinsics::_floatToFloat16       : // fall thru
      case vmIntrinsics::_float16ToFloat       : // fall thru
      case vmIntrinsics::_Continuation_doYield : // fall thru
        return false;

      default:
        return true;
    }
  }

  // Runtime support

  // length = invoke bytecode length (to advance to next bytecode)
  static address deopt_entry(TosState state, int length) { ShouldNotReachHere(); return nullptr; }
  static address return_entry(TosState state, int length, Bytecodes::Code code) { ShouldNotReachHere(); return nullptr; }

  static address    rethrow_exception_entry()                   { return _rethrow_exception_entry; }

  // Activation size in words for a method that is just being called.
  // Parameters haven't been pushed so count them too.
  static int        size_top_interpreter_activation(Method* method);

  // Deoptimization support
  // Compute the entry address for continuation after
  static address deopt_continue_after_entry(Method* method,
                                            address bcp,
                                            int callee_parameters,
                                            bool is_top_frame);
  // Compute the entry address for reexecution
  static address deopt_reexecute_entry(Method* method, address bcp);
  // Deoptimization should reexecute this bytecode
  static bool    bytecode_should_reexecute(Bytecodes::Code code);

  // deoptimization support
  static int        size_activation(int max_stack,
                                    int temps,
                                    int extra_args,
                                    int monitors,
                                    int callee_params,
                                    int callee_locals,
                                    bool is_top_frame);

  static void      layout_activation(Method* method,
                                     int temps,
                                     int popframe_args,
                                     int monitors,
                                     int caller_actual_parameters,
                                     int callee_params,
                                     int callee_locals,
                                     frame* caller,
                                     frame* interpreter_frame,
                                     bool is_top_frame,
                                     bool is_bottom_frame);

  // Runtime support
  static bool       is_not_reached(const methodHandle& method, int bci);
  // Safepoint support
  static void       notice_safepoints()                         { ShouldNotReachHere(); } // stops the thread when reaching a safepoint
  static void       ignore_safepoints()                         { ShouldNotReachHere(); } // ignores safepoints

  // Support for native calls
  static address    slow_signature_handler()                    { return _slow_signature_handler; }
  static address    result_handler(BasicType type)              { return _native_abi_to_tosca[BasicType_as_index(type)]; }
  static int        BasicType_as_index(BasicType type);         // computes index into result_handler_by_index table
  // Debugging/printing
  static void       print();                                    // prints the interpreter code

 public:
  // Interpreter helpers
  const static int stackElementWords   = 1;
  const static int stackElementSize    = stackElementWords * wordSize;
  const static int logStackElementSize = LogBytesPerWord;

  static int expr_index_at(int i) {
    return stackElementWords * i;
  }

  static int expr_offset_in_bytes(int i) {
#if !defined(ZERO) && (defined(PPC) || defined(S390))
    return stackElementSize * i + wordSize;  // both point to one word past TOS
#else
    return stackElementSize * i;
#endif
  }

  static int local_index_at(int i) {
    assert(i <= 0, "local direction already negated");
    return stackElementWords * i;
  }

#if !defined(ZERO) && (defined(IA32) || defined(AMD64))
  static Address::ScaleFactor stackElementScale() {
    return NOT_LP64(Address::times_4) LP64_ONLY(Address::times_8);
  }
#endif

  // Local values relative to locals[n]
  static int  local_offset_in_bytes(int n) {
    return ((frame::interpreter_frame_expression_stack_direction() * n) * stackElementSize);
  }

  // access to stacked values according to type:
  static oop* oop_addr_in_slot(intptr_t* slot_addr) {
    return (oop*) slot_addr;
  }
  static jint* int_addr_in_slot(intptr_t* slot_addr) {
    if ((int) sizeof(jint) < wordSize && !Endian::is_Java_byte_ordering_different())
      // big-endian LP64
      return (jint*)(slot_addr + 1) - 1;
    else
      return (jint*) slot_addr;
  }
  static jlong long_in_slot(intptr_t* slot_addr) {
    if (sizeof(intptr_t) >= sizeof(jlong)) {
      return *(jlong*) slot_addr;
    } else {
      return Bytes::get_native_u8((address)slot_addr);
    }
  }
  static void set_long_in_slot(intptr_t* slot_addr, jlong value) {
    if (sizeof(intptr_t) >= sizeof(jlong)) {
      *(jlong*) slot_addr = value;
    } else {
      Bytes::put_native_u8((address)slot_addr, value);
    }
  }

  static void initialize_method_handle_entries();
};

//------------------------------------------------------------------------------------------------------------------------
// The interpreter generator.

class Template;
class AbstractInterpreterGenerator: public StackObj {
 protected:
  InterpreterMacroAssembler* _masm;

 public:
  AbstractInterpreterGenerator();
};

#endif // SHARE_INTERPRETER_ABSTRACTINTERPRETER_HPP
