blob: dc94bb2e3380cdbffac25770126d11b8119bb27e [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.
*/
/**
* @author Alexander Astapchuk
*/
/**
* @file
* @brief Main Jitrino.JET's interface implementation.
*/
/**
* @mainpage
* @section sec_intro Introduction
* <center>
* Jitrino.JET: <b>J</b>itrino's <b>e</b>xpress compilation pa<b>t</b>h
* </center>
*
* Jitrino.JET is a simple baseline compiler for %Jitrino JIT.
*
* It's primarily targeted for fast compilation to ensure quick start for
* client applications and to support optimizing engine of main %Jitrino
* (instrumentation, profile generation, etc.).
*
* Jitrino.JET performs 2 passes over bytecode. On the first pass, basic
* blocks boundaries are found. On the second pass code is generated.
*
* The code is generated targeting an abstract CPU that is armed with
* registers, memory, memory stack and can perform several operations like
* move between memory/register, ALU operations, branch and call, etc
* (class Encoder generates primitive operations of this abstract CPU).
*
* Technically, Jitrino.JET generates a code that simulates stack-based
* operations of Java byte code using a register CPU. Every method
* compiled by Jitrino.JET creates a stack frame with a structure similar
* to the frame described by JVM spec (3.6). The stack frame contains local
* variables array and an area for operand stack plus some other auxilary
* items. Class StackFrame describes the stack frame structure.
*
* The compilation engine consists of two main classes - Compiler and
* CodeGen.
*
* Though the separation is quite relative, the main idea is that class
* Compiler processes high level method items, like basic blocks, whole
* method's data, code layout etc. The class CodeGen is more targeted to
* process instruction-level things (e.g. the byte code instructions
* themselves). Compiler organizes pass over the byte code, instruments
* CodeGen's fields with actual data (current compiler state, PC, etc) and
* invokes CodeGen's methods to generate code for each instruction.<br>
* Some bytecode instruction (like GOTO) need to deal with basic blocks
* information, thus their generation is placed into Compiler rather than
* in CodeGen.
*
*
* Class Compiler is based on CodeGen which in turn inherits from classes
* StaticConsts, Encoder and MethInfo. The StaticConsts class has no
* funtional interface, it's just used to keep static constants separately.
* Class Encoder represents generation of CPU operations.
* MethInfo provides an interface to obtain various info about method being
* compiled.
*
* As it was stated above, two passes over the byte code is performed.
*
* The first pass is linear scan of byte code (Compiler::comp_parse_bytecode)
* - it decodes all byte code instructions, finds boundaries of basic
* blocks, counts references for instructions and collects statistics about
* usage of local variabled. The reference count for instruction is number
* of incoming edges of control flow. For instructions inside basic block,
* the reference count is 1. For instructions that are basic block leaders,
* it may be more than 1. Reference count of zero means dead code.
*
* Then, a simple global register allocation performed
* (Compiler::comp_alloc_regs) basing on the info collected in
* Compiler::comp_parse_bytecode(). Local (per-basic block) register
* allocation is done during code generation (pass 2) via
* CodeGen::valloc(jtype) calls.
*
* The second pass is performed in depth-first search (DFS) order, and the
* code is generated (Compiler::comp_gen_code_bb). The code at first is
* generated into internal buffer (CodeGen::m_codeStream), and then a code
* layout is performed (Compiler::comp_layout_code) so the layout of
* generated code becomes exactly the same as byte code layout.
*
* During compilation, Jitrino.JET mimics Java operand stack operations
* (class JFrame), so its state is known for every byte code instruction.
* This mimic stack is used to get a GC info and eliminate many unnecessary
* temporary operations caused by stack-based nature of byte code (e.g.
* ICONST_0, ISTORE_1 => mov [local#1], 0). The JFrame class also contains
* local variables array. Both operand stack and local variables array in
* JFrame are used to track item locations (register, memory), known
* attributes (i.e. tested against null).
*
* Instance of JFrame is part of BBState class which is used to maintain
* per-basic block state of compiler.
*
* A special code is generated for GC support. During runtime 2 GC maps
* are maintained. GC map is a set of bits which shows whether an item
* contains a reference. GC map for local variables is build complitely
* during runtime. That is when a write to a local variable is generated,
* the code to set or clear approprate bit in GC map is also generated (see
* CodeGen::gen_gc_mark_local()).
*
* GC map for operand stack is semi-runtime. That is the operand stack
* state is maintaned duirng compilation. Before generate code for a call
* site special code is generated that updates GC map and operand stack
* depth at the given point (CodeGen::gen_gc_stack).
*
* To be accurate, there is on more GC map maintained - the GC map for
* callee-save registers. The code for this is also generated in
* CodeGen::gen_gc_mark_local(), as only local variables may reside on
* such regisers with current approach.
*
* When GC enumeration start, the runtime support code extracts these GC
* maps method's stack frame, and then objects are reported accordingly (
* see rt_enum()).
*
*
*/
#include "open/vm_method_access.h"
#include "jet.h"
#include "compiler.h"
#include "stats.h"
#include <jit_export_jpda.h>
#include <assert.h>
#include "trace.h"
#include "mkernel.h"
#include "PlatformDependant.h"
#include "version.h"
#include <set>
#include <string>
using std::set;
using std::string;
namespace Jitrino {
namespace Jet {
static void process_global_args(void);
static PMF* g_pmf = NULL;
void setup(JIT_Handle jit, const char * name)
{
g_pmf = &JITInstanceContext::getContextForJIT(jit)->getPMF();
process_global_args();
}
void cleanup(void)
{
#ifdef JIT_STATS
const char * lp = g_pmf->getArg(NULL, "stats");
if (lp != NULL && to_bool(lp)) {
Stats::dump();
}
#endif // ~JIT_STATS
g_pmf->deinit();
}
bool supports_compresed_refs(void)
{
#if defined(HYX86_64) || defined(_IPF_)
return true;
#else
return false;
#endif
}
const char *args[][2] =
{
//-------------------------------------------------------------------------
{"show",
" =help - prints out this text \n"
" =info \n"
" =id \n"
" =version - prints out build info \n"
" =all - help,version \n"
" =<empty> - same as all \n"
},
//-------------------------------------------------------------------------
{"log",
"The following categories are supported: \n"
"Compilation: \n"
"(don't forget to add 'log=ct'. default is code+sum) \n"
" sum - prints out short summary about compiled method \n"
" cg - trace every stage of code generation \n"
" code - dump resulting code \n"
" layout - addresses of generated basic blocks \n"
"Runtime: \n"
"(don't forget to add 'log=rt'!) \n"
" rtsupp - prints out runtime support events (unwind, GC enum, etc) \n"
" ee - logs method's enter and exit events \n"
" bc - logs execution of each bytecode instruction \n"
" \n"
"Examples: \n"
" -Djit.jet.arg.log=ct,sum,code \n"
" -Djit.jet.arg.log=ct (same as log=ct,sum,cg) \n"
" -Djit.jet.arg.log=rt -Djit.jet.filterName.arg.log=ee \n"
},
//-------------------------------------------------------------------------
{"break",
NULL
},
{"brk",
"type: bool or uint; default: off; scope: method \n"
"brk=on - triggers software breakpoint at the beginning of the method \n"
"brk=PC - triggers software breakpoint at bytecode @ PC \n"
},
//-------------------------------------------------------------------------
{"tbreak",
"type: uint; default: none; scope: global \n"
"Break into debugger when counter in dbg_rt reaches the specified \n"
"value. \n"
},
//-------------------------------------------------------------------------
{"checkstack",
"type: bool; default: off; scope: method \n"
"generates code to verify stack integrity before and after each \n"
"bytecode instruction. \n"
},
//-------------------------------------------------------------------------
{"checkmem",
"type: bool; default: off; scope: method \n"
"Enforces memory checks before and after compilation of a method. \n"
"Implementation is platform-dependent and may be no op on some \n"
"platforms/build configurations. Currently, only Windows/debug build \n"
"the check implemented. \n"
},
//-------------------------------------------------------------------------
{"emulate",
"type: bool; default: off; scope: method \n"
"Performs compilation, but do not register compiled code in VM. \n"
"Return JIT_FAILURE after compilation. \n"
},
//-------------------------------------------------------------------------
{"accept",
NULL,
},
{"reject",
"both accept and reject:\n"
"type: range of [uint][-uint]; default: none; scope: global \n"
"reject only: \n"
"type: bool; default: off; scope: method \n"
"On global scope defines a range of compilation ids of methods to be \n"
"accepted or rejected for compilation. Any part of range may be omitted.\n"
},
//-------------------------------------------------------------------------
{"list",
"type: string; default: none; scope: global \n"
"Sets name of file with list of fully qualified names of methods. \n"
"Any method not in the list will be rejected. \n"
},
//-------------------------------------------------------------------------
{"bbp",
"type: bool; default: on; scope: method \n"
"turns on and off generation of back branches polling code "
},
//-------------------------------------------------------------------------
{"hwnpe",
"type: bool; default: on; scope: method \n"
"Controls whether to generate hardware NPE checks instead of explicit \n"
"software checks \n"
},
#ifdef JIT_STATS
{"stats",
"type: bool; default: off; scope: global \n"
"Collects and shows various statistics about compiled methods. \n"
},
#endif // ~JIT_STATS
{"wb4c",
"type: bool; default: off; scope: method \n"
"Generates code with write barriers (C-based GC). \n"
},
{"wb4c.skip_statics",
"type: bool; default: TRUE; scope: method \n"
"If true (default) then do NOT report PUTSTATIC into write barrier. \n"
},
{"wb4j",
"type: bool; default: off; scope: method \n"
"Generates code with write barriers (Java-based GC). \n"
},
};
static void print_id(void);
static void print_help(void)
{
static bool help_printed = false;
if (help_printed) return;
print_id();
for (unsigned i=0; i<COUNTOF(args); i++) {
printf("%s\n", args[i][0]);
if (args[i][1] != NULL) {
printf("%s\n", args[i][1]);
}
}
help_printed = true;
}
#ifdef _DEBUG
static std::set<string> checked;
static Mutex checkedLock;
#endif
void check_arg_has_doc(const char* key)
{
#ifdef _DEBUG
//
checkedLock.lock();
if (checked.find(key) == checked.end()) {
checkedLock.unlock();
return;
}
checked.insert(key);
checkedLock.unlock();
//
bool found = false;
for (unsigned i=0; i<COUNTOF(args); i++) {
if (!strcmp(args[i][0], key)) {
found = true;
break;
}
}
if (!found) {
printf(
"WARNING: an argument named '%s' has no documentation !\n", key);
printf(
"Please, add appropriate description into \n\t" __FILE__ "\n");
}
#endif // ifdef _DEBUG
}
static const char *get_id_string(void)
{
static char buf[80] = {0};
if (buf[0] != 0) return buf;
unsigned len = sizeof(buf)-1;
const char revision[] = VERSION_SVN_TAG;
#ifdef PROJECT_JET
#define ALONE_STR ", alone"
#else
#define ALONE_STR ""
#endif
#ifdef _DEBUG
#define DBG_STR ", dbg"
#else
#define DBG_STR ""
#endif
#ifdef __INTEL_COMPILER
#define COMP_STR ", icl"
#else
#define COMP_STR ""
#endif
char revision_buf[80] = {0};
if (revision[0] != 'u') { /* ignore 'u'nknown */
snprintf(revision_buf, sizeof(revision_buf)-1, " Rev.: %s.",
revision);
}
snprintf(buf, len,
"Jitrino.JET" DBG_STR COMP_STR ALONE_STR ": "
"Built: " __DATE__ " " __TIME__
".%s", revision_buf);
return buf;
}
static void print_id(void)
{
static bool id_printed = false;
if (id_printed) return;
puts(get_id_string());
id_printed = true;
}
static void parse_range(const char* str, unsigned* pStart, unsigned *pEnd)
{
if (str[0] != '-' && !isdigit(str[0])) {
// wrong or empty params. print warning ?
return;
}
if (str[0] != '-') {
//'0-1' or '0' version
sscanf(str, "%u", pStart);
}
const char * pdash = strchr(str, '-');
if (pdash != NULL) {
sscanf(pdash+1, "%u", pEnd);
}
}
static void process_global_args(void)
{
const char * lp;
lp = g_pmf->getArg(NULL, "show");
if (lp != NULL) {
// empty string means 'all';
bool show_all = lp[0] == 0 || !strcmpi(lp, "all");
bool show_help = show_all || (NULL!=strstr(lp, "help"));
bool show_id = show_all ||
(NULL!=strstr(lp, "id")) ||
(NULL!=strstr(lp, "info")) ||
(NULL!=strstr(lp, "version"));
if (show_help) {
print_help();
}
if (show_id) {
print_id();
}
}
lp = g_pmf->getArg(NULL, "accept");
if (lp != NULL) {
parse_range(lp, &Compiler::g_acceptStartID, &
Compiler::g_acceptEndID);
}
lp = g_pmf->getArg(NULL, "reject");
if (lp != NULL) {
parse_range(lp, &Compiler::g_rejectStartID, &
Compiler::g_rejectEndID);
}
lp = g_pmf->getArg(NULL, "tbreak");
if (lp != NULL) {
g_tbreak_id = NOTHING;
sscanf(lp, "%u", &g_tbreak_id);
}
}
void cmd_line_arg(JIT_Handle jit, const char* name, const char* arg)
{
if (!strcmp(arg, "jet::help")) {
print_help();
}
else if (!strcmp(arg, "jet::id")) {
print_id();
}
else if (!strcmp(arg, "jet::info")) {
print_id();
print_help();
}
else if (!strncmp(arg, "jet::", 5)) {
static bool warning_printed = false;
if (!warning_printed) {
puts(
"*********************************************************************\n"
"* WARNING ! *\n"
"* Command line options in form of -Xjit jet::arg are deprecated ! *\n"
"* *\n"
"* The jet:: parameters are IGNORED *\n"
"* *\n"
"* To pass arguments to Jitrino.JET use *\n"
"* -Djit.<jit_name>.arg=value *\n"
"* Use *\n"
"* -Djit.<jit_name>.show=help *\n"
"* to get the list of supported args. *\n"
"*********************************************************************\n"
);
warning_printed = true;
}
}
}
OpenMethodExecutionParams get_exe_capabilities()
{
OpenMethodExecutionParams supported = {0};
supported.exe_notify_method_entry = true;
supported.exe_notify_method_exit = true;
supported.exe_do_code_mapping = true;
supported.exe_do_local_var_mapping = true;
supported.exe_restore_context_after_unwind = true;
supported.exe_provide_access_to_this = true;
return supported;
}
JIT_Result compile_with_params(JIT_Handle jit_handle, Compile_Handle ch,
Method_Handle method,
OpenMethodExecutionParams params)
{
::Jitrino::Jet::Compiler jit(jit_handle);
if (!CPUID::isSSE2Supported()) {
//TODO: return FAILURE only of method contains double ops!
return JIT_FAILURE;
}
return jit.compile(ch, method, params);
}
}}; // ~ namespace Jitrino::Jet
// standalone interface ?
#ifdef PROJECT_JET
/**
* @defgroup JITRINO_JET_STANDALONE Standalone interface
*
* Jitrino.JET may be compiled as a small separate JIT, mostly for
* debugging/testing purposes.
*
* To do this, a preprocessor macro PROJECT_JET must be defined. Also, some
* files are used from src/share - namely, mkernel.* and PlatformDependant.h.
*
* These exported functions represent inetrface required to interact with VM.
*
* @{
*/
#include <map>
using std::map;
#include "../main/Log.h"
#include "../main/LogStream.h"
#include "../main/PMF.h"
//
// PMF and JitInstanceContext things uses various stuff from Jitrino::.
// Define it here to allow standalone .jet build.
//
namespace Jitrino {
typedef map<JIT_Handle, JITInstanceContext*> JITCTXLIST;
static JITCTXLIST jitContextList;
static MemoryManager g_mm("global MM");
//
// CompilationContext stub
//
static TlsStack<CompilationContext> ccTls;
CompilationContext* CompilationContext::getCurrentContext() {
CompilationContext* currentCC = ccTls.get();
return currentCC;
}
CompilationContext::CompilationContext(MemoryManager& _mm,
CompilationInterface * ci,
JITInstanceContext * jtx) : mm(_mm)
{
compilationInterface = ci;
compilationFailed = false;
compilationFinished = false;
jitContext = jtx;
hirm = NULL;
lirm = NULL;
currentSessionAction = NULL;
currentSessionNum = 0;
currentLogStreams = NULL;
pipeline = NULL;
//
//
ccTls.push((CompilationContext*)this);
}
CompilationContext::~CompilationContext()
{
assert(this == ccTls.get());
ccTls.pop();
}
static int thread_nb = 0;
struct TlsLogStreams {
int threadnb;
MemoryManager mm;
typedef std::pair<JITInstanceContext*, LogStreams*> Jit2Log;
typedef StlVector<Jit2Log> Jit2Logs;
Jit2Logs jit2logs;
TlsLogStreams ()
:threadnb(thread_nb), mm(0, "TlsLogStreams"), jit2logs(mm) {}
~TlsLogStreams ();
};
TlsLogStreams::~TlsLogStreams ()
{
Jit2Logs::iterator ptr = jit2logs.begin(),
end = jit2logs.end();
for (; ptr != end; ++ptr)
ptr->second->~LogStreams();
}
static TlsStore<TlsLogStreams> tlslogstreams;
static Mutex logInfoLock;
/*
Because CompilationContext is a transient object (it created on start of compilation
and destroyed on end of compilation for every method), LogStreams table cannot reside
in it. Thread-local storage (TLS) is used to keep LogStreams.
On the other hand, different Jits can run on the same thread, so several LogStreams
have to be kept for single thread.
To optimize access, pointer to LogStreams is cached in CompilationContext.
*/
LogStreams& LogStreams::current(JITInstanceContext* jitContext) {
CompilationContext* ccp = CompilationContext::getCurrentContext();
LogStreams* cls = ccp->getCurrentLogs();
if (cls != 0)
return *cls;
// No cached pointer is available for this CompilationContext.
// Find TLS for this thread.
TlsLogStreams* sp = tlslogstreams.get();
if (sp == 0)
{ // new thread
logInfoLock.lock();
++thread_nb;
logInfoLock.unlock();
sp = new TlsLogStreams();
tlslogstreams.put(sp);
}
// Find which Jit is running now.
if (jitContext == 0)
jitContext = ccp->getCurrentJITContext();
// Was LogStreams created for this Jit already?
TlsLogStreams::Jit2Logs::iterator ptr = sp->jit2logs.begin(),
end = sp->jit2logs.end();
for (; ptr != end; ++ptr)
if (ptr->first == jitContext) {
// yes, it was - store pointer in the CompilationContext
ccp->setCurrentLogs(cls = ptr->second);
return *cls;
}
// This is the first logger usage by the running Jit in the current thread.
// Create LogStreams now.
cls = new (sp->mm) LogStreams(sp->mm, jitContext->getPMF(), sp->threadnb);
sp->jit2logs.push_back(TlsLogStreams::Jit2Log(jitContext, cls));
ccp->setCurrentLogs(cls);
return *cls;
}
LogStream& LogStream::log (SID sid, HPipeline* hp)
{
if (hp == 0)
hp = CompilationContext::getCurrentContext()->getPipeline();
Str name = ((PMF::Pipeline*)hp)->name;
return LogStream::log(sid, name.ptr, name.count);
}
//
// JITInstanceContex stub
//
JITInstanceContext::JITInstanceContext(MemoryManager& _mm,
JIT_Handle _jitHandle,
const char* _jitName) : mm(_mm)
{
jitHandle = _jitHandle;
jitName = _jitName;
pmf = new (mm) PMF(mm, *this);
profInterface = NULL;
useJet = true;
}
JITInstanceContext* JITInstanceContext::getContextForJIT(JIT_Handle jitHandle)
{
assert(jitContextList.find(jitHandle) != jitContextList.end());
return jitContextList[jitHandle];
}
JITInstanceContext* Jitrino::getJITInstanceContext(JIT_Handle jitHandle)
{
return JITInstanceContext::getContextForJIT(jitHandle);
}
//
// Fake XTimer stuff
double XTimer::getSeconds(void)const { return 0.0; }
void SummTimes::add(char const *,double) {}
//
// Crash handler
void crash(const char* fmt, ...)
{
va_list valist;
va_start(valist, fmt);
vprintf(fmt, valist);
exit(0);
}
}; // ~namespace Jitrino
//
// Symbols from local 'Jitrino::'
using Jitrino::JITInstanceContext;
using Jitrino::MemoryManager;
using Jitrino::jitContextList;
using Jitrino::g_mm;
//
//
using Jitrino::CompilationContext;
using Jitrino::PMF;
using Jitrino::HPipeline;
using Jitrino::LogStreams;
/**
* @see setup
*/
extern "C" JITEXPORT
void JIT_init(JIT_Handle jit, const char* name, vm_adaptor_t adaptor)
{
JITInstanceContext* jic =
new(g_mm) JITInstanceContext(g_mm, jit, name);
assert(jitContextList.find(jit) == jitContextList.end());
jitContextList[jit] = jic;
jic->getPMF().init();
Jitrino::Jet::setup(jit, name);
}
/**
* @see cleanup
*/
extern "C" JITEXPORT
void JIT_deinit(JIT_Handle jit)
{
Jitrino::Jet::cleanup();
}
/**
* @see cmd_line_arg
*/
extern "C" JITEXPORT
void JIT_next_command_line_argument(JIT_Handle jit, const char *name,
const char *arg)
{
Jitrino::Jet::cmd_line_arg(jit, name, arg);
}
extern "C" JITEXPORT
JIT_Result JIT_compile_method_with_params(JIT_Handle jit,
Compile_Handle ch,
Method_Handle method,
OpenMethodExecutionParams params)
{
//Jitrino::CompilationContext ctx(jit, method);
MemoryManager memManager(1024, "JIT_compile_method.memManager");
JITInstanceContext* jitContext = Jitrino::Jitrino::getJITInstanceContext(jit);
assert(jitContext!= NULL);
//DrlVMCompilationInterface
// compilationInterface(ch, method, jit, memManager, params, NULL);
Jitrino::CompilationInterface* pci = NULL;
CompilationContext cs(memManager, pci/*&compilationInterface*/, jitContext);
//compilationInterface.setCompilationContext(&cs);
static int method_seqnb = 0;
int current_nb = method_seqnb++;
Class_Handle klass = method_get_class(method);
const char* methodTypeName = class_get_name(klass);
const char* methodName = method_get_name(method);
const char* methodSig = method_get_descriptor(method);
PMF::Pipeline* pipep =
jitContext->getPMF().selectPipeline(methodTypeName, methodName, methodSig);
cs.setPipeline((HPipeline*)pipep);
LogStreams::current(jitContext).beginMethod(methodTypeName, methodName, methodSig, current_nb);
JIT_Result result = Jitrino::Jet::compile_with_params(jit, ch, method, params);
LogStreams::current(jitContext).endMethod();
return result;
}
/**
* @see get_exe_capabilities
*/
extern "C" JITEXPORT
OpenMethodExecutionParams JIT_get_exe_capabilities(JIT_Handle jit)
{
return Jitrino::Jet::get_exe_capabilities();
}
/**
* Noop in Jitrino.JET.
* @return FALSE
*/
extern "C" JITEXPORT Boolean JIT_recompiled_method_callback(
JIT_Handle jit, Method_Handle method, void * callback_data)
{
return FALSE;
}
/**
* @see rt_unwind
*/
extern "C" JITEXPORT
void JIT_unwind_stack_frame(JIT_Handle jit, Method_Handle method,
::JitFrameContext *context)
{
Jitrino::Jet::rt_unwind(jit, method, context);
}
/**
* @see rt_enum
*/
extern "C" JITEXPORT
void JIT_get_root_set_from_stack_frame(JIT_Handle jit, Method_Handle method,
GC_Enumeration_Handle henum,
::JitFrameContext *context)
{
Jitrino::Jet::rt_enum(jit, method, henum, context);
}
/**
* @see rt_fix_handler_context
*/
extern "C" JITEXPORT
void JIT_fix_handler_context(JIT_Handle jit, Method_Handle method,
::JitFrameContext *context)
{
Jitrino::Jet::rt_fix_handler_context(jit, method, context);
}
/**
* @see rt_get_address_of_this
*/
extern "C" JITEXPORT
void * JIT_get_address_of_this(JIT_Handle jit, Method_Handle method,
const ::JitFrameContext *context)
{
return Jitrino::Jet::rt_get_address_of_this(jit, method, context);
}
/**
* Inlining is unsupported by Jitrino.JET.
* @return 0
*/
extern "C" JITEXPORT
U_32 JIT_get_inline_depth(JIT_Handle jit, InlineInfoPtr ptr, U_32 offset)
{
return 0;
}
/**
* Inlining is unsupported by Jitrino.JET.
* @return 0
*/
extern "C" JITEXPORT
Method_Handle JIT_get_inlined_method(JIT_Handle jit, InlineInfoPtr ptr,
U_32 offset, U_32 inline_depth)
{
return 0;
}
/**
* Inlining is unsupported by Jitrino.JET.
* @return 0
*/
extern "C" JITEXPORT
uint16 JIT_get_inlined_bc(JIT_Handle jit, InlineInfoPtr ptr,
U_32 offset, U_32 inline_depth)
{
return 0;
}
/**
* @returns \b Whether Jitrino.JET support compressed references on current
* platform.
*/
extern "C" JITEXPORT
Boolean JIT_supports_compressed_references(JIT_Handle jit)
{
return ::Jitrino::Jet::supports_compresed_refs();
}
/**
* @todo need to be implemented
*/
extern "C" JITEXPORT
void JIT_get_root_set_for_thread_dump(JIT_Handle jit, Method_Handle method,
GC_Enumeration_Handle henum,
::JitFrameContext *context )
{
assert(false);
}
//**********************************************************************
//* exported routines for JVMTI
//**********************************************************************
extern "C" JITEXPORT
OpenExeJpdaError get_native_location_for_bc(JIT_Handle jit,
Method_Handle method,
uint16 bc_pc,
NativeCodePtr *pnative_pc)
{
Jitrino::Jet::rt_bc2native(jit, method, bc_pc, pnative_pc);
return EXE_ERROR_NONE;
}
extern "C" JITEXPORT
OpenExeJpdaError get_bc_location_for_native(JIT_Handle jit,
Method_Handle method,
NativeCodePtr native_pc,
uint16 *pbc_pc)
{
Jitrino::Jet::rt_native2bc(jit, method, native_pc, pbc_pc);
return EXE_ERROR_NONE;
}
extern "C" JITEXPORT
OpenExeJpdaError get_local_var(JIT_Handle jit,
Method_Handle method,
const ::JitFrameContext *context,
uint16 var_num,
VM_Data_Type var_type,
void *value_ptr)
{
return Jitrino::Jet::rt_get_local_var(jit, method, context,
(unsigned)var_num, var_type,
value_ptr);
}
extern "C" JITEXPORT
OpenExeJpdaError set_local_var(JIT_Handle jit,
Method_Handle method,
const ::JitFrameContext *context,
uint16 var_num, VM_Data_Type var_type,
void *value_ptr)
{
return Jitrino::Jet::rt_set_local_var(jit, method, context,
(unsigned)var_num, var_type,
value_ptr);
}
/// @} // ~ defgroup JITRINO_JET_STANDALONE
#endif // ~ifdef PROJECT_JET // standalone interface