Bug 1093573 part 15 - Add and optimize IsSuspendedStarGenerator. r=wingo

This commit is contained in:
Jan de Mooij 2014-11-13 21:10:05 +01:00
parent 45f6e7dcb0
commit 5f60319597
7 changed files with 137 additions and 16 deletions

View File

@ -3,14 +3,20 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function StarGeneratorNext(val) {
if (!IsObject(this) || !IsStarGeneratorObject(this))
return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorNext");
// The IsSuspendedStarGenerator call below is not necessary for
// correctness. It's a performance optimization to check for the
// common case with a single call. It's also inlined in Baseline.
if (StarGeneratorObjectIsClosed(this))
return { value: undefined, done: true };
if (!IsSuspendedStarGenerator(this)) {
if (!IsObject(this) || !IsStarGeneratorObject(this))
return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorNext");
if (GeneratorIsRunning(this))
ThrowError(JSMSG_NESTING_GENERATOR);
if (StarGeneratorObjectIsClosed(this))
return { value: undefined, done: true };
if (GeneratorIsRunning(this))
ThrowError(JSMSG_NESTING_GENERATOR);
}
try {
return resumeGenerator(this, val, 'next');
@ -22,14 +28,16 @@ function StarGeneratorNext(val) {
}
function StarGeneratorThrow(val) {
if (!IsObject(this) || !IsStarGeneratorObject(this))
return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorThrow");
if (!IsSuspendedStarGenerator(this)) {
if (!IsObject(this) || !IsStarGeneratorObject(this))
return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorThrow");
if (StarGeneratorObjectIsClosed(this))
throw val;
if (StarGeneratorObjectIsClosed(this))
throw val;
if (GeneratorIsRunning(this))
ThrowError(JSMSG_NESTING_GENERATOR);
if (GeneratorIsRunning(this))
ThrowError(JSMSG_NESTING_GENERATOR);
}
try {
return resumeGenerator(this, val, 'throw');

View File

@ -2151,9 +2151,12 @@ BaselineCompiler::emit_JSOP_GETALIASEDVAR()
Address address = getScopeCoordinateAddress(R0.scratchReg());
masm.loadValue(address, R0);
ICTypeMonitor_Fallback::Compiler compiler(cx, (ICMonitoredFallbackStub *) nullptr);
if (!emitOpIC(compiler.getStub(&stubSpace_)))
return false;
if (ionCompileable_) {
// No need to monitor types if we know Ion can't compile this script.
ICTypeMonitor_Fallback::Compiler compiler(cx, (ICMonitoredFallbackStub *) nullptr);
if (!emitOpIC(compiler.getStub(&stubSpace_)))
return false;
}
frame.push(R0);
return true;

View File

@ -8817,6 +8817,20 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
return true;
}
if (fun->native() == intrinsic_IsSuspendedStarGenerator) {
// This intrinsic only appears in self-hosted code.
MOZ_ASSERT(argc == 1);
JitSpew(JitSpew_BaselineIC, " Generating Call_IsSuspendedStarGenerator stub");
ICCall_IsSuspendedStarGenerator::Compiler compiler(cx);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
return true;
}
RootedNativeObject templateObject(cx);
if (MOZ_LIKELY(!isSpread)) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -9770,6 +9784,48 @@ ICCall_StringSplit::Compiler::generateStubCode(MacroAssembler &masm)
return true;
}
bool
ICCall_IsSuspendedStarGenerator::Compiler::generateStubCode(MacroAssembler &masm)
{
// The IsSuspendedStarGenerator intrinsic is only called in self-hosted
// code, so it's safe to assume we have a single argument and the callee
// is our intrinsic.
GeneralRegisterSet regs = availableGeneralRegs(0);
// Load the argument.
Address argAddr(BaselineStackReg, ICStackValueOffset);
ValueOperand argVal = regs.takeAnyValue();
masm.loadValue(argAddr, argVal);
// Check if it's an object.
Label returnFalse;
Register genObj = regs.takeAny();
masm.branchTestObject(Assembler::NotEqual, argVal, &returnFalse);
masm.unboxObject(argVal, genObj);
// Check if it's a StarGeneratorObject.
Register scratch = regs.takeAny();
masm.branchTestObjClass(Assembler::NotEqual, genObj, scratch, &StarGeneratorObject::class_,
&returnFalse);
// If the yield index slot holds an int32 value < YIELD_INDEX_CLOSING,
// the generator is suspended.
masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), argVal);
masm.branchTestInt32(Assembler::NotEqual, argVal, &returnFalse);
masm.unboxInt32(argVal, scratch);
masm.branch32(Assembler::AboveOrEqual, scratch, Imm32(StarGeneratorObject::YIELD_INDEX_CLOSING),
&returnFalse);
masm.moveValue(BooleanValue(true), R0);
EmitReturnFromIC(masm);
masm.bind(&returnFalse);
masm.moveValue(BooleanValue(false), R0);
EmitReturnFromIC(masm);
return true;
}
bool
ICCall_Native::Compiler::generateStubCode(MacroAssembler &masm)
{

View File

@ -380,6 +380,7 @@ class ICEntry
_(Call_ScriptedApplyArguments) \
_(Call_ScriptedFunCall) \
_(Call_StringSplit) \
_(Call_IsSuspendedStarGenerator) \
\
_(GetElem_Fallback) \
_(GetElem_NativeSlot) \
@ -6237,6 +6238,36 @@ class ICCall_StringSplit : public ICMonitoredStub
};
};
class ICCall_IsSuspendedStarGenerator : public ICStub
{
friend class ICStubSpace;
protected:
explicit ICCall_IsSuspendedStarGenerator(JitCode *stubCode)
: ICStub(ICStub::Call_IsSuspendedStarGenerator, stubCode)
{}
public:
static inline ICCall_IsSuspendedStarGenerator *New(ICStubSpace *space, JitCode *code) {
if (!code)
return nullptr;
return space->allocate<ICCall_IsSuspendedStarGenerator>(code);
}
class Compiler : public ICStubCompiler {
protected:
bool generateStubCode(MacroAssembler &masm);
public:
explicit Compiler(JSContext *cx)
: ICStubCompiler(cx, ICStub::Call_IsSuspendedStarGenerator)
{}
ICStub *getStub(ICStubSpace *space) {
return ICCall_IsSuspendedStarGenerator::New(space, getStubCode());
}
};
};
// Stub for performing a TableSwitch, updating the IC's return address to jump
// to whatever point the switch is branching to.
class ICTableSwitch : public ICStub

