[turbofan] Rename StringFromCodePoint to StringFromSingleCodePoint

Also add a new fast-path for String.fromCodePoint.

R=neis@chromium.org

Bug: v8:7570, v8:7340
Change-Id: I6cd6e6fc98943588ecd646f24fcda043d4033ab0
Reviewed-on: https://chromium-review.googlesource.com/978244
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52183}
This commit is contained in:
Sigurd Schneider 2018-03-23 14:43:08 +01:00 committed by Commit Bot
parent 3f7b6a0f7e
commit b6ddadd042
14 changed files with 124 additions and 76 deletions

View File

@ -2305,7 +2305,7 @@ TF_BUILTIN(StringIteratorPrototypeNext, StringBuiltinsAssembler) {
{
UnicodeEncoding encoding = UnicodeEncoding::UTF16;
TNode<Int32T> ch = LoadSurrogatePairAt(string, length, position, encoding);
TNode<String> value = StringFromCodePoint(ch, encoding);
TNode<String> value = StringFromSingleCodePoint(ch, encoding);
var_value.Bind(value);
TNode<IntPtrT> length = LoadStringLengthAsWord(value);
StoreObjectFieldNoWriteBarrier(iterator, JSStringIterator::kNextIndexOffset,

View File

@ -5451,8 +5451,8 @@ TNode<String> CodeStubAssembler::StringAdd(Node* context, TNode<String> left,
return result.value();
}
TNode<String> CodeStubAssembler::StringFromCodePoint(TNode<Int32T> codepoint,
UnicodeEncoding encoding) {
TNode<String> CodeStubAssembler::StringFromSingleCodePoint(
TNode<Int32T> codepoint, UnicodeEncoding encoding) {
VARIABLE(var_result, MachineRepresentation::kTagged, EmptyStringConstant());
Label if_isword16(this), if_isword32(this), return_result(this);

View File

@ -1246,8 +1246,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Variable* var_right, Node* right_instance_type,
Label* did_something);
TNode<String> StringFromCodePoint(TNode<Int32T> codepoint,
UnicodeEncoding encoding);
TNode<String> StringFromSingleCodePoint(TNode<Int32T> codepoint,
UnicodeEncoding encoding);
// Type conversion helpers.
enum class BigIntHandling { kConvertToNumber, kThrow };

View File

@ -827,8 +827,8 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStringFromSingleCharCode:
result = LowerStringFromSingleCharCode(node);
break;
case IrOpcode::kStringFromCodePoint:
result = LowerStringFromCodePoint(node);
case IrOpcode::kStringFromSingleCodePoint:
result = LowerStringFromSingleCodePoint(node);
break;
case IrOpcode::kStringIndexOf:
result = LowerStringIndexOf(node);
@ -3067,7 +3067,7 @@ Node* EffectControlLinearizer::LowerStringToUpperCaseIntl(Node* node) {
#endif // V8_INTL_SUPPORT
Node* EffectControlLinearizer::LowerStringFromCodePoint(Node* node) {
Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) {
Node* value = node->InputAt(0);
Node* code = value;

View File

@ -126,7 +126,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerStringToLowerCaseIntl(Node* node);
Node* LowerStringToUpperCaseIntl(Node* node);
Node* LowerStringFromSingleCharCode(Node* node);
Node* LowerStringFromCodePoint(Node* node);
Node* LowerStringFromSingleCodePoint(Node* node);
Node* LowerStringIndexOf(Node* node);
Node* LowerStringSubstring(Node* node);
Node* LowerStringLength(Node* node);

View File

@ -3465,6 +3465,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
#endif // V8_INTL_SUPPORT
case Builtins::kStringFromCharCode:
return ReduceStringFromCharCode(node);
case Builtins::kStringFromCodePoint:
return ReduceStringFromCodePoint(node);
case Builtins::kStringPrototypeIterator:
return ReduceStringPrototypeIterator(node);
case Builtins::kStringIteratorPrototypeNext:
@ -4996,6 +4998,33 @@ Reduction JSCallReducer::ReduceStringFromCharCode(Node* node) {
return NoChange();
}
// ES #sec-string.fromcodepoint
Reduction JSCallReducer::ReduceStringFromCodePoint(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
if (node->op()->ValueInputCount() == 3) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* input = NodeProperties::GetValueInput(node, 2);
input = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
input, effect, control);
input = effect =
graph()->NewNode(simplified()->CheckBounds(p.feedback()), input,
jsgraph()->Constant(0x10FFFF + 1), effect, control);
Node* value = graph()->NewNode(
simplified()->StringFromSingleCodePoint(UnicodeEncoding::UTF32), input);
ReplaceWithValue(node, value, effect);
return Replace(value);
}
return NoChange();
}
Reduction JSCallReducer::ReduceStringPrototypeIterator(Node* node) {
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
@ -5044,7 +5073,8 @@ Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
simplified()->StringCodePointAt(UnicodeEncoding::UTF16), string,
index, etrue0, if_true0);
vtrue0 = graph()->NewNode(
simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), codepoint);
simplified()->StringFromSingleCodePoint(UnicodeEncoding::UTF16),
codepoint);
// Update iterator.[[NextIndex]]
Node* char_length =

View File

@ -121,6 +121,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
#endif // V8_INTL_SUPPORT
Reduction ReduceStringFromCharCode(Node* node);
Reduction ReduceStringFromCodePoint(Node* node);
Reduction ReduceStringPrototypeIterator(Node* node);
Reduction ReduceStringIteratorPrototypeNext(Node* node);
Reduction ReduceStringPrototypeConcat(Node* node,

View File

@ -345,7 +345,7 @@
V(StringCharCodeAt) \
V(StringCodePointAt) \
V(StringFromSingleCharCode) \
V(StringFromCodePoint) \
V(StringFromSingleCodePoint) \
V(StringIndexOf) \
V(StringLength) \
V(StringToLowerCaseIntl) \

View File

@ -2364,7 +2364,7 @@ class RepresentationSelector {
MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kStringFromCodePoint: {
case IrOpcode::kStringFromSingleCodePoint: {
VisitUnop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kTaggedPointer);
return;

View File

@ -550,7 +550,7 @@ Type* AllocateTypeOf(const Operator* op) {
}
UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kStringFromCodePoint ||
DCHECK(op->opcode() == IrOpcode::kStringFromSingleCodePoint ||
op->opcode() == IrOpcode::kStringCodePointAt);
return OpParameter<UnicodeEncoding>(op);
}
@ -836,16 +836,17 @@ struct SimplifiedOperatorGlobalCache final {
kStringCodePointAtOperatorUTF32;
template <UnicodeEncoding kEncoding>
struct StringFromCodePointOperator final : public Operator1<UnicodeEncoding> {
StringFromCodePointOperator()
: Operator1<UnicodeEncoding>(IrOpcode::kStringFromCodePoint,
Operator::kPure, "StringFromCodePoint", 1,
0, 0, 1, 0, 0, kEncoding) {}
struct StringFromSingleCodePointOperator final
: public Operator1<UnicodeEncoding> {
StringFromSingleCodePointOperator()
: Operator1<UnicodeEncoding>(
IrOpcode::kStringFromSingleCodePoint, Operator::kPure,
"StringFromSingleCodePoint", 1, 0, 0, 1, 0, 0, kEncoding) {}
};
StringFromCodePointOperator<UnicodeEncoding::UTF16>
kStringFromCodePointOperatorUTF16;
StringFromCodePointOperator<UnicodeEncoding::UTF32>
kStringFromCodePointOperatorUTF32;
StringFromSingleCodePointOperator<UnicodeEncoding::UTF16>
kStringFromSingleCodePointOperatorUTF16;
StringFromSingleCodePointOperator<UnicodeEncoding::UTF32>
kStringFromSingleCodePointOperatorUTF32;
struct ArrayBufferWasNeuteredOperator final : public Operator {
ArrayBufferWasNeuteredOperator()
@ -1450,13 +1451,13 @@ const Operator* SimplifiedOperatorBuilder::StringCodePointAt(
UNREACHABLE();
}
const Operator* SimplifiedOperatorBuilder::StringFromCodePoint(
const Operator* SimplifiedOperatorBuilder::StringFromSingleCodePoint(
UnicodeEncoding encoding) {
switch (encoding) {
case UnicodeEncoding::UTF16:
return &cache_.kStringFromCodePointOperatorUTF16;
return &cache_.kStringFromSingleCodePointOperatorUTF16;
case UnicodeEncoding::UTF32:
return &cache_.kStringFromCodePointOperatorUTF32;
return &cache_.kStringFromSingleCodePointOperatorUTF32;
}
UNREACHABLE();
}

View File

@ -560,7 +560,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringCharCodeAt();
const Operator* StringCodePointAt(UnicodeEncoding encoding);
const Operator* StringFromSingleCharCode();
const Operator* StringFromCodePoint(UnicodeEncoding encoding);
const Operator* StringFromSingleCodePoint(UnicodeEncoding encoding);
const Operator* StringIndexOf();
const Operator* StringLength();
const Operator* StringToLowerCaseIntl();

View File

@ -326,7 +326,7 @@ class Typer::Visitor : public Reducer {
static Type* ReferenceEqualTyper(Type*, Type*, Typer*);
static Type* SameValueTyper(Type*, Type*, Typer*);
static Type* StringFromSingleCharCodeTyper(Type*, Typer*);
static Type* StringFromCodePointTyper(Type*, Typer*);
static Type* StringFromSingleCodePointTyper(Type*, Typer*);
Reduction UpdateType(Node* node, Type* current) {
if (NodeProperties::IsTyped(node)) {
@ -1966,7 +1966,7 @@ Type* Typer::Visitor::StringFromSingleCharCodeTyper(Type* type, Typer* t) {
return Type::String();
}
Type* Typer::Visitor::StringFromCodePointTyper(Type* type, Typer* t) {
Type* Typer::Visitor::StringFromSingleCodePointTyper(Type* type, Typer* t) {
return Type::String();
}
@ -1990,8 +1990,8 @@ Type* Typer::Visitor::TypeStringFromSingleCharCode(Node* node) {
return TypeUnaryOp(node, StringFromSingleCharCodeTyper);
}
Type* Typer::Visitor::TypeStringFromCodePoint(Node* node) {
return TypeUnaryOp(node, StringFromCodePointTyper);
Type* Typer::Visitor::TypeStringFromSingleCodePoint(Node* node) {
return TypeUnaryOp(node, StringFromSingleCodePointTyper);
}
Type* Typer::Visitor::TypeStringIndexOf(Node* node) {

View File

@ -1105,7 +1105,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::String());
break;
case IrOpcode::kStringFromCodePoint:
case IrOpcode::kStringFromSingleCodePoint:
// (Unsigned32) -> String
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::String());

View File

@ -5,56 +5,72 @@
// Tests taken from:
// https://github.com/mathiasbynens/String.fromCodePoint
assertEquals(String.fromCodePoint.length, 1);
assertEquals(String.propertyIsEnumerable("fromCodePoint"), false);
// Flags: --allow-natives-syntax
assertEquals(String.fromCodePoint(""), "\0");
assertEquals(String.fromCodePoint(), "");
assertEquals(String.fromCodePoint(-0), "\0");
assertEquals(String.fromCodePoint(0), "\0");
assertEquals(String.fromCodePoint(0x1D306), "\uD834\uDF06");
assertEquals(
function test() {
assertEquals(String.fromCodePoint.length, 1);
assertEquals(String.propertyIsEnumerable("fromCodePoint"), false);
assertEquals(String.fromCodePoint(""), "\0");
assertEquals(String.fromCodePoint(), "");
assertEquals(String.fromCodePoint(-0), "\0");
assertEquals(String.fromCodePoint(0), "\0");
assertEquals(String.fromCodePoint(0x1D306), "\uD834\uDF06");
assertEquals(
String.fromCodePoint(0x1D306, 0x61, 0x1D307),
"\uD834\uDF06a\uD834\uDF07");
assertEquals(String.fromCodePoint(0x61, 0x62, 0x1D307), "ab\uD834\uDF07");
assertEquals(String.fromCodePoint(false), "\0");
assertEquals(String.fromCodePoint(null), "\0");
assertEquals(String.fromCodePoint(0x61, 0x62, 0x1D307), "ab\uD834\uDF07");
assertEquals(String.fromCodePoint(false), "\0");
assertEquals(String.fromCodePoint(null), "\0");
assertThrows(function() { String.fromCodePoint("_"); }, RangeError);
assertThrows(function() { String.fromCodePoint("+Infinity"); }, RangeError);
assertThrows(function() { String.fromCodePoint("-Infinity"); }, RangeError);
assertThrows(function() { String.fromCodePoint(-1); }, RangeError);
assertThrows(function() { String.fromCodePoint(0x10FFFF + 1); }, RangeError);
assertThrows(function() { String.fromCodePoint(3.14); }, RangeError);
assertThrows(function() { String.fromCodePoint(3e-2); }, RangeError);
assertThrows(function() { String.fromCodePoint(-Infinity); }, RangeError);
assertThrows(function() { String.fromCodePoint(+Infinity); }, RangeError);
assertThrows(function() { String.fromCodePoint(NaN); }, RangeError);
assertThrows(function() { String.fromCodePoint(undefined); }, RangeError);
assertThrows(function() { String.fromCodePoint({}); }, RangeError);
assertThrows(function() { String.fromCodePoint(/./); }, RangeError);
assertThrows(function() { String.fromCodePoint({
valueOf: function() { throw Error(); } });
}, Error);
assertThrows(function() { String.fromCodePoint({
valueOf: function() { throw Error(); } });
}, Error);
var tmp = 0x60;
assertEquals(String.fromCodePoint({
valueOf: function() { ++tmp; return tmp; }
}), "a");
assertEquals(tmp, 0x61);
assertThrows(function () { String.fromCodePoint("_"); }, RangeError);
assertThrows(function () { String.fromCodePoint("+Infinity"); }, RangeError);
assertThrows(function () { String.fromCodePoint("-Infinity"); }, RangeError);
assertThrows(function () { String.fromCodePoint(-1); }, RangeError);
assertThrows(function () { String.fromCodePoint(0x10FFFF + 1); }, RangeError);
assertThrows(function () { String.fromCodePoint(3.14); }, RangeError);
assertThrows(function () { String.fromCodePoint(3e-2); }, RangeError);
assertThrows(function () { String.fromCodePoint(-Infinity); }, RangeError);
assertThrows(function () { String.fromCodePoint(+Infinity); }, RangeError);
assertThrows(function () { String.fromCodePoint(NaN); }, RangeError);
assertThrows(function () { String.fromCodePoint(undefined); }, RangeError);
assertThrows(function () { String.fromCodePoint({}); }, RangeError);
assertThrows(function () { String.fromCodePoint(/./); }, RangeError);
assertThrows(function () {
String.fromCodePoint({
valueOf: function () { throw Error(); }
});
}, Error);
assertThrows(function () {
String.fromCodePoint({
valueOf: function () { throw Error(); }
});
}, Error);
var tmp = 0x60;
assertEquals(String.fromCodePoint({
valueOf: function () { ++tmp; return tmp; }
}), "a");
assertEquals(tmp, 0x61);
var counter = Math.pow(2, 15) * 3 / 2;
var result = [];
while (--counter >= 0) {
result.push(0); // one code unit per symbol
var counter = Math.pow(2, 15) * 3 / 2;
var result = [];
while (--counter >= 0) {
result.push(0); // one code unit per symbol
}
String.fromCodePoint.apply(null, result); // must not throw
var counter = Math.pow(2, 15) * 3 / 2;
var result = [];
while (--counter >= 0) {
result.push(0xFFFF + 1); // two code units per symbol
}
String.fromCodePoint.apply(null, result); // must not throw
}
String.fromCodePoint.apply(null, result); // must not throw
var counter = Math.pow(2, 15) * 3 / 2;
var result = [];
while (--counter >= 0) {
result.push(0xFFFF + 1); // two code units per symbol
test();
test();
for (var i = 0; i < 100; ++i) {
%OptimizeFunctionOnNextCall(test);
test();
}
String.fromCodePoint.apply(null, result); // must not throw