Back out 3de5ec9de48a:7a1ecef13ae9 (bug 840696) and 62fa6ee0a279 (bug 814823) for Android bustage

CLOSED TREE
This commit is contained in:
Phil Ringnalda 2013-02-18 23:15:27 -08:00
parent ca0778b23c
commit ada83cb5e4
13 changed files with 1086 additions and 1151 deletions

View File

@ -1277,8 +1277,7 @@ public:
void testq_i32r(int imm, RegisterID dst)
{
spew("testq $0x%x, %s",
imm, nameIReg(dst));
FIXME_INSN_PRINTING;
m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst);
m_formatter.immediate32(imm);
}

View File

@ -33,91 +33,6 @@ using mozilla::Maybe;
namespace js {
namespace ion {
// This out-of-line cache is used to do a double dispatch including it-self and
// the wrapped IonCache.
class OutOfLineUpdateCache :
public OutOfLineCodeBase<CodeGenerator>,
public IonCacheVisitor
{
private:
LInstruction *lir_;
RepatchLabel repatchEntry_;
size_t cacheIndex_;
public:
OutOfLineUpdateCache(LInstruction *lir, size_t cacheIndex)
: lir_(lir),
cacheIndex_(cacheIndex)
{ }
void bind(MacroAssembler *masm) {
masm->bind(&repatchEntry_);
}
size_t getCacheIndex() const {
return cacheIndex_;
}
LInstruction *lir() const {
return lir_;
}
RepatchLabel *repatchEntry() {
return &repatchEntry_;
}
bool accept(CodeGenerator *codegen) {
return codegen->visitOutOfLineCache(this);
}
// ICs' visit functions delegating the work to the CodeGen visit funtions.
#define VISIT_CACHE_FUNCTION(op) \
bool visit##op##IC(CodeGenerator *codegen, op##IC *ic) { \
return codegen->visit##op##IC(this, ic); \
}
IONCACHE_KIND_LIST(VISIT_CACHE_FUNCTION)
#undef VISIT_CACHE_FUNCTION
};
// This function is declared here because it needs to instantiate an
// OutOfLineUpdateCache, but we want to keep it visible inside the
// CodeGeneratorShared such as we can specialize inline caches in function of
// the architecture.
bool
CodeGeneratorShared::addCache(LInstruction *lir, size_t cacheIndex)
{
IonCache *cache = static_cast<IonCache *>(getCache(cacheIndex));
MInstruction *mir = lir->mirRaw()->toInstruction();
if (mir->resumePoint())
cache->setScriptedLocation(mir->block()->info().script(),
mir->resumePoint()->pc());
else
cache->setIdempotent();
OutOfLineUpdateCache *ool = new OutOfLineUpdateCache(lir, cacheIndex);
if (!addOutOfLineCode(ool))
return false;
CodeOffsetJump jump = masm.jumpWithPatch(ool->repatchEntry());
CodeOffsetLabel label = masm.labelForPatch();
masm.bind(ool->rejoin());
cache->setInlineJump(jump, label);
return true;
}
bool
CodeGenerator::visitOutOfLineCache(OutOfLineUpdateCache *ool)
{
size_t cacheIndex = ool->getCacheIndex();
IonCache *cache = static_cast<IonCache *>(getCache(cacheIndex));
// Register the location of the OOL path in the IC.
cache->setFallbackLabel(masm.labelForPatch());
// Dispatch to ICs' accept functions.
return cache->accept(this, ool);
}
StringObject *
MNewStringObject::templateObj() const {
return &templateObj_->asString();
@ -2198,7 +2113,7 @@ CodeGenerator::visitNewArray(LNewArray *lir)
JS_ASSERT(gen->info().executionMode() == SequentialExecution);
Register objReg = ToRegister(lir->output());
JSObject *templateObject = lir->mir()->templateObject();
DebugOnly<uint32_t> count = lir->mir()->count();
uint32_t count = lir->mir()->count();
JS_ASSERT(count < JSObject::NELEMENTS_LIMIT);
@ -4301,8 +4216,8 @@ CodeGenerator::link()
IonScript::New(cx, graph.totalSlotCount(), scriptFrameSize, snapshots_.size(),
bailouts_.length(), graph.numConstants(),
safepointIndices_.length(), osiIndices_.length(),
cacheList_.length(), runtimeData_.length(),
safepoints_.size(), graph.mir().numScripts(),
cacheList_.length(), safepoints_.size(),
graph.mir().numScripts(),
executionMode == ParallelExecution ? ForkJoinSlices(cx) : 0);
SetIonScript(script, executionMode, ionScript);
@ -4324,28 +4239,21 @@ CodeGenerator::link()
ionScript->setMethod(code);
ionScript->setDeoptTable(deoptTable_);
// for generating inline caches during the execution.
if (runtimeData_.length())
ionScript->copyRuntimeData(&runtimeData_[0]);
if (cacheList_.length())
ionScript->copyCacheEntries(&cacheList_[0], masm);
// for marking during GC.
if (snapshots_.size())
ionScript->copySnapshots(&snapshots_);
if (bailouts_.length())
ionScript->copyBailoutTable(&bailouts_[0]);
if (graph.numConstants())
ionScript->copyConstants(graph.constantPool());
if (safepointIndices_.length())
ionScript->copySafepointIndices(&safepointIndices_[0], masm);
if (osiIndices_.length())
ionScript->copyOsiIndices(&osiIndices_[0], masm);
if (cacheList_.length())
ionScript->copyCacheEntries(&cacheList_[0], masm);
if (safepoints_.size())
ionScript->copySafepoints(&safepoints_);
// for reconvering from an Ion Frame.
if (bailouts_.length())
ionScript->copyBailoutTable(&bailouts_[0]);
if (osiIndices_.length())
ionScript->copyOsiIndices(&osiIndices_[0], masm);
if (snapshots_.size())
ionScript->copySnapshots(&snapshots_);
if (graph.numConstants())
ionScript->copyConstants(graph.constantPool());
JS_ASSERT(graph.mir().numScripts() > 0);
ionScript->copyScriptEntries(graph.mir().scripts());
@ -4520,186 +4428,321 @@ CodeGenerator::visitStoreFixedSlotT(LStoreFixedSlotT *ins)
return true;
}
bool
CodeGenerator::visitCallsiteCloneCache(LCallsiteCloneCache *ins)
// An out-of-line path to call an inline cache function.
class OutOfLineCache : public OutOfLineCodeBase<CodeGenerator>
{
const MCallsiteCloneCache *mir = ins->mir();
Register callee = ToRegister(ins->callee());
Register output = ToRegister(ins->output());
LInstruction *ins;
RepatchLabel repatchEntry_;
CodeOffsetJump inlineJump;
CodeOffsetLabel inlineLabel;
CallsiteCloneIC cache(callee, mir->block()->info().script(), mir->callPc(), output);
return addCache(ins, allocateCache(cache));
public:
OutOfLineCache(LInstruction *ins)
: ins(ins)
{}
void setInlineJump(CodeOffsetJump jump, CodeOffsetLabel label) {
inlineJump = jump;
inlineLabel = label;
}
CodeOffsetJump getInlineJump() const {
return inlineJump;
}
CodeOffsetLabel getInlineLabel() const {
return inlineLabel;
}
bool accept(CodeGenerator *codegen) {
switch (ins->op()) {
case LInstruction::LOp_GetPropertyCacheT:
case LInstruction::LOp_GetPropertyCacheV:
return codegen->visitOutOfLineCacheGetProperty(this);
case LInstruction::LOp_GetElementCacheV:
return codegen->visitOutOfLineGetElementCache(this);
case LInstruction::LOp_SetPropertyCacheT:
case LInstruction::LOp_SetPropertyCacheV:
return codegen->visitOutOfLineSetPropertyCache(this);
case LInstruction::LOp_BindNameCache:
return codegen->visitOutOfLineBindNameCache(this);
case LInstruction::LOp_GetNameCache:
return codegen->visitOutOfLineGetNameCache(this);
case LInstruction::LOp_CallsiteCloneCache:
return codegen->visitOutOfLineCallsiteCloneCache(this);
default:
JS_NOT_REACHED("Bad instruction");
return false;
}
}
LInstruction *cache() {
return ins;
}
void bind(MacroAssembler *masm) {
masm->bind(&repatchEntry_);
}
RepatchLabel *repatchEntry() {
return &repatchEntry_;
}
};
bool
CodeGenerator::visitCache(LInstruction *ins)
{
OutOfLineCache *ool = new OutOfLineCache(ins);
if (!addOutOfLineCode(ool))
return false;
#if 0
// NOTE: This is currently disabled. OSI and IC interaction are protected
// through other means in ICs, since the nops incur significant overhead.
//
// ensureOsiSpace();
#endif
CodeOffsetJump jump = masm.jumpWithPatch(ool->repatchEntry());
CodeOffsetLabel label = masm.labelForPatch();
masm.bind(ool->rejoin());
ool->setInlineJump(jump, label);
return true;
}
typedef JSObject *(*CallsiteCloneICFn)(JSContext *, size_t, HandleObject);
const VMFunction CallsiteCloneIC::UpdateInfo =
FunctionInfo<CallsiteCloneICFn>(CallsiteCloneIC::update);
typedef JSObject *(*CallsiteCloneCacheFn)(JSContext *, size_t, HandleObject);
static const VMFunction CallsiteCloneCacheInfo =
FunctionInfo<CallsiteCloneCacheFn>(CallsiteCloneCache);
bool
CodeGenerator::visitCallsiteCloneIC(OutOfLineUpdateCache *ool, CallsiteCloneIC *ic)
CodeGenerator::visitOutOfLineCallsiteCloneCache(OutOfLineCache *ool)
{
AssertCanGC();
LInstruction *lir = ool->lir();
LCallsiteCloneCache *lir = ool->cache()->toCallsiteCloneCache();
const MCallsiteCloneCache *mir = lir->mir();
Register callee = ToRegister(lir->callee());
RegisterSet liveRegs = lir->safepoint()->liveRegs();
Register output = ToRegister(lir->output());
IonCacheCallsiteClone cache(ool->getInlineJump(), ool->getInlineLabel(),
masm.labelForPatch(), liveRegs,
callee, mir->block()->info().script(), mir->callPc(), output);
JS_ASSERT(!mir->resumePoint());
size_t cacheIndex = allocateCache(cache);
saveLive(lir);
pushArg(ic->calleeReg());
pushArg(Imm32(ool->getCacheIndex()));
if (!callVM(CallsiteCloneIC::UpdateInfo, lir))
pushArg(callee);
pushArg(Imm32(cacheIndex));
if (!callVM(CallsiteCloneCacheInfo, lir))
return false;
StoreRegisterTo(ic->outputReg()).generate(this);
restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
masm.storeCallResult(output);
restoreLive(lir);
masm.jump(ool->rejoin());
return true;
}
bool
CodeGenerator::visitGetNameCache(LGetNameCache *ins)
{
Register scopeChain = ToRegister(ins->scopeObj());
TypedOrValueRegister output(GetValueOutput(ins));
bool isTypeOf = ins->mir()->accessKind() != MGetNameCache::NAME;
NameIC cache(isTypeOf, scopeChain, ins->mir()->name(), output);
return addCache(ins, allocateCache(cache));
}
typedef bool (*NameICFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
const VMFunction NameIC::UpdateInfo = FunctionInfo<NameICFn>(NameIC::update);
typedef bool (*GetNameCacheFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
static const VMFunction GetNameCacheInfo =
FunctionInfo<GetNameCacheFn>(GetNameCache);
bool
CodeGenerator::visitNameIC(OutOfLineUpdateCache *ool, NameIC *ic)
CodeGenerator::visitOutOfLineGetNameCache(OutOfLineCache *ool)
{
AssertCanGC();
LInstruction *lir = ool->lir();
LGetNameCache *lir = ool->cache()->toGetNameCache();
const MGetNameCache *mir = lir->mir();
Register scopeChain = ToRegister(lir->scopeObj());
RegisterSet liveRegs = lir->safepoint()->liveRegs();
TypedOrValueRegister output(GetValueOutput(lir));
IonCache::Kind kind = (mir->accessKind() == MGetNameCache::NAME)
? IonCache::Name
: IonCache::NameTypeOf;
IonCacheName cache(kind, ool->getInlineJump(), ool->getInlineLabel(),
masm.labelForPatch(), liveRegs,
scopeChain, mir->name(), output);
cache.setScriptedLocation(mir->block()->info().script(), mir->resumePoint()->pc());
size_t cacheIndex = allocateCache(cache);
saveLive(lir);
pushArg(ic->scopeChainReg());
pushArg(Imm32(ool->getCacheIndex()));
if (!callVM(NameIC::UpdateInfo, lir))
pushArg(scopeChain);
pushArg(Imm32(cacheIndex));
if (!callVM(GetNameCacheInfo, lir))
return false;
StoreValueTo(ic->outputReg()).generate(this);
restoreLiveIgnore(lir, StoreValueTo(ic->outputReg()).clobbered());
masm.storeCallResultValue(output);
restoreLive(lir);
masm.jump(ool->rejoin());
return true;
}
bool
CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
{
RegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
PropertyName *name = ins->mir()->name();
bool allowGetters = ins->mir()->allowGetters();
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
GetPropertyIC cache(liveRegs, objReg, name, output, allowGetters);
return addCache(ins, allocateCache(cache));
}
typedef bool (*GetPropertyCacheFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
static const VMFunction GetPropertyCacheInfo =
FunctionInfo<GetPropertyCacheFn>(GetPropertyCache);
bool
CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT *ins)
CodeGenerator::visitOutOfLineCacheGetProperty(OutOfLineCache *ool)
{
RegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
PropertyName *name = ins->mir()->name();
bool allowGetters = ins->mir()->allowGetters();
TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
RegisterSet liveRegs = ool->cache()->safepoint()->liveRegs();
GetPropertyIC cache(liveRegs, objReg, name, output, allowGetters);
return addCache(ins, allocateCache(cache));
}
LInstruction *ins = ool->cache();
MInstruction *mir = ins->mirRaw()->toInstruction();
typedef bool (*GetPropertyICFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
const VMFunction GetPropertyIC::UpdateInfo =
FunctionInfo<GetPropertyICFn>(GetPropertyIC::update);
TypedOrValueRegister output;
bool
CodeGenerator::visitGetPropertyIC(OutOfLineUpdateCache *ool, GetPropertyIC *ic)
{
AssertCanGC();
LInstruction *lir = ool->lir();
saveLive(lir);
Register objReg;
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
if (!callVM(GetPropertyIC::UpdateInfo, lir))
// Define the input and output registers each opcode wants,
// and which atom property it should get
// Note: because all registers are saved, the output register should be
// a def register, else the result will be overriden by restoreLive(ins)
PropertyName *name = NULL;
bool allowGetters = false;
switch (ins->op()) {
case LInstruction::LOp_GetPropertyCacheT:
name = ((LGetPropertyCacheT *) ins)->mir()->name();
objReg = ToRegister(ins->getOperand(0));
output = TypedOrValueRegister(mir->type(), ToAnyRegister(ins->getDef(0)));
JS_ASSERT(mir->isGetPropertyCache());
allowGetters = mir->toGetPropertyCache()->allowGetters();
break;
case LInstruction::LOp_GetPropertyCacheV:
name = ((LGetPropertyCacheV *) ins)->mir()->name();
objReg = ToRegister(ins->getOperand(0));
output = TypedOrValueRegister(GetValueOutput(ins));
JS_ASSERT(mir->isGetPropertyCache());
allowGetters = mir->toGetPropertyCache()->allowGetters();
break;
default:
JS_NOT_REACHED("Bad instruction");
return false;
StoreValueTo(ic->output()).generate(this);
restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
}
IonCacheGetProperty cache(ool->getInlineJump(), ool->getInlineLabel(),
masm.labelForPatch(), liveRegs,
objReg, name, output, allowGetters);
if (mir->resumePoint())
cache.setScriptedLocation(mir->block()->info().script(), mir->resumePoint()->pc());
else
cache.setIdempotent();
size_t cacheIndex = allocateCache(cache);
saveLive(ins);
pushArg(objReg);
pushArg(Imm32(cacheIndex));
if (!callVM(GetPropertyCacheInfo, ins))
return false;
masm.storeCallResultValue(output);
restoreLive(ins);
masm.jump(ool->rejoin());
return true;
}
typedef bool (*GetElementCacheFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
static const VMFunction GetElementCacheInfo = FunctionInfo<GetElementCacheFn>(GetElementCache);
bool
CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
CodeGenerator::visitOutOfLineGetElementCache(OutOfLineCache *ool)
{
LGetElementCacheV *ins = ool->cache()->toGetElementCacheV();
const MGetElementCache *mir = ins->mir();
Register obj = ToRegister(ins->object());
ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
GetElementIC cache(obj, index, output, ins->mir()->monitoredResult());
RegisterSet liveRegs = ins->safepoint()->liveRegs();
return addCache(ins, allocateCache(cache));
}
IonCacheGetElement cache(ool->getInlineJump(), ool->getInlineLabel(),
masm.labelForPatch(), liveRegs,
obj, index, output,
mir->monitoredResult());
typedef bool (*GetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
const VMFunction GetElementIC::UpdateInfo =
FunctionInfo<GetElementICFn>(GetElementIC::update);
cache.setScriptedLocation(mir->block()->info().script(), mir->resumePoint()->pc());
size_t cacheIndex = allocateCache(cache);
bool
CodeGenerator::visitGetElementIC(OutOfLineUpdateCache *ool, GetElementIC *ic)
{
AssertCanGC();
LInstruction *lir = ool->lir();
saveLive(lir);
saveLive(ins);
pushArg(ic->index());
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
if (!callVM(GetElementIC::UpdateInfo, lir))
pushArg(index);
pushArg(obj);
pushArg(Imm32(cacheIndex));
if (!callVM(GetElementCacheInfo, ins))
return false;
StoreValueTo(ic->output()).generate(this);
restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
masm.storeCallResultValue(output);
restoreLive(ins);
masm.jump(ool->rejoin());
return true;
}
typedef JSObject *(*BindNameCacheFn)(JSContext *, size_t, HandleObject);
static const VMFunction BindNameCacheInfo =
FunctionInfo<BindNameCacheFn>(BindNameCache);
bool
CodeGenerator::visitBindNameCache(LBindNameCache *ins)
CodeGenerator::visitOutOfLineBindNameCache(OutOfLineCache *ool)
{
LBindNameCache *ins = ool->cache()->toBindNameCache();
Register scopeChain = ToRegister(ins->scopeChain());
Register output = ToRegister(ins->output());
BindNameIC cache(scopeChain, ins->mir()->name(), output);
return addCache(ins, allocateCache(cache));
}
RegisterSet liveRegs = ins->safepoint()->liveRegs();
typedef JSObject *(*BindNameICFn)(JSContext *, size_t, HandleObject);
const VMFunction BindNameIC::UpdateInfo =
FunctionInfo<BindNameICFn>(BindNameIC::update);
const MBindNameCache *mir = ins->mir();
IonCacheBindName cache(ool->getInlineJump(), ool->getInlineLabel(),
masm.labelForPatch(), liveRegs,
scopeChain, mir->name(), output);
cache.setScriptedLocation(mir->script(), mir->pc());
size_t cacheIndex = allocateCache(cache);
bool
CodeGenerator::visitBindNameIC(OutOfLineUpdateCache *ool, BindNameIC *ic)
{
AssertCanGC();
LInstruction *lir = ool->lir();
saveLive(lir);
saveLive(ins);
pushArg(ic->scopeChainReg());
pushArg(Imm32(ool->getCacheIndex()));
if (!callVM(BindNameIC::UpdateInfo, lir))
pushArg(scopeChain);
pushArg(Imm32(cacheIndex));
if (!callVM(BindNameCacheInfo, ins))
return false;
StoreRegisterTo(ic->outputReg()).generate(this);
restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
masm.storeCallResult(output);
restoreLive(ins);
masm.jump(ool->rejoin());
return true;
}
ConstantOrRegister
CodeGenerator::getSetPropertyValue(LInstruction *ins)
{
if (ins->getOperand(1)->isConstant()) {
JS_ASSERT(ins->isSetPropertyCacheT());
return ConstantOrRegister(*ins->getOperand(1)->toConstant());
}
switch (ins->op()) {
case LInstruction::LOp_CallSetProperty:
return TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
case LInstruction::LOp_SetPropertyCacheV:
return TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
case LInstruction::LOp_SetPropertyCacheT: {
LSetPropertyCacheT *ins_ = ins->toSetPropertyCacheT();
return TypedOrValueRegister(ins_->valueType(), ToAnyRegister(ins->getOperand(1)));
}
default:
JS_NOT_REACHED("Bad opcode");
return ConstantOrRegister(UndefinedValue());
}
}
typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
HandlePropertyName, const HandleValue, bool, bool);
static const VMFunction SetPropertyInfo =
@ -4708,7 +4751,7 @@ static const VMFunction SetPropertyInfo =
bool
CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
{
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
ConstantOrRegister value = getSetPropertyValue(ins);
const Register objReg = ToRegister(ins->getOperand(0));
bool isSetName = JSOp(*ins->mir()->resumePoint()->pc()) == JSOP_SETNAME;
@ -4741,56 +4784,43 @@ CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir)
return callVM(DeletePropertyNonStrictInfo, lir);
}
typedef bool (*SetPropertyCacheFn)(JSContext *, size_t, HandleObject, HandleValue, bool);
static const VMFunction SetPropertyCacheInfo =
FunctionInfo<SetPropertyCacheFn>(ion::SetPropertyCache);
bool
CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
CodeGenerator::visitOutOfLineSetPropertyCache(OutOfLineCache *ool)
{
RegisterSet liveRegs = ins->safepoint()->liveRegs();
LInstruction *ins = ool->cache();
Register objReg = ToRegister(ins->getOperand(0));
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
bool isSetName = JSOp(*ins->mir()->resumePoint()->pc()) == JSOP_SETNAME;
SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value,
isSetName, ins->mir()->strict());
return addCache(ins, allocateCache(cache));
}
bool
CodeGenerator::visitSetPropertyCacheT(LSetPropertyCacheT *ins)
{
RegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
ConstantOrRegister value;
bool isSetName = JSOp(*ins->mir()->resumePoint()->pc()) == JSOP_SETNAME;
if (ins->getOperand(1)->isConstant())
value = ConstantOrRegister(*ins->getOperand(1)->toConstant());
else
value = TypedOrValueRegister(ins->valueType(), ToAnyRegister(ins->getOperand(1)));
ConstantOrRegister value = getSetPropertyValue(ins);
const MSetPropertyCache *mir = ins->mirRaw()->toSetPropertyCache();
SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value,
isSetName, ins->mir()->strict());
return addCache(ins, allocateCache(cache));
}
IonCacheSetProperty cache(ool->getInlineJump(), ool->getInlineLabel(),
masm.labelForPatch(), liveRegs,
objReg, mir->name(), value,
mir->strict());
typedef bool (*SetPropertyICFn)(JSContext *, size_t, HandleObject, HandleValue);
const VMFunction SetPropertyIC::UpdateInfo =
FunctionInfo<SetPropertyICFn>(SetPropertyIC::update);
size_t cacheIndex = allocateCache(cache);
bool isSetName = JSOp(*mir->resumePoint()->pc()) == JSOP_SETNAME;
bool
CodeGenerator::visitSetPropertyIC(OutOfLineUpdateCache *ool, SetPropertyIC *ic)
{
AssertCanGC();
LInstruction *lir = ool->lir();
saveLive(lir);
saveLive(ins);
pushArg(ic->value());
pushArg(ic->object());
pushArg(Imm32(ool->getCacheIndex()));
if (!callVM(SetPropertyIC::UpdateInfo, lir))
pushArg(Imm32(isSetName));
pushArg(value);
pushArg(objReg);
pushArg(Imm32(cacheIndex));
if (!callVM(SetPropertyCacheInfo, ool->cache()))
return false;
restoreLive(lir);
restoreLive(ins);
masm.jump(ool->rejoin());
return true;
}

View File

@ -29,11 +29,11 @@ class CheckOverRecursedFailure;
class ParCheckOverRecursedFailure;
class OutOfLineParCheckInterrupt;
class OutOfLineUnboxDouble;
class OutOfLineCache;
class OutOfLineStoreElementHole;
class OutOfLineTypeOfV;
class OutOfLineLoadTypedArray;
class OutOfLineParNewGCThing;
class OutOfLineUpdateCache;
class CodeGenerator : public CodeGeneratorSpecific
{
@ -220,31 +220,49 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitOutOfLineUnboxDouble(OutOfLineUnboxDouble *ool);
bool visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool);
bool visitOutOfLineCacheGetProperty(OutOfLineCache *ool);
bool visitOutOfLineGetElementCache(OutOfLineCache *ool);
bool visitOutOfLineSetPropertyCache(OutOfLineCache *ool);
bool visitOutOfLineBindNameCache(OutOfLineCache *ool);
bool visitOutOfLineGetNameCache(OutOfLineCache *ool);
bool visitOutOfLineCallsiteCloneCache(OutOfLineCache *ool);
bool visitOutOfLineParNewGCThing(OutOfLineParNewGCThing *ool);
bool visitOutOfLineParallelAbort(OutOfLineParallelAbort *ool);
// Inline caches visitors.
bool visitOutOfLineCache(OutOfLineUpdateCache *ool);
bool visitGetPropertyCacheV(LGetPropertyCacheV *ins);
bool visitGetPropertyCacheT(LGetPropertyCacheT *ins);
bool visitGetElementCacheV(LGetElementCacheV *ins);
bool visitBindNameCache(LBindNameCache *ins);
bool visitCallSetProperty(LInstruction *ins);
bool visitSetPropertyCacheV(LSetPropertyCacheV *ins);
bool visitSetPropertyCacheT(LSetPropertyCacheT *ins);
bool visitGetNameCache(LGetNameCache *ins);
bool visitCallsiteCloneCache(LCallsiteCloneCache *ins);
bool visitGetPropertyIC(OutOfLineUpdateCache *ool, GetPropertyIC *ic);
bool visitSetPropertyIC(OutOfLineUpdateCache *ool, SetPropertyIC *ic);
bool visitGetElementIC(OutOfLineUpdateCache *ool, GetElementIC *ic);
bool visitBindNameIC(OutOfLineUpdateCache *ool, BindNameIC *ic);
bool visitNameIC(OutOfLineUpdateCache *ool, NameIC *ic);
bool visitCallsiteCloneIC(OutOfLineUpdateCache *ool, CallsiteCloneIC *ic);
bool visitGetPropertyCacheV(LGetPropertyCacheV *ins) {
return visitCache(ins);
}
bool visitGetPropertyCacheT(LGetPropertyCacheT *ins) {
return visitCache(ins);
}
bool visitGetElementCacheV(LGetElementCacheV *ins) {
return visitCache(ins);
}
bool visitBindNameCache(LBindNameCache *ins) {
return visitCache(ins);
}
bool visitSetPropertyCacheV(LSetPropertyCacheV *ins) {
return visitCache(ins);
}
bool visitSetPropertyCacheT(LSetPropertyCacheT *ins) {
return visitCache(ins);
}
bool visitGetNameCache(LGetNameCache *ins) {
return visitCache(ins);
}
bool visitCallsiteCloneCache(LCallsiteCloneCache *ins) {
return visitCache(ins);
}
private:
bool visitCache(LInstruction *load);
bool visitCallSetProperty(LInstruction *ins);
bool checkForParallelBailout();
ConstantOrRegister getSetPropertyValue(LInstruction *ins);
bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
bool emitParAllocateGCThing(const Register &objReg,

View File

@ -451,24 +451,22 @@ IonScript::IonScript()
invalidateEpilogueOffset_(0),
invalidateEpilogueDataOffset_(0),
bailoutExpected_(false),
runtimeData_(0),
runtimeSize_(0),
cacheIndex_(0),
cacheEntries_(0),
safepointIndexOffset_(0),
safepointIndexEntries_(0),
safepointsStart_(0),
safepointsSize_(0),
frameSlots_(0),
frameSize_(0),
bailoutTable_(0),
bailoutEntries_(0),
osiIndexOffset_(0),
osiIndexEntries_(0),
snapshots_(0),
snapshotsSize_(0),
bailoutTable_(0),
bailoutEntries_(0),
constantTable_(0),
constantEntries_(0),
safepointIndexOffset_(0),
safepointIndexEntries_(0),
frameSlots_(0),
frameSize_(0),
osiIndexOffset_(0),
osiIndexEntries_(0),
cacheList_(0),
cacheEntries_(0),
safepointsStart_(0),
safepointsSize_(0),
scriptList_(0),
scriptEntries_(0),
parallelInvalidatedScriptList_(0),
@ -483,9 +481,8 @@ static const int DataAlignment = 4;
IonScript *
IonScript::New(JSContext *cx, uint32_t frameSlots, uint32_t frameSize, size_t snapshotsSize,
size_t bailoutEntries, size_t constants, size_t safepointIndices,
size_t osiIndices, size_t cacheEntries, size_t runtimeSize,
size_t safepointsSize, size_t scriptEntries,
size_t parallelInvalidatedScriptEntries)
size_t osiIndices, size_t cacheEntries, size_t safepointsSize,
size_t scriptEntries, size_t parallelInvalidatedScriptEntries)
{
if (snapshotsSize >= MAX_BUFFER_SIZE ||
(bailoutEntries >= MAX_BUFFER_SIZE / sizeof(uint32_t)))
@ -502,8 +499,7 @@ IonScript::New(JSContext *cx, uint32_t frameSlots, uint32_t frameSize, size_t sn
size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
size_t paddedOsiIndicesSize = AlignBytes(osiIndices * sizeof(OsiIndex), DataAlignment);
size_t paddedCacheEntriesSize = AlignBytes(cacheEntries * sizeof(uint32_t), DataAlignment);
size_t paddedRuntimeSize = AlignBytes(runtimeSize, DataAlignment);
size_t paddedCacheEntriesSize = AlignBytes(cacheEntries * sizeof(IonCache), DataAlignment);
size_t paddedSafepointSize = AlignBytes(safepointsSize, DataAlignment);
size_t paddedScriptSize = AlignBytes(scriptEntries * sizeof(RawScript), DataAlignment);
size_t paddedParallelInvalidatedScriptSize =
@ -514,7 +510,6 @@ IonScript::New(JSContext *cx, uint32_t frameSlots, uint32_t frameSize, size_t sn
paddedSafepointIndicesSize+
paddedOsiIndicesSize +
paddedCacheEntriesSize +
paddedRuntimeSize +
paddedSafepointSize +
paddedScriptSize +
paddedParallelInvalidatedScriptSize;
@ -527,37 +522,33 @@ IonScript::New(JSContext *cx, uint32_t frameSlots, uint32_t frameSize, size_t sn
uint32_t offsetCursor = sizeof(IonScript);
script->runtimeData_ = offsetCursor;
script->runtimeSize_ = runtimeSize;
offsetCursor += paddedRuntimeSize;
script->cacheIndex_ = offsetCursor;
script->cacheEntries_ = cacheEntries;
offsetCursor += paddedCacheEntriesSize;
script->safepointIndexOffset_ = offsetCursor;
script->safepointIndexEntries_ = safepointIndices;
offsetCursor += paddedSafepointIndicesSize;
script->safepointsStart_ = offsetCursor;
script->safepointsSize_ = safepointsSize;
offsetCursor += paddedSafepointSize;
script->snapshots_ = offsetCursor;
script->snapshotsSize_ = snapshotsSize;
offsetCursor += paddedSnapshotsSize;
script->bailoutTable_ = offsetCursor;
script->bailoutEntries_ = bailoutEntries;
offsetCursor += paddedBailoutSize;
script->constantTable_ = offsetCursor;
script->constantEntries_ = constants;
offsetCursor += paddedConstantsSize;
script->safepointIndexOffset_ = offsetCursor;
script->safepointIndexEntries_ = safepointIndices;
offsetCursor += paddedSafepointIndicesSize;
script->osiIndexOffset_ = offsetCursor;
script->osiIndexEntries_ = osiIndices;
offsetCursor += paddedOsiIndicesSize;
script->snapshots_ = offsetCursor;
script->snapshotsSize_ = snapshotsSize;
offsetCursor += paddedSnapshotsSize;
script->cacheList_ = offsetCursor;
script->cacheEntries_ = cacheEntries;
offsetCursor += paddedCacheEntriesSize;
script->constantTable_ = offsetCursor;
script->constantEntries_ = constants;
offsetCursor += paddedConstantsSize;
script->safepointsStart_ = offsetCursor;
script->safepointsSize_ = safepointsSize;
offsetCursor += paddedSafepointSize;
script->scriptList_ = offsetCursor;
script->scriptEntries_ = scriptEntries;
@ -632,9 +623,11 @@ IonScript::zeroParallelInvalidatedScripts()
void
IonScript::copySafepointIndices(const SafepointIndex *si, MacroAssembler &masm)
{
// Jumps in the caches reflect the offset of those jumps in the compiled
// code, not the absolute positions of the jumps. Update according to the
// final code address now.
/*
* Jumps in the caches reflect the offset of those jumps in the compiled
* code, not the absolute positions of the jumps. Update according to the
* final code address now.
*/
SafepointIndex *table = safepointIndices();
memcpy(table, si, safepointIndexEntries_ * sizeof(SafepointIndex));
for (size_t i = 0; i < safepointIndexEntries_; i++)
@ -650,19 +643,15 @@ IonScript::copyOsiIndices(const OsiIndex *oi, MacroAssembler &masm)
}
void
IonScript::copyRuntimeData(const uint8_t *data)
IonScript::copyCacheEntries(const IonCache *caches, MacroAssembler &masm)
{
memcpy(runtimeData(), data, runtimeSize());
}
memcpy(cacheList(), caches, numCaches() * sizeof(IonCache));
void
IonScript::copyCacheEntries(const uint32_t *caches, MacroAssembler &masm)
{
memcpy(cacheIndex(), caches, numCaches() * sizeof(uint32_t));
// Jumps in the caches reflect the offset of those jumps in the compiled
// code, not the absolute positions of the jumps. Update according to the
// final code address now.
/*
* Jumps in the caches reflect the offset of those jumps in the compiled
* code, not the absolute positions of the jumps. Update according to the
* final code address now.
*/
for (size_t i = 0; i < numCaches(); i++)
getCache(i).updateBaseAddress(method_, masm);
}

File diff suppressed because it is too large Load Diff

View File

@ -18,31 +18,12 @@ class JSScript;
namespace js {
namespace ion {
#define IONCACHE_KIND_LIST(_) \
_(GetProperty) \
_(SetProperty) \
_(GetElement) \
_(BindName) \
_(Name) \
_(CallsiteClone)
// Forward declarations of Cache kinds.
#define FORWARD_DECLARE(kind) class kind##IC;
IONCACHE_KIND_LIST(FORWARD_DECLARE)
#undef FORWARD_DECLARE
class IonCacheVisitor
{
public:
#define VISIT_INS(op) \
virtual bool visit##op##IC(CodeGenerator *codegen, op##IC *) { \
JS_NOT_REACHED("NYI: " #op "IC"); \
return false; \
}
IONCACHE_KIND_LIST(VISIT_INS)
#undef VISIT_INS
};
class IonCacheGetProperty;
class IonCacheSetProperty;
class IonCacheGetElement;
class IonCacheBindName;
class IonCacheName;
class IonCacheCallsiteClone;
// Common structure encoding the state of a polymorphic inline cache contained
// in the code for an IonScript. IonCaches are used for polymorphic operations
@ -74,70 +55,45 @@ class IonCacheVisitor
// for a cache, the cache itself may be marked as idempotent and become hoisted
// or coalesced by LICM or GVN. This also constrains the stubs which can be
// generated for the cache.
//
// * IonCache usage
//
// IonCache is the base structure of an inline cache, which generates code stubs
// dynamically and attaches them to an IonScript.
//
// A cache must at least provide a static update function which will usualy have
// a JSContext*, followed by the cache index. The rest of the arguments of the
// update function are usualy corresponding to the register inputs of the cache,
// as it must perform the same operation as any of the stubs that it might
// produce. The update function call is handled by the visit function of
// CodeGenerator corresponding to this IC.
//
// The CodeGenerator visit function, as opposed to other visit functions, has
// two arguments. The first one is the OutOfLineUpdateCache which stores the LIR
// instruction. The second one is the IC object. This function would be called
// once the IC is registered with the addCache function of CodeGeneratorShared.
//
// To register a cache, you must call the addCache function as follow:
//
// MyCodeIC cache(inputReg1, inputValueReg2, outputReg);
// if (!addCache(lir, allocateCache(cache)))
// return false;
//
// Once the cache is allocated with the allocateCache function, any modification
// made to the cache would be ignored.
//
// The addCache function will produce a patchable jump at the location where
// it is called. This jump will execute generated stubs and fallback on the code
// of the visitMyCodeIC function if no stub match.
//
// Warning: As the addCache function fallback on a VMCall, calls to
// addCache should not be in the same path as another VMCall or in the same
// path of another addCache as this is not supported by the invalidation
// procedure.
struct TypedOrValueRegisterSpace
{
mozilla::AlignedStorage2<TypedOrValueRegister> data_;
TypedOrValueRegister &data() {
return *data_.addr();
}
const TypedOrValueRegister &data() const {
return *data_.addr();
}
};
struct ConstantOrRegisterSpace
{
mozilla::AlignedStorage2<ConstantOrRegister> data_;
ConstantOrRegister &data() {
return *data_.addr();
}
const ConstantOrRegister &data() const {
return *data_.addr();
}
};
class IonCache
{
public:
enum Kind {
# define DEFINE_CACHEKINDS(ickind) Cache_##ickind,
IONCACHE_KIND_LIST(DEFINE_CACHEKINDS)
# undef DEFINE_CACHEKINDS
Cache_Invalid
Invalid = 0,
GetProperty,
SetProperty,
GetElement,
BindName,
Name,
NameTypeOf,
CallsiteClone
};
// Cache testing and cast.
# define CACHEKIND_CASTS(ickind) \
bool is##ickind() const { \
return kind() == Cache_##ickind; \
} \
inline ickind##IC &to##ickind();
IONCACHE_KIND_LIST(CACHEKIND_CASTS)
# undef CACHEKIND_CASTS
virtual Kind kind() const = 0;
virtual bool accept(CodeGenerator *codegen, IonCacheVisitor *visitor) = 0;
public:
static const char *CacheName(Kind kind);
protected:
Kind kind_ : 8;
bool pure_ : 1;
bool idempotent_ : 1;
bool disabled_ : 1;
@ -145,7 +101,7 @@ class IonCache
CodeLocationJump initialJump_;
CodeLocationJump lastJump_;
CodeLocationLabel fallbackLabel_;
CodeLocationLabel cacheLabel_;
// Offset from the initial jump to the rejoin label.
#ifdef JS_CPU_ARM
@ -153,22 +109,85 @@ class IonCache
#else
static const size_t REJOIN_LABEL_OFFSET = 0;
#endif
union {
struct {
Register object;
PropertyName *name;
TypedOrValueRegisterSpace output;
bool allowGetters : 1;
bool hasArrayLengthStub : 1;
bool hasTypedArrayLengthStub : 1;
} getprop;
struct {
Register object;
PropertyName *name;
ConstantOrRegisterSpace value;
bool strict;
} setprop;
struct {
Register object;
ConstantOrRegisterSpace index;
TypedOrValueRegisterSpace output;
bool monitoredResult : 1;
bool hasDenseStub : 1;
} getelem;
struct {
Register scopeChain;
PropertyName *name;
Register output;
} bindname;
struct {
Register scopeChain;
PropertyName *name;
TypedOrValueRegisterSpace output;
} name;
struct {
Register callee;
Register output;
JSScript *callScript;
jsbytecode *callPc;
} callsiteclone;
} u;
// Registers live after the cache, excluding output registers. The initial
// value of these registers must be preserved by the cache.
RegisterSet liveRegs;
// Location of this operation, NULL for idempotent caches.
JSScript *script;
jsbytecode *pc;
private:
static const size_t MAX_STUBS;
void incrementStubCount() {
// The IC should stop generating stubs before wrapping stubCount.
stubCount_++;
JS_ASSERT(stubCount_);
void init(Kind kind, RegisterSet liveRegs,
CodeOffsetJump initialJump,
CodeOffsetLabel rejoinLabel,
CodeOffsetLabel cacheLabel) {
this->kind_ = kind;
this->liveRegs = liveRegs;
this->initialJump_ = initialJump;
this->lastJump_ = initialJump;
this->cacheLabel_ = cacheLabel;
JS_ASSERT(rejoinLabel.offset() == initialJump.offset() + REJOIN_LABEL_OFFSET);
}
CodeLocationLabel fallbackLabel() const {
return fallbackLabel_;
public:
IonCache() { PodZero(this); }
void updateBaseAddress(IonCode *code, MacroAssembler &masm);
// disable the IC.
void disable();
inline bool isDisabled() const {
return disabled_;
}
// Reset the cache around garbage collection.
void reset();
CodeLocationJump lastJump() const { return lastJump_; }
CodeLocationLabel cacheLabel() const { return cacheLabel_; }
CodeLocationLabel rejoinLabel() const {
uint8_t *ptr = initialJump_.raw();
#ifdef JS_CPU_ARM
@ -179,77 +198,6 @@ class IonCache
return CodeLocationLabel(ptr);
}
public:
IonCache()
: pure_(false),
idempotent_(false),
disabled_(false),
stubCount_(0),
initialJump_(),
lastJump_(),
fallbackLabel_(),
script(NULL),
pc(NULL)
{
}
void disable();
inline bool isDisabled() const {
return disabled_;
}
// Set the initial jump state of the cache. The initialJump is the inline
// jump that will point to out-of-line code (such as the slow path, or
// stubs), and the rejoinLabel is the position that all out-of-line paths
// will rejoin to.
void setInlineJump(CodeOffsetJump initialJump, CodeOffsetLabel rejoinLabel) {
initialJump_ = initialJump;
lastJump_ = initialJump;
JS_ASSERT(rejoinLabel.offset() == initialJump.offset() + REJOIN_LABEL_OFFSET);
}
// Set the initial 'out-of-line' jump state of the cache. The fallbackLabel is
// the location of the out-of-line update (slow) path. This location will
// be set to the exitJump of the last generated stub.
void setFallbackLabel(CodeOffsetLabel fallbackLabel) {
fallbackLabel_ = fallbackLabel;
}
// Update labels once the code is copied and finalized.
void updateBaseAddress(IonCode *code, MacroAssembler &masm);
// Reset the cache around garbage collection.
void reset();
bool canAttachStub() const {
return stubCount_ < MAX_STUBS;
}
enum LinkStatus {
LINK_ERROR,
CACHE_FLUSHED,
LINK_GOOD
};
// Use the Linker to link the generated code and check if any
// monitoring/allocation caused an invalidation of the running ion script,
// this function returns CACHE_FLUSHED. In case of allocation issue this
// function returns LINK_ERROR.
LinkStatus linkCode(JSContext *cx, MacroAssembler &masm, IonScript *ion, IonCode **code);
// Fixup variables and update jumps in the list of stubs. Increment the
// number of attached stubs accordingly.
void attachStub(MacroAssembler &masm, IonCode *code, CodeOffsetJump &rejoinOffset,
CodeOffsetJump *exitOffset, CodeOffsetLabel *stubOffset = NULL);
// Combine both linkCode and attachStub into one function. In addition, it
// produces a spew augmented with the attachKind string.
bool linkAndAttachStub(JSContext *cx, MacroAssembler &masm, IonScript *ion,
const char *attachKind, CodeOffsetJump &rejoinOffset,
CodeOffsetJump *exitOffset, CodeOffsetLabel *stubOffset = NULL);
bool pure() {
return pure_;
}
@ -263,6 +211,44 @@ class IonCache
idempotent_ = true;
}
void updateLastJump(CodeLocationJump jump) {
lastJump_ = jump;
}
size_t stubCount() const {
return stubCount_;
}
void incrementStubCount() {
// The IC should stop generating stubs before wrapping stubCount.
stubCount_++;
JS_ASSERT(stubCount_);
}
IonCacheGetProperty &toGetProperty() {
JS_ASSERT(kind_ == GetProperty);
return *(IonCacheGetProperty *)this;
}
IonCacheSetProperty &toSetProperty() {
JS_ASSERT(kind_ == SetProperty);
return *(IonCacheSetProperty *)this;
}
IonCacheGetElement &toGetElement() {
JS_ASSERT(kind_ == GetElement);
return *(IonCacheGetElement *)this;
}
IonCacheBindName &toBindName() {
JS_ASSERT(kind_ == BindName);
return *(IonCacheBindName *)this;
}
IonCacheName &toName() {
JS_ASSERT(kind_ == Name || kind_ == NameTypeOf);
return *(IonCacheName *)this;
}
IonCacheCallsiteClone &toCallsiteClone() {
JS_ASSERT(kind_ == CallsiteClone);
return *(IonCacheCallsiteClone *)this;
}
void setScriptedLocation(UnrootedScript script, jsbytecode *pc) {
JS_ASSERT(!idempotent_);
this->script = script;
@ -275,71 +261,41 @@ class IonCache
}
};
// Define the cache kind and pre-declare data structures used for calling inline
// caches.
#define CACHE_HEADER(ickind) \
Kind kind() const { \
return IonCache::Cache_##ickind; \
} \
\
bool accept(CodeGenerator *codegen, IonCacheVisitor *visitor) { \
return visitor->visit##ickind##IC(codegen, this); \
} \
\
static const VMFunction UpdateInfo;
inline IonCache &
IonScript::getCache(size_t index) {
JS_ASSERT(index < numCaches());
return cacheList()[index];
}
// Subclasses of IonCache for the various kinds of caches. These do not define
// new data members; all caches must be of the same size.
class GetPropertyIC : public IonCache
class IonCacheGetProperty : public IonCache
{
protected:
// Registers live after the cache, excluding output registers. The initial
// value of these registers must be preserved by the cache.
RegisterSet liveRegs_;
Register object_;
PropertyName *name_;
TypedOrValueRegister output_;
bool allowGetters_ : 1;
bool hasArrayLengthStub_ : 1;
bool hasTypedArrayLengthStub_ : 1;
public:
GetPropertyIC(RegisterSet liveRegs,
IonCacheGetProperty(CodeOffsetJump initialJump,
CodeOffsetLabel rejoinLabel,
CodeOffsetLabel cacheLabel,
RegisterSet liveRegs,
Register object, PropertyName *name,
TypedOrValueRegister output,
bool allowGetters)
: liveRegs_(liveRegs),
object_(object),
name_(name),
output_(output),
allowGetters_(allowGetters),
hasArrayLengthStub_(false),
hasTypedArrayLengthStub_(false)
{
init(GetProperty, liveRegs, initialJump, rejoinLabel, cacheLabel);
u.getprop.object = object;
u.getprop.name = name;
u.getprop.output.data() = output;
u.getprop.allowGetters = allowGetters;
u.getprop.hasArrayLengthStub = false;
u.getprop.hasTypedArrayLengthStub = false;
}
CACHE_HEADER(GetProperty)
Register object() const {
return object_;
}
PropertyName *name() const {
return name_;
}
TypedOrValueRegister output() const {
return output_;
}
bool allowGetters() const {
return allowGetters_;
}
bool hasArrayLengthStub() const {
return hasArrayLengthStub_;
}
bool hasTypedArrayLengthStub() const {
return hasTypedArrayLengthStub_;
}
Register object() const { return u.getprop.object; }
PropertyName *name() const { return u.getprop.name; }
TypedOrValueRegister output() const { return u.getprop.output.data(); }
bool allowGetters() const { return u.getprop.allowGetters; }
bool hasArrayLengthStub() const { return u.getprop.hasArrayLengthStub; }
bool hasTypedArrayLengthStub() const { return u.getprop.hasTypedArrayLengthStub; }
bool attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
HandleShape shape);
@ -348,237 +304,196 @@ class GetPropertyIC : public IonCache
const SafepointIndex *safepointIndex, void *returnAddr);
bool attachArrayLength(JSContext *cx, IonScript *ion, JSObject *obj);
bool attachTypedArrayLength(JSContext *cx, IonScript *ion, JSObject *obj);
static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
};
class SetPropertyIC : public IonCache
class IonCacheSetProperty : public IonCache
{
protected:
// Registers live after the cache, excluding output registers. The initial
// value of these registers must be preserved by the cache.
RegisterSet liveRegs_;
Register object_;
PropertyName *name_;
ConstantOrRegister value_;
bool isSetName_;
bool strict_;
public:
SetPropertyIC(RegisterSet liveRegs, Register object, PropertyName *name,
ConstantOrRegister value, bool isSetName, bool strict)
: liveRegs_(liveRegs),
object_(object),
name_(name),
value_(value),
isSetName_(isSetName),
strict_(strict)
IonCacheSetProperty(CodeOffsetJump initialJump,
CodeOffsetLabel rejoinLabel,
CodeOffsetLabel cacheLabel,
RegisterSet liveRegs,
Register object, PropertyName *name,
ConstantOrRegister value,
bool strict)
{
init(SetProperty, liveRegs, initialJump, rejoinLabel, cacheLabel);
u.setprop.object = object;
u.setprop.name = name;
u.setprop.value.data() = value;
u.setprop.strict = strict;
}
CACHE_HEADER(SetProperty)
Register object() const {
return object_;
}
PropertyName *name() const {
return name_;
}
ConstantOrRegister value() const {
return value_;
}
bool isSetName() const {
return isSetName_;
}
bool strict() const {
return strict_;
}
Register object() const { return u.setprop.object; }
PropertyName *name() const { return u.setprop.name; }
ConstantOrRegister value() const { return u.setprop.value.data(); }
bool strict() const { return u.setprop.strict; }
bool attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape);
bool attachSetterCall(JSContext *cx, IonScript *ion, HandleObject obj,
HandleObject holder, HandleShape shape, void *returnAddr);
bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldshape,
HandleShape newshape, HandleShape propshape);
static bool
update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value);
};
class GetElementIC : public IonCache
class IonCacheGetElement : public IonCache
{
protected:
Register object_;
ConstantOrRegister index_;
TypedOrValueRegister output_;
bool monitoredResult_ : 1;
bool hasDenseStub_ : 1;
public:
GetElementIC(Register object, ConstantOrRegister index,
IonCacheGetElement(CodeOffsetJump initialJump,
CodeOffsetLabel rejoinLabel,
CodeOffsetLabel cacheLabel,
RegisterSet liveRegs,
Register object, ConstantOrRegister index,
TypedOrValueRegister output, bool monitoredResult)
: object_(object),
index_(index),
output_(output),
monitoredResult_(monitoredResult),
hasDenseStub_(false)
{
init(GetElement, liveRegs, initialJump, rejoinLabel, cacheLabel);
u.getelem.object = object;
u.getelem.index.data() = index;
u.getelem.output.data() = output;
u.getelem.monitoredResult = monitoredResult;
u.getelem.hasDenseStub = false;
}
CACHE_HEADER(GetElement)
Register object() const {
return object_;
return u.getelem.object;
}
ConstantOrRegister index() const {
return index_;
return u.getelem.index.data();
}
TypedOrValueRegister output() const {
return output_;
return u.getelem.output.data();
}
bool monitoredResult() const {
return monitoredResult_;
return u.getelem.monitoredResult;
}
bool hasDenseStub() const {
return hasDenseStub_;
return u.getelem.hasDenseStub;
}
void setHasDenseStub() {
JS_ASSERT(!hasDenseStub());
hasDenseStub_ = true;
u.getelem.hasDenseStub = true;
}
bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
bool attachTypedArrayElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
static bool
update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
MutableHandleValue vp);
};
class BindNameIC : public IonCache
class IonCacheBindName : public IonCache
{
protected:
Register scopeChain_;
PropertyName *name_;
Register output_;
public:
BindNameIC(Register scopeChain, PropertyName *name, Register output)
: scopeChain_(scopeChain),
name_(name),
output_(output)
IonCacheBindName(CodeOffsetJump initialJump,
CodeOffsetLabel rejoinLabel,
CodeOffsetLabel cacheLabel,
RegisterSet liveRegs,
Register scopeChain, PropertyName *name,
Register output)
{
init(BindName, liveRegs, initialJump, rejoinLabel, cacheLabel);
u.bindname.scopeChain = scopeChain;
u.bindname.name = name;
u.bindname.output = output;
}
CACHE_HEADER(BindName)
Register scopeChainReg() const {
return scopeChain_;
return u.bindname.scopeChain;
}
HandlePropertyName name() const {
return HandlePropertyName::fromMarkedLocation(&name_);
return HandlePropertyName::fromMarkedLocation(&u.bindname.name);
}
Register outputReg() const {
return output_;
return u.bindname.output;
}
bool attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain);
bool attachNonGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain, JSObject *holder);
static JSObject *
update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain);
};
class NameIC : public IonCache
class IonCacheName : public IonCache
{
protected:
bool typeOf_;
Register scopeChain_;
PropertyName *name_;
TypedOrValueRegister output_;
public:
NameIC(bool typeOf,
IonCacheName(Kind kind,
CodeOffsetJump initialJump,
CodeOffsetLabel rejoinLabel,
CodeOffsetLabel cacheLabel,
RegisterSet liveRegs,
Register scopeChain, PropertyName *name,
TypedOrValueRegister output)
: typeOf_(typeOf),
scopeChain_(scopeChain),
name_(name),
output_(output)
{
init(kind, liveRegs, initialJump, rejoinLabel, cacheLabel);
u.name.scopeChain = scopeChain;
u.name.name = name;
u.name.output.data() = output;
}
CACHE_HEADER(Name)
Register scopeChainReg() const {
return scopeChain_;
return u.name.scopeChain;
}
HandlePropertyName name() const {
return HandlePropertyName::fromMarkedLocation(&name_);
return HandlePropertyName::fromMarkedLocation(&u.name.name);
}
TypedOrValueRegister outputReg() const {
return output_;
return u.name.output.data();
}
bool isTypeOf() const {
return typeOf_;
return kind_ == NameTypeOf;
}
bool attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject obj,
HandleShape shape);
static bool
update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);
};
class CallsiteCloneIC : public IonCache
class IonCacheCallsiteClone : public IonCache
{
protected:
Register callee_;
Register output_;
JSScript *callScript_;
jsbytecode *callPc_;
public:
CallsiteCloneIC(Register callee, JSScript *callScript, jsbytecode *callPc, Register output)
: callee_(callee),
output_(output),
callScript_(callScript),
callPc_(callPc)
IonCacheCallsiteClone(CodeOffsetJump initialJump,
CodeOffsetLabel rejoinLabel,
CodeOffsetLabel cacheLabel,
RegisterSet liveRegs,
Register callee, JSScript *callScript, jsbytecode *callPc,
Register output)
{
init(CallsiteClone, liveRegs, initialJump, rejoinLabel, cacheLabel);
u.callsiteclone.callee = callee;
u.callsiteclone.callScript = callScript;
u.callsiteclone.callPc = callPc;
u.callsiteclone.output = output;
}
CACHE_HEADER(CallsiteClone)
Register calleeReg() const {
return callee_;
return u.callsiteclone.callee;
}
HandleScript callScript() const {
return HandleScript::fromMarkedLocation(&callScript_);
return HandleScript::fromMarkedLocation(&u.callsiteclone.callScript);
}
jsbytecode *callPc() const {
return callPc_;
return u.callsiteclone.callPc;
}
Register outputReg() const {
return output_;
return u.callsiteclone.output;
}
bool attach(JSContext *cx, IonScript *ion, HandleFunction original, HandleFunction clone);
static JSObject *update(JSContext *cx, size_t cacheIndex, HandleObject callee);
};
#undef CACHE_HEADER
bool
GetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
// Implement cache casts now that the compiler can see the inheritance.
#define CACHE_CASTS(ickind) \
ickind##IC &IonCache::to##ickind() \
{ \
JS_ASSERT(is##ickind()); \
return *static_cast<ickind##IC *>(this); \
}
IONCACHE_KIND_LIST(CACHE_CASTS)
#undef OPCODE_CASTS
bool
SetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value,
bool isSetName);
bool
GetElementCache(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
MutableHandleValue vp);
JSObject *
BindNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain);
bool
GetNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);
JSObject *
CallsiteCloneCache(JSContext *cx, size_t cacheIndex, HandleObject callee);
} // namespace ion
} // namespace js

