[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:
parent
3f7b6a0f7e
commit
b6ddadd042
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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 };
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -345,7 +345,7 @@
|
||||
V(StringCharCodeAt) \
|
||||
V(StringCodePointAt) \
|
||||
V(StringFromSingleCharCode) \
|
||||
V(StringFromCodePoint) \
|
||||
V(StringFromSingleCodePoint) \
|
||||
V(StringIndexOf) \
|
||||
V(StringLength) \
|
||||
V(StringToLowerCaseIntl) \
|
||||
|
@ -2364,7 +2364,7 @@ class RepresentationSelector {
|
||||
MachineRepresentation::kTaggedPointer);
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kStringFromCodePoint: {
|
||||
case IrOpcode::kStringFromSingleCodePoint: {
|
||||
VisitUnop(node, UseInfo::TruncatingWord32(),
|
||||
MachineRepresentation::kTaggedPointer);
|
||||
return;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user