Bug 906805 - Implement Baseline JSOP_GETELEM handlers which invoke getters. r=efaust

This commit is contained in:
Kannan Vijayan 2013-09-03 17:55:20 -04:00
Родитель 1bbecd33dc
Коммит eac17dea98
4 изменённых файлов: 860 добавлений и 143 удалений

Просмотреть файл

@ -183,20 +183,31 @@ ICStub::trace(JSTracer *trc)
MarkObject(trc, &callStub->callee(), "baseline-callnative-callee");
break;
}
case ICStub::GetElem_Native: {
ICGetElem_Native *getElemStub = toGetElem_Native();
case ICStub::GetElem_NativeSlot: {
ICGetElem_NativeSlot *getElemStub = toGetElem_NativeSlot();
MarkShape(trc, &getElemStub->shape(), "baseline-getelem-native-shape");
gc::MarkValue(trc, &getElemStub->idval(), "baseline-getelem-native-idval");
MarkString(trc, &getElemStub->name(), "baseline-getelem-native-name");
break;
}
case ICStub::GetElem_NativePrototype: {
ICGetElem_NativePrototype *getElemStub = toGetElem_NativePrototype();
case ICStub::GetElem_NativePrototypeSlot: {
ICGetElem_NativePrototypeSlot *getElemStub = toGetElem_NativePrototypeSlot();
MarkShape(trc, &getElemStub->shape(), "baseline-getelem-nativeproto-shape");
gc::MarkValue(trc, &getElemStub->idval(), "baseline-getelem-nativeproto-idval");
MarkString(trc, &getElemStub->name(), "baseline-getelem-nativeproto-name");
MarkObject(trc, &getElemStub->holder(), "baseline-getelem-nativeproto-holder");
MarkShape(trc, &getElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
break;
}
case ICStub::GetElem_NativePrototypeCallNative:
case ICStub::GetElem_NativePrototypeCallScripted: {
ICGetElemNativePrototypeCallStub *callStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub *>(this);
MarkShape(trc, &callStub->shape(), "baseline-getelem-nativeprotocall-shape");
MarkString(trc, &callStub->name(), "baseline-getelem-nativeprotocall-name");
MarkObject(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
MarkObject(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
MarkShape(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
break;
}
case ICStub::GetElem_Dense: {
ICGetElem_Dense *getElemStub = toGetElem_Dense();
MarkShape(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
@ -618,14 +629,20 @@ void
ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
{
// This should only be called from the following stubs.
JS_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted ||
kind == ICStub::Call_Native || kind == ICStub::GetProp_CallScripted ||
kind == ICStub::GetProp_CallNative || kind == ICStub::GetProp_CallDOMProxyNative ||
kind == ICStub::Call_ScriptedApplyArray ||
kind == ICStub::Call_ScriptedApplyArguments ||
kind == ICStub::GetProp_CallDOMProxyWithGenerationNative ||
kind == ICStub::GetProp_DOMProxyShadowed ||
kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
JS_ASSERT(kind == ICStub::Call_Scripted ||
kind == ICStub::Call_AnyScripted ||
kind == ICStub::Call_Native ||
kind == ICStub::Call_ScriptedApplyArray ||
kind == ICStub::Call_ScriptedApplyArguments ||
kind == ICStub::GetProp_CallScripted ||
kind == ICStub::GetProp_CallNative ||
kind == ICStub::GetProp_CallDOMProxyNative ||
kind == ICStub::GetElem_NativePrototypeCallNative ||
kind == ICStub::GetElem_NativePrototypeCallScripted ||
kind == ICStub::GetProp_CallDOMProxyWithGenerationNative ||
kind == ICStub::GetProp_DOMProxyShadowed ||
kind == ICStub::SetProp_CallScripted ||
kind == ICStub::SetProp_CallNative);
// Guard on bit in frame that indicates if the SPS frame was pushed in the first
// place. This code is expected to be called from within a stub that has already
@ -1544,6 +1561,31 @@ ICTypeUpdate_TypeObject::Compiler::generateStubCode(MacroAssembler &masm)
return true;
}
//
// VM function to help call native getters.
//
static bool
DoCallNativeGetter(JSContext *cx, HandleFunction callee, HandleObject obj,
MutableHandleValue result)
{
JS_ASSERT(callee->isNative());
JSNative natfun = callee->native();
Value vp[2] = { ObjectValue(*callee.get()), ObjectValue(*obj.get()) };
AutoValueArray rootVp(cx, vp, 2);
if (!natfun(cx, 0, vp))
return false;
result.set(vp[0]);
return true;
}
typedef bool (*DoCallNativeGetterFn)(JSContext *, HandleFunction, HandleObject, MutableHandleValue);
static const VMFunction DoCallNativeGetterInfo =
FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter);
//
// This_Fallback
//
@ -3414,6 +3456,143 @@ IsCacheableSetPropCall(JSObject *obj, JSObject *holder, Shape *shape, bool *isSc
return true;
}
static bool
GetElemNativeStubExists(ICGetElem_Fallback *stub, HandleObject obj, HandleObject holder,
HandlePropertyName propName, bool needsAtomize)
{
bool indirect = (obj.get() != holder.get());
for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
if (iter->kind() != ICStub::GetElem_NativeSlot &&
iter->kind() != ICStub::GetElem_NativePrototypeSlot &&
iter->kind() != ICStub::GetElem_NativePrototypeCallNative &&
iter->kind() != ICStub::GetElem_NativePrototypeCallScripted)
{
continue;
}
if (indirect && (iter->kind() != ICStub::GetElem_NativePrototypeSlot &&
iter->kind() != ICStub::GetElem_NativePrototypeCallNative &&
iter->kind() != ICStub::GetElem_NativePrototypeCallScripted))
{
continue;
}
ICGetElemNativeStub *getElemNativeStub = reinterpret_cast<ICGetElemNativeStub *>(*iter);
if (propName != getElemNativeStub->name())
continue;
if (obj->lastProperty() != getElemNativeStub->shape())
continue;
// If the new stub needs atomization, and the old stub doesn't atomize, then
// an appropriate stub doesn't exist.
if (needsAtomize && !getElemNativeStub->needsAtomize())
continue;
// For prototype gets, check the holder and holder shape.
if (indirect) {
if (iter->isGetElem_NativePrototypeSlot()) {
ICGetElem_NativePrototypeSlot *protoStub = iter->toGetElem_NativePrototypeSlot();
if (holder != protoStub->holder())
continue;
if (holder->lastProperty() != protoStub->holderShape())
continue;
} else {
JS_ASSERT(iter->isGetElem_NativePrototypeCallNative() ||
iter->isGetElem_NativePrototypeCallScripted());
ICGetElemNativePrototypeCallStub *protoStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub *>(*iter);
if (holder != protoStub->holder())
continue;
if (holder->lastProperty() != protoStub->holderShape())
continue;
}
}
return true;
}
return false;
}
static void
RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, HandleObject obj,
HandleObject holder, HandlePropertyName propName,
bool needsAtomize)
{
bool indirect = (obj.get() != holder.get());
for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) {
switch (iter->kind()) {
case ICStub::GetElem_NativeSlot:
if (indirect)
continue;
case ICStub::GetElem_NativePrototypeSlot:
case ICStub::GetElem_NativePrototypeCallNative:
case ICStub::GetElem_NativePrototypeCallScripted:
break;
default:
continue;
}
ICGetElemNativeStub *getElemNativeStub = reinterpret_cast<ICGetElemNativeStub *>(*iter);
if (propName != getElemNativeStub->name())
continue;
if (obj->lastProperty() != getElemNativeStub->shape())
continue;
// For prototype gets, check the holder and holder shape.
if (indirect) {
if (iter->isGetElem_NativePrototypeSlot()) {
ICGetElem_NativePrototypeSlot *protoStub = iter->toGetElem_NativePrototypeSlot();
if (holder != protoStub->holder())
continue;
// If the holder matches, but the holder's lastProperty doesn't match, then
// this stub is invalid anyway. Unlink it.
if (holder->lastProperty() != protoStub->holderShape()) {
iter.unlink(cx->zone());
continue;
}
} else {
JS_ASSERT(iter->isGetElem_NativePrototypeCallNative() ||
iter->isGetElem_NativePrototypeCallScripted());
ICGetElemNativePrototypeCallStub *protoStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub *>(*iter);
if (holder != protoStub->holder())
continue;
// If the holder matches, but the holder's lastProperty doesn't match, then
// this stub is invalid anyway. Unlink it.
if (holder->lastProperty() != protoStub->holderShape()) {
iter.unlink(cx->zone());
continue;
}
}
}
// If the new stub needs atomization, and the old stub doesn't atomize, then
// remove the old stub.
if (needsAtomize && !getElemNativeStub->needsAtomize()) {
iter.unlink(cx->zone());
continue;
}
// Should never get here, because this means a matching stub exists, and if
// a matching stub exists, this procedure should never have been called.
MOZ_ASSUME_UNREACHABLE("Procedure should never have been called.");
}
}
static bool
TypedArrayGetElemStubExists(ICGetElem_Fallback *stub, HandleObject obj)
{
@ -3439,10 +3618,15 @@ ArgumentsGetElemStubExists(ICGetElem_Fallback *stub, ICGetElem_Arguments::Which
}
static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script,
static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc,
ICGetElem_Fallback *stub, HandleObject obj,
HandleValue key)
{
// Native-object GetElem stubs can't deal with non-string keys.
if (!key.isString())
return true;
// Convert to interned property name.
RootedId id(cx);
if (!ValueToId<CanGC>(cx, key, &id))
return false;
@ -3452,33 +3636,92 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script,
return true;
RootedPropertyName propName(cx, JSID_TO_ATOM(id)->asPropertyName());
bool needsAtomize = !key.toString()->isAtom();
RootedShape shape(cx);
RootedObject holder(cx);
if (!EffectlesslyLookupProperty(cx, obj, propName, &holder, &shape))
return false;
if (!IsCacheableGetPropReadSlot(obj, holder, shape))
if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
// If a suitable stub already exists, nothing else to do.
if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize))
return true;
// Remove any existing stubs that may interfere with the new stub being added.
RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize);
bool isFixedSlot;
uint32_t offset;
GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlot
: ICStub::GetElem_NativePrototypeSlot;
IonSpew(IonSpew_BaselineIC, " Generating GetElem(Native %s%s slot) stub "
"(obj=%p, shape=%p, holder=%p, holderShape=%p)",
(obj == holder) ? "direct" : "prototype",
needsAtomize ? " atomizing" : "",
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot
: ICGetElemNativeStub::DynamicSlot;
ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype,
needsAtomize, offset);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
return true;
}
bool isFixedSlot;
uint32_t offset;
GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
bool getterIsScripted = false;
if (IsCacheableGetPropCall(obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) {
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_Native : ICStub::GetElem_NativePrototype;
// If a suitable stub already exists, nothing else to do.
if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize))
return true;
IonSpew(IonSpew_BaselineIC, " Generating GetElem(Native %s) stub (obj=%p, shape=%p, holder=%p, holderShape=%p)",
(obj == holder) ? "direct" : "prototype",
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
// Remove any existing stubs that may interfere with the new stub being added.
RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize);
ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, key,
isFixedSlot, offset);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
ICStub::Kind kind = getterIsScripted ? ICStub::GetElem_NativePrototypeCallScripted
: ICStub::GetElem_NativePrototypeCallNative;
if (getterIsScripted) {
IonSpew(IonSpew_BaselineIC,
" Generating GetElem(Native %s%s call scripted %s:%d) stub "
"(obj=%p, shape=%p, holder=%p, holderShape=%p)",
(obj == holder) ? "direct" : "prototype",
needsAtomize ? " atomizing" : "",
getter->nonLazyScript()->filename(), getter->nonLazyScript()->lineno,
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
} else {
IonSpew(IonSpew_BaselineIC,
" Generating GetElem(Native %s%s call native) stub "
"(obj=%p, shape=%p, holder=%p, holderShape=%p)",
(obj == holder) ? "direct" : "prototype",
needsAtomize ? " atomizing" : "",
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
}
ICGetElemNativeStub::AccessType acctype = getterIsScripted
? ICGetElemNativeStub::ScriptedGetter
: ICGetElemNativeStub::NativeGetter;
ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype,
needsAtomize, getter, pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
return true;
}
stub->addNewStub(newStub);
return true;
}
@ -3492,7 +3735,7 @@ TypedArrayRequiresFloatingPoint(TypedArrayObject *tarr)
}
static bool
TryAttachGetElemStub(JSContext *cx, HandleScript script, ICGetElem_Fallback *stub,
TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetElem_Fallback *stub,
HandleValue lhs, HandleValue rhs, HandleValue res)
{
// Check for String[i] => Char accesses.
@ -3562,7 +3805,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, ICGetElem_Fallback *stu
// Check for NativeObject[id] shape-optimizable accesses.
if (rhs.isString()) {
if (!TryAttachNativeGetElemStub(cx, script, stub, obj, rhs))
if (!TryAttachNativeGetElemStub(cx, script, pc, stub, obj, rhs))
return false;
}
}
@ -3640,7 +3883,7 @@ DoGetElemFallback(JSContext *cx, BaselineFrame *frame, ICGetElem_Fallback *stub,
}
// Try to attach an optimized stub.
if (!TryAttachGetElemStub(cx, script, stub, lhs, rhs, res))
if (!TryAttachGetElemStub(cx, script, pc, stub, lhs, rhs, res))
return false;
return true;
@ -3673,9 +3916,164 @@ ICGetElem_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
}
//
// GetElem_Native
// GetElem_NativeSlot
//
static bool
DoAtomizeString(JSContext *cx, HandleString string, MutableHandleValue result)
{
IonSpew(IonSpew_BaselineIC, " AtomizeString called");
RootedValue key(cx, StringValue(string));
// Convert to interned property name.
RootedId id(cx);
if (!ValueToId<CanGC>(cx, key, &id))
return false;
if (!JSID_IS_ATOM(id)) {
result.set(key);
return true;
}
result.set(StringValue(JSID_TO_ATOM(id)));
return true;
}
typedef bool (*DoAtomizeStringFn)(JSContext *, HandleString, MutableHandleValue);
static const VMFunction DoAtomizeStringInfo = FunctionInfo<DoAtomizeStringFn>(DoAtomizeString);
bool
ICGetElemNativeCompiler::emitCallNative(MacroAssembler &masm, Register objReg)
{
GeneralRegisterSet regs = availableGeneralRegs(0);
regs.takeUnchecked(objReg);
regs.takeUnchecked(BaselineTailCallReg);
enterStubFrame(masm, regs.getAny());
// Push object.
masm.push(objReg);
// Push native callee.
masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), objReg);
masm.push(objReg);
regs.add(objReg);
// Profiler hook.
{
Label skipProfilerUpdate;
Register scratch = regs.takeAny();
Register pcIdx = regs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
masm.load32(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime()->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
regs.add(scratch);
regs.add(pcIdx);
}
// Call helper.
if (!callVM(DoCallNativeGetterInfo, masm))
return false;
leaveStubFrame(masm);
return true;
}
bool
ICGetElemNativeCompiler::emitCallScripted(MacroAssembler &masm, Register objReg)
{
GeneralRegisterSet regs = availableGeneralRegs(0);
regs.takeUnchecked(objReg);
regs.takeUnchecked(BaselineTailCallReg);
// Enter stub frame.
enterStubFrame(masm, regs.getAny());
// Push |this| for getter (target object).
{
ValueOperand val = regs.takeAnyValue();
masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
masm.Push(val);
regs.add(val);
}
regs.add(objReg);
Register callee = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), callee);
// Push argc, callee, and descriptor.
{
Register callScratch = regs.takeAny();
EmitCreateStubFrameDescriptor(masm, callScratch);
masm.Push(Imm32(0)); // ActualArgc is 0
masm.Push(callee);
masm.Push(callScratch);
regs.add(callScratch);
}
Register code = regs.takeAnyExcluding(ArgumentsRectifierReg);
masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
masm.loadBaselineOrIonRaw(code, code, SequentialExecution, NULL);
Register scratch = regs.takeAny();
// Handle arguments underflow.
Label noUnderflow;
masm.load16ZeroExtend(Address(callee, offsetof(JSFunction, nargs)), scratch);
masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
{
// Call the arguments rectifier.
JS_ASSERT(ArgumentsRectifierReg != code);
IonCode *argumentsRectifier =
cx->runtime()->ionRuntime()->getArgumentsRectifier(SequentialExecution);
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
masm.loadPtr(Address(code, IonCode::offsetOfCode()), code);
masm.mov(Imm32(0), ArgumentsRectifierReg);
}
masm.bind(&noUnderflow);
// If needed, update SPS Profiler frame entry. At this point, callee and scratch can
// be clobbered.
{
Label skipProfilerUpdate;
// Need to avoid using ArgumentsRectifierReg and code register.
GeneralRegisterSet availRegs = availableGeneralRegs(0);
availRegs.take(ArgumentsRectifierReg);
availRegs.take(code);
Register scratch = availRegs.takeAny();
Register pcIdx = availRegs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
masm.load32(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfPCOffset()),
pcIdx);
masm.spsUpdatePCIdx(&cx->runtime()->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
}
masm.callIon(code);
leaveStubFrame(masm, true);
return true;
}
bool
ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
{
@ -3684,9 +4082,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
bool popR1 = false;
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
Address idValAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfIdval());
masm.branchTestValue(Assembler::NotEqual, idValAddr, R1, &failure);
masm.branchTestString(Assembler::NotEqual, R1, &failure);
GeneralRegisterSet regs(availableGeneralRegs(2));
Register scratchReg = regs.takeAny();
@ -3699,6 +4095,54 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
Address shapeAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfShape());
masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure);
// Check key identity. Don't automatically fail if this fails, since the incoming
// key maybe a non-interned string. Switch to a slowpath vm-call based check.
Address nameAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfName());
Register strExtract = masm.extractString(R1, ExtractTemp1);
// If needsAtomize_ is true, and the string is not already an atom, then atomize the
// string before proceeding.
if (needsAtomize_) {
Label skipAtomize;
// If string is already an atom, skip the atomize.
masm.branchTestPtr(Assembler::NonZero,
Address(strExtract, JSString::offsetOfLengthAndFlags()),
Imm32(JSString::ATOM_BIT),
&skipAtomize);
// Stow R0.
EmitStowICValues(masm, 1);
enterStubFrame(masm, R0.scratchReg());
// Atomize the string into a new value.
masm.push(strExtract);
if (!callVM(DoAtomizeStringInfo, masm))
return false;
// Atomized string is now in JSReturnOperand (R0).
// Leave stub frame, move atomized string into R1.
JS_ASSERT(R0 == JSReturnOperand);
leaveStubFrame(masm);
masm.moveValue(JSReturnOperand, R1);
// Unstow R0
EmitUnstowICValues(masm, 1);
// Extract string from R1 again.
Register strExtract2 = masm.extractString(R1, ExtractTemp1);
JS_ASSERT(strExtract2 == strExtract);
masm.bind(&skipAtomize);
}
// Since this stub sometimes enter a stub frame, we manually set this to true (lie).
entersStubFrame_ = true;
// Key has been atomized if necessary. Do identity check on string pointer.
masm.branchPtr(Assembler::NotEqual, nameAddr, strExtract, &failure);
Register holderReg;
if (obj_ == holder_) {
holderReg = objReg;
@ -3711,23 +4155,73 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
} else {
holderReg = regs.takeAny();
}
masm.loadPtr(Address(BaselineStubReg, ICGetElem_NativePrototype::offsetOfHolder()),
holderReg);
masm.loadPtr(Address(BaselineStubReg, ICGetElem_NativePrototype::offsetOfHolderShape()),
scratchReg);
if (kind == ICStub::GetElem_NativePrototypeCallNative ||
kind == ICStub::GetElem_NativePrototypeCallScripted)
{
masm.loadPtr(Address(BaselineStubReg,
ICGetElemNativePrototypeCallStub::offsetOfHolder()),
holderReg);
masm.loadPtr(Address(BaselineStubReg,
ICGetElemNativePrototypeCallStub::offsetOfHolderShape()),
scratchReg);
} else {
masm.loadPtr(Address(BaselineStubReg,
ICGetElem_NativePrototypeSlot::offsetOfHolder()),
holderReg);
masm.loadPtr(Address(BaselineStubReg,
ICGetElem_NativePrototypeSlot::offsetOfHolderShape()),
scratchReg);
}
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratchReg,
popR1 ? &failurePopR1 : &failure);
}
// Load from object.
if (!isFixedSlot_)
masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg);
if (acctype_ == ICGetElemNativeStub::DynamicSlot ||
acctype_ == ICGetElemNativeStub::FixedSlot)
{
// Load from object.
if (acctype_ == ICGetElemNativeStub::DynamicSlot)
masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg);
masm.load32(Address(BaselineStubReg, ICGetElem_Native::offsetOfOffset()), scratchReg);
masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0);
masm.load32(Address(BaselineStubReg, ICGetElemNativeSlotStub::offsetOfOffset()),
scratchReg);
masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0);
if (popR1)
masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
} else {
JS_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter ||
acctype_ == ICGetElemNativeStub::ScriptedGetter);
JS_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNative ||
kind == ICStub::GetElem_NativePrototypeCallScripted);
if (acctype_ == ICGetElemNativeStub::NativeGetter) {
// If calling a native getter, there is no chance of failure now.
// GetElem key (R1) is no longer needed.
if (popR1)
masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
emitCallNative(masm, objReg);
} else {
JS_ASSERT(acctype_ == ICGetElemNativeStub::ScriptedGetter);
// Load function in scratchReg and ensure that it has a jit script.
masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()),
scratchReg);
masm.loadBaselineOrIonRaw(scratchReg, scratchReg, SequentialExecution,
popR1 ? &failurePopR1 : &failure);
// At this point, we are guaranteed to successfully complete.
if (popR1)
masm.addPtr(Imm32(sizeof(size_t)), BaselineStackReg);
emitCallScripted(masm, objReg);
}
}
if (popR1)
masm.pop(R1.scratchReg());
// Enter type monitor IC to type-check result.
EmitEnterTypeMonitorIC(masm);
@ -3738,6 +4232,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
}
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
@ -5800,27 +6295,6 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
return true;
}
static bool
DoCallNativeGetter(JSContext *cx, HandleFunction callee, HandleObject obj,
MutableHandleValue result)
{
JS_ASSERT(callee->isNative());
JSNative natfun = callee->native();
Value vp[2] = { ObjectValue(*callee.get()), ObjectValue(*obj.get()) };
AutoValueArray rootVp(cx, vp, 2);
if (!natfun(cx, 0, vp))
return false;
result.set(vp[0]);
return true;
}
typedef bool (*DoCallNativeGetterFn)(JSContext *, HandleFunction, HandleObject, MutableHandleValue);
static const VMFunction DoCallNativeGetterInfo =
FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter);
bool
ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
{
@ -8548,29 +9022,54 @@ ICTypeUpdate_TypeObject::ICTypeUpdate_TypeObject(IonCode *stubCode, HandleTypeOb
ICGetElemNativeStub::ICGetElemNativeStub(ICStub::Kind kind, IonCode *stubCode,
ICStub *firstMonitorStub,
HandleShape shape, HandleValue idval,
bool isFixedSlot, uint32_t offset)
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize)
: ICMonitoredStub(kind, stubCode, firstMonitorStub),
shape_(shape),
idval_(idval),
offset_(offset)
name_(name)
{
extra_ = isFixedSlot;
extra_ = (static_cast<uint16_t>(acctype) << ACCESSTYPE_SHIFT) |
(static_cast<uint16_t>(needsAtomize) << NEEDS_ATOMIZE_SHIFT);
}
ICGetElemNativeStub::~ICGetElemNativeStub()
{ }
ICGetElem_NativePrototype::ICGetElem_NativePrototype(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleValue idval,
bool isFixedSlot, uint32_t offset,
HandleObject holder, HandleShape holderShape)
: ICGetElemNativeStub(ICStub::GetElem_NativePrototype, stubCode, firstMonitorStub, shape,
idval, isFixedSlot, offset),
ICGetElemNativeGetterStub::ICGetElemNativeGetterStub(
ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name, AccessType acctype,
bool needsAtomize, HandleFunction getter, uint32_t pcOffset)
: ICGetElemNativeStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize),
getter_(getter),
pcOffset_(pcOffset)
{
JS_ASSERT(kind == GetElem_NativePrototypeCallNative ||
kind == GetElem_NativePrototypeCallScripted);
JS_ASSERT(acctype == NativeGetter || acctype == ScriptedGetter);
}
ICGetElem_NativePrototypeSlot::ICGetElem_NativePrototypeSlot(
IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize, uint32_t offset,
HandleObject holder, HandleShape holderShape)
: ICGetElemNativeSlotStub(ICStub::GetElem_NativePrototypeSlot, stubCode, firstMonitorStub, shape,
name, acctype, needsAtomize, offset),
holder_(holder),
holderShape_(holderShape)
{ }
ICGetElemNativePrototypeCallStub::ICGetElemNativePrototypeCallStub(
ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize, HandleFunction getter,
uint32_t pcOffset, HandleObject holder, HandleShape holderShape)
: ICGetElemNativeGetterStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize,
getter, pcOffset),
holder_(holder),
holderShape_(holderShape)
{}
ICGetElem_Dense::ICGetElem_Dense(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape)
: ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub),
shape_(shape)