View File

@ -171,25 +171,22 @@ struct IonScript
// Flag set when we bailout, to avoid frequent bailouts.
bool bailoutExpected_;
// Any kind of data needed by the runtime, these can be either cache
// information or profiling info.
uint32_t runtimeData_;
uint32_t runtimeSize_;
// Offset from the start of the code buffer to its snapshot buffer.
uint32_t snapshots_;
uint32_t snapshotsSize_;
// State for polymorphic caches in the compiled code. All caches are stored
// in the runtimeData buffer and indexed by the cacheIndex which give a
// relative offset in the runtimeData array.
uint32_t cacheIndex_;
uint32_t cacheEntries_;
// Table mapping bailout IDs to snapshot offsets.
uint32_t bailoutTable_;
uint32_t bailoutEntries_;
// Constant table for constants stored in snapshots.
uint32_t constantTable_;
uint32_t constantEntries_;
// Map code displacement to safepoint / OSI-patch-delta.
uint32_t safepointIndexOffset_;
uint32_t safepointIndexEntries_;
// Offset to and length of the safepoint table in bytes.
uint32_t safepointsStart_;
uint32_t safepointsSize_;
// Number of STACK_SLOT_SIZE-length slots this function reserves on the
// stack.
uint32_t frameSlots_;
@ -198,21 +195,17 @@ struct IonScript
// with the frame prefix to get a valid IonJSFrameLayout.
uint32_t frameSize_;
// Table mapping bailout IDs to snapshot offsets.
uint32_t bailoutTable_;
uint32_t bailoutEntries_;
// Map OSI-point displacement to snapshot.
uint32_t osiIndexOffset_;
uint32_t osiIndexEntries_;
// Offset from the start of the code buffer to its snapshot buffer.
uint32_t snapshots_;
uint32_t snapshotsSize_;
// State for polymorphic caches in the compiled code.
uint32_t cacheList_;
uint32_t cacheEntries_;
// Constant table for constants stored in snapshots.
uint32_t constantTable_;
uint32_t constantEntries_;
// Offset to and length of the safepoint table in bytes.
uint32_t safepointsStart_;
uint32_t safepointsSize_;
// List of compiled/inlined JSScript's.
uint32_t scriptList_;
@ -233,50 +226,39 @@ struct IonScript
// Number of references from invalidation records.
size_t refcount_;
// Identifier of the compilation which produced this code.
types::RecompileInfo recompileInfo_;
private:
inline uint8_t *bottomBuffer() {
return reinterpret_cast<uint8_t *>(this);
}
inline const uint8_t *bottomBuffer() const {
return reinterpret_cast<const uint8_t *>(this);
}
public:
// Number of times this function has tried to call a non-IM compileable function
uint32_t slowCallCount;
SnapshotOffset *bailoutTable() {
return (SnapshotOffset *) &bottomBuffer()[bailoutTable_];
return (SnapshotOffset *)(reinterpret_cast<uint8_t *>(this) + bailoutTable_);
}
HeapValue *constants() {
return (HeapValue *) &bottomBuffer()[constantTable_];
return (HeapValue *)(reinterpret_cast<uint8_t *>(this) + constantTable_);
}
const SafepointIndex *safepointIndices() const {
return const_cast<IonScript *>(this)->safepointIndices();
}
SafepointIndex *safepointIndices() {
return (SafepointIndex *) &bottomBuffer()[safepointIndexOffset_];
return (SafepointIndex *)(reinterpret_cast<uint8_t *>(this) + safepointIndexOffset_);
}
const OsiIndex *osiIndices() const {
return const_cast<IonScript *>(this)->osiIndices();
}
OsiIndex *osiIndices() {
return (OsiIndex *) &bottomBuffer()[osiIndexOffset_];
return (OsiIndex *)(reinterpret_cast<uint8_t *>(this) + osiIndexOffset_);
}
uint32_t *cacheIndex() {
return (uint32_t *) &bottomBuffer()[cacheIndex_];
}
uint8_t *runtimeData() {
return &bottomBuffer()[runtimeData_];
IonCache *cacheList() {
return (IonCache *)(reinterpret_cast<uint8_t *>(this) + cacheList_);
}
JSScript **scriptList() const {
return (JSScript **) &bottomBuffer()[scriptList_];
return (JSScript **)(reinterpret_cast<const uint8_t *>(this) + scriptList_);
}
JSScript **parallelInvalidatedScriptList() {
return (JSScript **) &bottomBuffer()[parallelInvalidatedScriptList_];
return (JSScript **)(reinterpret_cast<const uint8_t *>(this) +
parallelInvalidatedScriptList_);
}
private:
@ -289,8 +271,7 @@ struct IonScript
static IonScript *New(JSContext *cx, uint32_t frameLocals, uint32_t frameSize,
size_t snapshotsSize, size_t snapshotEntries,
size_t constants, size_t safepointIndexEntries, size_t osiIndexEntries,
size_t cacheEntries, size_t runtimeSize,
size_t safepointsSize, size_t scriptEntries,
size_t cacheEntries, size_t safepointsSize, size_t scriptEntries,
size_t parallelInvalidatedScriptEntries);
static void Trace(JSTracer *trc, IonScript *script);
static void Destroy(FreeOp *fop, IonScript *script);
@ -411,18 +392,10 @@ struct IonScript
}
const OsiIndex *getOsiIndex(uint32_t disp) const;
const OsiIndex *getOsiIndex(uint8_t *retAddr) const;
inline IonCache &getCache(uint32_t index) {
JS_ASSERT(index < cacheEntries_);
uint32_t offset = cacheIndex()[index];
JS_ASSERT(offset < runtimeSize_);
return *(IonCache *) &runtimeData()[offset];
}
inline IonCache &getCache(size_t index);
size_t numCaches() const {
return cacheEntries_;
}
size_t runtimeSize() const {
return runtimeSize_;
}
void toggleBarriers(bool enabled);
void purgeCaches(JSCompartment *c);
void copySnapshots(const SnapshotWriter *writer);
@ -430,8 +403,7 @@ struct IonScript
void copyConstants(const HeapValue *vp);
void copySafepointIndices(const SafepointIndex *firstSafepointIndex, MacroAssembler &masm);
void copyOsiIndices(const OsiIndex *firstOsiIndex, MacroAssembler &masm);
void copyRuntimeData(const uint8_t *data);
void copyCacheEntries(const uint32_t *caches, MacroAssembler &masm);
void copyCacheEntries(const IonCache *caches, MacroAssembler &masm);
void copySafepoints(const SafepointWriter *writer);
void copyScriptEntries(JSScript **scripts);
void zeroParallelInvalidatedScripts();

