зеркало из https://github.com/mozilla/gecko-dev.git
Bug 906805 - Implement Baseline JSOP_GETELEM handlers which invoke getters. r=efaust
This commit is contained in:
Родитель
1bbecd33dc
Коммит
eac17dea98
|
@ -183,20 +183,31 @@ ICStub::trace(JSTracer *trc)
|
||||||
MarkObject(trc, &callStub->callee(), "baseline-callnative-callee");
|
MarkObject(trc, &callStub->callee(), "baseline-callnative-callee");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ICStub::GetElem_Native: {
|
case ICStub::GetElem_NativeSlot: {
|
||||||
ICGetElem_Native *getElemStub = toGetElem_Native();
|
ICGetElem_NativeSlot *getElemStub = toGetElem_NativeSlot();
|
||||||
MarkShape(trc, &getElemStub->shape(), "baseline-getelem-native-shape");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ICStub::GetElem_NativePrototype: {
|
case ICStub::GetElem_NativePrototypeSlot: {
|
||||||
ICGetElem_NativePrototype *getElemStub = toGetElem_NativePrototype();
|
ICGetElem_NativePrototypeSlot *getElemStub = toGetElem_NativePrototypeSlot();
|
||||||
MarkShape(trc, &getElemStub->shape(), "baseline-getelem-nativeproto-shape");
|
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");
|
MarkObject(trc, &getElemStub->holder(), "baseline-getelem-nativeproto-holder");
|
||||||
MarkShape(trc, &getElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
|
MarkShape(trc, &getElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
|
||||||
break;
|
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: {
|
case ICStub::GetElem_Dense: {
|
||||||
ICGetElem_Dense *getElemStub = toGetElem_Dense();
|
ICGetElem_Dense *getElemStub = toGetElem_Dense();
|
||||||
MarkShape(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
|
MarkShape(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
|
||||||
|
@ -618,14 +629,20 @@ void
|
||||||
ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
|
ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
|
||||||
{
|
{
|
||||||
// This should only be called from the following stubs.
|
// This should only be called from the following stubs.
|
||||||
JS_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted ||
|
JS_ASSERT(kind == ICStub::Call_Scripted ||
|
||||||
kind == ICStub::Call_Native || kind == ICStub::GetProp_CallScripted ||
|
kind == ICStub::Call_AnyScripted ||
|
||||||
kind == ICStub::GetProp_CallNative || kind == ICStub::GetProp_CallDOMProxyNative ||
|
kind == ICStub::Call_Native ||
|
||||||
kind == ICStub::Call_ScriptedApplyArray ||
|
kind == ICStub::Call_ScriptedApplyArray ||
|
||||||
kind == ICStub::Call_ScriptedApplyArguments ||
|
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_CallDOMProxyWithGenerationNative ||
|
||||||
kind == ICStub::GetProp_DOMProxyShadowed ||
|
kind == ICStub::GetProp_DOMProxyShadowed ||
|
||||||
kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
|
kind == ICStub::SetProp_CallScripted ||
|
||||||
|
kind == ICStub::SetProp_CallNative);
|
||||||
|
|
||||||
// Guard on bit in frame that indicates if the SPS frame was pushed in the first
|
// 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
|
// 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;
|
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
|
// This_Fallback
|
||||||
//
|
//
|
||||||
|
@ -3414,6 +3456,143 @@ IsCacheableSetPropCall(JSObject *obj, JSObject *holder, Shape *shape, bool *isSc
|
||||||
return true;
|
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
|
static bool
|
||||||
TypedArrayGetElemStubExists(ICGetElem_Fallback *stub, HandleObject obj)
|
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,
|
ICGetElem_Fallback *stub, HandleObject obj,
|
||||||
HandleValue key)
|
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);
|
RootedId id(cx);
|
||||||
if (!ValueToId<CanGC>(cx, key, &id))
|
if (!ValueToId<CanGC>(cx, key, &id))
|
||||||
return false;
|
return false;
|
||||||
|
@ -3452,33 +3636,92 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
RootedPropertyName propName(cx, JSID_TO_ATOM(id)->asPropertyName());
|
RootedPropertyName propName(cx, JSID_TO_ATOM(id)->asPropertyName());
|
||||||
|
bool needsAtomize = !key.toString()->isAtom();
|
||||||
|
|
||||||
RootedShape shape(cx);
|
RootedShape shape(cx);
|
||||||
RootedObject holder(cx);
|
RootedObject holder(cx);
|
||||||
if (!EffectlesslyLookupProperty(cx, obj, propName, &holder, &shape))
|
if (!EffectlesslyLookupProperty(cx, obj, propName, &holder, &shape))
|
||||||
return false;
|
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;
|
return true;
|
||||||
|
|
||||||
|
// Remove any existing stubs that may interfere with the new stub being added.
|
||||||
|
RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize);
|
||||||
|
|
||||||
bool isFixedSlot;
|
bool isFixedSlot;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
|
GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
|
||||||
|
|
||||||
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||||
ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_Native : ICStub::GetElem_NativePrototype;
|
ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlot
|
||||||
|
: ICStub::GetElem_NativePrototypeSlot;
|
||||||
|
|
||||||
IonSpew(IonSpew_BaselineIC, " Generating GetElem(Native %s) stub (obj=%p, shape=%p, holder=%p, holderShape=%p)",
|
IonSpew(IonSpew_BaselineIC, " Generating GetElem(Native %s%s slot) stub "
|
||||||
|
"(obj=%p, shape=%p, holder=%p, holderShape=%p)",
|
||||||
(obj == holder) ? "direct" : "prototype",
|
(obj == holder) ? "direct" : "prototype",
|
||||||
|
needsAtomize ? " atomizing" : "",
|
||||||
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
|
obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
|
||||||
|
|
||||||
ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, key,
|
ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot
|
||||||
isFixedSlot, offset);
|
: ICGetElemNativeStub::DynamicSlot;
|
||||||
|
ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype,
|
||||||
|
needsAtomize, offset);
|
||||||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
|
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||||
if (!newStub)
|
if (!newStub)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
stub->addNewStub(newStub);
|
stub->addNewStub(newStub);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getterIsScripted = false;
|
||||||
|
if (IsCacheableGetPropCall(obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) {
|
||||||
|
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3492,7 +3735,7 @@ TypedArrayRequiresFloatingPoint(TypedArrayObject *tarr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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)
|
HandleValue lhs, HandleValue rhs, HandleValue res)
|
||||||
{
|
{
|
||||||
// Check for String[i] => Char accesses.
|
// 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.
|
// Check for NativeObject[id] shape-optimizable accesses.
|
||||||
if (rhs.isString()) {
|
if (rhs.isString()) {
|
||||||
if (!TryAttachNativeGetElemStub(cx, script, stub, obj, rhs))
|
if (!TryAttachNativeGetElemStub(cx, script, pc, stub, obj, rhs))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3640,7 +3883,7 @@ DoGetElemFallback(JSContext *cx, BaselineFrame *frame, ICGetElem_Fallback *stub,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to attach an optimized 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 false;
|
||||||
|
|
||||||
return true;
|
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
|
bool
|
||||||
ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
|
ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
{
|
{
|
||||||
|
@ -3684,9 +4082,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
bool popR1 = false;
|
bool popR1 = false;
|
||||||
|
|
||||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||||
|
masm.branchTestString(Assembler::NotEqual, R1, &failure);
|
||||||
Address idValAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfIdval());
|
|
||||||
masm.branchTestValue(Assembler::NotEqual, idValAddr, R1, &failure);
|
|
||||||
|
|
||||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||||
Register scratchReg = regs.takeAny();
|
Register scratchReg = regs.takeAny();
|
||||||
|
@ -3699,6 +4095,54 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
Address shapeAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfShape());
|
Address shapeAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfShape());
|
||||||
masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure);
|
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;
|
Register holderReg;
|
||||||
if (obj_ == holder_) {
|
if (obj_ == holder_) {
|
||||||
holderReg = objReg;
|
holderReg = objReg;
|
||||||
|
@ -3711,23 +4155,73 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
} else {
|
} else {
|
||||||
holderReg = regs.takeAny();
|
holderReg = regs.takeAny();
|
||||||
}
|
}
|
||||||
masm.loadPtr(Address(BaselineStubReg, ICGetElem_NativePrototype::offsetOfHolder()),
|
|
||||||
|
if (kind == ICStub::GetElem_NativePrototypeCallNative ||
|
||||||
|
kind == ICStub::GetElem_NativePrototypeCallScripted)
|
||||||
|
{
|
||||||
|
masm.loadPtr(Address(BaselineStubReg,
|
||||||
|
ICGetElemNativePrototypeCallStub::offsetOfHolder()),
|
||||||
holderReg);
|
holderReg);
|
||||||
masm.loadPtr(Address(BaselineStubReg, ICGetElem_NativePrototype::offsetOfHolderShape()),
|
masm.loadPtr(Address(BaselineStubReg,
|
||||||
|
ICGetElemNativePrototypeCallStub::offsetOfHolderShape()),
|
||||||
scratchReg);
|
scratchReg);
|
||||||
|
} else {
|
||||||
|
masm.loadPtr(Address(BaselineStubReg,
|
||||||
|
ICGetElem_NativePrototypeSlot::offsetOfHolder()),
|
||||||
|
holderReg);
|
||||||
|
masm.loadPtr(Address(BaselineStubReg,
|
||||||
|
ICGetElem_NativePrototypeSlot::offsetOfHolderShape()),
|
||||||
|
scratchReg);
|
||||||
|
}
|
||||||
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratchReg,
|
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratchReg,
|
||||||
popR1 ? &failurePopR1 : &failure);
|
popR1 ? &failurePopR1 : &failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (acctype_ == ICGetElemNativeStub::DynamicSlot ||
|
||||||
|
acctype_ == ICGetElemNativeStub::FixedSlot)
|
||||||
|
{
|
||||||
// Load from object.
|
// Load from object.
|
||||||
if (!isFixedSlot_)
|
if (acctype_ == ICGetElemNativeStub::DynamicSlot)
|
||||||
masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg);
|
masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg);
|
||||||
|
|
||||||
masm.load32(Address(BaselineStubReg, ICGetElem_Native::offsetOfOffset()), scratchReg);
|
masm.load32(Address(BaselineStubReg, ICGetElemNativeSlotStub::offsetOfOffset()),
|
||||||
|
scratchReg);
|
||||||
masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0);
|
masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0);
|
||||||
|
|
||||||
if (popR1)
|
if (popR1)
|
||||||
masm.pop(R1.scratchReg());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Enter type monitor IC to type-check result.
|
// Enter type monitor IC to type-check result.
|
||||||
EmitEnterTypeMonitorIC(masm);
|
EmitEnterTypeMonitorIC(masm);
|
||||||
|
|
||||||
|
@ -3738,6 +4232,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
}
|
}
|
||||||
masm.bind(&failure);
|
masm.bind(&failure);
|
||||||
EmitStubGuardFailure(masm);
|
EmitStubGuardFailure(masm);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5800,27 +6295,6 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
return true;
|
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
|
bool
|
||||||
ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
|
ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
{
|
{
|
||||||
|
@ -8548,29 +9022,54 @@ ICTypeUpdate_TypeObject::ICTypeUpdate_TypeObject(IonCode *stubCode, HandleTypeOb
|
||||||
|
|
||||||
ICGetElemNativeStub::ICGetElemNativeStub(ICStub::Kind kind, IonCode *stubCode,
|
ICGetElemNativeStub::ICGetElemNativeStub(ICStub::Kind kind, IonCode *stubCode,
|
||||||
ICStub *firstMonitorStub,
|
ICStub *firstMonitorStub,
|
||||||
HandleShape shape, HandleValue idval,
|
HandleShape shape, HandlePropertyName name,
|
||||||
bool isFixedSlot, uint32_t offset)
|
AccessType acctype, bool needsAtomize)
|
||||||
: ICMonitoredStub(kind, stubCode, firstMonitorStub),
|
: ICMonitoredStub(kind, stubCode, firstMonitorStub),
|
||||||
shape_(shape),
|
shape_(shape),
|
||||||
idval_(idval),
|
name_(name)
|
||||||
offset_(offset)
|
|
||||||
{
|
{
|
||||||
extra_ = isFixedSlot;
|
extra_ = (static_cast<uint16_t>(acctype) << ACCESSTYPE_SHIFT) |
|
||||||
|
(static_cast<uint16_t>(needsAtomize) << NEEDS_ATOMIZE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ICGetElemNativeStub::~ICGetElemNativeStub()
|
ICGetElemNativeStub::~ICGetElemNativeStub()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
ICGetElem_NativePrototype::ICGetElem_NativePrototype(IonCode *stubCode, ICStub *firstMonitorStub,
|
ICGetElemNativeGetterStub::ICGetElemNativeGetterStub(
|
||||||
HandleShape shape, HandleValue idval,
|
ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
|
||||||
bool isFixedSlot, uint32_t offset,
|
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)
|
HandleObject holder, HandleShape holderShape)
|
||||||
: ICGetElemNativeStub(ICStub::GetElem_NativePrototype, stubCode, firstMonitorStub, shape,
|
: ICGetElemNativeSlotStub(ICStub::GetElem_NativePrototypeSlot, stubCode, firstMonitorStub, shape,
|
||||||
idval, isFixedSlot, offset),
|
name, acctype, needsAtomize, offset),
|
||||||
holder_(holder),
|
holder_(holder),
|
||||||
holderShape_(holderShape)
|
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)
|
ICGetElem_Dense::ICGetElem_Dense(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape)
|
||||||
: ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub),
|
: ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub),
|
||||||
shape_(shape)
|
shape_(shape)
|
||||||
|
|
|
@ -328,8 +328,10 @@ class ICEntry
|
||||||
_(Call_ScriptedApplyArguments) \
|
_(Call_ScriptedApplyArguments) \
|
||||||
\
|
\
|
||||||
_(GetElem_Fallback) \
|
_(GetElem_Fallback) \
|
||||||
_(GetElem_Native) \
|
_(GetElem_NativeSlot) \
|
||||||
_(GetElem_NativePrototype) \
|
_(GetElem_NativePrototypeSlot) \
|
||||||
|
_(GetElem_NativePrototypeCallNative) \
|
||||||
|
_(GetElem_NativePrototypeCallScripted) \
|
||||||
_(GetElem_String) \
|
_(GetElem_String) \
|
||||||
_(GetElem_Dense) \
|
_(GetElem_Dense) \
|
||||||
_(GetElem_TypedArray) \
|
_(GetElem_TypedArray) \
|
||||||
|
@ -735,6 +737,10 @@ class ICStub
|
||||||
case Call_ScriptedApplyArray:
|
case Call_ScriptedApplyArray:
|
||||||
case Call_ScriptedApplyArguments:
|
case Call_ScriptedApplyArguments:
|
||||||
case UseCount_Fallback:
|
case UseCount_Fallback:
|
||||||
|
case GetElem_NativeSlot:
|
||||||
|
case GetElem_NativePrototypeSlot:
|
||||||
|
case GetElem_NativePrototypeCallNative:
|
||||||
|
case GetElem_NativePrototypeCallScripted:
|
||||||
case GetProp_CallScripted:
|
case GetProp_CallScripted:
|
||||||
case GetProp_CallNative:
|
case GetProp_CallNative:
|
||||||
case GetProp_CallDOMProxyNative:
|
case GetProp_CallDOMProxyNative:
|
||||||
|
@ -2839,14 +2845,22 @@ class ICGetElem_Fallback : public ICMonitoredFallbackStub
|
||||||
|
|
||||||
class ICGetElemNativeStub : public ICMonitoredStub
|
class ICGetElemNativeStub : public ICMonitoredStub
|
||||||
{
|
{
|
||||||
HeapPtrShape shape_;
|
public:
|
||||||
HeapValue idval_;
|
enum AccessType { FixedSlot = 0, DynamicSlot, NativeGetter, ScriptedGetter };
|
||||||
uint32_t offset_;
|
|
||||||
|
|
||||||
protected:
|
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,
|
ICGetElemNativeStub(ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
|
||||||
HandleShape shape, HandleValue idval,
|
HandleShape shape, HandlePropertyName name, AccessType acctype,
|
||||||
bool isFixedSlot, uint32_t offset);
|
bool needsAtomize);
|
||||||
|
|
||||||
~ICGetElemNativeStub();
|
~ICGetElemNativeStub();
|
||||||
|
|
||||||
|
@ -2858,130 +2872,311 @@ class ICGetElemNativeStub : public ICMonitoredStub
|
||||||
return offsetof(ICGetElemNativeStub, shape_);
|
return offsetof(ICGetElemNativeStub, shape_);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapValue &idval() {
|
HeapPtrPropertyName &name() {
|
||||||
return idval_;
|
return name_;
|
||||||
}
|
}
|
||||||
static size_t offsetOfIdval() {
|
static size_t offsetOfName() {
|
||||||
return offsetof(ICGetElemNativeStub, idval_);
|
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 {
|
uint32_t offset() const {
|
||||||
return offset_;
|
return offset_;
|
||||||
}
|
}
|
||||||
static size_t offsetOfOffset() {
|
|
||||||
return offsetof(ICGetElemNativeStub, offset_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFixedSlot() const {
|
static size_t offsetOfOffset() {
|
||||||
return extra_;
|
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;
|
friend class ICStubSpace;
|
||||||
ICGetElem_Native(IonCode *stubCode, ICStub *firstMonitorStub,
|
ICGetElem_NativeSlot(IonCode *stubCode, ICStub *firstMonitorStub,
|
||||||
HandleShape shape, HandleValue idval,
|
HandleShape shape, HandlePropertyName name,
|
||||||
bool isFixedSlot, uint32_t offset)
|
AccessType acctype, bool needsAtomize, uint32_t offset)
|
||||||
: ICGetElemNativeStub(ICStub::GetElem_Native, stubCode, firstMonitorStub, shape, idval,
|
: ICGetElemNativeSlotStub(ICStub::GetElem_NativeSlot, stubCode, firstMonitorStub, shape,
|
||||||
isFixedSlot, offset)
|
name, acctype, needsAtomize, offset)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static inline ICGetElem_Native *New(ICStubSpace *space, IonCode *code,
|
static inline ICGetElem_NativeSlot *New(ICStubSpace *space, IonCode *code,
|
||||||
ICStub *firstMonitorStub,
|
ICStub *firstMonitorStub,
|
||||||
HandleShape shape, HandleValue idval,
|
HandleShape shape, HandlePropertyName name,
|
||||||
bool isFixedSlot, uint32_t offset)
|
AccessType acctype, bool needsAtomize, uint32_t offset)
|
||||||
{
|
{
|
||||||
if (!code)
|
if (!code)
|
||||||
return NULL;
|
return NULL;
|
||||||
return space->allocate<ICGetElem_Native>(code, firstMonitorStub, shape, idval,
|
return space->allocate<ICGetElem_NativeSlot>(code, firstMonitorStub, shape, name,
|
||||||
isFixedSlot, offset);
|
acctype, needsAtomize, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICGetElem_NativePrototype : public ICGetElemNativeStub
|
class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
HeapPtrObject holder_;
|
HeapPtrObject holder_;
|
||||||
HeapPtrShape holderShape_;
|
HeapPtrShape holderShape_;
|
||||||
|
|
||||||
ICGetElem_NativePrototype(IonCode *stubCode, ICStub *firstMonitorStub,
|
ICGetElem_NativePrototypeSlot(IonCode *stubCode, ICStub *firstMonitorStub,
|
||||||
HandleShape shape, HandleValue idval,
|
HandleShape shape, HandlePropertyName name,
|
||||||
bool isFixedSlot, uint32_t offset,
|
AccessType acctype, bool needsAtomize, uint32_t offset,
|
||||||
HandleObject holder, HandleShape holderShape);
|
HandleObject holder, HandleShape holderShape);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static inline ICGetElem_NativePrototype *New(ICStubSpace *space, IonCode *code,
|
static inline ICGetElem_NativePrototypeSlot *New(ICStubSpace *space, IonCode *code,
|
||||||
ICStub *firstMonitorStub,
|
ICStub *firstMonitorStub,
|
||||||
HandleShape shape, HandleValue idval,
|
HandleShape shape, HandlePropertyName name,
|
||||||
bool isFixedSlot, uint32_t offset,
|
AccessType acctype, bool needsAtomize,
|
||||||
HandleObject holder, HandleShape holderShape)
|
uint32_t offset, HandleObject holder,
|
||||||
|
HandleShape holderShape)
|
||||||
{
|
{
|
||||||
if (!code)
|
if (!code)
|
||||||
return NULL;
|
return NULL;
|
||||||
return space->allocate<ICGetElem_NativePrototype>(code, firstMonitorStub, shape, idval,
|
return space->allocate<ICGetElem_NativePrototypeSlot>(
|
||||||
isFixedSlot, offset, holder, holderShape);
|
code, firstMonitorStub, shape, name, acctype, needsAtomize, offset, holder,
|
||||||
|
holderShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapPtrObject &holder() {
|
HeapPtrObject &holder() {
|
||||||
return holder_;
|
return holder_;
|
||||||
}
|
}
|
||||||
static size_t offsetOfHolder() {
|
static size_t offsetOfHolder() {
|
||||||
return offsetof(ICGetElem_NativePrototype, holder_);
|
return offsetof(ICGetElem_NativePrototypeSlot, holder_);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapPtrShape &holderShape() {
|
HeapPtrShape &holderShape() {
|
||||||
return holderShape_;
|
return holderShape_;
|
||||||
}
|
}
|
||||||
static size_t offsetOfHolderShape() {
|
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
|
class ICGetElemNativeCompiler : public ICStubCompiler
|
||||||
{
|
{
|
||||||
ICStub *firstMonitorStub_;
|
ICStub *firstMonitorStub_;
|
||||||
HandleObject obj_;
|
HandleObject obj_;
|
||||||
HandleObject holder_;
|
HandleObject holder_;
|
||||||
HandleValue idval_;
|
HandlePropertyName name_;
|
||||||
bool isFixedSlot_;
|
ICGetElemNativeStub::AccessType acctype_;
|
||||||
|
bool needsAtomize_;
|
||||||
uint32_t offset_;
|
uint32_t offset_;
|
||||||
|
HandleFunction getter_;
|
||||||
|
uint32_t pcOffset_;
|
||||||
|
|
||||||
|
bool emitCallNative(MacroAssembler &masm, Register objReg);
|
||||||
|
bool emitCallScripted(MacroAssembler &masm, Register objReg);
|
||||||
bool generateStubCode(MacroAssembler &masm);
|
bool generateStubCode(MacroAssembler &masm);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int32_t getKey() const {
|
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:
|
public:
|
||||||
ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub,
|
ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub,
|
||||||
HandleObject obj, HandleObject holder, HandleValue idval,
|
HandleObject obj, HandleObject holder, HandlePropertyName name,
|
||||||
bool isFixedSlot, uint32_t offset)
|
ICGetElemNativeStub::AccessType acctype, bool needsAtomize,
|
||||||
|
uint32_t offset)
|
||||||
: ICStubCompiler(cx, kind),
|
: ICStubCompiler(cx, kind),
|
||||||
firstMonitorStub_(firstMonitorStub),
|
firstMonitorStub_(firstMonitorStub),
|
||||||
obj_(obj),
|
obj_(obj),
|
||||||
holder_(holder),
|
holder_(holder),
|
||||||
idval_(idval),
|
name_(name),
|
||||||
isFixedSlot_(isFixedSlot),
|
acctype_(acctype),
|
||||||
offset_(offset)
|
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) {
|
ICStub *getStub(ICStubSpace *space) {
|
||||||
RootedShape shape(cx, obj_->lastProperty());
|
RootedShape shape(cx, obj_->lastProperty());
|
||||||
if (kind == ICStub::GetElem_Native) {
|
if (kind == ICStub::GetElem_NativeSlot) {
|
||||||
JS_ASSERT(obj_ == holder_);
|
JS_ASSERT(obj_ == holder_);
|
||||||
return ICGetElem_Native::New(space, getStubCode(), firstMonitorStub_, shape, idval_,
|
return ICGetElem_NativeSlot::New(
|
||||||
isFixedSlot_, offset_);
|
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
|
||||||
|
offset_);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(obj_ != holder_);
|
JS_ASSERT(obj_ != holder_);
|
||||||
JS_ASSERT(kind == ICStub::GetElem_NativePrototype);
|
|
||||||
RootedShape holderShape(cx, holder_->lastProperty());
|
RootedShape holderShape(cx, holder_->lastProperty());
|
||||||
return ICGetElem_NativePrototype::New(space, getStubCode(), firstMonitorStub_, shape,
|
if (kind == ICStub::GetElem_NativePrototypeSlot) {
|
||||||
idval_, isFixedSlot_, offset_, holder_, holderShape);
|
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);
|
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||||
|
|
||||||
|
// 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(tagOf(valaddr), ScratchRegister);
|
ma_ldr(tagOf(valaddr), ScratchRegister);
|
||||||
branchPtr(cond, ScratchRegister, value.typeReg(), label);
|
branchPtr(NotEqual, ScratchRegister, value.typeReg(), label);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Label fallthrough;
|
||||||
|
|
||||||
ma_ldr(payloadOf(valaddr), ScratchRegister);
|
ma_ldr(payloadOf(valaddr), ScratchRegister);
|
||||||
branchPtr(cond, ScratchRegister, value.payloadReg(), label);
|
branchPtr(NotEqual, ScratchRegister, value.payloadReg(), &fallthrough);
|
||||||
|
|
||||||
|
ma_ldr(tagOf(valaddr), ScratchRegister);
|
||||||
|
branchPtr(Equal, ScratchRegister, value.typeReg(), label);
|
||||||
|
|
||||||
|
bind(&fallthrough);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unboxing code
|
// unboxing code
|
||||||
|
|
|
@ -423,8 +423,17 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||||
Label *label)
|
Label *label)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||||
branchPtr(cond, tagOf(valaddr), value.typeReg(), label);
|
// Check payload before tag, since payload is more likely to differ.
|
||||||
branchPtr(cond, payloadOf(valaddr), value.payloadReg(), label);
|
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) {
|
void cmpPtr(Register lhs, const ImmWord rhs) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче