Skip to content

Commit

Permalink
Bug 1297749 - Inline String.fromCodePoint in Ion. r=jandem
Browse files Browse the repository at this point in the history
  • Loading branch information
anba committed Oct 5, 2016
1 parent 232803b commit 1a45b66
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 8 deletions.
32 changes: 32 additions & 0 deletions js/src/jit-test/tests/ion/testStringFromCodePoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
setJitCompilerOption("ion.warmup.trigger", 20);

function testBailout() {
function f(v, r) {
for (var i = 0; i < 50; ++i) {
// Ensure DCE and LICM don't eliminate calls to fromCodePoint in
// case the input argument is not a valid code point.
if (i === 0) {
r();
}
String.fromCodePoint(v);
String.fromCodePoint(v);
String.fromCodePoint(v);
}
}

var result = [];
function r() {
result.push("ok");
}

do {
result.length = 0;
try {
f(0, r);
f(0, r);
f(0x10ffff + 1, r);
} catch (e) {}
assertEq(result.length, 3);
} while (!inIon());
}
testBailout();
29 changes: 29 additions & 0 deletions js/src/jit/CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7676,6 +7676,35 @@ CodeGenerator::visitFromCharCode(LFromCharCode* lir)
masm.bind(ool->rejoin());
}

typedef JSString* (*StringFromCodePointFn)(JSContext*, int32_t);
static const VMFunction StringFromCodePointInfo =
FunctionInfo<StringFromCodePointFn>(jit::StringFromCodePoint, "StringFromCodePoint");

void
CodeGenerator::visitFromCodePoint(LFromCodePoint* lir)
{
Register codePoint = ToRegister(lir->codePoint());
Register output = ToRegister(lir->output());
LSnapshot* snapshot = lir->snapshot();

OutOfLineCode* ool = oolCallVM(StringFromCodePointInfo, lir, ArgList(codePoint),
StoreRegisterTo(output));

// Use a bailout if the input is not a valid code point, because
// MFromCodePoint is movable and it'd be observable when a moved
// fromCodePoint throws an exception before its actual call site.
bailoutCmp32(Assembler::Above, codePoint, Imm32(unicode::NonBMPMax), snapshot);

// OOL path if code point >= UNIT_STATIC_LIMIT.
masm.branch32(Assembler::AboveOrEqual, codePoint, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
ool->entry());

masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
masm.loadPtr(BaseIndex(output, codePoint, ScalePointer), output);

masm.bind(ool->rejoin());
}

void
CodeGenerator::visitSinCos(LSinCos *lir)
{
Expand Down
1 change: 1 addition & 0 deletions js/src/jit/CodeGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitConcat(LConcat* lir);
void visitCharCodeAt(LCharCodeAt* lir);
void visitFromCharCode(LFromCharCode* lir);
void visitFromCodePoint(LFromCodePoint* lir);
void visitSinCos(LSinCos *lir);
void visitStringSplit(LStringSplit* lir);
void visitFunctionEnvironment(LFunctionEnvironment* lir);
Expand Down
1 change: 1 addition & 0 deletions js/src/jit/InlinableNatives.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
_(String) \
_(StringCharCodeAt) \
_(StringFromCharCode) \
_(StringFromCodePoint) \
_(StringCharAt) \
\
_(IntrinsicStringReplaceString) \
Expand Down
1 change: 1 addition & 0 deletions js/src/jit/IonBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ class IonBuilder
InliningStatus inlineStrCharCodeAt(CallInfo& callInfo);
InliningStatus inlineConstantCharCodeAt(CallInfo& callInfo);
InliningStatus inlineStrFromCharCode(CallInfo& callInfo);
InliningStatus inlineStrFromCodePoint(CallInfo& callInfo);
InliningStatus inlineStrCharAt(CallInfo& callInfo);

// String intrinsics.
Expand Down
13 changes: 13 additions & 0 deletions js/src/jit/Lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1900,6 +1900,19 @@ LIRGenerator::visitFromCharCode(MFromCharCode* ins)
assignSafepoint(lir, ins);
}

void
LIRGenerator::visitFromCodePoint(MFromCodePoint* ins)
{
MDefinition* codePoint = ins->getOperand(0);

MOZ_ASSERT(codePoint->type() == MIRType::Int32);

LFromCodePoint* lir = new(alloc()) LFromCodePoint(useRegister(codePoint));
assignSnapshot(lir, Bailout_BoundsCheck);
define(lir, ins);
assignSafepoint(lir, ins);
}

void
LIRGenerator::visitStart(MStart* start)
{
Expand Down
1 change: 1 addition & 0 deletions js/src/jit/Lowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitConcat(MConcat* ins);
void visitCharCodeAt(MCharCodeAt* ins);
void visitFromCharCode(MFromCharCode* ins);
void visitFromCodePoint(MFromCodePoint* ins);
void visitSinCos(MSinCos *ins);
void visitStringSplit(MStringSplit* ins);
void visitStart(MStart* start);
Expand Down
26 changes: 23 additions & 3 deletions js/src/jit/MCallOptimize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineStrCharCodeAt(callInfo);
case InlinableNative::StringFromCharCode:
return inlineStrFromCharCode(callInfo);
case InlinableNative::StringFromCodePoint:
return inlineStrFromCodePoint(callInfo);
case InlinableNative::StringCharAt:
return inlineStrCharAt(callInfo);

Expand Down Expand Up @@ -1703,10 +1705,28 @@ IonBuilder::inlineStrFromCharCode(CallInfo& callInfo)

callInfo.setImplicitlyUsedUnchecked();

MToInt32* charCode = MToInt32::New(alloc(), callInfo.getArg(0));
current->add(charCode);
MFromCharCode* string = MFromCharCode::New(alloc(), callInfo.getArg(0));
current->add(string);
current->push(string);
return InliningStatus_Inlined;
}

MFromCharCode* string = MFromCharCode::New(alloc(), charCode);
IonBuilder::InliningStatus
IonBuilder::inlineStrFromCodePoint(CallInfo& callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}

if (getInlineReturnType() != MIRType::String)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType::Int32)
return InliningStatus_NotInlined;

callInfo.setImplicitlyUsedUnchecked();

MFromCodePoint* string = MFromCodePoint::New(alloc(), callInfo.getArg(0));
current->add(string);
current->push(string);
return InliningStatus_Inlined;
Expand Down
27 changes: 27 additions & 0 deletions js/src/jit/MIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -7327,6 +7327,33 @@ class MFromCharCode
ALLOW_CLONE(MFromCharCode)
};

class MFromCodePoint
: public MUnaryInstruction,
public IntPolicy<0>::Data
{
explicit MFromCodePoint(MDefinition* codePoint)
: MUnaryInstruction(codePoint)
{
setGuard(); // throws on invalid code point
setMovable();
setResultType(MIRType::String);
}

public:
INSTRUCTION_HEADER(FromCodePoint)
TRIVIAL_NEW_WRAPPERS

AliasSet getAliasSet() const override {
return AliasSet::None();
}
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
bool possiblyCalls() const override {
return true;
}
};

class MSinCos
: public MUnaryInstruction,
public FloatingPointPolicy<0>::Data
Expand Down
1 change: 1 addition & 0 deletions js/src/jit/MOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ namespace jit {
_(Concat) \
_(CharCodeAt) \
_(FromCharCode) \
_(FromCodePoint) \
_(SinCos) \
_(StringSplit) \
_(Substr) \
Expand Down
10 changes: 10 additions & 0 deletions js/src/jit/VMFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,16 @@ StringFromCharCode(JSContext* cx, int32_t code)
return NewStringCopyN<CanGC>(cx, &c, 1);
}