View File

@ -113,7 +113,7 @@ class MacroAssembler : public MacroAssemblerSpecific
return size();
}
void propagateOOM(bool success) {
void reportMemory(bool success) {
enoughMemory_ &= success;
}
bool oom() const {

View File

@ -396,33 +396,14 @@ class CodeOffsetLabel
class CodeLocationJump
{
uint8_t *raw_;
#ifdef DEBUG
bool absolute_;
void setAbsolute() {
absolute_ = true;
}
void setRelative() {
absolute_ = false;
}
#else
void setAbsolute() const {
}
void setRelative() const {
}
#endif
mozilla::DebugOnly<bool> absolute_;
#ifdef JS_SMALL_BRANCH
uint8_t *jumpTableEntry_;
#endif
public:
CodeLocationJump() {
raw_ = (uint8_t *) 0xdeadc0de;
setAbsolute();
#ifdef JS_SMALL_BRANCH
jumpTableEntry_ = (uint8_t *) 0xdeadab1e;
#endif
}
CodeLocationJump() {}
CodeLocationJump(IonCode *code, CodeOffsetJump base) {
*this = base;
repoint(code);
@ -430,7 +411,7 @@ class CodeLocationJump
void operator = (CodeOffsetJump base) {
raw_ = (uint8_t *) base.offset();
setRelative();
absolute_ = false;
#ifdef JS_SMALL_BRANCH
jumpTableEntry_ = (uint8_t *) base.jumpTableIndex();
#endif
@ -439,11 +420,11 @@ class CodeLocationJump
void repoint(IonCode *code, MacroAssembler* masm = NULL);
uint8_t *raw() const {
JS_ASSERT(absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
JS_ASSERT(absolute_);
return raw_;
}
uint8_t *offset() const {
JS_ASSERT(!absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
JS_ASSERT(!absolute_);
return raw_;
}
@ -458,42 +439,26 @@ class CodeLocationJump
class CodeLocationLabel
{
uint8_t *raw_;
#ifdef DEBUG
bool absolute_;
void setAbsolute() {
absolute_ = true;
}
void setRelative() {
absolute_ = false;
}
#else
void setAbsolute() const {
}
void setRelative() const {
}
#endif
mozilla::DebugOnly<bool> absolute_;
public:
CodeLocationLabel() {
raw_ = (uint8_t *) 0xdeadc0de;
setAbsolute();
}
CodeLocationLabel() {}
CodeLocationLabel(IonCode *code, CodeOffsetLabel base) {
*this = base;
repoint(code);
}
CodeLocationLabel(IonCode *code) {
raw_ = code->raw();
setAbsolute();
absolute_ = true;
}
CodeLocationLabel(uint8_t *raw) {
raw_ = raw;
setAbsolute();
absolute_ = true;
}
void operator = (CodeOffsetLabel base) {
raw_ = (uint8_t *)base.offset();
setRelative();
absolute_ = false;
}
ptrdiff_t operator - (const CodeLocationLabel &other) {
return raw_ - other.raw_;
@ -502,11 +467,11 @@ class CodeLocationLabel
void repoint(IonCode *code, MacroAssembler *masm = NULL);
uint8_t *raw() {
JS_ASSERT(absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
JS_ASSERT(absolute_);
return raw_;
}
uint8_t *offset() {
JS_ASSERT(!absolute_ && raw_ != (uint8_t *) 0xdeadc0de);
JS_ASSERT(!absolute_);
return raw_;
}
};

View File

@ -25,12 +25,10 @@ namespace ion {
class OutOfLineCode;
class CodeGenerator;
class MacroAssembler;
class IonCache;
class OutOfLineParallelAbort;
template <class ArgSeq, class StoreOutputTo>
class OutOfLineCallVM;
class OutOfLineTruncateSlow;
class CodeGeneratorShared : public LInstructionVisitor
@ -62,11 +60,8 @@ class CodeGeneratorShared : public LInstructionVisitor
// Mapping from bailout table ID to an offset in the snapshot buffer.
js::Vector<SnapshotOffset, 0, SystemAllocPolicy> bailouts_;
// Allocated data space needed at runtime.
js::Vector<uint8_t, 0, SystemAllocPolicy> runtimeData_;
// Vector of information about generated polymorphic inline caches.
js::Vector<uint32_t, 0, SystemAllocPolicy> cacheList_;
js::Vector<IonCache, 0, SystemAllocPolicy> cacheList_;
// List of stack slots that have been pushed as arguments to an MCall.
js::Vector<uint32_t, 0, SystemAllocPolicy> pushedArgumentSlots_;
@ -159,35 +154,10 @@ class CodeGeneratorShared : public LInstructionVisitor
}
protected:
// Ensure the cache is an IonCache while expecting the size of the derived
// class.
size_t allocateCache(const IonCache &, size_t size) {
size_t dataOffset = allocateData(size);
size_t allocateCache(const IonCache &cache) {
size_t index = cacheList_.length();
masm.propagateOOM(cacheList_.append(dataOffset));
return index;
}
// This is needed by addCache to update the cache with the jump
// informations provided by the out-of-line path.
IonCache *getCache(size_t index) {
return reinterpret_cast<IonCache *>(&runtimeData_[cacheList_[index]]);
}
protected:
size_t allocateData(size_t size) {
JS_ASSERT(size % sizeof(void *) == 0);
size_t dataOffset = runtimeData_.length();
masm.propagateOOM(runtimeData_.appendN(0, size));
return dataOffset;
}
template <typename T>
inline size_t allocateCache(const T &cache) {
size_t index = allocateCache(cache, sizeof(mozilla::AlignedStorage2<T>));
// Use the copy constructor on the allocated space.
new (&runtimeData_[cacheList_.back()]) T(cache);
masm.reportMemory(cacheList_.append(cache));
return index;
}
@ -307,8 +277,6 @@ class CodeGeneratorShared : public LInstructionVisitor
inline OutOfLineCode *oolCallVM(const VMFunction &fun, LInstruction *ins, const ArgSeq &args,
const StoreOutputTo &out);
bool addCache(LInstruction *lir, size_t cacheIndex);
protected:
bool addOutOfLineCode(OutOfLineCode *code);
bool generateOutOfLineCode();
@ -405,7 +373,7 @@ class OutOfLineCodeBase : public OutOfLineCode
// ArgSeq store arguments for OutOfLineCallVM.
//
// OutOfLineCallVM are created with "oolCallVM" function. The third argument of
// OutOfLineCallVM are created with "oolCallVM" function. The last argument of
// this function is an instance of a class which provides a "generate" function
// to call the "pushArg" needed by the VMFunction call. The list of argument
// can be created by using the ArgList function which create an empty list of
@ -444,7 +412,6 @@ class ArgSeq : public SeqType
}
};
// Mark the end of an argument list.
template <>
class ArgSeq<void, void>
{

View File

@ -1,37 +0,0 @@
// This test is made to be effective with --no-jm.
var list = [
{ entry00: 0, length: 1 },
{ entry01: 0, length: 1 },
{ entry02: 0, length: 1 },
{ entry03: 0, length: 1 },
{ entry04: 0, length: 1 },
{ entry05: 0, length: 1 },
{ entry06: 0, length: 1 },
{ entry07: 0, length: 1 },
{ entry08: 0, length: 1 },
{ entry09: 0, length: 1 },
{ entry10: 0, length: 1 },
{ entry11: 0, length: 1 },
{ entry12: 0, length: 1 },
{ entry13: 0, length: 1 },
{ entry14: 0, length: 1 },
{ entry15: 0, length: 1 },
{ entry16: 0, length: 1 }, // cause an overflow.
{ entry17: 0, length: 1 },
[0],
(new Uint8Array(new ArrayBuffer(1)))
];
function f(obj) {
return obj.length;
}
// Cook the f function on the top of the list to make sure we do not register
// our test cases.
for (var i = 0; i < 100; i++)
f(list[i % 10]);
// Register & check stubs.
for (var i = 0; i < 40; i++)
assertEq(f(list[i % 20]), 1);

View File

@ -748,7 +748,7 @@ GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *objArg, bool wasObje
uint32_t index;
if (IsDefinitelyIndex(rref, &index)) {
if (analyze && !objArg->isNative() && !objArg->isTypedArray()) {
if (analyze && !objArg->isNative()) {
JSScript *script = NULL;
jsbytecode *pc = NULL;
types::TypeScript::GetPcScript(cx, &script, &pc);
@ -775,7 +775,7 @@ GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *objArg, bool wasObje
if (script->hasAnalysis()) {
script->analysis()->getCode(pc).getStringElement = true;
if (!objArg->isArray() && !objArg->isNative() && !objArg->isTypedArray())
if (!objArg->isArray() && !objArg->isNative())
script->analysis()->getCode(pc).nonNativeGetElement = true;
}
}