Commit 5a5ffc63 authored by bmeurer's avatar bmeurer Committed by Commit bot

[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}
parent ed7bef5b
...@@ -2447,104 +2447,63 @@ EffectControlLinearizer::LowerStringFromCharCode(Node* node, Node* effect, ...@@ -2447,104 +2447,63 @@ EffectControlLinearizer::LowerStringFromCharCode(Node* node, Node* effect,
Node* branch0 = Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* efalse0 = effect;
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* etrue0 = effect; 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); // Load the isolate wide single character string cache.
Node* etrue1 = etrue0; Node* cache =
Node* vtrue1; jsgraph()->HeapConstant(factory()->single_character_string_cache());
{
// 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}. // Compute the {cache} index for {code}.
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); Node* index = machine()->Is32()
Node* efalse1 = etrue0; ? code
Node* vfalse1 = entry; : graph()->NewNode(machine()->ChangeUint32ToUint64(), code);
if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); // Check if we have an entry for the {code} in the single character string
etrue0 = // cache already.
graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); Node* entry = etrue0 = graph()->NewNode(
vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), cache,
vtrue1, vfalse1, if_true0); index, etrue0, if_true0);
}
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); Node* check1 = graph()->NewNode(machine()->WordEqual(), entry,
Node* efalse0 = effect; jsgraph()->UndefinedConstant());
Node* vfalse0; 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}. if_true1 = graph()->NewNode(common()->Merge(2), if_true1, if_false0);
vfalse0 = efalse0 = etrue1 =
graph()->NewNode(simplified()->Allocate(NOT_TENURED), graph()->NewNode(common()->EffectPhi(2), etrue1, efalse0, if_true1);
jsgraph()->Int32Constant(SeqTwoByteString::SizeFor(1)), Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
efalse0, if_false0); Runtime::FunctionId id = Runtime::kStringCharFromCode;
efalse0 = graph()->NewNode( CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
simplified()->StoreField(AccessBuilder::ForMap()), vfalse0, graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
jsgraph()->HeapConstant(factory()->string_map()), efalse0, if_false0); vtrue1 = etrue1 = graph()->NewNode(
efalse0 = graph()->NewNode( common()->Call(desc), jsgraph()->CEntryStubConstant(1),
simplified()->StoreField(AccessBuilder::ForNameHashField()), vfalse0, ChangeInt32ToSmi(code),
jsgraph()->IntPtrConstant(Name::kEmptyHashField), efalse0, if_false0); jsgraph()->ExternalConstant(ExternalReference(id, isolate())),
efalse0 = graph()->NewNode( jsgraph()->Int32Constant(1), jsgraph()->NoContextConstant(), etrue1,
simplified()->StoreField(AccessBuilder::ForStringLength()), vfalse0, if_true1);
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);
} }
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); control = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); effect = graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, control);
value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue0, vfalse0, control); vtrue1, vfalse1, control);
return ValueEffectControl(value, effect, control); return ValueEffectControl(value, effect, control);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment