blob: 26a0dd030c279a5d6d3ab44e38ef1a22abeb3d9e [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 Declaration of Compiler class.
*/
#if !defined(__COMPILER_H_INCLUDED__)
#define __COMPILER_H_INCLUDED__
#include "jframe.h"
#include "rt.h"
#include "cg.h"
#include "open/rt_types.h"
#include <assert.h>
#include <vector>
#include <map>
#include <string>
#include <stack>
#include <bitset>
namespace Jitrino {
namespace Jet {
/**
* @brief The name says it all.
*
* The constant used to preallocate memory in code stream to avoid
* multiple reallocation during code gen stage.
*
* @todo Was calculated for IA-32 long time ago, may require tuning for
* IA-64 and Intel-64.
*/
#define NATIVE_CODE_SIZE_2_BC_SIZE_RATIO (10)
#define NATIVE_STACK_SIZE_2_THROW_SYN_EXC (2)
/**
* The class represents a JIT compiler for the Java bytecode under DRLVM
* environment.
*/
class Compiler : public CodeGen {
public:
Compiler(JIT_Handle jh)
{
m_hjit = jh;
m_bEmulation = false;
hasSOEHandlers = false;
}
/**
* @brief Main compilation routine.
*/
JIT_Result compile(Compile_Handle ch, Method_Handle method,
const OpenMethodExecutionParams& params);
/**
* @brief Adds a flag to default compilation flags.
* @see JMF_
*/
static void addDefaultFlag(unsigned flag)
{
defaultFlags |= flag;
}
/**
* @brief Removes a flag from default compilation flags.
* @see JMF_
*/
static void deleteDefaultFlag(unsigned flag)
{
defaultFlags &= ~flag;
}
/**
* If not NOTHING, then only methods with compilation id more or equal
* to this id are compiled.
*/
static unsigned g_acceptStartID;
/**
* If not NOTHING, then only methods with compilation id less or equal
* to this id are compiled.
*/
static unsigned g_acceptEndID;
/**
* If not NOTHING, then methods with compilation id more or equal
* to this id are rejected (JIT_FAILURE returned) without compilation.
*/
static unsigned g_rejectStartID;
/**
* If not NOTHING, then methods with compilation id less or equal
* to this id are rejected (JIT_FAILURE returned) without compilation.
*/
static unsigned g_rejectEndID;
/**
* @brief Dumps out the basic blocks structure.
* For debugging only.
*/
void dbg_dump_bbs(void);
/**
* @brief Dumps out disassembled piece of code.
* For debugging only.
*/
void dbg_dump_code(const char * code, unsigned length, const char * name);
/**
* @brief Dumps out disassembled the whole code of the method, mixed with
* appropriate bytecode.
* For debugging only.
*
* The code must be already generated and available for VM -
* \b method_get_code_block_jit is used to obtain the code.
*/
void dbg_dump_code_bc(const char * code, unsigned codeLen);
/**
* @brief Converts the JInst into the human-readable string.
* For debugging only.
*
* @param jinst - instruction to be presented as string.
* @param show_names - if \b true, then the string contains symbolic
* names, otherwise only constant pool indexes.
*/
::std::string toStr(const JInst& jinst, bool show_names);
/**
* @brief Prints out a string 'compilation started'.
* For debugging only.
* @see DBG_TRACE_SUMM
*/
void dbg_trace_comp_start(void);
/**
* @brief Prints out a string 'compilation finished', with a reason why
* compilation failed, if \c success is \b false.
* For debugging only.
* @see DBG_TRACE_SUMM
*/
void dbg_trace_comp_end(bool success, const char * reason);
/**
* @brief Generates code to ensure stack integrity at the beginning
* of a basic block at runtime.
*
* This is used to ensure stack integrity after branches which can not be
* controlled by #gen_dbg_check_stack.
*
* @note For debug checks only.
*/
void gen_dbg_check_bb_stack(void);
/**
* @brief If not #NOTHING, then software breakpoint inserted before the
* code at the specified PC of the generated code.
*
* For debugging only.
*/
unsigned dbg_break_pc;
private:
/**
* @brief Default flags for compilation.
* @see JMF_
*/
static unsigned defaultFlags;
/**
* @brief Decodes bytecode instructions, finds basic blocks and
* collects local vars usage info.
*/
void comp_parse_bytecode(void);
/**
* @brief Helper function for comp_parse_bytecode().
*
* Creates a BBInfo record for the given \c pc or returns an one.
*/
BBInfo& comp_create_bb(unsigned pc);
/**
* @brief Performs global register allocation.
*/
void comp_alloc_regs(void);
/**
* @brief Generates code for a given basic block.
*
* When pc=0, also generates prolog code.
*
* If \c jsr_lead is not NOTHING, which means that this basic block
* is part of JSR subroutine, then the final state of the stack on a RET
* instruction will be stored for this jsr_lead and then reused if there
* are several JSR instructions point to the same (jsr_lead) block.
*
* @param pc - program counter of the basic block
*/
void comp_gen_code_bb(unsigned pc);
/**
* @param pc - program counter of the basic block
* @param parentPC - program counter of basic block which is
* predecessor of \c pc block. This is the block the BBState is
* inherited from.
* @param jsr_lead - PC of the beginning of the JSR block, we're
* currently in, or #NOTHING we're not in JSR block.
*/
bool comp_gen_insts(unsigned pc, unsigned parentPC, unsigned jsr_lead);
/**
* @brief Performs layout of the native code, so it become same as byte
* code layout.
* @param prolog_ipoff - offset of prolog code m_codeStream/
* @param prolog_size - size of prolog code, in bytes.
*/
void comp_layout_code(unsigned prolog_ipoff, unsigned prolog_size);
/**
* @brief Resolves method's exception handlers.
*
* @note Does call resolve_class() and thus must not be used when the
* lock protecting method's data is locked.
* @return \c true if resolution was successful, \c false otherwise
*/
bool comp_resolve_ehandlers(void);
/**
* @brief Registers method's exception handlers.
*
* @note Does \b not call resolve_class() and may be used when a lock
* protecting method's data is locked.
*/
void comp_set_ehandlers(void);
/**
* @brief Fills out a native addresses of an exception handler and
* a block it protects.
* @param[in,out] hi - info about handler to process.
*/
bool comp_hi_to_native(HandlerInfo& hi);
/**
* @brief Performs code patching.
*
* The code patching is to finalize addresses for relative-addressing
* instructions like ÎMP, and for instructions which refer to a data
* allocated after the instructions generated (indirect JMPs for
* LOOKUP/TABLE-SWITCH).
*/
void comp_patch_code(void);
/**
* @brief Fetches out and decodes a bytecode instruction starting
* from the given 'pc'.
* @return PC of the next instruction, or NOTHING if end of byte code
* reached.
*/
unsigned fetch(unsigned pc, JInst& jinst);
/**
* @brief Invokes appropriate handle_ik_ method to generate native code.
*/
void handle_inst(void);
/** @brief a helper method for #handle_inst() */
void handle_ik_meth(const JInst& jinst);
/** @brief a helper method for #handle_inst() */
void handle_ik_obj(const JInst& jinst);
/** @brief a helper method for #handle_inst() */
void handle_ik_stack(const JInst& jinst);
/** @brief a helper method for #handle_inst() */
void handle_ik_a(const JInst& jinst);
/** @brief a helper method for #handle_inst() */
void handle_ik_cf(const JInst& jinst);
/** @brief a helper method for #handle_inst() */
void handle_ik_cnv(const JInst& jinst);
/** @brief a helper method for #handle_inst() */
void handle_ik_ls(const JInst& jinst);
//
// CodeGeneration stuff. Most of these functions are like CodeGen's
// ones, but they deal with basic blocks, so it's better to place
// them here in Compiler.
//
/**
* @brief Generates method's prolog code.
*/
void gen_prolog(void);
/**
* @brief Generates method's epilogue (on RETURN instructions) code.
*/
void gen_return(const CallSig& cs);
/**
* @brief Prepares BBState as it was left by gen_bb_leave().
* @see gen_bb_leave
*/
void gen_bb_enter(void);
/**
* @brief Generates code to leave current basic block.
*
* The leave code is to place operands on their places - stack operands
* go to memory, globally allocated variables are loaded into registers
* and not allocated scratch registers are freed.
*
* Such leave code is executed only if \c to basic block has more than
* one reference. Otherwise no code generated.
* @see gen_bb_enter
*/
void gen_bb_leave(unsigned to);
/**
* @brief Generates either LOOKUPSWITCH or TABLESWITCH.
*/
void gen_switch(const JInst& jinst);
/**
* @brief Generates various IF_ operations.
*
* Also inserts back branch polling (if the \link #JMF_BBPOLLING
* appropriate flag\endlink set), and \link #JMF_PROF_ENTRY_BE \endlink
* instrumentation code.
*/
void gen_if(JavaByteCodes opcod, unsigned target);
/**
* @brief Generates various IF_ICMP operations.
*
* Also inserts back branch polling (if the \link #JMF_BBPOLLING
* appropriate flag\endlink set), and \link #JMF_PROF_ENTRY_BE \endlink
* instrumentation code.
*/
void gen_if_icmp(JavaByteCodes opcod, unsigned target);
/**
* @brief Generates GOTO operation.
*
* Also inserts back branch polling (if the \link #JMF_BBPOLLING
* appropriate flag\endlink set), and \link #JMF_PROF_ENTRY_BE \endlink
* instrumentation code.
*/
void gen_goto(unsigned target);
/**
* @brief Generates JSR/JSR_W operation.
*/
void gen_jsr(unsigned target);
/**
* @brief Generates RET operation.
* @param idx - index of local variable.
*/
void gen_ret(unsigned idx);
/**
* @brief Checks current inst and generates magic if needed
* @return - true if current inst is magic call, false otherwise.
*/
bool gen_magic(void);
//
// Method being compiled info
//
/**
* @brief Return type of the method.
*/
jtype m_retType;
/**
* @brief A list to keep exception handlers' info.
*/
typedef ::std::vector<HandlerInfo> HADLERS_LIST;
/**
* @brief List of infos about exception handlers.
*
* The list preserves the order in which the VM returns the info about
* the handlers.
*/
HADLERS_LIST m_handlers;
/**
* @brief Map of basic blocks. A key is basic block's leader's PC.
*/
BBMAP m_bbs;
/**
* @brief Bunch of preallocated BBState-s.
*
* A key in the map is basic block's PC.
*/
map<unsigned, BBState*> m_bbStates;
/**
* @brief Pre-calculated BBState-s at the end of JSR subroutines.
*
* A key in the map is JSR subroutine beginning PC.
*/
map<unsigned, BBState*> m_jsrStates;
/**
* @brief Array of decoded instructions.
* @todo check whether changing AoS=>SoA gives a compilation speedup.
*/
SmartPtr<JInst> m_insts;
/**
* @brief Only emulates compilation - do not register the generated
* code in VM.
*/
bool m_bEmulation;
/**
* @brief Code buffer allocated by VM.
*/
char * m_vmCode;
/// 'TRUE' if this method has catch handlers suitable for StackOverflowError
bool hasSOEHandlers;
/**
* @brief Parses method's signature at the given constant pool entry.
*
* @brief Parses a constant pool entry (presuming it contains a method's
* signature) and fills the info about the method's arguments and
* return type.
* @param is_static - must be \b true, if the signature belongs to static
* method (this is to add additional 'this' which is not reflected
* in signature for instance methods).
* @param cp_idx - constant pool index.
* @param args - an array to fill out. Must be empty.
* @param retType - [out] return type of the method. Must not be NULL.
*/
void get_args_info(bool is_static, unsigned cp_idx,
::std::vector<jtype>& args, jtype * retType);
/**
* @brief Obtains an arguments and return info from the given method.
* @param meth - method handle to get the info for.
* @param args - an array to fill out. Must be empty.
* @param[out] retType - return type of the method. Must not be NULL.
*/
static void get_args_info(Method_Handle meth,
::std::vector<jtype>& args, jtype * retType);
static jtype to_jtype(VM_Data_Type vmtype)
{
return ::Jitrino::Jet::to_jtype(vmtype);
}
/**
* @brief Converts VM_Data_Type to appropriate #jtype.
*/
static jtype to_jtype(Type_Info_Handle th);
private:
/**
* @brief Initializes all global stuff in StaticConsts.
*/
static void initStatics(void);
/**
* @brief Initializes profiling data.
*
* Adds appropriate JMF_ flags to \c pflags if necessary.
* @param[out] pflags - flags which will be used for compilation. Must
* be non-NULL.
*/
void initProfilingData(unsigned * pflags);
};
}}; // ~namespace Jitrino::Jet
#include "bcproc.inl"
#endif // __COMPILER_H_INCLUDED__