Просмотреть файл

@ -328,8 +328,10 @@ class ICEntry
_(Call_ScriptedApplyArguments) \
\
_(GetElem_Fallback) \
_(GetElem_Native) \
_(GetElem_NativePrototype) \
_(GetElem_NativeSlot) \
_(GetElem_NativePrototypeSlot) \
_(GetElem_NativePrototypeCallNative) \
_(GetElem_NativePrototypeCallScripted) \
_(GetElem_String) \
_(GetElem_Dense) \
_(GetElem_TypedArray) \
@ -735,6 +737,10 @@ class ICStub
case Call_ScriptedApplyArray:
case Call_ScriptedApplyArguments:
case UseCount_Fallback:
case GetElem_NativeSlot:
case GetElem_NativePrototypeSlot:
case GetElem_NativePrototypeCallNative:
case GetElem_NativePrototypeCallScripted:
case GetProp_CallScripted:
case GetProp_CallNative:
case GetProp_CallDOMProxyNative:
@ -2839,14 +2845,22 @@ class ICGetElem_Fallback : public ICMonitoredFallbackStub
class ICGetElemNativeStub : public ICMonitoredStub
{
HeapPtrShape shape_;
HeapValue idval_;
uint32_t offset_;
public:
enum AccessType { FixedSlot = 0, DynamicSlot, NativeGetter, ScriptedGetter };
protected:
HeapPtrShape shape_;
HeapPtrPropertyName name_;
static const unsigned NEEDS_ATOMIZE_SHIFT = 0;
static const uint16_t NEEDS_ATOMIZE_MASK = 0x1;
static const unsigned ACCESSTYPE_SHIFT = 1;
static const uint16_t ACCESSTYPE_MASK = 0x3;
ICGetElemNativeStub(ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleValue idval,
bool isFixedSlot, uint32_t offset);
HandleShape shape, HandlePropertyName name, AccessType acctype,
bool needsAtomize);
~ICGetElemNativeStub();
@ -2858,130 +2872,311 @@ class ICGetElemNativeStub : public ICMonitoredStub
return offsetof(ICGetElemNativeStub, shape_);
}
HeapValue &idval() {
return idval_;
HeapPtrPropertyName &name() {
return name_;
}
static size_t offsetOfIdval() {
return offsetof(ICGetElemNativeStub, idval_);
static size_t offsetOfName() {
return offsetof(ICGetElemNativeStub, name_);
}
AccessType accessType() const {
return static_cast<AccessType>((extra_ >> ACCESSTYPE_SHIFT) & ACCESSTYPE_MASK);
}
bool needsAtomize() const {
return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK;
}
};
class ICGetElemNativeSlotStub : public ICGetElemNativeStub
{
protected:
uint32_t offset_;
ICGetElemNativeSlotStub(ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize, uint32_t offset)
: ICGetElemNativeStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize),
offset_(offset)
{
JS_ASSERT(kind == GetElem_NativeSlot || kind == GetElem_NativePrototypeSlot);
JS_ASSERT(acctype == FixedSlot || acctype == DynamicSlot);
}
public:
uint32_t offset() const {
return offset_;
}
static size_t offsetOfOffset() {
return offsetof(ICGetElemNativeStub, offset_);
}
bool isFixedSlot() const {
return extra_;
static size_t offsetOfOffset() {
return offsetof(ICGetElemNativeSlotStub, offset_);
}
};
class ICGetElem_Native : public ICGetElemNativeStub
class ICGetElemNativeGetterStub : public ICGetElemNativeStub
{
protected:
HeapPtrFunction getter_;
uint32_t pcOffset_;
ICGetElemNativeGetterStub(ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name, AccessType acctype,
bool needsAtomize, HandleFunction getter, uint32_t pcOffset);
public:
HeapPtrFunction &getter() {
return getter_;
}
static size_t offsetOfGetter() {
return offsetof(ICGetElemNativeGetterStub, getter_);
}
static size_t offsetOfPCOffset() {
return offsetof(ICGetElemNativeGetterStub, pcOffset_);
}
};
class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub
{
friend class ICStubSpace;
ICGetElem_Native(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleValue idval,
bool isFixedSlot, uint32_t offset)
: ICGetElemNativeStub(ICStub::GetElem_Native, stubCode, firstMonitorStub, shape, idval,
isFixedSlot, offset)
ICGetElem_NativeSlot(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize, uint32_t offset)
: ICGetElemNativeSlotStub(ICStub::GetElem_NativeSlot, stubCode, firstMonitorStub, shape,
name, acctype, needsAtomize, offset)
{}
public:
static inline ICGetElem_Native *New(ICStubSpace *space, IonCode *code,
ICStub *firstMonitorStub,
HandleShape shape, HandleValue idval,
bool isFixedSlot, uint32_t offset)
static inline ICGetElem_NativeSlot *New(ICStubSpace *space, IonCode *code,
ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize, uint32_t offset)
{
if (!code)
return NULL;
return space->allocate<ICGetElem_Native>(code, firstMonitorStub, shape, idval,
isFixedSlot, offset);
return space->allocate<ICGetElem_NativeSlot>(code, firstMonitorStub, shape, name,
acctype, needsAtomize, offset);
}
};
class ICGetElem_NativePrototype : public ICGetElemNativeStub
class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub
{
friend class ICStubSpace;
HeapPtrObject holder_;
HeapPtrShape holderShape_;
ICGetElem_NativePrototype(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleValue idval,
bool isFixedSlot, uint32_t offset,
HandleObject holder, HandleShape holderShape);
ICGetElem_NativePrototypeSlot(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize, uint32_t offset,
HandleObject holder, HandleShape holderShape);
public:
static inline ICGetElem_NativePrototype *New(ICStubSpace *space, IonCode *code,
ICStub *firstMonitorStub,
HandleShape shape, HandleValue idval,
bool isFixedSlot, uint32_t offset,
HandleObject holder, HandleShape holderShape)
static inline ICGetElem_NativePrototypeSlot *New(ICStubSpace *space, IonCode *code,
ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize,
uint32_t offset, HandleObject holder,
HandleShape holderShape)
{
if (!code)
return NULL;
return space->allocate<ICGetElem_NativePrototype>(code, firstMonitorStub, shape, idval,
isFixedSlot, offset, holder, holderShape);
return space->allocate<ICGetElem_NativePrototypeSlot>(
code, firstMonitorStub, shape, name, acctype, needsAtomize, offset, holder,
holderShape);
}
HeapPtrObject &holder() {
return holder_;
}
static size_t offsetOfHolder() {
return offsetof(ICGetElem_NativePrototype, holder_);
return offsetof(ICGetElem_NativePrototypeSlot, holder_);
}
HeapPtrShape &holderShape() {
return holderShape_;
}
static size_t offsetOfHolderShape() {
return offsetof(ICGetElem_NativePrototype, holderShape_);
return offsetof(ICGetElem_NativePrototypeSlot, holderShape_);
}
};
// Compiler for GetElem_Native and GetElem_NativePrototype stubs.
class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub
{
friend class ICStubSpace;
HeapPtrObject holder_;
HeapPtrShape holderShape_;
protected:
ICGetElemNativePrototypeCallStub(ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize, HandleFunction getter,
uint32_t pcOffset, HandleObject holder,
HandleShape holderShape);
public:
HeapPtrObject &holder() {
return holder_;
}
static size_t offsetOfHolder() {
return offsetof(ICGetElemNativePrototypeCallStub, holder_);
}
HeapPtrShape &holderShape() {
return holderShape_;
}
static size_t offsetOfHolderShape() {
return offsetof(ICGetElemNativePrototypeCallStub, holderShape_);
}
};
class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub
{
friend class ICStubSpace;
ICGetElem_NativePrototypeCallNative(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize,
HandleFunction getter, uint32_t pcOffset,
HandleObject holder, HandleShape holderShape)
: ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallNative,
stubCode, firstMonitorStub, shape, name,
acctype, needsAtomize, getter, pcOffset, holder,
holderShape)
{}
public:
static inline ICGetElem_NativePrototypeCallNative *New(
ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name, AccessType acctype,
bool needsAtomize, HandleFunction getter, uint32_t pcOffset,
HandleObject holder, HandleShape holderShape)
{
if (!code)
return NULL;
return space->allocate<ICGetElem_NativePrototypeCallNative>(
code, firstMonitorStub, shape, name, acctype, needsAtomize, getter,
pcOffset, holder, holderShape);
}
};
class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub
{
friend class ICStubSpace;
ICGetElem_NativePrototypeCallScripted(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name,
AccessType acctype, bool needsAtomize,
HandleFunction getter, uint32_t pcOffset,
HandleObject holder, HandleShape holderShape)
: ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallScripted,
stubCode, firstMonitorStub, shape, name,
acctype, needsAtomize, getter, pcOffset, holder,
holderShape)
{}
public:
static inline ICGetElem_NativePrototypeCallScripted *New(
ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
HandleShape shape, HandlePropertyName name, AccessType acctype,
bool needsAtomize, HandleFunction getter, uint32_t pcOffset,
HandleObject holder, HandleShape holderShape)
{
if (!code)
return NULL;
return space->allocate<ICGetElem_NativePrototypeCallScripted>(
code, firstMonitorStub, shape, name, acctype, needsAtomize, getter,
pcOffset, holder, holderShape);
}
};
// Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs.
class ICGetElemNativeCompiler : public ICStubCompiler
{
ICStub *firstMonitorStub_;
HandleObject obj_;
HandleObject holder_;
HandleValue idval_;
bool isFixedSlot_;
HandlePropertyName name_;
ICGetElemNativeStub::AccessType acctype_;
bool needsAtomize_;
uint32_t offset_;
HandleFunction getter_;
uint32_t pcOffset_;
bool emitCallNative(MacroAssembler &masm, Register objReg);
bool emitCallScripted(MacroAssembler &masm, Register objReg);
bool generateStubCode(MacroAssembler &masm);
protected:
virtual int32_t getKey() const {
return static_cast<int32_t>(kind) | (static_cast<int32_t>(isFixedSlot_) << 16);
return static_cast<int32_t>(kind) | (static_cast<int32_t>(needsAtomize_) << 16) |
(static_cast<int32_t>(acctype_) << 17);
}
public:
ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub,
HandleObject obj, HandleObject holder, HandleValue idval,
bool isFixedSlot, uint32_t offset)
HandleObject obj, HandleObject holder, HandlePropertyName name,
ICGetElemNativeStub::AccessType acctype, bool needsAtomize,
uint32_t offset)
: ICStubCompiler(cx, kind),
firstMonitorStub_(firstMonitorStub),
obj_(obj),
holder_(holder),
idval_(idval),
isFixedSlot_(isFixedSlot),
offset_(offset)
name_(name),
acctype_(acctype),
needsAtomize_(needsAtomize),
offset_(offset),
getter_(NULL),
pcOffset_(0)
{}
ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub,
HandleObject obj, HandleObject holder, HandlePropertyName name,
ICGetElemNativeStub::AccessType acctype, bool needsAtomize,
HandleFunction getter, uint32_t pcOffset)
: ICStubCompiler(cx, kind),
firstMonitorStub_(firstMonitorStub),
obj_(obj),
holder_(holder),
name_(name),
acctype_(acctype),
needsAtomize_(needsAtomize),
offset_(0),
getter_(getter),
pcOffset_(pcOffset)
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape shape(cx, obj_->lastProperty());
if (kind == ICStub::GetElem_Native) {
if (kind == ICStub::GetElem_NativeSlot) {
JS_ASSERT(obj_ == holder_);
return ICGetElem_Native::New(space, getStubCode(), firstMonitorStub_, shape, idval_,
isFixedSlot_, offset_);
return ICGetElem_NativeSlot::New(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
offset_);
}
JS_ASSERT(obj_ != holder_);
JS_ASSERT(kind == ICStub::GetElem_NativePrototype);
RootedShape holderShape(cx, holder_->lastProperty());
return ICGetElem_NativePrototype::New(space, getStubCode(), firstMonitorStub_, shape,
idval_, isFixedSlot_, offset_, holder_, holderShape);
if (kind == ICStub::GetElem_NativePrototypeSlot) {
return ICGetElem_NativePrototypeSlot::New(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
offset_, holder_, holderShape);
}
if (kind == ICStub::GetElem_NativePrototypeCallNative) {
return ICGetElem_NativePrototypeCallNative::New(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
getter_, pcOffset_, holder_, holderShape);
}
JS_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScripted);
if (kind == ICStub::GetElem_NativePrototypeCallScripted) {
return ICGetElem_NativePrototypeCallScripted::New(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
getter_, pcOffset_, holder_, holderShape);
}
MOZ_ASSUME_UNREACHABLE("Invalid kind.");
return NULL;
}
};