View File

@ -978,6 +978,8 @@ bool intrinsic_ObjectIsTypeDescr(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_TypeDescrIsSimpleType(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_TypeDescrIsArrayType(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_IsSuspendedStarGenerator(JSContext *cx, unsigned argc, Value *vp);
class AutoLockForExclusiveAccess
{
JSRuntime *runtime;

View File

@ -136,8 +136,12 @@ class GeneratorObject : public NativeObject
return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_CLOSING;
}
bool isSuspended() const {
// Note: also update Baseline's IsSuspendedStarGenerator code if this
// changes.
MOZ_ASSERT(!isClosed());
return !isRunning() && !isClosing();
static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING,
"test below should return false for YIELD_INDEX_RUNNING");
return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING;
}
void setRunning() {
MOZ_ASSERT(isSuspended());

View File

@ -681,6 +681,22 @@ intrinsic_StarGeneratorObjectIsClosed(JSContext *cx, unsigned argc, Value *vp)
return true;
}
bool
js::intrinsic_IsSuspendedStarGenerator(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
if (!args[0].isObject() || !args[0].toObject().is<StarGeneratorObject>()) {
args.rval().setBoolean(false);
return true;
}
StarGeneratorObject &genObj = args[0].toObject().as<StarGeneratorObject>();
args.rval().setBoolean(!genObj.isClosed() && genObj.isSuspended());
return true;
}
static bool
intrinsic_IsLegacyGeneratorObject(JSContext *cx, unsigned argc, Value *vp)
{
@ -1035,6 +1051,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("IsStarGeneratorObject", intrinsic_IsStarGeneratorObject, 1,0),
JS_FN("StarGeneratorObjectIsClosed", intrinsic_StarGeneratorObjectIsClosed, 1,0),
JS_FN("IsSuspendedStarGenerator",intrinsic_IsSuspendedStarGenerator,1,0),
JS_FN("IsLegacyGeneratorObject", intrinsic_IsLegacyGeneratorObject, 1,0),
JS_FN("LegacyGeneratorObjectIsClosed", intrinsic_LegacyGeneratorObjectIsClosed, 1,0),