[turbofan] Reduce code size for StringFromCharCode.

Don't inline the full StringFromCharCode logic into TurboFan, but only
the common case, and use the %StringFromCharCode runtime function for
the rest, similar to what we do in HStringCharFromCode in Crankshaft.
This greatly reduces compile time for TurboFan due to greatly reduced
number of nodes. For example it reduces overall runtime of the base64
benchmark by up to 15% with the future pipeline.

R=yangguo@chromium.org

Review-Url: https://codereview.chromium.org/2445273002
Cr-Commit-Position: refs/heads/master@{#40544}
This commit is contained in:
bmeurer 2016-10-24 23:01:13 -07:00 committed by Commit bot
parent ed7bef5b91
commit 5a5ffc63e2

View File

@ -2447,104 +2447,63 @@ EffectControlLinearizer::LowerStringFromCharCode(Node* node, Node* effect,
Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* etrue0 = effect;
Node* vtrue0;
{
// Load the isolate wide single character string cache.
Node* cache =
jsgraph()->HeapConstant(factory()->single_character_string_cache());
// Compute the {cache} index for {code}.
Node* index =
machine()->Is32() ? code : graph()->NewNode(
machine()->ChangeUint32ToUint64(), code);
// Check if we have an entry for the {code} in the single character string
// cache already.
Node* entry = etrue0 = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), cache,
index, etrue0, if_true0);
Node* check1 = graph()->NewNode(machine()->WordEqual(), entry,
jsgraph()->UndefinedConstant());
Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check1, if_true0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* etrue1 = etrue0;
Node* vtrue1;
{
// Allocate a new SeqOneByteString for {code}.
vtrue1 = etrue1 = graph()->NewNode(
simplified()->Allocate(NOT_TENURED),
jsgraph()->Int32Constant(SeqOneByteString::SizeFor(1)), etrue1,
if_true1);
etrue1 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForMap()), vtrue1,
jsgraph()->HeapConstant(factory()->one_byte_string_map()), etrue1,
if_true1);
etrue1 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForNameHashField()), vtrue1,
jsgraph()->IntPtrConstant(Name::kEmptyHashField), etrue1, if_true1);
etrue1 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForStringLength()), vtrue1,
jsgraph()->SmiConstant(1), etrue1, if_true1);
etrue1 = graph()->NewNode(
machine()->Store(StoreRepresentation(MachineRepresentation::kWord8,
kNoWriteBarrier)),
vtrue1, jsgraph()->IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag),
code, etrue1, if_true1);
// Remember it in the {cache}.
etrue1 = graph()->NewNode(
simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()),
cache, index, vtrue1, etrue1, if_true1);
}
// Use the {entry} from the {cache}.
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* efalse1 = etrue0;
Node* vfalse1 = entry;
if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
etrue0 =
graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0);
vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue1, vfalse1, if_true0);
}
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* efalse0 = effect;
Node* vfalse0;
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* etrue0 = effect;
// Load the isolate wide single character string cache.
Node* cache =
jsgraph()->HeapConstant(factory()->single_character_string_cache());
// Compute the {cache} index for {code}.
Node* index = machine()->Is32()
? code
: graph()->NewNode(machine()->ChangeUint32ToUint64(), code);
// Check if we have an entry for the {code} in the single character string
// cache already.
Node* entry = etrue0 = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), cache,
index, etrue0, if_true0);
Node* check1 = graph()->NewNode(machine()->WordEqual(), entry,
jsgraph()->UndefinedConstant());
Node* branch1 =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_true0);
// Use the {entry} from the {cache}.
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* efalse1 = etrue0;
Node* vfalse1 = entry;
// Let %StringFromCharCode handle this case.
// TODO(turbofan): At some point we may consider adding a stub for this
// deferred case, so that we don't need to call to C++ here.
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* etrue1 = etrue0;
Node* vtrue1;
{
// Allocate a new SeqTwoByteString for {code}.
vfalse0 = efalse0 =
graph()->NewNode(simplified()->Allocate(NOT_TENURED),
jsgraph()->Int32Constant(SeqTwoByteString::SizeFor(1)),
efalse0, if_false0);
efalse0 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForMap()), vfalse0,
jsgraph()->HeapConstant(factory()->string_map()), efalse0, if_false0);
efalse0 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForNameHashField()), vfalse0,
jsgraph()->IntPtrConstant(Name::kEmptyHashField), efalse0, if_false0);
efalse0 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForStringLength()), vfalse0,
jsgraph()->SmiConstant(1), efalse0, if_false0);
efalse0 = graph()->NewNode(
machine()->Store(StoreRepresentation(MachineRepresentation::kWord16,
kNoWriteBarrier)),
vfalse0, jsgraph()->IntPtrConstant(SeqTwoByteString::kHeaderSize -
kHeapObjectTag),
code, efalse0, if_false0);
if_true1 = graph()->NewNode(common()->Merge(2), if_true1, if_false0);
etrue1 =
graph()->NewNode(common()->EffectPhi(2), etrue1, efalse0, if_true1);
Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
Runtime::FunctionId id = Runtime::kStringCharFromCode;
CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
vtrue1 = etrue1 = graph()->NewNode(
common()->Call(desc), jsgraph()->CEntryStubConstant(1),
ChangeInt32ToSmi(code),
jsgraph()->ExternalConstant(ExternalReference(id, isolate())),
jsgraph()->Int32Constant(1), jsgraph()->NoContextConstant(), etrue1,
if_true1);
}
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
control = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
effect = graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, control);
value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue0, vfalse0, control);
vtrue1, vfalse1, control);
return ValueEffectControl(value, effect, control);
}