mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 602703 - TM: create a layer over Nanojit's LIR creation API. r=lw.
This commit is contained in:
parent
036c4f5377
commit
505e8ac40a
@ -254,7 +254,9 @@ INSTALLED_HEADERS = \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TRACEJIT
|
||||
VPATH += $(srcdir)/nanojit
|
||||
VPATH += \
|
||||
$(srcdir)/tracejit \
|
||||
$(srcdir)/nanojit \
|
||||
|
||||
INSTALLED_HEADERS += \
|
||||
jsbuiltins.h \
|
||||
@ -263,15 +265,18 @@ INSTALLED_HEADERS += \
|
||||
CodeAlloc.h \
|
||||
Containers.h \
|
||||
LIR.h \
|
||||
LIRopcode.tbl \
|
||||
avmplus.h \
|
||||
Fragmento.h \
|
||||
Native.h \
|
||||
NativeCommon.h \
|
||||
Native$(NANOJIT_ARCH).h \
|
||||
njconfig.h \
|
||||
njconfig.h \
|
||||
njcpudetect.h \
|
||||
RegAlloc.h \
|
||||
nanojit.h \
|
||||
VMPI.h \
|
||||
Writer.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS += \
|
||||
@ -286,8 +291,9 @@ CPPSRCS += \
|
||||
RegAlloc.cpp \
|
||||
avmplus.cpp \
|
||||
Native$(NANOJIT_ARCH).cpp \
|
||||
jsbuiltins.cpp \
|
||||
jsbuiltins.cpp \
|
||||
VMPI.cpp \
|
||||
Writer.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef WINCE
|
||||
|
@ -451,7 +451,7 @@ js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
|
||||
}
|
||||
/* This function and its callees do not touch any object's .clasp field. */
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL, js_EnsureDenseArrayCapacity, CONTEXT, OBJECT, INT32,
|
||||
0, nanojit::ACCSET_STORE_ANY & ~ACCSET_OBJ_CLASP)
|
||||
0, nanojit::ACCSET_STORE_ANY & ~tjit::ACCSET_OBJ_CLASP)
|
||||
#endif
|
||||
|
||||
static JSBool
|
||||
@ -828,7 +828,7 @@ js_Array_dense_setelem_hole(JSContext* cx, JSObject* obj, jsint i)
|
||||
}
|
||||
/* storeAccSet == ACCSET_OBJ_PRIVATE: because it can set 'length'. */
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL, js_Array_dense_setelem_hole, CONTEXT, OBJECT, INT32,
|
||||
0, ACCSET_OBJ_PRIVATE)
|
||||
0, tjit::ACCSET_OBJ_PRIVATE)
|
||||
#endif
|
||||
|
||||
static JSBool
|
||||
|
@ -49,97 +49,6 @@
|
||||
#undef THIS
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* See ValidateWriter::checkAccSet() for what each of these access regions
|
||||
* mean.
|
||||
*
|
||||
* *** WARNING WARNING WARNING ***
|
||||
*
|
||||
* Any incorrect access region annotations on loads/stores/calls could lead to
|
||||
* subtle bugs that manifest rarely, eg. when two loads are CSE'd that
|
||||
* shouldn't be.
|
||||
*
|
||||
* If you add a new access region you will need to add some sanity checking to
|
||||
* ValidateWriter::checkAccSet(). Do not skimp on this checking! Make it as
|
||||
* strong as you can. Look at the existing cases for inspiration. This
|
||||
* checking helps prevent these subtle bugs.
|
||||
*
|
||||
* Furthermore, do not add a "catch-all" region such as "ACCSET_OTHER". There
|
||||
* are two reasons for this. First, no checking could be done on loads/stores
|
||||
* bearing it. Second, it would be too easy for someone in the future who
|
||||
* doesn't understand how AccSets work to use it inappropriately. Only
|
||||
* ACCSET_ALL (the union of all access regions) should be used as a catch-all,
|
||||
* it can always be used safely, but it reduces optimization possibilities.
|
||||
*
|
||||
* Most of the access regions are type-based, ie. all structs of a particular
|
||||
* type combined together form a region. This is less precise than
|
||||
* considering each struct separately, but also much simpler.
|
||||
*
|
||||
* - ACCSET_STATE: The TracerState struct.
|
||||
* - ACCSET_STACK: The stack.
|
||||
* - ACCSET_RSTACK: The return stack.
|
||||
* - ACCSET_CX: All JSContext structs.
|
||||
* - ACCSET_EOS: The globals area.
|
||||
* - ACCSET_ALLOC: All memory blocks allocated with LIR_allocp (in
|
||||
* other words, this region is the AR space).
|
||||
* - ACCSET_FRAMEREGS: All JSFrameRegs structs.
|
||||
* - ACCSET_STACKFRAME: All JSStackFrame objects.
|
||||
* - ACCSET_RUNTIME: The JSRuntime object.
|
||||
* - ACCSET_OBJ_CLASP: The 'clasp' field of all JSObjects.
|
||||
* - ACCSET_OBJ_FLAGS: The 'flags' field of all JSObjects.
|
||||
* - ACCSET_OBJ_SHAPE: The 'shape' field of all JSObjects.
|
||||
* - ACCSET_OBJ_PROTO: The 'proto' field of all JSObjects.
|
||||
* - ACCSET_OBJ_PARENT: The 'parent' field of all JSObjects.
|
||||
* - ACCSET_OBJ_PRIVATE: The 'private' field of all JSObjects.
|
||||
* - ACCSET_OBJ_CAPACITY: The 'capacity' field of all JSObjects.
|
||||
* - ACCSET_OBJ_SLOTS: The 'slots' field of all JSObjects.
|
||||
* - ACCSET_SLOTS: The slots (be they fixed or dynamic) of all JSObjects.
|
||||
* - ACCSET_TARRAY: All TypedArray structs.
|
||||
* - ACCSET_TARRAY_DATA: All TypedArray data arrays.
|
||||
* - ACCSET_ITER: All NativeIterator structs.
|
||||
* - ACCSET_ITER_PROPS: The props_arrays of all NativeIterator structs.
|
||||
* - ACCSET_STRING: All JSString structs.
|
||||
* - ACCSET_STRING_MCHARS: All JSString mchars arrays.
|
||||
* - ACCSET_TYPEMAP: All typemaps form a single region.
|
||||
* - ACCSET_FCSLOTS: All fcslots arrays form a single region.
|
||||
* - ACCSET_ARGS_DATA: All Arguments data arrays form a single region.
|
||||
*/
|
||||
static const nanojit::AccSet ACCSET_STATE = (1 << 0);
|
||||
static const nanojit::AccSet ACCSET_STACK = (1 << 1);
|
||||
static const nanojit::AccSet ACCSET_RSTACK = (1 << 2);
|
||||
static const nanojit::AccSet ACCSET_CX = (1 << 3);
|
||||
static const nanojit::AccSet ACCSET_EOS = (1 << 4);
|
||||
static const nanojit::AccSet ACCSET_ALLOC = (1 << 5);
|
||||
static const nanojit::AccSet ACCSET_FRAMEREGS = (1 << 6);
|
||||
static const nanojit::AccSet ACCSET_STACKFRAME = (1 << 7);
|
||||
static const nanojit::AccSet ACCSET_RUNTIME = (1 << 8);
|
||||
|
||||
// Nb: JSObject::{lastProp,map} don't have an AccSet because they are never accessed on trace
|
||||
static const nanojit::AccSet ACCSET_OBJ_CLASP = (1 << 9);
|
||||
static const nanojit::AccSet ACCSET_OBJ_FLAGS = (1 << 10);
|
||||
static const nanojit::AccSet ACCSET_OBJ_SHAPE = (1 << 11);
|
||||
static const nanojit::AccSet ACCSET_OBJ_PROTO = (1 << 12);
|
||||
static const nanojit::AccSet ACCSET_OBJ_PARENT = (1 << 13);
|
||||
static const nanojit::AccSet ACCSET_OBJ_PRIVATE = (1 << 14);
|
||||
static const nanojit::AccSet ACCSET_OBJ_CAPACITY = (1 << 15);
|
||||
static const nanojit::AccSet ACCSET_OBJ_SLOTS = (1 << 16); // the pointer to the slots
|
||||
|
||||
static const nanojit::AccSet ACCSET_SLOTS = (1 << 17); // the slots themselves
|
||||
static const nanojit::AccSet ACCSET_TARRAY = (1 << 18);
|
||||
static const nanojit::AccSet ACCSET_TARRAY_DATA = (1 << 19);
|
||||
static const nanojit::AccSet ACCSET_ITER = (1 << 20);
|
||||
static const nanojit::AccSet ACCSET_ITER_PROPS = (1 << 21);
|
||||
static const nanojit::AccSet ACCSET_STRING = (1 << 22);
|
||||
static const nanojit::AccSet ACCSET_STRING_MCHARS = (1 << 23);
|
||||
static const nanojit::AccSet ACCSET_TYPEMAP = (1 << 24);
|
||||
static const nanojit::AccSet ACCSET_FCSLOTS = (1 << 25);
|
||||
static const nanojit::AccSet ACCSET_ARGS_DATA = (1 << 26);
|
||||
}
|
||||
|
||||
static const uint8_t TM_NUM_USED_ACCS = 27; // number of access regions used by TraceMonkey
|
||||
|
||||
enum JSTNErrType { INFALLIBLE, FAIL_STATUS, FAIL_NULL, FAIL_NEG, FAIL_NEITHER };
|
||||
enum {
|
||||
JSTN_ERRTYPE_MASK = 0x07,
|
||||
|
@ -43,6 +43,7 @@
|
||||
/*
|
||||
* JavaScript iterators.
|
||||
*/
|
||||
#include "jscntxt.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsversion.h"
|
||||
|
@ -48,6 +48,7 @@
|
||||
#endif
|
||||
|
||||
#include "jsbit.h"
|
||||
#include "jsstaticcheck.h"
|
||||
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
@ -456,6 +457,14 @@ Max(T t1, T t2)
|
||||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
/* Allows a const variable to be initialized after its declaration. */
|
||||
template <class T>
|
||||
static T&
|
||||
InitConst(const T &t)
|
||||
{
|
||||
return const_cast<T &>(t);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jstl_h_ */
|
||||
|
2745
js/src/jstracer.cpp
2745
js/src/jstracer.cpp
File diff suppressed because it is too large
Load Diff
@ -52,13 +52,10 @@
|
||||
#include "jslock.h"
|
||||
#include "jsnum.h"
|
||||
#include "jsvector.h"
|
||||
#include "Writer.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
#if defined(DEBUG) && !defined(JS_JIT_SPEW)
|
||||
#define JS_JIT_SPEW
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class Queue {
|
||||
T* _data;
|
||||
@ -230,25 +227,6 @@ public:
|
||||
TreeFragment* toTreeFragment();
|
||||
};
|
||||
|
||||
#if defined(JS_JIT_SPEW) || defined(NJ_NO_VARIADIC_MACROS)
|
||||
|
||||
enum LC_TMBits {
|
||||
/*
|
||||
* Output control bits for all non-Nanojit code. Only use bits 16 and
|
||||
* above, since Nanojit uses 0 .. 15 itself.
|
||||
*/
|
||||
LC_TMMinimal = 1<<16,
|
||||
LC_TMTracer = 1<<17,
|
||||
LC_TMRecorder = 1<<18,
|
||||
LC_TMAbort = 1<<19,
|
||||
LC_TMStats = 1<<20,
|
||||
LC_TMRegexp = 1<<21,
|
||||
LC_TMTreeVis = 1<<22,
|
||||
LC_TMProfiler = 1<<23
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NJ_NO_VARIADIC_MACROS
|
||||
|
||||
#define debug_only_stmt(action) /* */
|
||||
@ -1045,10 +1023,6 @@ class TraceRecorder
|
||||
/* If non-null, the side exit from which we are growing. */
|
||||
VMSideExit* const anchor;
|
||||
|
||||
/* The LIR-generation pipeline used to build |fragment|. */
|
||||
nanojit::LirWriter* const lir;
|
||||
nanojit::CseFilter* const cse_filter;
|
||||
|
||||
/* Instructions yielding the corresponding trace-const members of TracerState. */
|
||||
nanojit::LIns* const cx_ins;
|
||||
nanojit::LIns* const eos_ins;
|
||||
@ -1137,25 +1111,28 @@ class TraceRecorder
|
||||
/* Temporary JSValueType array used to construct temporary typemaps. */
|
||||
js::Vector<JSValueType, 256> tempTypeMap;
|
||||
|
||||
/* Used to generate LIR. Has a short name because it's used a lot. */
|
||||
tjit::Writer w;
|
||||
|
||||
/************************************************************* 10 bajillion member functions */
|
||||
|
||||
/*
|
||||
* These can be put around a control-flow diamond if it's important that
|
||||
* CSE work across the diamond. Duplicated expressions within the diamond
|
||||
* will be CSE'd, but expressions defined within the diamond won't be
|
||||
* added to the tables of CSEable expressions. Loads are still
|
||||
* invalidated if they alias any stores that occur within diamonds.
|
||||
/*
|
||||
* These would be in Writer if they didn't modify TraceRecorder state.
|
||||
* They are invoked the via macros below that make them look like they are
|
||||
* part of Writer (hence the "w_" prefix, which looks like "w.").
|
||||
*/
|
||||
void suspendCSE() { if (cse_filter) cse_filter->suspend(); }
|
||||
void resumeCSE() { if (cse_filter) cse_filter->resume(); }
|
||||
nanojit::LIns* w_immpObjGC(JSObject* obj);
|
||||
nanojit::LIns* w_immpFunGC(JSFunction* fun);
|
||||
nanojit::LIns* w_immpStrGC(JSString* str);
|
||||
nanojit::LIns* w_immpShapeGC(const js::Shape* shape);
|
||||
nanojit::LIns* w_immpIdGC(jsid id);
|
||||
|
||||
nanojit::LIns* insImmVal(const Value& val);
|
||||
nanojit::LIns* insImmObj(JSObject* obj);
|
||||
nanojit::LIns* insImmFun(JSFunction* fun);
|
||||
nanojit::LIns* insImmStr(JSString* str);
|
||||
nanojit::LIns* insImmShape(const js::Shape* shape);
|
||||
nanojit::LIns* insImmId(jsid id);
|
||||
nanojit::LIns* p2i(nanojit::LIns* ins);
|
||||
#define immpObjGC(obj) name(w_immpObjGC(obj), #obj)
|
||||
#define immpFunGC(fun) name(w_immpFunGC(fun), #fun)
|
||||
#define immpStrGC(str) name(w_immpStrGC(str), #str)
|
||||
#define immpAtomGC(atom) name(w_immpStrGC(ATOM_TO_STRING(atom)), "ATOM_TO_STRING(" #atom ")")
|
||||
#define immpShapeGC(shape) name(w_immpShapeGC(shape), #shape)
|
||||
#define immpIdGC(id) name(w_immpIdGC(id), #id)
|
||||
|
||||
/*
|
||||
* Examines current interpreter state to record information suitable for returning to the
|
||||
@ -1197,11 +1174,9 @@ class TraceRecorder
|
||||
JS_REQUIRES_STACK ptrdiff_t nativeStackSlot(const Value* p) const;
|
||||
JS_REQUIRES_STACK ptrdiff_t nativespOffsetImpl(const void* p) const;
|
||||
JS_REQUIRES_STACK ptrdiff_t nativespOffset(const Value* p) const;
|
||||
JS_REQUIRES_STACK void importImpl(nanojit::LIns* base, ptrdiff_t offset, nanojit::AccSet accSet,
|
||||
const void* p, JSValueType t,
|
||||
JS_REQUIRES_STACK void importImpl(tjit::Address addr, const void* p, JSValueType t,
|
||||
const char *prefix, uintN index, JSStackFrame *fp);
|
||||
JS_REQUIRES_STACK void import(nanojit::LIns* base, ptrdiff_t offset, nanojit::AccSet accSet,
|
||||
const Value* p, JSValueType t,
|
||||
JS_REQUIRES_STACK void import(tjit::Address addr, const Value* p, JSValueType t,
|
||||
const char *prefix, uintN index, JSStackFrame *fp);
|
||||
JS_REQUIRES_STACK void import(TreeFragment* tree, nanojit::LIns* sp, unsigned stackSlots,
|
||||
unsigned callDepth, unsigned ngslots, JSValueType* typeMap);
|
||||
@ -1220,9 +1195,6 @@ class TraceRecorder
|
||||
JS_REQUIRES_STACK nanojit::LIns* guard_xov(nanojit::LOpcode op, nanojit::LIns* d0,
|
||||
nanojit::LIns* d1, VMSideExit* exit);
|
||||
|
||||
nanojit::LIns* addName(nanojit::LIns* ins, const char* name);
|
||||
nanojit::LIns* insComment(const char* str);
|
||||
|
||||
nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset,
|
||||
bool demote);
|
||||
|
||||
@ -1290,7 +1262,7 @@ class TraceRecorder
|
||||
JS_REQUIRES_STACK nanojit::LIns* var(unsigned n);
|
||||
JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i);
|
||||
JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, Value& v);
|
||||
nanojit::LIns* stackLoad(nanojit::LIns* addr, nanojit::AccSet accSet, uint8 type);
|
||||
nanojit::LIns* stackLoad(tjit::Address addr, uint8 type);
|
||||
JS_REQUIRES_STACK nanojit::LIns* stack(int n);
|
||||
JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i);
|
||||
|
||||
@ -1298,14 +1270,8 @@ class TraceRecorder
|
||||
JS_REQUIRES_STACK nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1,
|
||||
nanojit::LIns* s0, nanojit::LIns* s1);
|
||||
|
||||
bool condBranch(nanojit::LOpcode op, nanojit::LIns* cond, nanojit::LIns** brOut);
|
||||
nanojit::LIns* unoptimizableCondBranch(nanojit::LOpcode op, nanojit::LIns* cond);
|
||||
void labelForBranch(nanojit::LIns* br);
|
||||
void labelForBranches(nanojit::LIns* br1, nanojit::LIns* br2);
|
||||
|
||||
nanojit::LIns* i2d(nanojit::LIns* i);
|
||||
nanojit::LIns* d2i(nanojit::LIns* f, bool resultCanBeImpreciseIfFractional = false);
|
||||
nanojit::LIns* f2u(nanojit::LIns* f);
|
||||
nanojit::LIns* d2u(nanojit::LIns* d);
|
||||
JS_REQUIRES_STACK RecordingStatus makeNumberInt32(nanojit::LIns* d, nanojit::LIns** num_ins);
|
||||
JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v);
|
||||
|
||||
@ -1349,8 +1315,6 @@ class TraceRecorder
|
||||
|
||||
void forgetGuardedShapes();
|
||||
|
||||
inline nanojit::LIns* shape_ins(nanojit::LIns *obj_ins);
|
||||
inline nanojit::LIns* slots(nanojit::LIns *obj_ins);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
JSObject*& obj2, PCVal& pcval);
|
||||
JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins,
|
||||
@ -1366,16 +1330,8 @@ class TraceRecorder
|
||||
void stobj_set_slot(JSObject *obj, nanojit::LIns* obj_ins, unsigned slot,
|
||||
nanojit::LIns*& slots_ins, const Value &v, nanojit::LIns* v_ins);
|
||||
|
||||
nanojit::LIns* stobj_get_slot_uint32(nanojit::LIns* obj_ins, unsigned slot);
|
||||
nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
|
||||
VMSideExit *exit);
|
||||
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins);
|
||||
nanojit::LIns* stobj_get_private(nanojit::LIns* obj_ins);
|
||||
nanojit::LIns* stobj_get_private_uint32(nanojit::LIns* obj_ins);
|
||||
nanojit::LIns* stobj_get_proto(nanojit::LIns* obj_ins);
|
||||
|
||||
/* For slots holding private pointers. */
|
||||
nanojit::LIns* stobj_get_const_private_ptr(nanojit::LIns *obj_ins, unsigned slot);
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus name(Value*& vp, nanojit::LIns*& ins, NameResult& nr);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
@ -1391,14 +1347,12 @@ class TraceRecorder
|
||||
VMSideExit* exit);
|
||||
JS_REQUIRES_STACK nanojit::LIns *canonicalizeNaNs(nanojit::LIns *dval_ins);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus typedArrayElement(Value& oval, Value& idx, Value*& vp,
|
||||
nanojit::LIns*& v_ins,
|
||||
nanojit::LIns*& addr_ins);
|
||||
nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus getProp(Value& v);
|
||||
JS_REQUIRES_STACK RecordingStatus getThis(nanojit::LIns*& this_ins);
|
||||
|
||||
JS_REQUIRES_STACK void storeMagic(JSWhyMagic why, nanojit::LIns *addr_ins, ptrdiff_t offset,
|
||||
nanojit::AccSet accSet);
|
||||
JS_REQUIRES_STACK void storeMagic(JSWhyMagic why, tjit::Address addr);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus unboxNextValue(nanojit::LIns* &v_ins);
|
||||
|
||||
JS_REQUIRES_STACK VMSideExit* enterDeepBailCall();
|
||||
@ -1419,9 +1373,6 @@ class TraceRecorder
|
||||
nanojit::LIns* obj_ins,
|
||||
const js::Shape* shape);
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* getStringLengthAndFlags(nanojit::LIns* str_ins);
|
||||
JS_REQUIRES_STACK nanojit::LIns* getStringLength(nanojit::LIns* str_ins);
|
||||
JS_REQUIRES_STACK nanojit::LIns* getStringChars(nanojit::LIns* str_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getCharCodeAt(JSString *str,
|
||||
nanojit::LIns* str_ins, nanojit::LIns* idx_ins,
|
||||
nanojit::LIns** out_ins);
|
||||
@ -1449,18 +1400,15 @@ class TraceRecorder
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus setElem(int lval_spindex, int idx_spindex,
|
||||
int v_spindex);
|
||||
|
||||
void box_undefined_into(nanojit::LIns *dstaddr_ins, ptrdiff_t offset, nanojit::AccSet accSet);
|
||||
void box_undefined_into(tjit::Address addr);
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
void box_null_into(nanojit::LIns *dstaddr_ins, ptrdiff_t offset, nanojit::AccSet accSet);
|
||||
nanojit::LIns* unbox_number_as_double(nanojit::LIns* vaddr_ins, ptrdiff_t offset,
|
||||
nanojit::LIns* tag_ins, VMSideExit* exit,
|
||||
nanojit::AccSet accSet);
|
||||
nanojit::LIns* unbox_object(nanojit::LIns* vaddr_ins, ptrdiff_t offset,
|
||||
nanojit::LIns* tag_ins, JSValueType type, VMSideExit* exit,
|
||||
nanojit::AccSet accSet);
|
||||
nanojit::LIns* unbox_non_double_object(nanojit::LIns* vaddr_ins, ptrdiff_t offset,
|
||||
nanojit::LIns* tag_ins, JSValueType type,
|
||||
VMSideExit* exit, nanojit::AccSet accSet);
|
||||
void box_null_into(tjit::Address addr);
|
||||
nanojit::LIns* unbox_number_as_double(tjit::Address addr, nanojit::LIns* tag_ins,
|
||||
VMSideExit* exit);
|
||||
nanojit::LIns* unbox_object(tjit::Address addr, nanojit::LIns* tag_ins, JSValueType type,
|
||||
VMSideExit* exit);
|
||||
nanojit::LIns* unbox_non_double_object(tjit::Address addr, nanojit::LIns* tag_ins,
|
||||
JSValueType type, VMSideExit* exit);
|
||||
#elif JS_BITS_PER_WORD == 64
|
||||
nanojit::LIns* non_double_object_value_has_type(nanojit::LIns* v_ins, JSValueType type);
|
||||
nanojit::LIns* unpack_ptr(nanojit::LIns* v_ins);
|
||||
@ -1469,22 +1417,18 @@ class TraceRecorder
|
||||
nanojit::LIns* unbox_non_double_object(nanojit::LIns* v_ins, JSValueType type, VMSideExit* exit);
|
||||
#endif
|
||||
|
||||
nanojit::LIns* unbox_value(const Value& v, nanojit::LIns* vaddr_ins,
|
||||
ptrdiff_t offset, nanojit::AccSet accSet, VMSideExit* exit,
|
||||
nanojit::LIns* unbox_value(const Value& v, tjit::Address addr, VMSideExit* exit,
|
||||
bool force_double=false);
|
||||
void unbox_any_object(nanojit::LIns* vaddr_ins, nanojit::LIns** obj_ins,
|
||||
nanojit::LIns** is_obj_ins, nanojit::AccSet accSet);
|
||||
nanojit::LIns* is_boxed_true(nanojit::LIns* vaddr_ins, nanojit::AccSet accSet);
|
||||
nanojit::LIns* is_boxed_magic(nanojit::LIns* vaddr_ins, JSWhyMagic why, nanojit::AccSet accSet);
|
||||
void unbox_any_object(tjit::Address addr, nanojit::LIns** obj_ins, nanojit::LIns** is_obj_ins);
|
||||
nanojit::LIns* is_boxed_true(tjit::Address addr);
|
||||
nanojit::LIns* is_boxed_magic(tjit::Address addr, JSWhyMagic why);
|
||||
|
||||
nanojit::LIns* is_string_id(nanojit::LIns* id_ins);
|
||||
nanojit::LIns* unbox_string_id(nanojit::LIns* id_ins);
|
||||
nanojit::LIns* unbox_int_id(nanojit::LIns* id_ins);
|
||||
|
||||
/* Box a slot on trace into the given address at the given offset. */
|
||||
void box_value_into(const Value& v, nanojit::LIns* v_ins,
|
||||
nanojit::LIns* dstaddr_ins, ptrdiff_t offset,
|
||||
nanojit::AccSet accSet);
|
||||
void box_value_into(const Value& v, nanojit::LIns* v_ins, tjit::Address addr);
|
||||
|
||||
/*
|
||||
* Box a slot so that it may be passed with value semantics to a native. On
|
||||
|
548
js/src/tracejit/Writer.cpp
Normal file
548
js/src/tracejit/Writer.cpp
Normal file
@ -0,0 +1,548 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** 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 Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* May 28, 2008.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Nicholas Nethercote <nnethercote@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
#include "jsprf.h"
|
||||
#include "jstl.h"
|
||||
#include "Writer.h"
|
||||
#include "nanojit.h"
|
||||
|
||||
namespace js {
|
||||
namespace tjit {
|
||||
|
||||
using namespace nanojit;
|
||||
|
||||
class FuncFilter : public LirWriter
|
||||
{
|
||||
public:
|
||||
FuncFilter(LirWriter *out):
|
||||
LirWriter(out)
|
||||
{
|
||||
}
|
||||
|
||||
LIns *ins2(LOpcode v, LIns *s0, LIns *s1)
|
||||
{
|
||||
if (s0 == s1 && v == LIR_eqd) {
|
||||
if (IsPromote(s0)) {
|
||||
// double(int) and double(uint) cannot be nan
|
||||
return insImmI(1);
|
||||
}
|
||||
if (s0->isop(LIR_muld) || s0->isop(LIR_subd) || s0->isop(LIR_addd)) {
|
||||
LIns *lhs = s0->oprnd1();
|
||||
LIns *rhs = s0->oprnd2();
|
||||
if (IsPromote(lhs) && IsPromote(rhs)) {
|
||||
// add/sub/mul promoted ints can't be nan
|
||||
return insImmI(1);
|
||||
}
|
||||
}
|
||||
} else if (isCmpDOpcode(v)) {
|
||||
if (IsPromoteInt(s0) && IsPromoteInt(s1)) {
|
||||
// demote fcmp to cmp
|
||||
v = cmpOpcodeD2I(v);
|
||||
return out->ins2(v, Demote(out, s0), Demote(out, s1));
|
||||
} else if (IsPromoteUint(s0) && IsPromoteUint(s1)) {
|
||||
// uint compare
|
||||
v = cmpOpcodeD2UI(v);
|
||||
return out->ins2(v, Demote(out, s0), Demote(out, s1));
|
||||
}
|
||||
}
|
||||
return out->ins2(v, s0, s1);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
Writer::init(LogControl *logc_)
|
||||
{
|
||||
JS_ASSERT(logc_);
|
||||
logc = logc_;
|
||||
|
||||
LirWriter *&lir = InitConst(this->lir);
|
||||
CseFilter *&cse = InitConst(this->cse);
|
||||
lir = new (alloc) LirBufWriter(lirbuf, AvmCore::config);
|
||||
#ifdef DEBUG
|
||||
ValidateWriter *validate2;
|
||||
lir = validate2 =
|
||||
new (alloc) ValidateWriter(lir, lirbuf->printer, "end of writer pipeline");
|
||||
#endif
|
||||
#ifdef JS_JIT_SPEW
|
||||
if (logc->lcbits & LC_TMRecorder)
|
||||
lir = new (alloc) VerboseWriter(*alloc, lir, lirbuf->printer, logc);
|
||||
#endif
|
||||
// CseFilter must be downstream of SoftFloatFilter (see bug 527754 for why).
|
||||
if (avmplus::AvmCore::config.cseopt)
|
||||
lir = cse = new (alloc) CseFilter(lir, TM_NUM_USED_ACCS, *alloc);
|
||||
lir = new (alloc) ExprFilter(lir);
|
||||
lir = new (alloc) FuncFilter(lir);
|
||||
#ifdef DEBUG
|
||||
ValidateWriter *validate1 =
|
||||
new (alloc) ValidateWriter(lir, lirbuf->printer, "start of writer pipeline");
|
||||
lir = validate1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
IsPromoteInt(LIns* ins)
|
||||
{
|
||||
if (ins->isop(LIR_i2d))
|
||||
return true;
|
||||
if (ins->isImmD()) {
|
||||
jsdouble d = ins->immD();
|
||||
return d == jsdouble(jsint(d)) && !JSDOUBLE_IS_NEGZERO(d);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
IsPromoteUint(LIns* ins)
|
||||
{
|
||||
if (ins->isop(LIR_ui2d))
|
||||
return true;
|
||||
if (ins->isImmD()) {
|
||||
jsdouble d = ins->immD();
|
||||
return d == jsdouble(jsuint(d)) && !JSDOUBLE_IS_NEGZERO(d);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
IsPromote(LIns* ins)
|
||||
{
|
||||
return IsPromoteInt(ins) || IsPromoteUint(ins);
|
||||
}
|
||||
|
||||
LIns *
|
||||
Demote(LirWriter *out, LIns *ins)
|
||||
{
|
||||
JS_ASSERT(ins->isD());
|
||||
if (ins->isCall())
|
||||
return ins->callArgN(0);
|
||||
if (ins->isop(LIR_i2d) || ins->isop(LIR_ui2d))
|
||||
return ins->oprnd1();
|
||||
JS_ASSERT(ins->isImmD());
|
||||
double cf = ins->immD();
|
||||
int32_t ci = cf > 0x7fffffff ? uint32_t(cf) : int32_t(cf);
|
||||
return out->insImmI(ci);
|
||||
}
|
||||
|
||||
} /* namespace tjit */
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef DEBUG
|
||||
namespace nanojit {
|
||||
|
||||
using namespace js;
|
||||
using namespace js::tjit;
|
||||
|
||||
static bool
|
||||
match(LIns *base, LOpcode opcode, AccSet accSet, int32_t disp)
|
||||
{
|
||||
return base->isop(opcode) &&
|
||||
base->accSet() == accSet &&
|
||||
base->disp() == disp;
|
||||
}
|
||||
|
||||
static bool
|
||||
match(LIns *base, LOpcode opcode, AccSet accSet, LoadQual loadQual, int32_t disp)
|
||||
{
|
||||
return base->isop(opcode) &&
|
||||
base->accSet() == accSet &&
|
||||
base->loadQual() == loadQual &&
|
||||
base->disp() == disp;
|
||||
}
|
||||
|
||||
static bool
|
||||
couldBeObjectOrString(LIns *ins)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (ins->isop(LIR_callp)) {
|
||||
// ins = callp ... # could be a call to an object-creating function
|
||||
ret = true;
|
||||
|
||||
} else if (ins->isop(LIR_ldp)) {
|
||||
// ins = ldp ... # could be an object, eg. loaded from the stack
|
||||
ret = true;
|
||||
|
||||
} else if (ins->isImmP()) {
|
||||
// ins = immp ... # could be a pointer to an object
|
||||
uintptr_t val = uintptr_t(ins->immP());
|
||||
if (val == 0 || val > 4096)
|
||||
ret = true; // Looks like a pointer
|
||||
|
||||
} else if (ins->isop(LIR_cmovp)) {
|
||||
// ins = cmovp <JSObject>, <JSObject>
|
||||
ret = couldBeObjectOrString(ins->oprnd2()) &&
|
||||
couldBeObjectOrString(ins->oprnd3());
|
||||
|
||||
} else if (!avmplus::AvmCore::use_cmov() &&
|
||||
ins->isop(LIR_ori) &&
|
||||
ins->oprnd1()->isop(LIR_andi) &&
|
||||
ins->oprnd2()->isop(LIR_andi))
|
||||
{
|
||||
// This is a partial check for the insChoose() code that only occurs
|
||||
// is use_cmov() is false.
|
||||
//
|
||||
// ins_oprnd1 = andi ...
|
||||
// ins_oprnd2 = andi ...
|
||||
// ins = ori ins_oprnd1, ins_oprnd2
|
||||
ret = true;
|
||||
|
||||
#if JS_BITS_PER_WORD == 64
|
||||
} else if (ins->isop(LIR_andq) &&
|
||||
ins->oprnd1()->isop(LIR_ldq) &&
|
||||
ins->oprnd2()->isImmQ() &&
|
||||
uintptr_t(ins->oprnd2()->immQ()) == JSVAL_PAYLOAD_MASK)
|
||||
{
|
||||
// ins_oprnd1 = ldq ...
|
||||
// ins_oprnd2 = immq JSVAL_PAYLOAD_MASK
|
||||
// ins = andq ins_oprnd1, ins_oprnd2
|
||||
ret = true;
|
||||
#endif
|
||||
} else if (ins->isop(LIR_addp) &&
|
||||
((ins->oprnd1()->isImmP() &&
|
||||
(void *)ins->oprnd1()->immP() == JSString::unitStringTable) ||
|
||||
(ins->oprnd2()->isImmP() &&
|
||||
(void *)ins->oprnd2()->immP() == JSString::unitStringTable)))
|
||||
{
|
||||
// (String only)
|
||||
// ins = addp ..., JSString::unitStringTable
|
||||
// OR
|
||||
// ins = addp JSString::unitStringTable, ...
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
isConstPrivatePtr(LIns *ins, unsigned slot)
|
||||
{
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
// ins = ldp.slots/c ...[<offset of slot>]
|
||||
return match(ins, LIR_ldp, ACCSET_SLOTS, LOAD_CONST, slot * sizeof(Value) + sPayloadOffset);
|
||||
#elif JS_BITS_PER_WORD == 64
|
||||
// ins_oprnd1 = ldp.slots/c ...[<offset of slot>]
|
||||
// ins_oprnd2 = immi 1
|
||||
// ins = lshq ins_oprnd1, ins_oprnd2
|
||||
return ins->isop(LIR_lshq) &&
|
||||
match(ins->oprnd1(), LIR_ldp, ACCSET_SLOTS, LOAD_CONST, slot * sizeof(Value)) &&
|
||||
ins->oprnd2()->isImmI(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Any time you use an AccSet annotation other than ACCSET_ALL, you are making
|
||||
* a promise to Nanojit about the properties of the annotated load/store/call.
|
||||
* If that annotation is wrong, it could cause rare and subtle bugs. So this
|
||||
* function does its damnedest to prevent such bugs occurring by carefully
|
||||
* checking every load and store.
|
||||
*
|
||||
* For some access regions, we can check perfectly -- eg. for an ACCSET_STATE
|
||||
* load/store, the base pointer must be 'state'. For others, we can only
|
||||
* check imperfectly -- eg. for an ACCSET_OBJ_CLASP load/store, we can check that
|
||||
* the base pointer has one of several forms, but it's possible that a
|
||||
* non-object has that form as well. This imperfect checking is unfortunate
|
||||
* but unavoidable. Also, multi-region load/store AccSets are not checked,
|
||||
* and so are best avoided (they're rarely needed). Finally, the AccSet
|
||||
* annotations on calls cannot be checked here; in some cases they can be
|
||||
* partially checked via assertions (eg. by checking that certain values
|
||||
* are not changed by the function).
|
||||
*/
|
||||
void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet accSet)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
NanoAssert(accSet != ACCSET_NONE);
|
||||
|
||||
#define dispWithin(Struct) \
|
||||
(0 <= disp && disp < int32_t(sizeof(Struct)))
|
||||
|
||||
switch (accSet) {
|
||||
case ACCSET_STATE:
|
||||
// base = paramp 0 0
|
||||
// ins = {ld,st}X.state base[<disp within TracerState>]
|
||||
ok = dispWithin(TracerState) &&
|
||||
base->isop(LIR_paramp) &&
|
||||
base->paramKind() == 0 &&
|
||||
base->paramArg() == 0;
|
||||
break;
|
||||
|
||||
case ACCSET_STACK:
|
||||
// base = ldp.state ...[offsetof(TracerState, sp)]
|
||||
// ins = {ld,st}X.sp base[...]
|
||||
// OR
|
||||
// base_oprnd1 = ldp.state ...[offsetof(TraceState, sp)]
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = {ld,st}X.sp base[...]
|
||||
ok = match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, sp)) ||
|
||||
(base->isop(LIR_addp) &&
|
||||
match(base->oprnd1(), LIR_ldp, ACCSET_STATE, offsetof(TracerState, sp)));
|
||||
break;
|
||||
|
||||
case ACCSET_RSTACK:
|
||||
// base = ldp.state ...[offsetof(TracerState, rp)]
|
||||
// ins = {ld,st}p.rp base[...]
|
||||
// OR
|
||||
// base = ldp.state ...[offsetof(TracerState, callstackBaseOffset)]
|
||||
// ins = {ld,st}p.rp base[...]
|
||||
ok = (op == LIR_ldp || op == LIR_stp) &&
|
||||
(match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, rp)) ||
|
||||
match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, callstackBase)));
|
||||
break;
|
||||
|
||||
case ACCSET_CX:
|
||||
// base = ldp.state ...[offsetof(TracerState, cx)]
|
||||
// ins = {ld,st}X.cx base[<disp within JSContext>]
|
||||
ok = dispWithin(JSContext) &&
|
||||
match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, cx));
|
||||
break;
|
||||
|
||||
case ACCSET_EOS:
|
||||
// base = ldp.state ...[offsetof(TracerState, eos)]
|
||||
// ins = {ld,st}X.eos base[...]
|
||||
ok = match(base, LIR_ldp, ACCSET_STATE, offsetof(TracerState, eos));
|
||||
break;
|
||||
|
||||
case ACCSET_ALLOC:
|
||||
// base = allocp ...
|
||||
// ins = {ld,st}X.alloc base[...]
|
||||
// OR
|
||||
// base_oprnd1 = allocp ...
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = {ld,st}X.alloc base[...]
|
||||
ok = base->isop(LIR_allocp) ||
|
||||
(base->isop(LIR_addp) &&
|
||||
base->oprnd1()->isop(LIR_allocp));
|
||||
break;
|
||||
|
||||
case ACCSET_FRAMEREGS:
|
||||
// base = ldp.cx ...[offsetof(JSContext, regs)]
|
||||
// ins = ldp.regs base[<disp within JSFrameRegs>]
|
||||
ok = op == LIR_ldp &&
|
||||
dispWithin(JSFrameRegs) &&
|
||||
match(base, LIR_ldp, ACCSET_CX, offsetof(JSContext, regs));
|
||||
break;
|
||||
|
||||
case ACCSET_STACKFRAME:
|
||||
// base = ldp.regs ...[offsetof(JSFrameRegs, fp)]
|
||||
// ins = {ld,st}X.sf base[<disp within JSStackFrame>]
|
||||
ok = dispWithin(JSStackFrame) &&
|
||||
match(base, LIR_ldp, ACCSET_FRAMEREGS, offsetof(JSFrameRegs, fp));
|
||||
break;
|
||||
|
||||
case ACCSET_RUNTIME:
|
||||
// base = ldp.cx ...[offsetof(JSContext, runtime)]
|
||||
// ins = ldp.rt base[<disp within JSRuntime>]
|
||||
ok = dispWithin(JSRuntime) &&
|
||||
match(base, LIR_ldp, ACCSET_CX, offsetof(JSContext, runtime));
|
||||
break;
|
||||
|
||||
// This check is imperfect.
|
||||
//
|
||||
// base = <JSObject>
|
||||
// ins = ldp.obj<field> base[offsetof(JSObject, <field>)]
|
||||
#define OK_OBJ_FIELD(ldop, field) \
|
||||
op == ldop && \
|
||||
disp == offsetof(JSObject, field) && \
|
||||
couldBeObjectOrString(base)
|
||||
|
||||
case ACCSET_OBJ_CLASP:
|
||||
ok = OK_OBJ_FIELD(LIR_ldp, clasp);
|
||||
break;
|
||||
|
||||
case ACCSET_OBJ_FLAGS:
|
||||
ok = OK_OBJ_FIELD(LIR_ldi, flags);
|
||||
break;
|
||||
|
||||
case ACCSET_OBJ_SHAPE:
|
||||
ok = OK_OBJ_FIELD(LIR_ldi, objShape);
|
||||
break;
|
||||
|
||||
case ACCSET_OBJ_PROTO:
|
||||
ok = OK_OBJ_FIELD(LIR_ldp, proto);
|
||||
break;
|
||||
|
||||
case ACCSET_OBJ_PARENT:
|
||||
ok = OK_OBJ_FIELD(LIR_ldp, parent);
|
||||
break;
|
||||
|
||||
case ACCSET_OBJ_PRIVATE:
|
||||
// base = <JSObject>
|
||||
// ins = ldp.objprivate base[offsetof(JSObject, privateData)]
|
||||
ok = (op == LIR_ldi || op == LIR_ldp) &&
|
||||
disp == offsetof(JSObject, privateData) &&
|
||||
couldBeObjectOrString(base);
|
||||
break;
|
||||
|
||||
case ACCSET_OBJ_CAPACITY:
|
||||
ok = OK_OBJ_FIELD(LIR_ldi, capacity);
|
||||
break;
|
||||
|
||||
case ACCSET_OBJ_SLOTS:
|
||||
ok = OK_OBJ_FIELD(LIR_ldp, slots);
|
||||
break;
|
||||
|
||||
case ACCSET_SLOTS:
|
||||
// This check is imperfect.
|
||||
//
|
||||
// base = <JSObject> # direct slot access
|
||||
// ins = {ld,st}X.slots base[...]
|
||||
// OR
|
||||
// base = ldp.objslots ...[offsetof(JSObject, slots)] # indirect slot access
|
||||
// ins = {ld,st}X.slots base[...]
|
||||
// OR
|
||||
// base_oprnd1 = ldp.objslots ...[offsetof(JSObject, slots)] # indirect scaled slot access
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = {ld,st}X.slots base[...]
|
||||
ok = couldBeObjectOrString(base) ||
|
||||
match(base, LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots)) ||
|
||||
(base->isop(LIR_addp) &&
|
||||
match(base->oprnd1(), LIR_ldp, ACCSET_OBJ_SLOTS, offsetof(JSObject, slots)));
|
||||
break;
|
||||
|
||||
case ACCSET_TARRAY:
|
||||
// This check is imperfect.
|
||||
//
|
||||
// base = ldp.objprivate ...[offsetof(JSObject, privateData)]
|
||||
// ins = ld{i,p}.tarray base[<disp within TypedArray>]
|
||||
ok = (op == LIR_ldi || op == LIR_ldp) &&
|
||||
dispWithin(TypedArray) &&
|
||||
match(base, LIR_ldp, ACCSET_OBJ_PRIVATE, offsetof(JSObject, privateData));
|
||||
break;
|
||||
|
||||
case ACCSET_TARRAY_DATA:
|
||||
// base_oprnd1 = ldp.tarray ...[TypedArray::dataOffset()]
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = {ld,st}X.tdata base[...]
|
||||
ok = base->isop(LIR_addp) &&
|
||||
match(base->oprnd1(), LIR_ldp, ACCSET_TARRAY, TypedArray::dataOffset());
|
||||
break;
|
||||
|
||||
case ACCSET_ITER:
|
||||
// base = ldp.objprivate ...[offsetof(JSObject, privateData)]
|
||||
// ins = {ld,st}p.iter base[<disp within NativeIterator>]
|
||||
ok = (op == LIR_ldp || op == LIR_stp) &&
|
||||
dispWithin(NativeIterator) &&
|
||||
match(base, LIR_ldp, ACCSET_OBJ_PRIVATE, offsetof(JSObject, privateData));
|
||||
break;
|
||||
|
||||
case ACCSET_ITER_PROPS:
|
||||
// base = ldp.iter ...[offsetof(NativeIterator, props_cursor)]
|
||||
// ins = ld{i,p,d}.iterprops base[0|4]
|
||||
ok = (op == LIR_ldi || op == LIR_ldp || op == LIR_ldd) &&
|
||||
(disp == 0 || disp == 4) &&
|
||||
match(base, LIR_ldp, ACCSET_ITER, offsetof(NativeIterator, props_cursor));
|
||||
break;
|
||||
|
||||
case ACCSET_STRING:
|
||||
// This check is imperfect.
|
||||
//
|
||||
// base = <JSString>
|
||||
// ins = {ld,st}X.str base[<disp within JSString>]
|
||||
ok = dispWithin(JSString) &&
|
||||
couldBeObjectOrString(base);
|
||||
break;
|
||||
|
||||
case ACCSET_STRING_MCHARS:
|
||||
// base = ldp.string ...[offsetof(JSString, mChars)]
|
||||
// ins = ldus2ui.strchars/c base[0]
|
||||
// OR
|
||||
// base_oprnd1 = ldp.string ...[offsetof(JSString, mChars)]
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = ldus2ui.strchars/c base[0]
|
||||
ok = op == LIR_ldus2ui &&
|
||||
disp == 0 &&
|
||||
(match(base, LIR_ldp, ACCSET_STRING, offsetof(JSString, mChars)) ||
|
||||
(base->isop(LIR_addp) &&
|
||||
match(base->oprnd1(), LIR_ldp, ACCSET_STRING, offsetof(JSString, mChars))));
|
||||
break;
|
||||
|
||||
case ACCSET_TYPEMAP:
|
||||
// This check is imperfect, things get complicated once you get back
|
||||
// farther than 'base'. But the parts we check are pretty distinctive
|
||||
// and should be good enough.
|
||||
//
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = lduc2ui.typemap/c base[0]
|
||||
ok = op == LIR_lduc2ui &&
|
||||
disp == 0 &&
|
||||
base->isop(LIR_addp);
|
||||
break;
|
||||
|
||||
case ACCSET_FCSLOTS:
|
||||
// This check is imperfect.
|
||||
//
|
||||
// base = <const private ptr slots[JSSLOT_FLAT_CLOSURE_UPVARS]>
|
||||
// ins = {ld,st}X.fcslots base[...]
|
||||
ok = isConstPrivatePtr(base, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
|
||||
break;
|
||||
|
||||
case ACCSET_ARGS_DATA:
|
||||
// This check is imperfect.
|
||||
//
|
||||
// base = <const private ptr slots[JSSLOT_ARGS_DATA]>
|
||||
// ins = st{i,p,d}.argsdata base[...]
|
||||
// OR
|
||||
// base_oprnd1 = <const private ptr slots[JSSLOT_ARGS_DATA]>
|
||||
// base = addp base_oprnd1, ...
|
||||
// ins = {ld,st}X.argsdata base[...]
|
||||
ok = (isConstPrivatePtr(base, JSObject::JSSLOT_ARGS_DATA) ||
|
||||
(base->isop(LIR_addp) &&
|
||||
isConstPrivatePtr(base->oprnd1(), JSObject::JSSLOT_ARGS_DATA)));
|
||||
break;
|
||||
|
||||
default:
|
||||
// This assertion will fail if any single-region AccSets aren't covered
|
||||
// by the switch -- only multi-region AccSets should be handled here.
|
||||
JS_ASSERT(!isSingletonAccSet(accSet));
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
InsBuf b1, b2;
|
||||
printer->formatIns(&b1, base);
|
||||
JS_snprintf(b2.buf, b2.len, "base = (%s); disp = %d", b1.buf, disp);
|
||||
errorAccSet(lirNames[op], accSet, b2.buf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1185
js/src/tracejit/Writer.h
Normal file
1185
js/src/tracejit/Writer.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user