Bug 794475 - Inline "new String(x)". r=dvander

This commit is contained in:
Jan de Mooij 2012-09-27 12:45:55 +02:00
Родитель 7372386461
Коммит 5ab8c0a036
17 изменённых файлов: 171 добавлений и 8 удалений

Просмотреть файл

@ -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);