gecko/js/src/nanojit/LIR.h

766 lines
20 KiB
C
Raw Normal View History

2008-06-30 15:33:41 -07:00
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
2008-06-18 21:11:15 -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_LIR__
#define __nanojit_LIR__
namespace avmplus { class RegionTracker; }
namespace nanojit
{
#define is_trace_skip_tramp(op) ((op) <= LIR_tramp)
enum LOpcode
#if defined(_MSC_VER) && _MSC_VER >= 1400
: unsigned
#endif
2008-06-18 21:11:15 -07:00
{
// flags; upper bits reserved
LIR64 = 0x40, // result is double or quad
// special operations (must be 0..N)
LIR_trace = 2,
2008-07-16 14:21:31 -07:00
LIR_nearskip = 3, // must be LIR_skip-1 and lsb=1
LIR_skip = 4,
LIR_neartramp = 5, // must be LIR_tramp-1 and lsb=1
LIR_tramp = 6,
2008-06-18 21:11:15 -07:00
// non-pure operations
LIR_param = 10,
LIR_st = 11,
LIR_ld = 12,
LIR_sti = 14,
LIR_call = 18,
// guards
LIR_loop = 19, // loop fragment
LIR_x = 20, // exit always
// operators
LIR_feq = 26,
LIR_flt = 27,
LIR_fgt = 28,
LIR_fle = 29,
LIR_fge = 30,
2008-06-18 21:11:15 -07:00
LIR_cmov = 31, // conditional move (op1=cond, op2=cond(iftrue,iffalse))
LIR_short = 32,
LIR_int = 33,
LIR_ldc = 34, // non-volatile load
LIR_2 = 35, // wraps a pair of refs
LIR_neg = 36, // [ 1 integer input / integer output ]
LIR_add = 37, // [ 2 operand integer intputs / integer output ]
LIR_sub = 38,
LIR_mul = 39,
LIR_callh = 40,
LIR_and = 41,
LIR_or = 42,
LIR_xor = 43,
LIR_not = 44,
LIR_lsh = 45,
LIR_rsh = 46, // >>
LIR_ush = 47, // >>>
// conditional guards, op^1 to complement
LIR_xt = 48, // exit if true 0x30 0011 0000
LIR_xf = 49, // exit if false 0x31 0011 0001
LIR_qlo = 50,
LIR_qhi = 51,
LIR_ldcb = 52, // non-volatile 8-bit load
2008-06-30 15:33:41 -07:00
LIR_ov = 53,
LIR_cs = 54,
2008-06-18 21:11:15 -07:00
LIR_eq = 55,
// relational operators. op^1 to swap left/right, op^3 to complement.
LIR_lt = 56, // 0x38 0011 1000
LIR_gt = 57, // 0x39 0011 1001
LIR_le = 58, // 0x3A 0011 1010
LIR_ge = 59, // 0x3B 0011 1011
LIR_ult = 60, // 0x3C 0011 1100
LIR_ugt = 61, // 0x3D 0011 1101
LIR_ule = 62, // 0x3E 0011 1110
LIR_uge = 63, // 0x3F 0011 1111
/**
* 64bit operations
2008-06-18 21:11:15 -07:00
*/
LIR_stq = LIR_st | LIR64,
LIR_stqi = LIR_sti | LIR64,
2008-06-18 21:11:15 -07:00
LIR_quad = LIR_int | LIR64,
LIR_ldq = LIR_ld | LIR64,
2008-08-18 12:32:14 -07:00
LIR_qiand = 24 | LIR64,
LIR_qiadd = 25 | LIR64,
LIR_qilsh = LIR_lsh | LIR64,
2008-06-18 21:11:15 -07:00
LIR_fcall = LIR_call | LIR64,
LIR_fneg = LIR_neg | LIR64,
LIR_fadd = LIR_add | LIR64,
LIR_fsub = LIR_sub | LIR64,
LIR_fmul = LIR_mul | LIR64,
LIR_fdiv = 40 | LIR64,
LIR_qcmov = LIR_cmov | LIR64,
2008-06-18 21:11:15 -07:00
LIR_qjoin = 41 | LIR64,
LIR_i2f = 42 | LIR64,
LIR_u2f = 43 | LIR64,
LIR_qior = 44 | LIR64
2008-06-18 21:11:15 -07:00
};
2008-08-18 12:32:14 -07:00
#if defined NANOJIT_64BIT
#define LIR_ldp LIR_ldq
#define LIR_piadd LIR_qiadd
#define LIR_piand LIR_qiand
#define LIR_pilsh LIR_qilsh
#define LIR_pcmov LIR_qcmov
#define LIR_pior LIR_qior
2008-07-31 13:28:12 -07:00
#else
2008-08-18 12:32:14 -07:00
#define LIR_ldp LIR_ld
#define LIR_piadd LIR_add
#define LIR_piand LIR_and
#define LIR_pilsh LIR_lsh
#define LIR_pcmov LIR_cmov
#define LIR_pior LIR_or
2008-07-31 13:28:12 -07:00
#endif
2008-07-16 14:21:31 -07:00
inline uint32_t argwords(uint32_t argc) {
return (argc+3)>>2;
}
2008-06-18 21:11:15 -07:00
struct SideExit;
struct Page;
struct CallInfo;
// Low-level Instruction 4B
// had to lay it our as a union with duplicate code fields since msvc couldn't figure out how to compact it otherwise.
class LIns
{
2008-07-16 14:21:31 -07:00
friend class LirBufWriter;
2008-06-18 21:11:15 -07:00
// 3-operand form (backwards reach only)
struct u_type
{
LOpcode code:8;
2008-07-16 14:21:31 -07:00
uint32_t oprnd_3:8; // only used for store, since this location gets clobbered during generation
2008-06-18 21:11:15 -07:00
uint32_t oprnd_1:8; // 256 ins window and since they only point backwards this is sufficient.
uint32_t oprnd_2:8;
};
struct sti_type
{
LOpcode code:8;
2008-07-16 14:21:31 -07:00
int32_t disp:8;
2008-06-18 21:11:15 -07:00
uint32_t oprnd_1:8; // 256 ins window and since they only point backwards this is sufficient.
uint32_t oprnd_2:8;
};
// imm8 form
struct c_type
{
LOpcode code:8;
2008-07-16 14:21:31 -07:00
uint32_t resv:8; // cobberred during assembly
2008-06-18 21:11:15 -07:00
uint32_t imm8a:8;
uint32_t imm8b:8;
};
2008-07-16 14:21:31 -07:00
// imm24 form for short tramp & skip
struct t_type
{
LOpcode code:8;
int32_t imm24:24;
};
2008-06-18 21:11:15 -07:00
// imm16 form
struct i_type
{
LOpcode code:8;
uint32_t resv:8; // cobberred during assembly
2008-07-16 14:21:31 -07:00
int32_t imm16:16;
2008-06-18 21:11:15 -07:00
};
// overlay used during code generation ( note that last byte is reserved for allocation )
struct g_type
{
LOpcode code:8;
uint32_t resv:8; // cobberred during assembly
2008-07-16 14:21:31 -07:00
uint32_t unused:16;
2008-06-18 21:11:15 -07:00
};
/**
* Various forms of the instruction.
*
* In general the oprnd_x entries contain an uint value 0-255 that identifies a previous
* instruction, where 0 means the previous instruction and 255 means the instruction two
* hundred and fifty five prior to this one.
*
* For pointing to instructions further than this range LIR_tramp is used.
*/
union
{
u_type u;
c_type c;
i_type i;
2008-07-16 14:21:31 -07:00
t_type t;
2008-06-18 21:11:15 -07:00
g_type g;
sti_type sti;
};
2008-07-16 14:21:31 -07:00
uint32_t reference(LIns*) const;
LIns* deref(int32_t off) const;
2008-06-18 21:11:15 -07:00
public:
LIns* FASTCALL oprnd1() const;
LIns* FASTCALL oprnd2() const;
LIns* FASTCALL oprnd3() const;
inline LOpcode opcode() const { return u.code; }
inline uint8_t imm8() const { return c.imm8a; }
inline int16_t imm16() const { return i.imm16; }
2008-07-16 14:21:31 -07:00
inline LIns* ref() const {
#if defined NANOJIT_64BIT
return (t.code & 1) ? (LIns*)this+t.imm24 : *(LIns**)(this-2);
#else
2008-07-16 14:21:31 -07:00
return (t.code & 1) ? (LIns*)this+t.imm24 : *(LIns**)(this-1);
#endif
2008-07-16 14:21:31 -07:00
}
2008-06-18 21:11:15 -07:00
inline int32_t imm32() const { return *(int32_t*)(this-1); }
inline uint8_t resv() const { return g.resv; }
void* payload() const;
inline Page* page() { return (Page*) alignTo(this,NJ_PAGE_SIZE); }
2008-07-16 14:21:31 -07:00
// index args in r-l order. arg(0) is rightmost arg
inline LIns* arg(uint32_t i) {
uint32_t c = argc();
NanoAssert(i < c);
uint8_t* offs = (uint8_t*) (this-argwords(c));
return deref(offs[i]);
}
2008-06-18 21:11:15 -07:00
inline int32_t immdisp()const
{
return (u.code&~LIR64) == LIR_sti ? sti.disp : oprnd3()->constval();
2008-06-18 21:11:15 -07:00
}
inline static bool sameop(LIns* a, LIns* b)
{
// hacky but more efficient than opcode() == opcode() due to bit masking of 7-bit field
union {
uint32_t x;
u_type u;
} tmp;
tmp.x = *(uint32_t*)a ^ *(uint32_t*)b;
return tmp.u.code == 0;
}
inline int32_t constval() const
{
NanoAssert(isconst());
return isop(LIR_short) ? imm16() : imm32();
}
2008-08-18 12:32:14 -07:00
2008-06-18 21:11:15 -07:00
inline uint64_t constvalq() const
{
NanoAssert(isconstq());
#ifdef AVMPLUS_UNALIGNED_ACCESS
return *(const uint64_t*)(this-2);
#else
2008-08-15 09:55:32 -07:00
union { uint64_t tmp; int32_t dst[2]; } u;
2008-07-31 13:28:12 -07:00
const int32_t* src = (const int32_t*)(this-2);
2008-08-15 09:55:32 -07:00
u.dst[0] = src[0];
u.dst[1] = src[1];
return u.tmp;
2008-06-18 21:11:15 -07:00
#endif
}
inline void* constvalp() const
{
#ifdef AVMPLUS_64BIT
return (void*)constvalq();
#else
return (void*)constval();
#endif
}
2008-06-18 21:11:15 -07:00
inline double constvalf() const
{
NanoAssert(isconstq());
#ifdef AVMPLUS_UNALIGNED_ACCESS
return *(const double*)(this-2);
#else
2008-08-15 09:55:32 -07:00
union { uint32_t dst[2]; double tmpf; } u;
2008-07-31 13:28:12 -07:00
const int32_t* src = (const int32_t*)(this-2);
2008-08-15 09:55:32 -07:00
u.dst[0] = src[0];
u.dst[1] = src[1];
2008-07-16 14:21:31 -07:00
return u.tmpf;
2008-06-18 21:11:15 -07:00
#endif
}
bool isCse(const CallInfo *functions) const;
bool isop(LOpcode o) const { return u.code == o; }
bool isQuad() const;
2008-06-30 15:33:41 -07:00
bool isCond() const;
2008-06-18 21:11:15 -07:00
bool isCmp() const;
bool isCall() const;
bool isStore() const;
bool isLoad() const;
bool isGuard() const;
bool isconst() const;
bool isconstval(int32_t val) const;
bool isconstq() const;
bool isconstp() const;
2008-07-16 14:21:31 -07:00
bool isTramp() {
return isop(LIR_neartramp) || isop(LIR_tramp);
}
2008-06-18 21:11:15 -07:00
void setimm16(int32_t i);
void setimm24(int32_t i);
void setresv(uint32_t resv);
void initOpcode(LOpcode);
void setOprnd1(LIns*);
void setOprnd2(LIns*);
void setOprnd3(LIns*);
void setDisp(int8_t d);
SideExit *exit();
2008-07-16 14:21:31 -07:00
inline uint32_t argc() {
NanoAssert(isCall());
return c.imm8b;
}
inline uint8_t fid() const {
NanoAssert(isCall());
return c.imm8a;
}
2008-06-18 21:11:15 -07:00
};
typedef LIns* LInsp;
bool FASTCALL isCse(LOpcode v);
bool FASTCALL isCmp(LOpcode v);
2008-06-30 15:33:41 -07:00
bool FASTCALL isCond(LOpcode v);
2008-06-18 21:11:15 -07:00
LIns* FASTCALL callArgN(LInsp i, uint32_t n);
extern const uint8_t operandCount[];
2008-06-18 21:11:15 -07:00
class Fragmento; // @todo remove this ; needed for minbuild for some reason?!? Should not be compiling this code at all
class LirFilter;
struct CallInfo;
2008-07-01 14:46:10 -07:00
// make it a GCObject so we can explicitly delete it early
class LirWriter : public GCObject
2008-06-18 21:11:15 -07:00
{
2008-07-01 14:46:10 -07:00
public:
2008-06-18 21:11:15 -07:00
LirWriter *out;
public:
const CallInfo *_functions;
virtual ~LirWriter() {}
LirWriter(LirWriter* out)
: out(out), _functions(out?out->_functions : 0) {}
virtual LInsp ins0(LOpcode v) {
return out->ins0(v);
}
virtual LInsp ins1(LOpcode v, LIns* a) {
return out->ins1(v, a);
}
virtual LInsp ins2(LOpcode v, LIns* a, LIns* b) {
return out->ins2(v, a, b);
}
virtual LInsp insGuard(LOpcode v, LIns *c, SideExit *x) {
return out->insGuard(v, c, x);
}
2008-07-16 14:21:31 -07:00
virtual LInsp insParam(int32_t i) {
return out->insParam(i);
2008-06-18 21:11:15 -07:00
}
virtual LInsp insImm(int32_t imm) {
return out->insImm(imm);
}
virtual LInsp insImmq(uint64_t imm) {
return out->insImmq(imm);
}
virtual LInsp insLoad(LOpcode op, LIns* base, LIns* d) {
return out->insLoad(op, base, d);
}
virtual LInsp insStore(LIns* value, LIns* base, LIns* disp) {
return out->insStore(value, base, disp);
}
virtual LInsp insStorei(LIns* value, LIns* base, int32_t d) {
return isS8(d) ? out->insStorei(value, base, d)
: out->insStore(value, base, insImm(d));
}
2008-07-16 14:21:31 -07:00
virtual LInsp insCall(uint32_t fid, LInsp args[]) {
2008-06-18 21:11:15 -07:00
return out->insCall(fid, args);
}
// convenience
LIns* insLoadi(LIns *base, int disp);
LIns* insLoad(LOpcode op, LIns *base, int disp);
LIns* ins_choose(LIns* cond, LIns* iftrue, LIns* iffalse, bool);
LIns* ins_eq0(LIns* oprnd1);
LIns* ins2i(LOpcode op, LIns *oprnd1, int32_t);
LIns* qjoin(LInsp lo, LInsp hi);
2008-06-30 15:33:41 -07:00
LIns* insImmPtr(const void *ptr);
2008-06-18 21:11:15 -07:00
};
#ifdef NJ_VERBOSE
extern const char* lirNames[];
2008-06-18 21:11:15 -07:00
/**
* map address ranges to meaningful names.
*/
2008-07-15 13:06:05 -07:00
class LabelMap MMGC_SUBCLASS_DECL
2008-06-18 21:11:15 -07:00
{
LabelMap* parent;
2008-07-15 13:06:05 -07:00
class Entry MMGC_SUBCLASS_DECL
{
2008-06-18 21:11:15 -07:00
public:
Entry(int) : name(0), size(0), align(0) {}
Entry(avmplus::String *n, size_t s, size_t a) : name(n),size(s),align(a) {}
~Entry();
2008-06-18 21:11:15 -07:00
DRCWB(avmplus::String*) name;
size_t size:29, align:3;
};
avmplus::SortedMap<const void*, Entry*, avmplus::LIST_GCObjects> names;
bool addrs, pad[3];
char buf[1000], *end;
void formatAddr(const void *p, char *buf);
public:
AvmCore *core;
LabelMap(AvmCore *, LabelMap* parent);
~LabelMap();
2008-06-18 21:11:15 -07:00
void add(const void *p, size_t size, size_t align, const char *name);
void add(const void *p, size_t size, size_t align, avmplus::String*);
const char *dup(const char *);
const char *format(const void *p);
void promoteAll(const void *newbase);
2008-06-18 21:11:15 -07:00
};
2008-07-15 13:06:05 -07:00
class LirNameMap MMGC_SUBCLASS_DECL
2008-06-18 21:11:15 -07:00
{
class CountMap: public avmplus::SortedMap<int, int, avmplus::LIST_NonGCObjects> {
public:
CountMap(GC*gc) : avmplus::SortedMap<int, int, avmplus::LIST_NonGCObjects>(gc) {};
int add(int i) {
int c = 1;
if (containsKey(i)) {
c = 1+get(i);
}
put(i,c);
return c;
}
} lircounts, funccounts;
2008-07-15 13:06:05 -07:00
class Entry MMGC_SUBCLASS_DECL
{
2008-06-18 21:11:15 -07:00
public:
Entry(int) : name(0) {}
Entry(avmplus::String *n) : name(n) {}
~Entry();
2008-06-18 21:11:15 -07:00
DRCWB(avmplus::String*) name;
};
avmplus::SortedMap<LInsp, Entry*, avmplus::LIST_GCObjects> names;
const CallInfo *_functions;
LabelMap *labels;
void formatImm(int32_t c, char *buf);
public:
LirNameMap(GC *gc, const CallInfo *_functions, LabelMap *r)
: lircounts(gc),
funccounts(gc),
names(gc),
_functions(_functions),
labels(r)
{}
~LirNameMap();
2008-06-18 21:11:15 -07:00
void addName(LInsp i, const char *s);
void addName(LInsp i, avmplus::String *s);
void copyName(LInsp i, const char *s, int suffix);
const char *formatRef(LIns *ref);
const char *formatIns(LInsp i);
void formatGuard(LInsp i, char *buf);
2008-06-18 21:11:15 -07:00
};
2008-06-30 15:33:41 -07:00
class VerboseWriter : public LirWriter
{
avmplus::List<LInsp, avmplus::LIST_NonGCObjects> code;
LirNameMap *names;
public:
VerboseWriter(GC *gc, LirWriter *out, LirNameMap* names)
: LirWriter(out), code(gc), names(names)
{}
LInsp add(LInsp i) {
code.add(i);
return i;
}
void flush()
{
for (int j=0, n=code.size(); j < n; j++)
printf(" %s\n",names->formatIns(code[j]));
code.clear();
printf("\n");
}
LIns* insGuard(LOpcode op, LInsp cond, SideExit *x) {
LInsp i = add(out->insGuard(op,cond,x));
if (i)
flush();
return i;
}
LIns* ins0(LOpcode v) {
LInsp i = add(out->ins0(v));
if (i)
flush();
return i;
}
LIns* ins1(LOpcode v, LInsp a) {
return add(out->ins1(v, a));
}
LIns* ins2(LOpcode v, LInsp a, LInsp b) {
return v == LIR_2 ? out->ins2(v,a,b) : add(out->ins2(v, a, b));
}
2008-07-16 14:21:31 -07:00
LIns* insCall(uint32_t fid, LInsp args[]) {
2008-06-30 15:33:41 -07:00
return add(out->insCall(fid, args));
}
2008-07-16 14:21:31 -07:00
LIns* insParam(int32_t i) {
return add(out->insParam(i));
2008-06-30 15:33:41 -07:00
}
LIns* insLoad(LOpcode v, LInsp base, LInsp disp) {
return add(out->insLoad(v, base, disp));
}
LIns* insStore(LInsp v, LInsp b, LInsp d) {
return add(out->insStore(v, b, d));
}
LIns* insStorei(LInsp v, LInsp b, int32_t d) {
return add(out->insStorei(v, b, d));
}
};
2008-06-18 21:11:15 -07:00
#endif
class ExprFilter: public LirWriter
{
public:
ExprFilter(LirWriter *out) : LirWriter(out) {}
LIns* ins1(LOpcode v, LIns* a);
LIns* ins2(LOpcode v, LIns* a, LIns* b);
LIns* insGuard(LOpcode v, LIns *c, SideExit *x);
};
// @todo, this could be replaced by a generic HashMap or HashSet, if we had one
class LInsHashSet
{
// must be a power of 2.
// don't start too small, or we'll waste time growing and rehashing.
// don't start too large, will waste memory.
static const uint32_t kInitialCap = 2048;
InsList m_list;
uint32_t m_used;
GC* m_gc;
static uint32_t FASTCALL hashcode(LInsp i);
uint32_t FASTCALL find(LInsp name, uint32_t hash, const InsList& list, uint32_t cap);
static bool FASTCALL equals(LInsp a, LInsp b);
void FASTCALL grow();
public:
LInsHashSet(GC* gc);
LInsp find32(int32_t a, uint32_t &i);
LInsp find64(uint64_t a, uint32_t &i);
LInsp find1(LOpcode v, LInsp a, uint32_t &i);
LInsp find2(LOpcode v, LInsp a, LInsp b, uint32_t &i);
2008-07-16 14:21:31 -07:00
LInsp findcall(uint32_t fid, uint32_t argc, LInsp args[], uint32_t &i);
2008-06-18 21:11:15 -07:00
LInsp add(LInsp i, uint32_t k);
void replace(LInsp i);
2008-06-18 21:11:15 -07:00
static uint32_t FASTCALL hashimm(int32_t);
static uint32_t FASTCALL hashimmq(uint64_t);
static uint32_t FASTCALL hash1(LOpcode v, LInsp);
static uint32_t FASTCALL hash2(LOpcode v, LInsp, LInsp);
2008-07-16 14:21:31 -07:00
static uint32_t FASTCALL hashcall(uint32_t fid, uint32_t argc, LInsp args[]);
2008-06-18 21:11:15 -07:00
};
class CseFilter: public LirWriter
{
public:
LInsHashSet exprs;
2008-06-18 21:11:15 -07:00
CseFilter(LirWriter *out, GC *gc);
LIns* insImm(int32_t imm);
LIns* insImmq(uint64_t q);
LIns* ins1(LOpcode v, LInsp);
LIns* ins2(LOpcode v, LInsp, LInsp);
LIns* insLoad(LOpcode v, LInsp b, LInsp d);
2008-07-16 14:21:31 -07:00
LIns* insCall(uint32_t fid, LInsp args[]);
2008-06-18 21:11:15 -07:00
LIns* insGuard(LOpcode op, LInsp cond, SideExit *x);
};
struct Page;
class LirBuffer : public GCFinalizedObject
{
public:
DWB(Fragmento*) _frago;
LirBuffer(Fragmento* frago, const CallInfo* functions);
virtual ~LirBuffer();
2008-07-15 13:06:05 -07:00
void clear();
2008-06-18 21:11:15 -07:00
LInsp next();
LInsp commit(uint32_t count);
bool addPage();
bool outOmem() { return _noMem != 0; }
debug_only (void validate() const;)
2008-07-15 13:06:05 -07:00
verbose_only(DWB(LirNameMap*) names;)
verbose_only(int insCount();)
verbose_only(int byteCount();)
2008-06-18 21:11:15 -07:00
// stats
struct
{
2008-07-15 13:06:05 -07:00
uint32_t lir; // # instructions
2008-06-18 21:11:15 -07:00
uint32_t pages; // pages consumed
}
_stats;
const CallInfo* _functions;
2008-07-16 14:21:31 -07:00
LInsp state,param1,sp,rp;
2008-06-18 21:11:15 -07:00
private:
Page* pageAlloc();
Page* _start; // first page
LInsp _unused; // next unused instruction slot
int _noMem; // set if ran out of memory when writing to buffer
};
class LirBufWriter : public LirWriter
{
DWB(LirBuffer*) _buf; // underlying buffer housing the instructions
2008-07-16 14:21:31 -07:00
LInsp spref, rpref;
2008-06-18 21:11:15 -07:00
public:
LirBufWriter(LirBuffer* buf)
: LirWriter(0), _buf(buf) {
_functions = buf->_functions;
}
// LirWriter interface
LInsp insLoad(LOpcode op, LInsp base, LInsp off);
LInsp insStore(LInsp o1, LInsp o2, LInsp o3);
LInsp insStorei(LInsp o1, LInsp o2, int32_t imm);
LInsp ins0(LOpcode op);
LInsp ins1(LOpcode op, LInsp o1);
LInsp ins2(LOpcode op, LInsp o1, LInsp o2);
2008-07-16 14:21:31 -07:00
LInsp insParam(int32_t i);
2008-06-18 21:11:15 -07:00
LInsp insImm(int32_t imm);
LInsp insImmq(uint64_t imm);
2008-07-16 14:21:31 -07:00
LInsp insCall(uint32_t fid, LInsp args[]);
2008-06-18 21:11:15 -07:00
LInsp insGuard(LOpcode op, LInsp cond, SideExit *x);
// buffer mgmt
LInsp skip(size_t);
2008-07-16 14:21:31 -07:00
LInsp insFar(LOpcode op, LInsp target);
2008-06-18 21:11:15 -07:00
LInsp ensureReferenceable(LInsp i, int32_t addedDistance);
bool ensureRoom(uint32_t count);
bool canReference(LInsp from, LInsp to) {
return isU8(from-to-1);
}
};
class LirFilter
{
public:
LirFilter *in;
LirFilter(LirFilter *in) : in(in) {}
virtual ~LirFilter() {}
virtual LInsp read() {
return in->read();
}
virtual LInsp pos() {
return in->pos();
}
};
// concrete
class LirReader : public LirFilter
{
LInsp _i; // current instruction that this decoder is operating on.
public:
LirReader(LirBuffer* buf) : LirFilter(0), _i(buf->next()-1) { }
LirReader(LInsp i) : LirFilter(0), _i(i) { }
virtual ~LirReader() {}
// LirReader i/f
LInsp read(); // advance to the prior instruction
LInsp pos() {
return _i;
}
};
class Assembler;
void compile(Assembler *assm, Fragment *frag);
verbose_only( void printTracker(const char* s, avmplus::RegionTracker& trk, Assembler* assm); )
verbose_only(void live(GC *gc, Assembler *assm, Fragment *frag);)
class StackFilter: public LirFilter
2008-06-18 21:11:15 -07:00
{
GC *gc;
Fragment *frag;
LInsp sp;
avmplus::BitSet stk;
int top;
int getTop(LInsp guard);
2008-06-18 21:11:15 -07:00
public:
StackFilter(LirFilter *in, GC *gc, Fragment *frag, LInsp sp);
virtual ~StackFilter() {}
2008-06-18 21:11:15 -07:00
LInsp read();
};
class CseReader: public LirFilter
{
LInsHashSet *exprs;
const CallInfo *functions;
public:
CseReader(LirFilter *in, LInsHashSet *exprs, const CallInfo*);
LInsp read();
};
2008-06-18 21:11:15 -07:00
}
#endif // __nanojit_LIR__