Просмотреть файл

@ -2522,11 +2522,25 @@ MacroAssemblerARMCompat::branchTestValue(Condition cond, const Address &valaddr,
{
JS_ASSERT(cond == Equal || cond == NotEqual);
ma_ldr(tagOf(valaddr), ScratchRegister);
branchPtr(cond, ScratchRegister, value.typeReg(), label);
// Check payload before tag, since payload is more likely to differ.
if (cond == NotEqual) {
ma_ldr(payloadOf(valaddr), ScratchRegister);
branchPtr(NotEqual, ScratchRegister, value.payloadReg(), label);
ma_ldr(payloadOf(valaddr), ScratchRegister);
branchPtr(cond, ScratchRegister, value.payloadReg(), label);
ma_ldr(tagOf(valaddr), ScratchRegister);
branchPtr(NotEqual, ScratchRegister, value.typeReg(), label);
} else {
Label fallthrough;
ma_ldr(payloadOf(valaddr), ScratchRegister);
branchPtr(NotEqual, ScratchRegister, value.payloadReg(), &fallthrough);
ma_ldr(tagOf(valaddr), ScratchRegister);
branchPtr(Equal, ScratchRegister, value.typeReg(), label);
bind(&fallthrough);
}
}
// unboxing code

Просмотреть файл

@ -423,8 +423,17 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
Label *label)
{
JS_ASSERT(cond == Equal || cond == NotEqual);
branchPtr(cond, tagOf(valaddr), value.typeReg(), label);
branchPtr(cond, payloadOf(valaddr), value.payloadReg(), label);
// Check payload before tag, since payload is more likely to differ.
if (cond == NotEqual) {
branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), label);
branchPtr(NotEqual, tagOf(valaddr), value.typeReg(), label);
} else {
Label fallthrough;
branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), &fallthrough);
branchPtr(Equal, tagOf(valaddr), value.typeReg(), label);
bind(&fallthrough);
}
}
void cmpPtr(Register lhs, const ImmWord rhs) {