зеркало из https://github.com/mozilla/gecko-dev.git
Bug 794475 - Inline "new String(x)". r=dvander
This commit is contained in:
Родитель
7372386461
Коммит
5ab8c0a036
|
@ -14,6 +14,8 @@
|
|||
#include "jsmath.h"
|
||||
#include "jsinterpinlines.h"
|
||||
|
||||
#include "vm/StringObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
|
@ -1528,6 +1530,35 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitNewStringObject(LNewStringObject *lir)
|
||||
{
|
||||
Register input = ToRegister(lir->input());
|
||||
Register output = ToRegister(lir->output());
|
||||
Register temp = ToRegister(lir->temp());
|
||||
|
||||
typedef JSObject *(*pf)(JSContext *, HandleString);
|
||||
static const VMFunction NewStringObjectInfo = FunctionInfo<pf>(NewStringObject);
|
||||
|
||||
StringObject *templateObj = lir->mir()->templateObj();
|
||||
|
||||
OutOfLineCode *ool = oolCallVM(NewStringObjectInfo, lir, (ArgList(), input),
|
||||
StoreRegisterTo(output));
|
||||
if (!ool)
|
||||
return false;
|
||||
|
||||
masm.newGCThing(output, templateObj, ool->entry());
|
||||
masm.initGCThing(output, templateObj);
|
||||
|
||||
masm.loadStringLength(input, temp);
|
||||
|
||||
masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
|
||||
masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitInitProp(LInitProp *lir)
|
||||
{
|
||||
|
@ -1652,11 +1683,10 @@ CodeGenerator::visitTypedArrayElements(LTypedArrayElements *lir)
|
|||
bool
|
||||
CodeGenerator::visitStringLength(LStringLength *lir)
|
||||
{
|
||||
Address lengthAndFlags(ToRegister(lir->string()), JSString::offsetOfLengthAndFlags());
|
||||
Register input = ToRegister(lir->string());
|
||||
Register output = ToRegister(lir->output());
|
||||
|
||||
masm.loadPtr(lengthAndFlags, output);
|
||||
masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), output);
|
||||
masm.loadStringLength(input, output);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
bool visitNewObject(LNewObject *lir);
|
||||
bool visitOutOfLineNewObject(OutOfLineNewObject *ool);
|
||||
bool visitNewCallObject(LNewCallObject *lir);
|
||||
bool visitNewStringObject(LNewStringObject *lir);
|
||||
bool visitInitProp(LInitProp *lir);
|
||||
bool visitCreateThis(LCreateThis *lir);
|
||||
bool visitCreateThisVM(LCreateThisVM *lir);
|
||||
|
|
|
@ -382,6 +382,7 @@ class IonBuilder : public MIRGenerator
|
|||
bool constructing);
|
||||
|
||||
// String natives.
|
||||
InliningStatus inlineStringObject(uint32 argc, bool constructing);
|
||||
InliningStatus inlineStrCharCodeAt(uint32 argc, bool constructing);
|
||||
InliningStatus inlineStrFromCharCode(uint32 argc, bool constructing);
|
||||
InliningStatus inlineStrCharAt(uint32 argc, bool constructing);
|
||||
|
|
|
@ -149,6 +149,11 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
loadPtr(Address(dest, offsetof(types::TypeObject, proto)), dest);
|
||||
}
|
||||
|
||||
void loadStringLength(Register str, Register dest) {
|
||||
loadPtr(Address(str, JSString::offsetOfLengthAndFlags()), dest);
|
||||
rshiftPtr(Imm32(JSString::LENGTH_SHIFT), dest);
|
||||
}
|
||||
|
||||
void loadJSContext(const Register &dest) {
|
||||
movePtr(ImmWord(GetIonContext()->cx->runtime), dest);
|
||||
loadPtr(Address(dest, offsetof(JSRuntime, ionJSContext)), dest);
|
||||
|
|
|
@ -292,6 +292,27 @@ class LNewCallObject : public LInstructionHelper<1, 1, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LNewStringObject : public LInstructionHelper<1, 1, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(NewStringObject);
|
||||
|
||||
LNewStringObject(const LAllocation &input, const LDefinition &temp) {
|
||||
setOperand(0, input);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const LAllocation *input() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LDefinition *temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
MNewStringObject *mir() const {
|
||||
return mir_->toNewStringObject();
|
||||
}
|
||||
};
|
||||
|
||||
// Takes in an Object and a Value.
|
||||
class LInitProp : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
_(NewObject) \
|
||||
_(NewSlots) \
|
||||
_(NewCallObject) \
|
||||
_(NewStringObject) \
|
||||
_(InitProp) \
|
||||
_(CheckOverRecursed) \
|
||||
_(RecompileCheck) \
|
||||
|
|
|
@ -138,6 +138,15 @@ LIRGenerator::visitNewCallObject(MNewCallObject *ins)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitNewStringObject(MNewStringObject *ins)
|
||||
{
|
||||
JS_ASSERT(ins->input()->type() == MIRType_String);
|
||||
|
||||
LNewStringObject *lir = new LNewStringObject(useRegister(ins->input()), temp());
|
||||
return define(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitInitProp(MInitProp *ins)
|
||||
{
|
||||
|
|
|
@ -81,6 +81,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
bool visitNewArray(MNewArray *ins);
|
||||
bool visitNewObject(MNewObject *ins);
|
||||
bool visitNewCallObject(MNewCallObject *ins);
|
||||
bool visitNewStringObject(MNewStringObject *ins);
|
||||
bool visitInitProp(MInitProp *ins);
|
||||
bool visitCheckOverRecursed(MCheckOverRecursed *ins);
|
||||
bool visitDefVar(MDefVar *ins);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "MIRGraph.h"
|
||||
#include "IonBuilder.h"
|
||||
|
||||
#include "vm/StringObject-inl.h"
|
||||
|
||||
namespace js {
|
||||
namespace ion {
|
||||
|
||||
|
@ -53,6 +55,8 @@ IonBuilder::inlineNativeCall(JSNative native, uint32 argc, bool constructing)
|
|||
return inlineMathFunction(MMathFunction::Log, argc, constructing);
|
||||
|
||||
// String natives.
|
||||
if (native == js_String)
|
||||
return inlineStringObject(argc, constructing);
|
||||
if (native == js_str_charCodeAt)
|
||||
return inlineStrCharCodeAt(argc, constructing);
|
||||
if (native == js::str_fromCharCode)
|
||||
|
@ -556,6 +560,36 @@ IonBuilder::inlineMathMinMax(bool max, uint32 argc, bool constructing)
|
|||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineStringObject(uint32 argc, bool constructing)
|
||||
{
|
||||
if (argc != 1 || !constructing)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// MToString only supports int32 or string values.
|
||||
MIRType type = getInlineArgType(argc, 1);
|
||||
if (type != MIRType_Int32 && type != MIRType_String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MDefinitionVector argv;
|
||||
if (!discardCall(argc, argv, current))
|
||||
return InliningStatus_Error;
|
||||
|
||||
RootedString emptyString(cx, cx->runtime->emptyString);
|
||||
RootedObject templateObj(cx, StringObject::create(cx, emptyString));
|
||||
if (!templateObj)
|
||||
return InliningStatus_Error;
|
||||
|
||||
MNewStringObject *ins = MNewStringObject::New(argv[1], templateObj);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
if (!resumeAfter(ins))
|
||||
return InliningStatus_Error;
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineStrCharCodeAt(uint32 argc, bool constructing)
|
||||
{
|
||||
|
|
|
@ -5288,6 +5288,37 @@ class MNewCallObject : public MUnaryInstruction
|
|||
}
|
||||
};
|
||||
|
||||
class MNewStringObject :
|
||||
public MUnaryInstruction,
|
||||
public StringPolicy
|
||||
{
|
||||
CompilerRootObject templateObj_;
|
||||
|
||||
MNewStringObject(MDefinition *input, HandleObject templateObj)
|
||||
: MUnaryInstruction(input),
|
||||
templateObj_(templateObj)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(NewStringObject);
|
||||
|
||||
static MNewStringObject *New(MDefinition *input, HandleObject templateObj) {
|
||||
return new MNewStringObject(input, templateObj);
|
||||
}
|
||||
|
||||
MDefinition *input() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
StringObject *templateObj() const {
|
||||
return &templateObj_->asString();
|
||||
}
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// Node that represents that a script has begun executing. This comes at the
|
||||
// start of the function and is called once per function (including inline
|
||||
// ones)
|
||||
|
|
|
@ -70,6 +70,7 @@ namespace ion {
|
|||
_(NewArray) \
|
||||
_(NewObject) \
|
||||
_(NewCallObject) \
|
||||
_(NewStringObject) \
|
||||
_(InitProp) \
|
||||
_(Start) \
|
||||
_(OsrEntry) \
|
||||
|
|
|
@ -282,7 +282,15 @@ StringPolicy::staticAdjustInputs(MInstruction *def)
|
|||
if (in->type() == MIRType_String)
|
||||
return true;
|
||||
|
||||
MUnbox *replace = MUnbox::New(in, MIRType_String, MUnbox::Fallible);
|
||||
MInstruction *replace;
|
||||
if (in->type() == MIRType_Int32) {
|
||||
replace = MToString::New(in);
|
||||
} else {
|
||||
if (in->type() != MIRType_Value)
|
||||
in = boxAt(def, in);
|
||||
replace = MUnbox::New(in, MIRType_String, MUnbox::Fallible);
|
||||
}
|
||||
|
||||
def->block()->insertBefore(def, replace);
|
||||
def->replaceOperand(0, replace);
|
||||
return true;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "ion/IonFrames.h"
|
||||
#include "ion/IonFrames-inl.h" // for GetTopIonJSScript
|
||||
|
||||
#include "vm/StringObject-inl.h"
|
||||
|
||||
#include "jsinterpinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -385,6 +387,12 @@ NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot
|
|||
return CallObject::create(cx, shape, type, slots);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
NewStringObject(JSContext *cx, HandleString str)
|
||||
{
|
||||
return StringObject::create(cx, str);
|
||||
}
|
||||
|
||||
bool SPSEnter(JSContext *cx, HandleScript script)
|
||||
{
|
||||
return cx->runtime->spsProfiler.enter(cx, script, script->function());
|
||||
|
|
|
@ -439,6 +439,7 @@ bool InterruptCheck(JSContext *cx);
|
|||
|
||||
HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
|
||||
JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
|
||||
JSObject *NewStringObject(JSContext *cx, HandleString str);
|
||||
|
||||
bool SPSEnter(JSContext *cx, HandleScript script);
|
||||
bool SPSExit(JSContext *cx, HandleScript script);
|
||||
|
|
|
@ -1315,6 +1315,16 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, Type type)
|
|||
}
|
||||
}
|
||||
|
||||
if (native == js_String && callsite->isNew) {
|
||||
// Note that "new String()" returns a String object and "String()"
|
||||
// returns a primitive string.
|
||||
TypeObject *res = TypeScript::StandardType(cx, script, JSProto_String);
|
||||
if (!res)
|
||||
return;
|
||||
|
||||
callsite->returnTypes->addType(cx, Type::ObjectType(res));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -865,9 +865,7 @@ class GetPropCompiler : public PICStubCompiler
|
|||
|
||||
Jump notStringObj = masm.guardShape(pic.objReg, obj);
|
||||
|
||||
masm.loadPayload(Address(pic.objReg, StringObject::getPrimitiveValueOffset()), pic.objReg);
|
||||
masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg);
|
||||
masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg);
|
||||
masm.loadPayload(Address(pic.objReg, StringObject::offsetOfLength()), pic.objReg);
|
||||
masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
|
||||
Jump done = masm.jump();
|
||||
|
||||
|
|
|
@ -41,9 +41,12 @@ class StringObject : public JSObject
|
|||
return size_t(getFixedSlot(LENGTH_SLOT).toInt32());
|
||||
}
|
||||
|
||||
static size_t getPrimitiveValueOffset() {
|
||||
static size_t offsetOfPrimitiveValue() {
|
||||
return getFixedSlotOffset(PRIMITIVE_VALUE_SLOT);
|
||||
}
|
||||
static size_t offsetOfLength() {
|
||||
return getFixedSlotOffset(LENGTH_SLOT);
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool init(JSContext *cx, HandleString str);
|
||||
|
|
Загрузка…
Ссылка в новой задаче