2009-07-10 12:58:34 -07:00
|
|
|
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
2008-06-18 21:32:23 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (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.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is [Open Source Virtual Machine].
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Adobe System Incorporated.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2004-2007
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Adobe AS3 Team
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __nanojit_Assembler__
|
|
|
|
#define __nanojit_Assembler__
|
|
|
|
|
|
|
|
|
|
|
|
namespace nanojit
|
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
/**
|
|
|
|
* Some notes on this Assembler (Emitter).
|
|
|
|
*
|
|
|
|
* The class RegAlloc is essentially the register allocator from MIR
|
|
|
|
*
|
|
|
|
* The Assembler class parses the LIR instructions starting at any point and converts
|
|
|
|
* them to machine code. It does the translation using expression trees which are simply
|
|
|
|
* LIR instructions in the stream that have side-effects. Any other instruction in the
|
|
|
|
* stream is simply ignored.
|
|
|
|
* This approach is interesting in that dead code elimination occurs for 'free', strength
|
|
|
|
* reduction occurs fairly naturally, along with some other optimizations.
|
|
|
|
*
|
|
|
|
* A negative is that we require state as we 'push' and 'pop' nodes along the tree.
|
|
|
|
* Also, this is most easily performed using recursion which may not be desirable in
|
|
|
|
* the mobile environment.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define STACK_GRANULARITY sizeof(void *)
|
|
|
|
|
|
|
|
struct AR
|
|
|
|
{
|
2009-07-30 14:21:19 -07:00
|
|
|
LIns* entry[ NJ_MAX_STACK_ENTRY ]; /* maps to 4B contiguous locations relative to the frame pointer */
|
2009-07-10 12:58:34 -07:00
|
|
|
uint32_t tos; /* current top of stack entry */
|
2009-07-30 14:21:19 -07:00
|
|
|
uint32_t highwatermark; /* max tos hit */
|
|
|
|
uint32_t lowwatermark; /* we pre-allocate entries from 0 upto this index-1; so dynamic entries are added above this index */
|
2009-07-10 12:58:34 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef AVMPLUS_WIN32
|
|
|
|
#define AVMPLUS_ALIGN16(type) __declspec(align(16)) type
|
|
|
|
#else
|
|
|
|
#define AVMPLUS_ALIGN16(type) type __attribute__ ((aligned (16)))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct Stats
|
|
|
|
{
|
|
|
|
counter_define(steals;)
|
|
|
|
counter_define(remats;)
|
|
|
|
counter_define(spills;)
|
|
|
|
counter_define(native;)
|
2008-06-18 21:32:23 -07:00
|
|
|
counter_define(exitnative;)
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
int32_t pages;
|
|
|
|
NIns* codeStart;
|
|
|
|
NIns* codeExitStart;
|
|
|
|
|
|
|
|
DECLARE_PLATFORM_STATS()
|
2008-06-18 21:32:23 -07:00
|
|
|
#ifdef __GNUC__
|
2009-07-10 12:58:34 -07:00
|
|
|
// inexplicably, gnuc gives padding/alignment warnings without this. pacify it.
|
|
|
|
bool pad[4];
|
2008-06-18 21:32:23 -07:00
|
|
|
#endif
|
2009-07-10 12:58:34 -07:00
|
|
|
};
|
|
|
|
|
2009-07-30 14:28:26 -07:00
|
|
|
class Fragmento;
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
// error codes
|
|
|
|
enum AssmError
|
|
|
|
{
|
|
|
|
None = 0
|
|
|
|
,OutOMem
|
|
|
|
,StackFull
|
|
|
|
,RegionFull
|
2008-06-18 21:32:23 -07:00
|
|
|
,MaxLength
|
|
|
|
,MaxExit
|
|
|
|
,MaxXJump
|
|
|
|
,UnknownPrim
|
2008-10-13 13:29:18 -07:00
|
|
|
,UnknownBranch
|
2009-07-10 12:58:34 -07:00
|
|
|
};
|
2008-06-24 15:57:33 -07:00
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
typedef avmplus::List<NIns*, avmplus::LIST_NonGCObjects> NInsList;
|
|
|
|
typedef avmplus::SortedMap<LIns*,NIns*,avmplus::LIST_NonGCObjects> InsMap;
|
|
|
|
typedef avmplus::SortedMap<NIns*,LIns*,avmplus::LIST_NonGCObjects> NInsMap;
|
2008-10-13 13:29:18 -07:00
|
|
|
|
|
|
|
class LabelState MMGC_SUBCLASS_DECL
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RegAlloc regs;
|
|
|
|
NIns *addr;
|
|
|
|
LabelState(NIns *a, RegAlloc &r) : regs(r), addr(a)
|
|
|
|
{}
|
|
|
|
};
|
2008-07-01 14:46:10 -07:00
|
|
|
|
2008-10-13 13:29:18 -07:00
|
|
|
class LabelStateMap
|
|
|
|
{
|
2008-11-07 15:52:51 -08:00
|
|
|
avmplus::GC *gc;
|
2008-10-13 13:29:18 -07:00
|
|
|
avmplus::SortedMap<LIns*, LabelState*, avmplus::LIST_GCObjects> labels;
|
|
|
|
public:
|
2008-11-07 15:52:51 -08:00
|
|
|
LabelStateMap(avmplus::GC *gc) : gc(gc), labels(gc)
|
2008-10-13 13:29:18 -07:00
|
|
|
{}
|
2008-11-04 19:22:13 -08:00
|
|
|
~LabelStateMap();
|
2008-10-13 13:29:18 -07:00
|
|
|
|
|
|
|
void add(LIns *label, NIns *addr, RegAlloc ®s);
|
|
|
|
LabelState *get(LIns *);
|
|
|
|
};
|
2008-06-18 21:32:23 -07:00
|
|
|
/**
|
2009-07-30 14:21:19 -07:00
|
|
|
* Information about the activation record for the method is built up
|
|
|
|
* as we generate machine code. As part of the prologue, we issue
|
2009-07-10 12:58:34 -07:00
|
|
|
* a stack adjustment instruction and then later patch the adjustment
|
|
|
|
* value. Temporary values can be placed into the AR as method calls
|
2009-07-30 14:21:19 -07:00
|
|
|
* are issued. Also MIR_alloc instructions will consume space.
|
2009-07-10 12:58:34 -07:00
|
|
|
*/
|
|
|
|
class Assembler MMGC_SUBCLASS_DECL
|
|
|
|
{
|
|
|
|
friend class VerboseBlockReader;
|
|
|
|
public:
|
|
|
|
#ifdef NJ_VERBOSE
|
|
|
|
static char outline[8192];
|
|
|
|
static char outlineEOL[512]; // string to be added to the end of the line
|
|
|
|
static char* outputAlign(char* s, int col);
|
|
|
|
|
|
|
|
void FASTCALL outputForEOL(const char* format, ...);
|
|
|
|
void FASTCALL output(const char* s);
|
|
|
|
void FASTCALL outputf(const char* format, ...);
|
|
|
|
void FASTCALL output_asm(const char* s);
|
|
|
|
|
2009-07-30 14:21:19 -07:00
|
|
|
// if outputAddr=true then next asm instr. will include
|
|
|
|
// address in output
|
|
|
|
bool outputAddr, vpad[2];
|
2009-07-10 12:58:34 -07:00
|
|
|
void printActivationState();
|
|
|
|
|
|
|
|
StringList* _outputCache;
|
|
|
|
|
|
|
|
// Log controller object. Contains what-stuff-should-we-print
|
|
|
|
// bits, and a sink function for debug printing
|
|
|
|
LogControl* _logc;
|
|
|
|
#endif
|
|
|
|
|
2009-07-30 14:28:26 -07:00
|
|
|
Assembler(Fragmento* frago, LogControl* logc);
|
2008-06-18 21:32:23 -07:00
|
|
|
~Assembler() {}
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
void assemble(Fragment* frag, NInsList& loopJumps);
|
|
|
|
void endAssembly(Fragment* frag, NInsList& loopJumps);
|
|
|
|
void beginAssembly(Fragment *frag, RegAllocMap* map);
|
|
|
|
void copyRegisters(RegAlloc* copyTo);
|
|
|
|
void releaseRegisters();
|
2008-06-18 21:32:23 -07:00
|
|
|
void patch(GuardRecord *lr);
|
2008-10-21 17:50:32 -07:00
|
|
|
void patch(SideExit *exit);
|
2009-02-11 17:40:27 -08:00
|
|
|
#ifdef NANOJIT_IA32
|
2009-07-30 14:21:19 -07:00
|
|
|
void patch(SideExit* exit, SwitchInfo* si);
|
2009-02-11 17:40:27 -08:00
|
|
|
#endif
|
2009-07-10 12:58:34 -07:00
|
|
|
AssmError error() { return _err; }
|
|
|
|
void setError(AssmError e) { _err = e; }
|
2009-07-30 14:28:26 -07:00
|
|
|
void pageReset();
|
|
|
|
int32_t codeBytes();
|
|
|
|
Page* handoverPages(bool exitPages=false);
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-30 14:21:19 -07:00
|
|
|
debug_only ( void pageValidate(); )
|
2009-07-30 14:28:26 -07:00
|
|
|
debug_only ( bool onPage(NIns* where, bool exitPages=false); )
|
2009-07-10 12:58:34 -07:00
|
|
|
|
|
|
|
// support calling out from a fragment ; used to debug the jit
|
|
|
|
debug_only( void resourceConsistencyCheck(); )
|
|
|
|
debug_only( void registerConsistencyCheck(); )
|
|
|
|
|
2009-07-30 14:21:19 -07:00
|
|
|
Stats _stats;
|
2008-10-13 13:29:18 -07:00
|
|
|
int hasLoop;
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
private:
|
|
|
|
|
2009-07-08 15:54:31 -07:00
|
|
|
void gen(LirFilter* toCompile, NInsList& loopJumps, LabelStateMap& labels,
|
|
|
|
NInsMap& patches);
|
2009-07-30 14:21:19 -07:00
|
|
|
NIns* genPrologue();
|
|
|
|
NIns* genEpilogue();
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
uint32_t arReserve(LIns* l);
|
|
|
|
void arFree(uint32_t idx);
|
|
|
|
void arReset();
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
Register registerAlloc(RegisterMask allow);
|
|
|
|
void registerResetAll();
|
|
|
|
void evictRegs(RegisterMask regs);
|
2008-10-13 13:29:18 -07:00
|
|
|
void evictScratchRegs();
|
2009-07-10 12:58:34 -07:00
|
|
|
void intersectRegisterState(RegAlloc& saved);
|
|
|
|
void unionRegisterState(RegAlloc& saved);
|
2008-10-13 13:29:18 -07:00
|
|
|
void assignSaved(RegAlloc &saved, RegisterMask skip);
|
2009-07-10 12:58:34 -07:00
|
|
|
LInsp findVictim(RegAlloc& regs, RegisterMask allow);
|
2008-10-20 10:15:07 -07:00
|
|
|
|
|
|
|
Register getBaseReg(LIns *i, int &d, RegisterMask allow);
|
2009-07-30 14:21:19 -07:00
|
|
|
int findMemFor(LIns* i);
|
2009-07-10 12:58:34 -07:00
|
|
|
Register findRegFor(LIns* i, RegisterMask allow);
|
|
|
|
void findRegFor2(RegisterMask allow, LIns* ia, Reservation* &ra, LIns *ib, Reservation* &rb);
|
|
|
|
Register findSpecificRegFor(LIns* i, Register w);
|
|
|
|
Register prepResultReg(LIns *i, RegisterMask allow);
|
|
|
|
void freeRsrcOf(LIns *i, bool pop);
|
|
|
|
void evict(Register r);
|
|
|
|
RegisterMask hint(LIns*i, RegisterMask allow);
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-07-30 14:25:03 -07:00
|
|
|
void resetInstructionPointer();
|
|
|
|
void recordStartingInstructionPointer();
|
|
|
|
|
2009-07-30 14:28:26 -07:00
|
|
|
NIns* pageAlloc(bool exitPage=false);
|
|
|
|
void pagesFree(Page*& list);
|
|
|
|
void internalReset();
|
2008-10-13 13:29:18 -07:00
|
|
|
bool canRemat(LIns*);
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
Reservation* getresv(LIns *x) {
|
2009-05-17 23:15:24 -07:00
|
|
|
Reservation* r = x->resv();
|
|
|
|
return r->used ? r : 0;
|
2008-10-13 13:29:18 -07:00
|
|
|
}
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-07-30 14:28:26 -07:00
|
|
|
DWB(Fragmento*) _frago;
|
2009-07-10 12:58:34 -07:00
|
|
|
avmplus::GC* _gc;
|
2009-07-30 14:21:19 -07:00
|
|
|
DWB(Fragment*) _thisfrag;
|
2009-07-10 12:58:34 -07:00
|
|
|
RegAllocMap* _branchStateMap;
|
|
|
|
|
2009-07-30 14:21:19 -07:00
|
|
|
NIns* _nIns; // current native instruction
|
|
|
|
NIns* _nExitIns; // current instruction in exit fragment page
|
|
|
|
NIns* _startingIns; // starting location of code compilation for error handling
|
2009-07-10 12:58:34 -07:00
|
|
|
NIns* _epilogue;
|
2009-07-30 14:28:26 -07:00
|
|
|
Page* _nativePages; // list of NJ_PAGE_SIZE pages that have been alloc'd
|
|
|
|
Page* _nativeExitPages; // list of pages that have been allocated for exit code
|
2009-07-30 14:21:19 -07:00
|
|
|
AssmError _err; // 0 = means assemble() appears ok, otherwise it failed
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-30 14:21:19 -07:00
|
|
|
AR _activation;
|
2009-07-10 12:58:34 -07:00
|
|
|
RegAlloc _allocator;
|
|
|
|
|
|
|
|
bool _inExit, vpad2[3];
|
|
|
|
|
|
|
|
void asm_cmp(LIns *cond);
|
|
|
|
void asm_fcmp(LIns *cond);
|
2008-10-13 13:29:18 -07:00
|
|
|
void asm_setcc(Register res, LIns *cond);
|
|
|
|
NIns * asm_jmpcc(bool brOnFalse, LIns *cond, NIns *target);
|
2009-07-10 12:58:34 -07:00
|
|
|
void asm_mmq(Register rd, int dd, Register rs, int ds);
|
2008-06-24 15:57:33 -07:00
|
|
|
NIns* asm_exit(LInsp guard);
|
2009-07-30 14:21:19 -07:00
|
|
|
NIns* asm_leave_trace(LInsp guard);
|
2008-06-18 21:32:23 -07:00
|
|
|
void asm_qjoin(LIns *ins);
|
|
|
|
void asm_store32(LIns *val, int d, LIns *base);
|
|
|
|
void asm_store64(LIns *val, int d, LIns *base);
|
2009-07-10 12:58:34 -07:00
|
|
|
void asm_restore(LInsp, Reservation*, Register);
|
|
|
|
void asm_load(int d, Register r);
|
|
|
|
void asm_spilli(LInsp i, Reservation *resv, bool pop);
|
|
|
|
void asm_spill(Register rr, int d, bool pop, bool quad);
|
|
|
|
void asm_load64(LInsp i);
|
|
|
|
void asm_pusharg(LInsp p);
|
|
|
|
void asm_quad(LInsp i);
|
|
|
|
void asm_loop(LInsp i, NInsList& loopJumps);
|
|
|
|
void asm_fcond(LInsp i);
|
|
|
|
void asm_cond(LInsp i);
|
|
|
|
void asm_arith(LInsp i);
|
|
|
|
void asm_neg_not(LInsp i);
|
|
|
|
void asm_ld(LInsp i);
|
|
|
|
void asm_cmov(LInsp i);
|
|
|
|
void asm_param(LInsp i);
|
|
|
|
void asm_int(LInsp i);
|
|
|
|
void asm_short(LInsp i);
|
|
|
|
void asm_qlo(LInsp i);
|
|
|
|
void asm_qhi(LInsp i);
|
|
|
|
void asm_fneg(LInsp ins);
|
|
|
|
void asm_fop(LInsp ins);
|
|
|
|
void asm_i2f(LInsp ins);
|
|
|
|
void asm_u2f(LInsp ins);
|
|
|
|
Register asm_prep_fcall(Reservation *rR, LInsp ins);
|
|
|
|
void asm_nongp_copy(Register r, Register s);
|
|
|
|
void asm_call(LInsp);
|
2008-07-16 14:21:31 -07:00
|
|
|
void asm_arg(ArgSize, LInsp, Register);
|
2009-07-10 12:58:34 -07:00
|
|
|
Register asm_binop_rhs_reg(LInsp ins);
|
2009-07-23 22:41:32 -07:00
|
|
|
NIns* asm_branch(bool branchOnFalse, LInsp cond, NIns* targ);
|
2009-07-10 12:58:34 -07:00
|
|
|
void asm_switch(LIns* ins, NIns* target);
|
|
|
|
void emitJumpTable(SwitchInfo* si, NIns* target);
|
2008-10-31 16:48:14 -07:00
|
|
|
void assignSavedRegs();
|
|
|
|
void reserveSavedRegs();
|
|
|
|
void assignParamRegs();
|
2009-07-08 15:54:31 -07:00
|
|
|
void handleLoopCarriedExprs(InsList& pending_lives);
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-30 14:28:26 -07:00
|
|
|
// flag values for nMarkExecute
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PAGE_READ = 0x0, // here only for clarity: all permissions include READ
|
|
|
|
PAGE_WRITE = 0x01,
|
|
|
|
PAGE_EXEC = 0x02
|
|
|
|
};
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
// platform specific implementation (see NativeXXX.cpp file)
|
|
|
|
void nInit(AvmCore *);
|
|
|
|
Register nRegisterAllocFromSet(int32_t set);
|
|
|
|
void nRegisterResetAll(RegAlloc& a);
|
2009-07-30 14:28:26 -07:00
|
|
|
void nMarkExecute(Page* page, int flags);
|
2009-07-10 12:58:34 -07:00
|
|
|
NIns* nPatchBranch(NIns* branch, NIns* location);
|
|
|
|
void nFragExit(LIns* guard);
|
|
|
|
|
|
|
|
// platform specific methods
|
2008-06-18 21:32:23 -07:00
|
|
|
public:
|
2009-07-10 12:58:34 -07:00
|
|
|
const static Register savedRegs[NumSavedRegs];
|
|
|
|
DECLARE_PLATFORM_ASSEMBLER()
|
|
|
|
|
|
|
|
private:
|
2009-07-30 14:21:19 -07:00
|
|
|
debug_only( int32_t _fpuStkDepth; )
|
|
|
|
debug_only( int32_t _sv_fpuStkDepth; )
|
2009-07-10 12:58:34 -07:00
|
|
|
|
|
|
|
// since we generate backwards the depth is negative
|
|
|
|
inline void fpu_push() {
|
|
|
|
debug_only( ++_fpuStkDepth; /*char foo[8]= "FPUSTK0"; foo[6]-=_fpuStkDepth; output_asm(foo);*/ NanoAssert(_fpuStkDepth<=0); )
|
|
|
|
}
|
|
|
|
inline void fpu_pop() {
|
|
|
|
debug_only( --_fpuStkDepth; /*char foo[8]= "FPUSTK0"; foo[6]-=_fpuStkDepth; output_asm(foo);*/ NanoAssert(_fpuStkDepth<=0); )
|
|
|
|
}
|
|
|
|
#ifdef AVMPLUS_PORTING_API
|
|
|
|
// these pointers are required to store
|
|
|
|
// the address range where code has been
|
|
|
|
// modified so we can flush the instruction cache.
|
|
|
|
void* _endJit2Addr;
|
|
|
|
#endif // AVMPLUS_PORTING_API
|
|
|
|
avmplus::Config &config;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline int32_t disp(Reservation* r)
|
|
|
|
{
|
|
|
|
return stack_direction((int32_t)STACK_GRANULARITY) * int32_t(r->arIndex) + NJ_STACK_OFFSET;
|
|
|
|
}
|
2008-06-18 21:32:23 -07:00
|
|
|
}
|
|
|
|
#endif // __nanojit_Assembler__
|