Bug 723636: Implement MRegExp, take 2. (r=jandem)

This commit is contained in:
Chris Leary 2012-02-03 12:59:41 -08:00
parent 5a6d92618a
commit 58b89e0902
20 changed files with 126 additions and 21 deletions

View File

@ -983,7 +983,7 @@ static bool
EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
{
const size_t len = 1 + UINT32_INDEX_LEN;
JS_ASSERT(js_CodeSpec[op].length == len);
JS_ASSERT(size_t(js_CodeSpec[op].length) == len);
ptrdiff_t offset = EmitCheck(cx, bce, len);
if (offset < 0)
return false;

View File

@ -245,13 +245,24 @@ bool
CodeGenerator::visitIntToString(LIntToString *lir)
{
typedef JSString *(*pf)(JSContext *, jsint);
static const VMFunction js_IntToStringInfo =
FunctionInfo<pf>(js_IntToString);
static const VMFunction js_IntToStringInfo = FunctionInfo<pf>(js_IntToString);
pushArg(ToRegister(lir->input()));
if (!callVM(js_IntToStringInfo, lir))
return false;
return true;
return callVM(js_IntToStringInfo, lir);
}
bool
CodeGenerator::visitRegExp(LRegExp *lir)
{
GlobalObject *global = gen->info().script()->global();
JSObject *proto = global->getOrCreateRegExpPrototype(gen->cx);
typedef JSObject *(*pf)(JSContext *, JSObject *, JSObject *);
static const VMFunction js_CloneRegExpObjectInfo = FunctionInfo<pf>(js_CloneRegExpObject);
pushArg(ImmGCPtr(proto));
pushArg(ImmGCPtr(lir->mir()->source()));
return callVM(js_CloneRegExpObjectInfo, lir);
}
bool

View File

@ -90,6 +90,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitTruncateDToInt32(LTruncateDToInt32 *lir);
bool visitIntToString(LIntToString *lir);
bool visitInteger(LInteger *lir);
bool visitRegExp(LRegExp *lir);
bool visitPointer(LPointer *lir);
bool visitSlots(LSlots *lir);
bool visitStoreSlotV(LStoreSlotV *store);

View File

@ -97,6 +97,9 @@ class CompileInfo
JSAtom *getAtom(jsbytecode *pc) const {
return script_->getAtom(GET_INDEX(pc));
}
RegExpObject *getRegExp(jsbytecode *pc) const {
return script_->getRegExp(GET_INDEX(pc));
}
const Value &getConst(jsbytecode *pc) const {
return script_->getConst(GET_INDEX(pc));
}

View File

@ -794,6 +794,9 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_SETNAME:
return jsop_setprop(info().getAtom(pc));
case JSOP_REGEXP:
return jsop_regexp(info().getRegExp(pc));
default:
#ifdef DEBUG
return abort("Unsupported opcode: %s (line %d)", js_CodeName[op], info().lineno(cx, pc));
@ -3425,6 +3428,16 @@ IonBuilder::jsop_setprop(JSAtom *atom)
return resumeAfter(ins);
}
bool
IonBuilder::jsop_regexp(RegExpObject *reobj)
{
MRegExp *ins = MRegExp::New(reobj, MRegExp::MustClone);
current->add(ins);
current->push(ins);
return true;
}
bool
IonBuilder::jsop_this()
{

View File

@ -304,6 +304,7 @@ class IonBuilder : public MIRGenerator
bool jsop_getprop(JSAtom *atom);
bool jsop_setprop(JSAtom *atom);
bool jsop_newarray(uint32 count);
bool jsop_regexp(RegExpObject *reobj);
bool jsop_this();
/* Inlining. */

View File

@ -900,6 +900,16 @@ class LOsrScopeChain : public LInstructionHelper<1, 1, 0>
}
};
class LRegExp : public LCallInstructionHelper<1, 0, 0>
{
public:
LIR_HEADER(RegExp);
const MRegExp *mir() const {
return mir_->toRegExp();
}
};
// Determines the implicit |this| value for function calls.
class LImplicitThis : public LInstructionHelper<BOX_PIECES, 1, 0>
{

View File

@ -90,6 +90,7 @@
_(OsrEntry) \
_(OsrValue) \
_(OsrScopeChain) \
_(RegExp) \
_(ImplicitThis) \
_(Slots) \
_(Elements) \

View File

@ -702,6 +702,13 @@ LIRGenerator::visitCopy(MCopy *ins)
return false;
}
bool
LIRGenerator::visitRegExp(MRegExp *ins)
{
LRegExp *lir = new LRegExp();
return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitImplicitThis(MImplicitThis *ins)
{

View File

@ -143,6 +143,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitTruncateToInt32(MTruncateToInt32 *truncate);
bool visitToString(MToString *convert);
bool visitCopy(MCopy *ins);
bool visitRegExp(MRegExp *ins);
bool visitImplicitThis(MImplicitThis *ins);
bool visitSlots(MSlots *ins);
bool visitElements(MElements *ins);

View File

@ -553,8 +553,11 @@ class MAryInstruction : public MInstruction
}
};
class MNullaryInstruction : public MAryInstruction<0>
{ };
// Generates an LSnapshot without further effect.
class MStart : public MAryInstruction<0>
class MStart : public MNullaryInstruction
{
public:
enum StartType {
@ -584,7 +587,7 @@ class MStart : public MAryInstruction<0>
// Instruction marking on entrypoint for on-stack replacement.
// OSR may occur at loop headers (at JSOP_TRACE).
// There is at most one MOsrEntry per MIRGraph.
class MOsrEntry : public MAryInstruction<0>
class MOsrEntry : public MNullaryInstruction
{
protected:
MOsrEntry() {
@ -599,7 +602,7 @@ class MOsrEntry : public MAryInstruction<0>
};
// A constant js::Value.
class MConstant : public MAryInstruction<0>
class MConstant : public MNullaryInstruction
{
js::Value value_;
uint32 constantPoolIndex_;
@ -637,7 +640,7 @@ class MConstant : public MAryInstruction<0>
}
};
class MParameter : public MAryInstruction<0>
class MParameter : public MNullaryInstruction
{
int32 index_;
types::TypeSet *typeSet_;
@ -668,7 +671,7 @@ class MParameter : public MAryInstruction<0>
bool congruentTo(MDefinition * const &ins) const;
};
class MCallee : public MAryInstruction<0>
class MCallee : public MNullaryInstruction
{
public:
MCallee()
@ -925,7 +928,7 @@ class MThrow
}
};
class MNewArray : public MAryInstruction<0>
class MNewArray : public MNullaryInstruction
{
// Number of space to allocate for the array.
uint32 count_;
@ -953,7 +956,7 @@ class MNewArray : public MAryInstruction<0>
// Designates the start of call frame construction.
// Generates code to adjust the stack pointer for the argument vector.
// Argc is inferred by checking the use chain during lowering.
class MPrepareCall : public MAryInstruction<0>
class MPrepareCall : public MNullaryInstruction
{
public:
INSTRUCTION_HEADER(PrepareCall);
@ -2000,7 +2003,7 @@ class MOsrScopeChain : public MAryInstruction<1>
};
// Check the current frame for over-recursion past the global stack limit.
class MCheckOverRecursed : public MAryInstruction<0>
class MCheckOverRecursed : public MNullaryInstruction
{
public:
INSTRUCTION_HEADER(CheckOverRecursed);
@ -2008,7 +2011,7 @@ class MCheckOverRecursed : public MAryInstruction<0>
// Check the script's use count and trigger recompilation to inline
// calls when the script becomes hot.
class MRecompileCheck : public MAryInstruction<0>
class MRecompileCheck : public MNullaryInstruction
{
MRecompileCheck() {
setGuard();
@ -2026,6 +2029,52 @@ class MRecompileCheck : public MAryInstruction<0>
}
};
class MRegExp : public MNullaryInstruction
{
public:
// In the future we can optimize MRegExp to reuse the source object
// instead of cloning in the case of some
// single-use-is-a-known-native-that-can't-observe-the-object
// operations (like test).
enum CloneBehavior {
UseSource,
MustClone
};
private:
HeapPtr<RegExpObject> source_;
CloneBehavior shouldClone_;
MRegExp(RegExpObject *source, CloneBehavior shouldClone)
: source_(source),
shouldClone_(shouldClone)
{
setResultType(MIRType_Object);
// Can't move if we're cloning, because cloning takes into
// account the RegExpStatics flags.
if (shouldClone == UseSource)
setMovable();
}
public:
INSTRUCTION_HEADER(RegExp)
static MRegExp *New(RegExpObject *source, CloneBehavior shouldClone) {
return new MRegExp(source, shouldClone);
}
const HeapPtr<RegExpObject> &source() const {
return source_;
}
CloneBehavior shouldClone() const {
return shouldClone_;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
// Determines the implicit |this| value for function calls.
class MImplicitThis
: public MUnaryInstruction,

View File

@ -88,6 +88,7 @@ namespace ion {
_(NewArray) \
_(Start) \
_(OsrEntry) \
_(RegExp) \
_(ImplicitThis) \
_(Slots) \
_(Elements) \

View File

@ -160,6 +160,8 @@ LIRGeneratorShared::defineReturn(LInstructionHelper<BOX_PIECES, Ops, Temps> *lir
template <size_t Defs, size_t Ops, size_t Temps> bool
LIRGeneratorShared::defineVMReturn(LInstructionHelper<Defs, Ops, Temps> *lir, MDefinition *mir)
{
JS_ASSERT(lir->isCall());
uint32 vreg = getVirtualRegister();
if (vreg >= MAX_VIRTUAL_REGISTERS)
return false;

View File

@ -237,6 +237,9 @@ class Assembler : public AssemblerX86Shared
push(Imm32(ptr.value));
writeDataRelocation(masm.currentOffset());
}
void push(const ImmWord imm) {
push(Imm32(imm.value));
}
void push(const FloatRegister &src) {
subl(Imm32(sizeof(double)), StackPointer);
movsd(src, Operand(StackPointer, 0));

View File

@ -563,6 +563,7 @@ class Value
JS_ALWAYS_INLINE
uint32_t payloadAsRawUint32() const {
JS_ASSERT(!isDouble());
JS_ASSERT_IF(isBoolean(), isTrue() || isFalse());
return data.s.payload.u32;
}

View File

@ -738,7 +738,7 @@ struct JSScript : public js::gc::Cell {
inline JSFunction *getFunction(size_t index);
inline JSFunction *getCallerFunction();
inline JSObject *getRegExp(size_t index);
inline js::RegExpObject *getRegExp(size_t index);
const js::Value &getConst(size_t index) {
JSConstArray *arr = consts();

View File

@ -162,14 +162,14 @@ JSScript::getCallerFunction()
return getFunction(0);
}
inline JSObject *
inline js::RegExpObject *
JSScript::getRegExp(size_t index)
{
JSObjectArray *arr = regexps();
JS_ASSERT(uint32_t(index) < arr->length);
JSObject *obj = arr->vector[index];
JS_ASSERT(obj->isRegExp());
return obj;
return (js::RegExpObject *) obj;
}
inline bool

View File

@ -594,6 +594,7 @@ JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
{
JS_ASSERT_IF(l.s.tag == JSVAL_TAG_BOOLEAN, l.s.payload.boo == !!l.s.payload.boo);
return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b);
}

View File

@ -148,7 +148,7 @@ RegExpObjectBuilder::clone(RegExpObject *other, RegExpObject *proto)
* the clone -- if the |RegExpStatics| provides more flags we'll
* need a different |RegExpShared|.
*/
RegExpStatics *res = cx->regExpStatics();
RegExpStatics *res = proto->getParent()->asGlobal().getRegExpStatics();
RegExpFlag origFlags = other->getFlags();
RegExpFlag staticsFlags = res->getFlags();
if ((origFlags & staticsFlags) != staticsFlags) {
@ -540,7 +540,7 @@ RegExpShared::create(JSContext *cx, JSLinearString *str, JSString *opt, TokenStr
return create(cx, str, flags, ts);
}
JSObject * JS_FASTCALL
JSObject *
js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
{
JS_ASSERT(obj->isRegExp());

View File

@ -481,7 +481,7 @@ RegExpToShared(JSContext *cx, JSObject &obj);
} /* namespace js */
extern JS_FRIEND_API(JSObject *) JS_FASTCALL
extern JS_FRIEND_API(JSObject *)
js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto);
JSBool