mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
Bug 723636: Implement MRegExp, take 2. (r=jandem)
This commit is contained in:
parent
5a6d92618a
commit
58b89e0902
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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. */
|
||||
|
@ -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>
|
||||
{
|
||||
|
@ -90,6 +90,7 @@
|
||||
_(OsrEntry) \
|
||||
_(OsrValue) \
|
||||
_(OsrScopeChain) \
|
||||
_(RegExp) \
|
||||
_(ImplicitThis) \
|
||||
_(Slots) \
|
||||
_(Elements) \
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -88,6 +88,7 @@ namespace ion {
|
||||
_(NewArray) \
|
||||
_(Start) \
|
||||
_(OsrEntry) \
|
||||
_(RegExp) \
|
||||
_(ImplicitThis) \
|
||||
_(Slots) \
|
||||
_(Elements) \
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user