Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Unified Diff: src/compiler/js-typed-lowering.cc

Issue 1431543002: [turbofan] Optimize inlining and direct function calls. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add unittest. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | test/unittests/compiler/js-typed-lowering-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-typed-lowering.cc
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc
index 1fcb0f272e7422d191e8cab62bd0cbe44bbe91e8..0d83d2baf1949a94def00b654b5abd74e10bcc47 100644
--- a/src/compiler/js-typed-lowering.cc
+++ b/src/compiler/js-typed-lowering.cc
@@ -844,6 +844,85 @@ Reduction JSTypedLowering::ReduceJSToString(Node* node) {
}
+Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
+ DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
+ Node* receiver = NodeProperties::GetValueInput(node, 0);
+ Type* receiver_type = NodeProperties::GetType(receiver);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ if (!receiver_type->Is(Type::Receiver())) {
+ // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
+ if (receiver_type->Maybe(Type::NullOrUndefined()) &&
+ NodeProperties::IsExceptionalCall(node)) {
+ // ToObject throws for null or undefined inputs.
+ return NoChange();
+ }
+
+ // Check whether {receiver} is a Smi.
+ Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
+ Node* branch0 =
+ graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* etrue0 = effect;
+
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ Node* efalse0 = effect;
+
+ // Determine the instance type of {receiver}.
+ Node* receiver_map = efalse0 =
+ graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
+ receiver, efalse0, if_false0);
+ Node* receiver_instance_type = efalse0 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
+ receiver_map, efalse0, if_false0);
+
+ // Check whether {receiver} is a spec object.
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+ Node* check1 =
+ graph()->NewNode(machine()->Uint32LessThanOrEqual(),
+ jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
+ receiver_instance_type);
+ Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
+ check1, if_false0);
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* etrue1 = efalse0;
+
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ Node* efalse1 = efalse0;
+
+ // Convert {receiver} using the ToObjectStub.
+ Node* if_convert =
+ graph()->NewNode(common()->Merge(2), if_true0, if_false1);
+ Node* econvert =
+ graph()->NewNode(common()->EffectPhi(2), etrue0, efalse1, if_convert);
+ Node* rconvert;
+ {
+ Callable callable = CodeFactory::ToObject(isolate());
+ CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
+ isolate(), graph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNeedsFrameState, node->op()->properties());
+ rconvert = econvert = graph()->NewNode(
+ common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
+ receiver, context, frame_state, econvert, if_convert);
+ }
+
+ // The {receiver} is already a spec object.
+ Node* if_done = if_true1;
+ Node* edone = etrue1;
+ Node* rdone = receiver;
+
+ control = graph()->NewNode(common()->Merge(2), if_convert, if_done);
+ effect = graph()->NewNode(common()->EffectPhi(2), econvert, edone, control);
+ receiver = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), rconvert,
+ rdone, control);
+ }
+ ReplaceWithValue(node, receiver, effect, control);
+ return Changed(receiver);
+}
+
+
Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 0);
@@ -1181,7 +1260,62 @@ Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
graph()->NewNode(javascript()->ToObject(), receiver, context,
frame_state, effect, control);
} else {
- return NoChange();
+ // Check {receiver} for undefined.
+ Node* check0 =
+ graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
+ receiver, jsgraph()->UndefinedConstant());
+ Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+ check0, control);
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+
+ // Check {receiver} for null.
+ Node* check1 =
+ graph()->NewNode(simplified()->ReferenceEqual(receiver_type),
+ receiver, jsgraph()->NullConstant());
+ Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+ check1, if_false0);
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+
+ // Convert {receiver} using ToObject.
+ Node* if_convert = if_false1;
+ Node* econvert = effect;
+ Node* rconvert;
+ {
+ rconvert = econvert =
+ graph()->NewNode(javascript()->ToObject(), receiver, context,
+ frame_state, econvert, if_convert);
+ }
+
+ // Replace {receiver} with global proxy of {context}.
+ Node* if_global =
+ graph()->NewNode(common()->Merge(2), if_true0, if_true1);
+ Node* eglobal = effect;
+ Node* rglobal;
+ {
+ if (context_type->IsConstant()) {
+ Handle<JSObject> global_proxy(
+ Handle<Context>::cast(context_type->AsConstant()->Value())
+ ->global_proxy(),
+ isolate());
+ rglobal = jsgraph()->Constant(global_proxy);
+ } else {
+ Node* global_object = eglobal = graph()->NewNode(
+ javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true),
+ context, context, eglobal);
+ rglobal = eglobal =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForGlobalObjectGlobalProxy()),
+ global_object, eglobal, if_global);
+ }
+ }
+
+ control = graph()->NewNode(common()->Merge(2), if_convert, if_global);
+ effect =
+ graph()->NewNode(common()->EffectPhi(2), econvert, eglobal, control);
+ receiver = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), rconvert,
+ rglobal, control);
}
}
ReplaceWithValue(node, receiver, effect, control);
@@ -1554,10 +1688,14 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
int const arity = static_cast<int>(p.arity() - 2);
+ ConvertReceiverMode const convert_mode = p.convert_mode();
Node* target = NodeProperties::GetValueInput(node, 0);
Type* target_type = NodeProperties::GetType(target);
Node* receiver = NodeProperties::GetValueInput(node, 1);
Type* receiver_type = NodeProperties::GetType(receiver);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
// Check if {target} is a known JSFunction.
if (target_type->IsConstant() &&
@@ -1566,28 +1704,27 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
Handle<JSFunction>::cast(target_type->AsConstant()->Value());
Handle<SharedFunctionInfo> shared(function->shared(), isolate());
if (shared->internal_formal_parameter_count() == arity) {
- // Check if we need to wrap the {receiver}.
- if (is_sloppy(shared->language_mode()) && !shared->native()) {
- if (receiver_type->Is(Type::NullOrUndefined())) {
- // Change {receiver} to global proxy of {function}.
- receiver =
- jsgraph()->Constant(handle(function->global_proxy(), isolate()));
- } else if (!receiver_type->Is(Type::Receiver())) {
- // TODO(bmeurer): Add support for wrapping abitrary receivers.
- return NoChange();
- }
- NodeProperties::ReplaceValueInput(node, receiver, 1);
- }
-
// Grab the context from the {function}.
Node* context =
jsgraph()->Constant(handle(function->context(), isolate()));
NodeProperties::ReplaceContextInput(node, context);
- CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
- if (p.AllowTailCalls()) {
- flags |= CallDescriptor::kSupportsTailCalls;
+
+ // Check if we need to convert the {receiver}.
+ if (is_sloppy(shared->language_mode()) && !shared->native() &&
+ !receiver_type->Is(Type::Receiver())) {
+ receiver = effect =
+ graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
+ receiver, context, frame_state, effect, control);
+ NodeProperties::ReplaceEffectInput(node, effect);
+ NodeProperties::ReplaceValueInput(node, receiver, 1);
}
+
+ // Remove the eager bailout frame state.
NodeProperties::RemoveFrameStateInput(node, 1);
+
+ // Patch {node} to a direct call.
+ CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
+ if (p.AllowTailCalls()) flags |= CallDescriptor::kSupportsTailCalls;
NodeProperties::ChangeOp(node,
common()->Call(Linkage::GetJSCallDescriptor(
graph()->zone(), false, 1 + arity, flags)));
@@ -1943,6 +2080,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSToNumber(node);
case IrOpcode::kJSToString:
return ReduceJSToString(node);
+ case IrOpcode::kJSToObject:
+ return ReduceJSToObject(node);
case IrOpcode::kJSLoadNamed:
return ReduceJSLoadNamed(node);
case IrOpcode::kJSLoadProperty:
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | test/unittests/compiler/js-typed-lowering-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698