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-29 16:21:40 -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-29 16:21:40 -07:00
|
|
|
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
|
|
|
};
|
|
|
|
|
|
|
|
// error codes
|
|
|
|
enum AssmError
|
|
|
|
{
|
|
|
|
None = 0
|
|
|
|
,StackFull
|
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-08-04 10:21:15 -07:00
|
|
|
typedef SeqBuilder<NIns*> NInsList;
|
2009-08-04 08:06:46 -07:00
|
|
|
typedef HashMap<NIns*, LIns*> NInsMap;
|
2008-10-13 13:29:18 -07:00
|
|
|
|
2009-08-04 07:48:48 -07:00
|
|
|
class LabelState
|
2008-10-13 13:29:18 -07:00
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
2009-08-04 07:48:48 -07:00
|
|
|
Allocator& alloc;
|
|
|
|
HashMap<LIns*, LabelState*> labels;
|
2008-10-13 13:29:18 -07:00
|
|
|
public:
|
2009-08-04 07:48:48 -07:00
|
|
|
LabelStateMap(Allocator& alloc) : alloc(alloc), labels(alloc)
|
2008-10-13 13:29:18 -07:00
|
|
|
{}
|
|
|
|
|
2009-08-04 08:33:14 -07:00
|
|
|
void clear() { labels.clear(); }
|
2008-10-13 13:29:18 -07:00
|
|
|
void add(LIns *label, NIns *addr, RegAlloc ®s);
|
|
|
|
LabelState *get(LIns *);
|
|
|
|
};
|
2009-08-04 06:54:47 -07:00
|
|
|
|
|
|
|
typedef SeqBuilder<char*> StringList;
|
|
|
|
|
2009-08-04 07:48:48 -07:00
|
|
|
/** map tracking the register allocation state at each bailout point
|
|
|
|
* (represented by SideExit*) in a trace fragment. */
|
|
|
|
typedef HashMap<SideExit*, RegAlloc*> RegAllocMap;
|
|
|
|
|
2008-06-18 21:32:23 -07:00
|
|
|
/**
|
2009-07-29 16:21:40 -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-29 16:21:40 -07:00
|
|
|
* are issued. Also LIR_alloc instructions will consume space.
|
2009-07-10 12:58:34 -07:00
|
|
|
*/
|
2009-08-20 17:22:47 -07:00
|
|
|
class Assembler
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2009-08-30 00:11:12 -07:00
|
|
|
void outputForEOL(const char* format, ...);
|
|
|
|
void output(const char* s);
|
|
|
|
void outputf(const char* format, ...);
|
|
|
|
void output_asm(const char* s);
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-29 16:21:40 -07:00
|
|
|
bool outputAddr, vpad[3]; // if outputAddr=true then next asm instr. will include address in output
|
2009-09-24 17:21:35 -07:00
|
|
|
void printActivationState(const char* what);
|
2009-07-10 12:58:34 -07:00
|
|
|
|
|
|
|
StringList* _outputCache;
|
|
|
|
|
|
|
|
// Log controller object. Contains what-stuff-should-we-print
|
|
|
|
// bits, and a sink function for debug printing
|
|
|
|
LogControl* _logc;
|
2009-09-15 15:05:53 -07:00
|
|
|
size_t codeBytes;
|
|
|
|
size_t exitBytes;
|
2009-07-10 12:58:34 -07:00
|
|
|
#endif
|
|
|
|
|
2009-08-04 06:54:47 -07:00
|
|
|
Assembler(CodeAlloc& codeAlloc, Allocator& alloc, AvmCore* core, LogControl* logc);
|
2008-06-18 21:32:23 -07:00
|
|
|
~Assembler() {}
|
|
|
|
|
2009-08-29 23:26:54 -07:00
|
|
|
void endAssembly(Fragment* frag);
|
2009-09-01 15:27:34 -07:00
|
|
|
void assemble(Fragment* frag);
|
|
|
|
void beginAssembly(Fragment *frag);
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
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-29 16:21:40 -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-09-01 15:27:34 -07:00
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
void reset();
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-29 16:21:40 -07:00
|
|
|
debug_only ( void pageValidate(); )
|
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-29 16:21:40 -07:00
|
|
|
Stats _stats;
|
2009-07-15 16:50:01 -07:00
|
|
|
CodeList* codeList; // finished blocks of code.
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
private:
|
|
|
|
|
2009-09-01 15:27:34 -07:00
|
|
|
void gen(LirFilter* toCompile);
|
2009-07-29 16:21:40 -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();
|
2009-09-10 23:21:10 -07:00
|
|
|
void evictAllActiveRegs();
|
|
|
|
void evictSomeActiveRegs(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-09-03 16:18:01 -07:00
|
|
|
LInsp findVictim(RegisterMask allow);
|
2008-10-20 10:15:07 -07:00
|
|
|
|
|
|
|
Register getBaseReg(LIns *i, int &d, RegisterMask allow);
|
2009-07-29 16:21:40 -07:00
|
|
|
int findMemFor(LIns* i);
|
2009-07-10 12:58:34 -07:00
|
|
|
Register findRegFor(LIns* i, RegisterMask allow);
|
2009-09-09 18:00:18 -07:00
|
|
|
void findRegFor2(RegisterMask allow, LIns* ia, Reservation* &resva, LIns *ib, Reservation* &resvb);
|
|
|
|
void findRegFor2b(RegisterMask allow, LIns* ia, Register &ra, LIns *ib, Register &rb);
|
2009-07-10 12:58:34 -07:00
|
|
|
Register findSpecificRegFor(LIns* i, Register w);
|
|
|
|
Register prepResultReg(LIns *i, RegisterMask allow);
|
|
|
|
void freeRsrcOf(LIns *i, bool pop);
|
2009-08-30 18:48:21 -07:00
|
|
|
void evictIfActive(Register r);
|
|
|
|
void evict(Register r, LIns* vic);
|
2009-07-10 12:58:34 -07:00
|
|
|
RegisterMask hint(LIns*i, RegisterMask allow);
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-09-15 15:05:53 -07:00
|
|
|
void codeAlloc(NIns *&start, NIns *&end, NIns *&eip
|
|
|
|
verbose_only(, size_t &nBytes));
|
2008-10-13 13:29:18 -07:00
|
|
|
bool canRemat(LIns*);
|
2008-06-18 21:32:23 -07:00
|
|
|
|
2009-09-09 18:00:18 -07:00
|
|
|
bool isKnownReg(Register r) {
|
|
|
|
return r != UnknownReg;
|
|
|
|
}
|
|
|
|
|
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-08-04 11:18:38 -07:00
|
|
|
Allocator& alloc;
|
2009-08-04 11:53:56 -07:00
|
|
|
CodeAlloc& _codeAlloc;
|
2009-09-10 16:29:36 -07:00
|
|
|
Fragment* _thisfrag;
|
2009-09-01 15:27:34 -07:00
|
|
|
RegAllocMap _branchStateMap;
|
|
|
|
NInsMap _patches;
|
|
|
|
LabelStateMap _labels;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
NIns *codeStart, *codeEnd; // current block we're adding code to
|
|
|
|
NIns *exitStart, *exitEnd; // current block for exit stubs
|
2009-07-29 16:21:40 -07:00
|
|
|
NIns* _nIns; // current native instruction
|
|
|
|
NIns* _nExitIns; // current instruction in exit fragment page
|
2009-07-10 12:58:34 -07:00
|
|
|
NIns* _epilogue;
|
2009-07-29 16:21:40 -07:00
|
|
|
AssmError _err; // 0 = means assemble() appears ok, otherwise it failed
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-29 16:21:40 -07:00
|
|
|
AR _activation;
|
2009-07-10 12:58:34 -07:00
|
|
|
RegAlloc _allocator;
|
|
|
|
|
|
|
|
bool _inExit, vpad2[3];
|
|
|
|
|
2009-09-15 15:05:53 -07:00
|
|
|
verbose_only( void asm_inc_m32(uint32_t*); )
|
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-29 16:21:40 -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);
|
2009-09-09 18:00:18 -07:00
|
|
|
void asm_spilli(LInsp i, bool pop);
|
2009-07-10 12:58:34 -07:00
|
|
|
void asm_spill(Register rr, int d, bool pop, bool quad);
|
|
|
|
void asm_load64(LInsp i);
|
2009-08-24 16:57:25 -07:00
|
|
|
void asm_ret(LInsp p);
|
2009-07-10 12:58:34 -07:00
|
|
|
void asm_quad(LInsp i);
|
|
|
|
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_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);
|
2009-08-24 16:57:25 -07:00
|
|
|
void asm_promote(LIns *ins);
|
2009-07-10 12:58:34 -07:00
|
|
|
Register asm_prep_fcall(Reservation *rR, LInsp ins);
|
|
|
|
void asm_nongp_copy(Register r, Register s);
|
|
|
|
void asm_call(LInsp);
|
|
|
|
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
|
|
|
|
|
|
|
// platform specific implementation (see NativeXXX.cpp file)
|
|
|
|
void nInit(AvmCore *);
|
2009-08-31 16:35:50 -07:00
|
|
|
void nBeginAssembly();
|
2009-08-27 13:50:30 -07:00
|
|
|
Register nRegisterAllocFromSet(RegisterMask set);
|
2009-07-10 12:58:34 -07:00
|
|
|
void nRegisterResetAll(RegAlloc& a);
|
2009-08-27 13:47:39 -07:00
|
|
|
static void nPatchBranch(NIns* branch, NIns* location);
|
2009-07-10 12:58:34 -07:00
|
|
|
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-09-15 23:00:51 -07:00
|
|
|
#ifdef NANOJIT_IA32
|
2009-07-29 16:21:40 -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); )
|
|
|
|
}
|
2009-09-15 23:00:51 -07:00
|
|
|
#endif
|
2009-07-10 12:58:34 -07:00
|
|
|
avmplus::Config &config;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline int32_t disp(Reservation* r)
|
|
|
|
{
|
2009-08-31 16:14:22 -07:00
|
|
|
// even on 64bit cpu's, we allocate stack area in 4byte chunks
|
|
|
|
return stack_direction(4 * int32_t(r->arIndex));
|
2009-07-10 12:58:34 -07:00
|
|
|
}
|
2009-09-09 18:00:18 -07:00
|
|
|
inline int32_t disp(LIns* ins)
|
|
|
|
{
|
|
|
|
// even on 64bit cpu's, we allocate stack area in 4byte chunks
|
|
|
|
return stack_direction(4 * int32_t(ins->getArIndex()));
|
|
|
|
}
|
2008-06-18 21:32:23 -07:00
|
|
|
}
|
|
|
|
#endif // __nanojit_Assembler__
|