JSString*
StringFromCodePoint(JSContext* cx, int32_t codePoint)
{
RootedValue rval(cx, Int32Value(codePoint));
if (!str_fromCodePoint_one_arg(cx, rval, &rval))
return nullptr;

return rval.toString();
}

bool
SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
bool strict, jsbytecode* pc)
Expand Down
1 change: 1 addition & 0 deletions js/src/jit/VMFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ JSString* ArrayJoin(JSContext* cx, HandleObject array, HandleString sep);
MOZ_MUST_USE bool
CharCodeAt(JSContext* cx, HandleString str, int32_t index, uint32_t* code);
JSFlatString* StringFromCharCode(JSContext* cx, int32_t code);
JSString* StringFromCodePoint(JSContext* cx, int32_t codePoint);

MOZ_MUST_USE bool
SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
Expand Down
15 changes: 15 additions & 0 deletions js/src/jit/shared/LIR-shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -4037,6 +4037,21 @@ class LFromCharCode : public LInstructionHelper<1, 1, 0>
}
};

// Convert uint32 code point to a string.
class LFromCodePoint : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(FromCodePoint)

explicit LFromCodePoint(const LAllocation& codePoint) {
setOperand(0, codePoint);
}

const LAllocation* codePoint() {
return this->getOperand(0);
}
};

// Calculates sincos(x) and returns two values (sin/cos).
class LSinCos : public LCallInstructionHelper<2, 1, 2>
{
Expand Down
1 change: 1 addition & 0 deletions js/src/jit/shared/LOpcodes-shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
_(Concat) \
_(CharCodeAt) \
_(FromCharCode) \
_(FromCodePoint) \
_(SinCos) \
_(StringSplit) \
_(Int32ToDouble) \
Expand Down
10 changes: 5 additions & 5 deletions js/src/jsstr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2799,8 +2799,8 @@ ToCodePoint(JSContext* cx, HandleValue code, uint32_t* codePoint)
return true;
}

static bool
str_fromCodePoint_one_arg(JSContext* cx, HandleValue code, MutableHandleValue rval)
bool
js::str_fromCodePoint_one_arg(JSContext* cx, HandleValue code, MutableHandleValue rval)
{
// Steps 1-4 (omitted).

Expand Down Expand Up @@ -2855,8 +2855,8 @@ str_fromCodePoint_few_args(JSContext* cx, const CallArgs& args)

// ES2017 draft rev 40edb3a95a475c1b251141ac681b8793129d9a6d
// 21.1.2.2 String.fromCodePoint(...codePoints)
static bool
str_fromCodePoint(JSContext* cx, unsigned argc, Value* vp)
bool
js::str_fromCodePoint(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);

Expand Down Expand Up @@ -2909,8 +2909,8 @@ str_fromCodePoint(JSContext* cx, unsigned argc, Value* vp)

static const JSFunctionSpec string_static_methods[] = {
JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
JS_INLINABLE_FN("fromCodePoint", js::str_fromCodePoint, 1, 0, StringFromCodePoint),

JS_FN("fromCodePoint", str_fromCodePoint, 1,0),
JS_SELF_HOSTED_FN("raw", "String_static_raw", 2,JSFUN_HAS_REST),
JS_SELF_HOSTED_FN("substring", "String_static_substring", 3,0),
JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0),
Expand Down
6 changes: 6 additions & 0 deletions js/src/jsstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ str_fromCharCode(JSContext* cx, unsigned argc, Value* vp);
extern bool
str_fromCharCode_one_arg(JSContext* cx, HandleValue code, MutableHandleValue rval);

extern bool
str_fromCodePoint(JSContext* cx, unsigned argc, Value* vp);

extern bool
str_fromCodePoint_one_arg(JSContext* cx, HandleValue code, MutableHandleValue rval);

/* String methods exposed so they can be installed in the self-hosting global. */

extern bool
Expand Down

0 comments on commit 1a45b66

Please sign in to comment.