mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
571 lines
19 KiB
C++
571 lines
19 KiB
C++
/* -*- 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 "jscompartment.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) {
|
|
// 'eqd x, x' will always succeed if 'x' cannot be NaN
|
|
if (IsPromotedInt32OrUint32(s0)) {
|
|
// x = <a number that fits in int32 or uint32> # cannot be NaN
|
|
// c = eqd x, x
|
|
return insImmI(1);
|
|
}
|
|
if (s0->isop(LIR_addd) || s0->isop(LIR_subd) || s0->isop(LIR_muld)) {
|
|
LIns *lhs = s0->oprnd1();
|
|
LIns *rhs = s0->oprnd2();
|
|
if (IsPromotedInt32OrUint32(lhs) && IsPromotedInt32OrUint32(rhs)) {
|
|
// a = <a number that fits in int32 or uint32> # cannot be NaN
|
|
// b = <a number that fits in int32 or uint32> # cannot be NaN
|
|
// x = addd/subd/muld a, b # cannot be NaN
|
|
// c = eqd x, x
|
|
return insImmI(1);
|
|
}
|
|
}
|
|
} else if (isCmpDOpcode(v)) {
|
|
if (IsPromotedInt32(s0) && IsPromotedInt32(s1)) {
|
|
v = cmpOpcodeD2I(v);
|
|
return out->ins2(v, DemoteToInt32(out, s0), DemoteToInt32(out, s1));
|
|
} else if (IsPromotedUint32(s0) && IsPromotedUint32(s1)) {
|
|
// uint compare
|
|
v = cmpOpcodeD2UI(v);
|
|
return out->ins2(v, DemoteToUint32(out, s0), DemoteToUint32(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
|
|
if (avmplus::AvmCore::config.cseopt) {
|
|
cse = new (alloc) CseFilter(lir, TM_NUM_USED_ACCS, *alloc);
|
|
if (!cse->initOOM)
|
|
lir = cse; // Skip CseFilter if we OOM'd when creating it.
|
|
}
|
|
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
|
|
IsPromotedInt32(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
|
|
IsPromotedUint32(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
|
|
IsPromotedInt32OrUint32(LIns* ins)
|
|
{
|
|
return IsPromotedInt32(ins) || IsPromotedUint32(ins);
|
|
}
|
|
|
|
LIns *
|
|
DemoteToInt32(LirWriter *out, LIns *ins)
|
|
{
|
|
JS_ASSERT(IsPromotedInt32(ins));
|
|
if (ins->isop(LIR_i2d))
|
|
return ins->oprnd1();
|
|
JS_ASSERT(ins->isImmD());
|
|
return out->insImmI(int32_t(ins->immD()));
|
|
}
|
|
|
|
LIns *
|
|
DemoteToUint32(LirWriter *out, LIns *ins)
|
|
{
|
|
JS_ASSERT(IsPromotedUint32(ins));
|
|
if (ins->isop(LIR_ui2d))
|
|
return ins->oprnd1();
|
|
JS_ASSERT(ins->isImmD());
|
|
return out->insImmI(uint32_t(ins->immD()));
|
|
}
|
|
|
|
} /* 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_TM:
|
|
// base = immp
|
|
ok = base->isImmP() && disp == 0;
|
|
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 = {ld,st}p.objprivate base[offsetof(JSObject, privateData)]
|
|
ok = (op == LIR_ldi || op == LIR_ldp ||
|
|
op == LIR_sti || op == LIR_stp) &&
|
|
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 = ldp.tarray/c ...[TypedArray::dataOffset()]
|
|
// ins = {ld,st}X.tdata base[...]
|
|
// OR
|
|
// base_oprnd1 = ldp.tarray/c ...[TypedArray::dataOffset()]
|
|
// base = addp base_oprnd1, ...
|
|
// ins = {ld,st}X.tdata base[...]
|
|
ok = match(base, LIR_ldp, ACCSET_TARRAY, LOAD_CONST, TypedArray::dataOffset()) ||
|
|
(base->isop(LIR_addp) &&
|
|
match(base->oprnd1(), LIR_ldp, ACCSET_TARRAY, LOAD_CONST, 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, chars)]
|
|
// ins = ldus2ui.strchars/c base[0]
|
|
// OR
|
|
// base_oprnd1 = ldp.string ...[offsetof(JSString, chars)]
|
|
// base = addp base_oprnd1, ...
|
|
// ins = ldus2ui.strchars/c base[0]
|
|
ok = op == LIR_ldus2ui &&
|
|
disp == 0 &&
|
|
(match(base, LIR_ldp, ACCSET_STRING, JSString::offsetOfChars()) ||
|
|
(base->isop(LIR_addp) &&
|
|
match(base->oprnd1(), LIR_ldp, ACCSET_STRING, JSString::offsetOfChars())));
|
|
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
|
|
|