blob: a24b67c9bc61f6f2a06dc2b09032754530f84f21 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Major interpreter-related definitions.
*/
#include "environment.h"
#include "vm_threads.h"
#include "open/bytecodes.h"
#include "open/vm_util.h"
#include "ini.h"
#include "jvmti_types.h"
#include "vm_log.h"
//#define INTERPRETER_DEEP_DEBUG
/** \def DEBUG(a)
* \brief Does nothing.*/
#define DEBUG(a)
#ifdef NDEBUG
/** \def DEBUG_BYTECODE(a)
* \brief If <code>DEBUG</code> is off, does nothing.*/
# define DEBUG_BYTECODE(a)
#else
/** \def DEBUG_BYTECODE(a)
* \brief If <code>DEBUG</code> is on, calls TRACE(a).*/
# define DEBUG_BYTECODE(a) { if (frame.dump_bytecodes) TRACE(a); }
#endif
/** \def DEBUG_GC(a)
* \brief Calls <code>TRACE2</code> with the <code>gc_interpreter</code>
* category.
*/
#define DEBUG_GC(a) TRACE2("gc_interpreter", a)
/** <code>TRUE</code> if the interpreter enables debug.*/
extern bool interpreter_enable_debug;
/** \def DEBUG_TRACE(a)
* \brief Calls <code>TRACE2</code> with the <code>folded_interpreter</code>
* category.*/
#define DEBUG_TRACE(a) TRACE2("folded_interpreter", a)
/** \def ASSERT_TAGS(a)
* \brief Does nothing.*/
#define ASSERT_TAGS(a)
/** \def ASSERT_OBJECT(a)
* \brief Checks the object.*/
#define ASSERT_OBJECT(a) \
assert((a == 0) || \
( (*((a)->vt()->clss->get_class_handle()))->vt()->clss == \
VM_Global_State::loader_env->JavaLangClass_Class))
#ifndef INTERPRETER_USE_MALLOC_ALLOCATION
/** \def ALLOC_FRAME(sz)
* \brief Calls <code>alloca(sz)</code>.*/
#define ALLOC_FRAME(sz) alloca(sz)
/** \def FREE_FRAME(ptr)
* \brief If <code>INTERPRETER_USE_MALLOC_ALLOCATION</code> is on, does
* nothing.*/
#define FREE_FRAME(ptr)
#else
#define ALLOC_FRAME(sz) m_malloc(sz)
#define FREE_FRAME(ptr) m_free(ptr)
#endif
#if POINTER64
# define COMPACT_FIELDS
# define uword uint64
# define word int64
#else
# define uword U_32
# define word I_32
#endif
#if defined(POINTER64) && defined(REFS_USE_COMPRESSED)
#define REF32 // Use compressed references
typedef COMPRESSED_REFERENCE REF;
#else
typedef ManagedObject* REF; // Use uncompressed references
#endif
#if defined(REF32) || !defined(POINTER64)
#define VAL32 // Value is 32-bit
#endif
// Create uncompressed value
#define MAKEREFVAL(_val_) (*((ManagedObject**)(&(_val_))))
// Create compressed value
#define MAKECRVAL(_val_) (*((COMPRESSED_REFERENCE*)(&(_val_))))
// Macros to compress/uncompress references in fiels and arrays
// Note: VM references are references in heap and fields and arrays
// interpreter references are references in method stack and local vars
#if defined(REFS_USE_COMPRESSED)
// Both VM and interpreter references are compressed
#define STORE_UREF_BY_ADDR(_addr_, _val_) \
*((COMPRESSED_REFERENCE*)(_addr_)) = compress_reference(_val_)
#define UNCOMPRESS_REF(cref) (uncompress_compressed_reference(MAKECRVAL(cref)))
//----------------------
#elif defined(REFS_USE_UNCOMPRESSED)
// Both VM and interpreter references are uncompressed
#define STORE_UREF_BY_ADDR(_addr_, _val_) \
*((ManagedObject**)(_addr_)) = (ManagedObject*)(_val_)
#define UNCOMPRESS_REF(cref) ((ManagedObject*)(cref))
//----------------------
#else // for REFS_USE_RUNTIME_SWITCH
// interpreter refs are uncompressed; VM refs can be either
#define STORE_UREF_BY_ADDR(_addr_, _val_) \
if (REFS_IS_COMPRESSED_MODE) { \
*((COMPRESSED_REFERENCE*)(_addr_)) = compress_reference(_val_); \
} else { \
*((ManagedObject**)(_addr_)) = (ManagedObject*)(_val_); \
}
#define UNCOMPRESS_REF(cref) ( REFS_IS_COMPRESSED_MODE ? \
(uncompress_compressed_reference(MAKECRVAL(cref))) : \
(MAKEREFVAL(cref)))
//----------------------
#endif
// Macros for compressing/uncompressing referenceses in interpreter's
// method stack and local vars
#ifdef REF32
#define COMPRESS_INTERP(ref) (compress_reference(ref))
#define UNCOMPRESS_INTERP(cref) (uncompress_compressed_reference(cref))
#define REF_NULL (MANAGED_NULL)
#else // REF32
#define COMPRESS_INTERP(ref) ((ManagedObject*)(ref))
#define UNCOMPRESS_INTERP(cref) ((ManagedObject*)(cref))
#define REF_NULL 0
#endif // REF32
/** Defines byte ordering in Value2 in different situations.*/
/** The stack value.
* @note Values on the java stack are placed in the reversed order, so that the
* reversed copy in the function call works correctly.*/
#define s0 1
#define s1 0
/** The local value.*/
#define l0 0
/** The local value.*/
#define l1 1
/** The constant value.*/
#define c0 0
/** The constant value.*/
#define c1 1
/** The argument value.*/
#define a0 0
/** The argument value.*/
#define a1 1
/** The array value.*/
#define ar0 0
/** The array value.*/
#define ar1 1
/** The result value.*/
#define res0 1
/** The result value.*/
#define res1 0
/** Holds 32-bit values.*/
union Value {
/** The unsigned integer value.*/
U_32 u;
/** The integer value.*/
I_32 i;
/** The float value.*/
float f;
///** Compressed/uncompressed reference.*/
REF ref;
};
/** Holds 64-bit values */
union Value2 {
#ifdef VAL32
/** Two 32-bit values */
Value v[2];
#else
Value v0;
#endif
/** The long-long value.*/
int64 i64;
/** The unsigned long-long value */
uint64 u64;
/** The double value */
double d;
/** The reference */
ManagedObject* ref;
};
/** The local variable types.*/
enum {
/** The element of stack or local variables that is not an object.*/
FLAG_NONE = 0,
/** The container for the return address from a subroutine.*/
FLAG_RET_ADDR = 2,
/** The containter for an object reference.*/
FLAG_OBJECT = 3
};
/** The <code>pop_frame</code> states.*/
enum PopFrameState {
/** Indicates that the frame cannot be popped.*/
POP_FRAME_UNAVAILABLE,
/** Indicates that the frame can be popped.*/
POP_FRAME_AVAILABLE,
/** Indicates that the frame is being popped.*/
POP_FRAME_NOW
};
/**
* @brief %The stack for executing the Java method.
*
* This structure contains a set of operations specific for the Java stack.
*/
class Stack {
/** The stack element value.*/
Value *data;
/** The value to the object reference.*/
U_8 *refs;
/** The number of elements on the stack.*/
I_32 index;
/** The stack size.*/
I_32 size;
public:
/** The empty constructor.*/
inline Stack() {}
/** The destructor.*/
inline ~Stack();
/**
* Initializes the stack of a method.
*
* @param[in] ptr - the pointer to the data
* @param[in] size - the stack size
*/
inline void init(void *ptr, int size);
/**
* Returns the reference to the value on the top of the stack.
*
* @param[in] offset - the offset value
* @return The reference to the value on the top of the stack.
*/
inline Value& pick(int offset = 0);
/**
* Sets and resets the value to the object reference.
*
* @param[in] offset - the offset value
* @return The value to the object reference.
*/
inline U_8& ref(int offset = 0);
/**
* Only moves the stack pointer.
*
* @param[in] size - the size value
*/
inline void push(int size = 1);
/**
* Decreases the stack pointer.
* By default, decreases the pointer by one step or as specified in <i>size</i>.
*
* @param[in] size - the required size
*/
inline void pop(int size = 1);
/**
* Is similar to pop().
* Does the same as pop() and clears the type value associated with
* every cleared stack element via the ref() function.
*
* @param[in] size - the required size
*/
inline void popClearRef(int size = 1);
/**
* Sets the value of an object of the <code>Long</code> or <code>Double</code> type
* contained in two adjacent stack elements.
*
* @param[in] idx - the pointer to the stack depth of the <code>Long</code> value
* @param[in] val - the <code>Long</code> value
*/
inline void setLong(int idx, Value2 val);
/**
* Returns the <code>Long</code> value located at the depth specified by <i>idx</i>.
*
* @param[in] idx - the value identifier
* @return The <code>Long</code> value.
*/
inline Value2 getLong(int idx);
/** Clears the stack.*/
inline void clear();
/**
* Returns the size of the allocated stack area by the elements' size.
*
* @param[in] size - the size in elements
* @return The size of the allocated area.
*/
static inline int getStorageSize(int size);
/**
* Returns the number of elements on the stack.
*
* @return The number of elements on the stack.
*/
inline int getIndex() { return index + 1; }
/**
* Enumerates references associated with the thread.
*
* @param[in] VM_thread - the pointer to the thread
*/
friend void interp_enumerate_root_set_single_thread_on_stack(VM_thread*);
/**
* Enumerates references associated with the thread.
*
* @param[in] ti_env - the pointer to the jvmti environment
* @param[in] VM_thread - the pointer to the thread
*/
friend void interp_ti_enumerate_root_set_single_thread_on_stack(jvmtiEnv* ti_env, VM_thread *thread);
};
/** The storage for local variables of the executed Java method.*/
class Locals {
// local variable value
Value *vars;
// references to the local variable type
U_8 *refs;
// locals size
U_32 varNum;
public:
/** The empty constructor.*/
inline Locals() {}
/** The desctructor.*/
inline ~Locals();
/**
* Initializes the stack of a method.
*
* @param[in] ptr - the pointer to the data
* @param[in] size - the locals size value
*/
inline void init(void *ptr, U_32 size);
/**
* Returns the reference to the local variable of the specifie ID.
*
* @param[in] id - the local variable ID
* @return The reference to the requested local variable.
*/
inline Value& operator () (U_32 id);
/**
* Sets the value of an object of the <code>Long</code> or <code>Double</code>
* type contained in two adjacent elements.
*
* @param[in] idx - the local variable number
* @param[in] val - the local variable value
*/
inline void setLong(int idx, Value2 val);
/**
* Returns the value of an object of the <code>Long</code> or <code>Double</code>
* type contained in two adjacent elements.
*
* @param[in] idx - the local variable number
* @return The requested object value.
*/
inline Value2 getLong(int idx);
/**
* Returns the reference to the type of the local variable.
*
* @param[in] idx - the local variable number
* @return The reference to the local variable type.
* @sa FLAG_NONE, FLAG_RET_ADDR, FLAG_OBJECT
*/
inline U_8& ref(U_32 id);
/**
* Returns the size of the allocated locals area by its size in elements.
*
* @param[in] size - size of locals area in elements
* @return The size of the allocated area.
*/
static inline int getStorageSize(int size);
/**
* Returns the number of local variables in this object.
*
* @return The number of local variables.*/
inline U_32 getLocalsNumber() { return varNum; }
/**
* Enumerates references associated with the thread.
*
* @param[in] VM_thread - the pointer to the thread*/
friend void interp_enumerate_root_set_single_thread_on_stack(VM_thread*);
/**
* Enumerates references associated with the thread.
*
* @param[in] ti_env - the pointer to the jvmti environment
* @param[in] VM_thread - the pointer to the thread */
friend void interp_ti_enumerate_root_set_single_thread_on_stack(jvmtiEnv* ti_env, VM_thread *thread);
};
/** The list of functions that listen for the <code>PopFrame</code> event.*/
struct FramePopListener {
/** The pointer to the listener.*/
void *listener;
/** The next element.*/
FramePopListener *next;
};
/** The list of monitors locked by this method.*/
struct MonitorList {
/** The pointer to the monitor.*/
ManagedObject *monitor;
/** The next element.*/
MonitorList *next;
};
/** The representation of the method being executed.*/
struct StackFrame {
public:
/** The address of the bytecode being executed.*/
U_8 *ip;
/** The stack of this method.*/
Stack stack;
/** The local variables of this method.*/
Locals locals;
/** The pointer to the structure of this method.*/
Method *method;
/** The reference to the caller method.*/
StackFrame *prev;
/** The list of functions listening for the <code>PopFrame</code> event.*/
FramePopListener *framePopListener;
/** <code>This</code> pointer of the method being executed.*/
ManagedObject *This;
/** The list of locked monitors.*/
struct MonitorList *locked_monitors;
/** The auxiliary structure for storing available monitor structures.*/
struct MonitorList *free_monitors;
/** The method state: whether the JVMTI frame pop can be performed on it.*/
PopFrameState jvmti_pop_frame;
#ifndef NDEBUG
bool dump_bytecodes;
#endif
#ifdef INTERPRETER_DEEP_DEBUG
U_8 last_bytecodes[8];
int n_last_bytecode;
#endif
/** The <code>Exception</code> object that has been thrown and for which
* the JVMTI <code>Exception</code> (?) event has been sent.*/
ManagedObject *exc;
/** The <code>Exception</code> object that has been caught and for which
* the JVMTI <code>ExceptionCaught</code> (?) event has been sent.*/
ManagedObject *exc_catch;
};
/**
* \defgroup Prototypes Prototypes
*/
/*@{*/
/**
* The function for interpreter breakpoint processing.
*
* @param[in] frame - the method ID*/
extern U_8 Opcode_BREAKPOINT(StackFrame& frame);
/**
* Enumerates references associated with the thread.
*
* @param[in] VM_thread - the pointer to the thread*/
extern void interp_enumerate_root_set_single_thread_on_stack(VM_thread*);
/**
* Executes the native method.
*
* @param[in] method - the native-method structure pointer
* @param[out] return_value - the return value pointer
* @param[in] args - the method arguments pointer*/
extern void interpreter_execute_native_method(
Method *method, jvalue *return_value, jvalue *args);
/**
* Calls the static native method.
*
* @param[in] prevFrame - the previous frame pointer
* @param[in] frame - the frame pointer
* @param[in] method - the native-method structure pointer*/
extern void interpreterInvokeStaticNative(
StackFrame& prevFrame, StackFrame& frame, Method *method);
/**
* Calls the virtual native method.
*
* @param[in] prevFrame - the previous frame pointer
* @param[in] frame - the frame pointer
* @param[in] method - the method structure pointer*/
extern void interpreterInvokeVirtualNative(
StackFrame& prevFrame, StackFrame& frame, Method *method, int sz);
/**
* Executes the method.
*
* @param[in] method - the method structure pointer
* @param[out] return_value - the return value pointer
* @param[in] args - the method arguments pointer*/
extern void interpreter_execute_method(
Method *method, jvalue *return_value, jvalue *args);
/**
* Processes method entry events.
*
* @param[in] method - the method structure pointer*/
void method_entry_callback(Method *method);
/**
* Processes method exit events.
*
* @param[in] method - the method structure pointer
* @param[in] was_popped_by_exception - if was popped by exception
* @param[in] ret_val - the return value pointer*/
void method_exit_callback(Method *method, bool was_popped_by_exception, jvalue ret_val);
/**
* Processes method exit events.
*
* @param[in] method - the method structure pointer
* @param[in] frame - the frame pointer*/
void method_exit_callback_with_frame(Method *method, StackFrame& frame);
/**
* Processes the field modification event.
*
* @param[in] field - the field structure pointer
* @param[in] frame - the frame pointer*/
void putfield_callback(Field *field, StackFrame& frame);
/**
* Processes the field modification event.
*
* @param[in] field - the field structure pointer
* @param[in] frame - the frame pointer*/
void getfield_callback(Field *field, StackFrame& frame);
/**
* Processes the field modification event.
*
* @param[in] field - the field structure pointer
* @param[in] frame - the frame pointer*/
void putstatic_callback(Field *field, StackFrame& frame);
/**
* Processes the field modification event.
*
* @param[in] field - the field structure pointer
* @param[in] frame - the frame pointer*/
void getstatic_callback(Field *field, StackFrame& frame);
/**
* Processes the frame pop event.
*
* @param[in] l - the pointer to the list of functions that
* listen for the <code>PopFrame</code> event
* @param[in] method - the pointer to the method structure
* @param[in] was_popped_by_exception - if <code>was_popped_by_exception</code>*/
void frame_pop_callback(FramePopListener *l, Method *method, jboolean was_popped_by_exception);
/**
* Processes the single step event.
*
* @param[in] frame - the frame pointer*/
void single_step_callback(StackFrame &frame);
/**
* Finds the exception handler.
*
* @param[in] frame - the frame pointer
* @param[in] exception - the exception pointer
* @param[in] h - - the pointer to the representation of a catch block in
* a method's code array
* @return <code>TRUE</code> on success.*/
bool findExceptionHandler(StackFrame& frame, ManagedObject **exception, Handler **h);
/**
* Loads method handled exceptions.
*
* @param[in] method - the method structure pointer
* @return <code>TRUE</code> on success.*/
bool load_method_handled_exceptions(Method *m);
/*@}*/
/**
* \defgroup Inlines Inline Functions
*/
/*@{*/
/**
* Returns the last stack frame.
*
* @return The last stack frame.*/
static inline StackFrame*
getLastStackFrame() {
return (StackFrame*)get_thread_ptr()->lastFrame;
}
/**
* Returns the last stack frame.
*
* @param[in] thread - the thread pointer
* @return The last stack frame.*/
static inline StackFrame*
getLastStackFrame(VM_thread *thread) {
return (StackFrame*)(thread->lastFrame);
}
/** The interpreter states.*/
enum interpreter_state {
INTERP_STATE_STACK_OVERFLOW = 1
};
/**
* Sets the last stack frame.
*
* @param[in] frame - the frame pointer*/
static inline void setLastStackFrame(StackFrame *frame) {
get_thread_ptr()->lastFrame = frame;
}
/*@}*/
void
Stack::init(void *ptr, int sz) {
data = (Value*)ptr;
refs = (U_8*)(data + sz);
size = sz;
index = -1;
for(int i = 0; i < size; i++) refs[i] = 0;
}
Stack::~Stack() {
FREE_FRAME(data);
}
Locals::~Locals() {
FREE_FRAME(data);
}
void
Locals::init(void *ptr, U_32 size) {
vars = (Value*) ptr;
refs = (U_8*)(vars + size);
varNum = size;
for(U_32 i = 0; i < varNum; i++) refs[i] = 0;
}
int
Locals::getStorageSize(int size) {
return (size * (sizeof(Value) + sizeof(U_8)) + 7) & ~7;
}
Value&
Locals::operator () (U_32 id) {
assert(id < varNum);
return vars[id];
}
void
Locals::setLong(int idx, Value2 val) {
#ifdef VAL32
operator() (idx+l0) = val.v[a0];
operator() (idx+l1) = val.v[a1];
#else
operator() (idx+l0) = val.v0;
#endif
}
Value2
Locals::getLong(int idx) {
Value2 val;
#ifdef VAL32
val.v[a0] = operator() (idx+l0);
val.v[a1] = operator() (idx+l1);
#else
val.v0 = operator() (idx+l0);
#endif
return val;
}
U_8&
Locals::ref(U_32 id) {
assert(id < varNum);
return refs[id];
}
void
Stack::clear() {
index = -1;
for(int i = 0; i < size; i++) refs[i] = 0;
}
U_8&
Stack::ref(int offset) {
assert(index - offset >= 0);
return refs[index - offset];
}
Value&
Stack::pick(int offset) {
assert(index - offset >= 0);
return data[index - offset];
}
void
Stack::setLong(int idx, Value2 val) {
#ifdef VAL32
pick(idx + s0) = val.v[a0];
pick(idx + s1) = val.v[a1];
#else
pick(idx + s0) = val.v0;
#endif
}
Value2
Stack::getLong(int idx) {
Value2 val;
#ifdef VAL32
val.v[a0] = pick(idx + s0);
val.v[a1] = pick(idx + s1);
#else
val.v0 = pick(idx + s0);
#endif
return val;
}
void
Stack::pop(int off) {
index -= off;
assert(index >= -1);
}
void
Stack::popClearRef(int off) {
assert(index - off >= -1);
for(int i = 0; i < off; i++)
refs[index - i] = FLAG_NONE;
index -= off;
}
void
Stack::push(int off) {
index += off;
assert(index < size);
}
int
Stack::getStorageSize(int size) {
return (size * (sizeof(Value) + sizeof(U_8)) + 7) & ~7;
}
/** Sets up locals and stack on the C stack.*/
#define SETUP_LOCALS_AND_STACK(frame,method) \
int max_stack = method->get_max_stack(); \
frame.stack.init(ALLOC_FRAME( \
Stack::getStorageSize(max_stack)), max_stack); \
int max_locals = method->get_max_locals(); \
frame.locals.init(ALLOC_FRAME( \
Locals::getStorageSize(max_locals)), max_locals)
/** The interpreter jvmti events.*/
enum interpreter_ti_events {
/** The method entry event.*/
INTERPRETER_TI_METHOD_ENTRY_EVENT = 1,
/** The method exit event.*/
INTERPRETER_TI_METHOD_EXIT_EVENT = 2,
/** The single step event.*/
INTERPRETER_TI_SINGLE_STEP_EVENT = 4,
/** The pop-frame event.*/
INTERPRETER_TI_POP_FRAME_EVENT = 8,
/** The field access event.*/
INTERPRETER_TI_FIELD_ACCESS = 16,
/** The field modification event.*/
INTERPRETER_TI_FIELD_MODIFICATION = 32,
/** For other events.*/
INTERPRETER_TI_OTHER = 64 /* EXCEPTION, EXCEPTION_CATCH */
};
/**
* The global flags' section.
*
* Bitwise or of enabled <code>interpreter_ti_events</code>
*/
extern int interpreter_ti_notification_mode;