Commit 1d0b7bd2 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Optimize JSConvertReceiver if we know something about the receiver.

Typed lowering can lower JSConvertReceiver either based on the operator
hints or the (statically) known receiver type.

R=jarin@chromium.org
BUG=chromium:548557, v8:4493, v8:4470
LOG=n

Review URL: https://codereview.chromium.org/1426893002

Cr-Commit-Position: refs/heads/master@{#31618}
parent dfedad42
......@@ -131,10 +131,18 @@ FieldAccess AccessBuilder::ForStringLength(Zone* zone) {
}
// static
FieldAccess AccessBuilder::ForGlobalObjectGlobalProxy() {
FieldAccess access = {kTaggedBase, GlobalObject::kGlobalProxyOffset,
Handle<Name>(), Type::Receiver(), kMachAnyTagged};
return access;
}
// static
FieldAccess AccessBuilder::ForGlobalObjectNativeContext() {
FieldAccess access = {kTaggedBase, GlobalObject::kNativeContextOffset,
Handle<Name>(), Type::Any(), kMachAnyTagged};
Handle<Name>(), Type::Internal(), kMachAnyTagged};
return access;
}
......
......@@ -61,6 +61,9 @@ class AccessBuilder final : public AllStatic {
// Provides access to String::length() field.
static FieldAccess ForStringLength(Zone* zone);
// Provides access to GlobalObject::global_proxy() field.
static FieldAccess ForGlobalObjectGlobalProxy();
// Provides access to GlobalObject::native_context() field.
static FieldAccess ForGlobalObjectNativeContext();
......
......@@ -40,12 +40,12 @@ size_t hash_value(VectorSlotPair const& p) {
}
size_t hash_value(ConvertReceiverMode const& mode) {
size_t hash_value(ConvertReceiverMode mode) {
return base::hash_value(static_cast<int>(mode));
}
std::ostream& operator<<(std::ostream& os, ConvertReceiverMode const& mode) {
std::ostream& operator<<(std::ostream& os, ConvertReceiverMode mode) {
switch (mode) {
case ConvertReceiverMode::kNullOrUndefined:
return os << "NULL_OR_UNDEFINED";
......@@ -59,6 +59,12 @@ std::ostream& operator<<(std::ostream& os, ConvertReceiverMode const& mode) {
}
ConvertReceiverMode ConvertReceiverModeOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kJSConvertReceiver, op->opcode());
return OpParameter<ConvertReceiverMode>(op);
}
std::ostream& operator<<(std::ostream& os, CallFunctionParameters const& p) {
os << p.arity() << ", " << p.flags() << ", " << p.language_mode();
if (p.AllowTailCalls()) {
......
......@@ -44,17 +44,17 @@ size_t hash_value(VectorSlotPair const&);
// Defines hints about receiver values based on structural knowledge. This is
// used as a parameter by JSConvertReceiver operators.
enum class ConvertReceiverMode {
enum class ConvertReceiverMode : int {
kNullOrUndefined, // Guaranteed to be null or undefined.
kNotNullOrUndefined, // Guaranteed to never be null or undefined.
kAny // No specific knowledge about receiver.
};
size_t hash_value(ConvertReceiverMode const&);
size_t hash_value(ConvertReceiverMode);
std::ostream& operator<<(std::ostream&, ConvertReceiverMode const&);
std::ostream& operator<<(std::ostream&, ConvertReceiverMode);
const ConvertReceiverMode& ConvertReceiverModeOf(const Operator* op);
ConvertReceiverMode ConvertReceiverModeOf(const Operator* op);
// Defines whether tail call optimization is allowed.
......
......@@ -1149,6 +1149,48 @@ Reduction JSTypedLowering::ReduceJSLoadDynamicContext(Node* node) {
}
Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
Node* receiver = NodeProperties::GetValueInput(node, 0);
Type* receiver_type = NodeProperties::GetType(receiver);
Node* context = NodeProperties::GetContextInput(node);
Type* context_type = NodeProperties::GetType(context);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (!receiver_type->Is(Type::Receiver())) {
if (receiver_type->Is(Type::NullOrUndefined()) ||
mode == ConvertReceiverMode::kNullOrUndefined) {
if (context_type->IsConstant()) {
Handle<JSObject> global_proxy(
Handle<Context>::cast(context_type->AsConstant()->Value())
->global_proxy(),
isolate());
receiver = jsgraph()->Constant(global_proxy);
} else {
Node* global_object = effect = graph()->NewNode(
javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true),
context, context, effect);
receiver = effect =
graph()->NewNode(simplified()->LoadField(
AccessBuilder::ForGlobalObjectGlobalProxy()),
global_object, effect, control);
}
} else if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
mode == ConvertReceiverMode::kNotNullOrUndefined) {
receiver = effect =
graph()->NewNode(javascript()->ToObject(), receiver, context,
frame_state, effect, control);
} else {
return NoChange();
}
}
ReplaceWithValue(node, receiver, effect, control);
return Changed(receiver);
}
Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
CreateArgumentsParameters const& p = CreateArgumentsParametersOf(node->op());
......@@ -1859,6 +1901,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSLoadDynamicGlobal(node);
case IrOpcode::kJSLoadDynamicContext:
return ReduceJSLoadDynamicContext(node);
case IrOpcode::kJSConvertReceiver:
return ReduceJSConvertReceiver(node);
case IrOpcode::kJSCreateArguments:
return ReduceJSCreateArguments(node);
case IrOpcode::kJSCreateClosure:
......
......@@ -56,6 +56,7 @@ class JSTypedLowering final : public AdvancedReducer {
Reduction ReduceJSToNumber(Node* node);
Reduction ReduceJSToStringInput(Node* input);
Reduction ReduceJSToString(Node* node);
Reduction ReduceJSConvertReceiver(Node* node);
Reduction ReduceJSCreateArguments(Node* node);
Reduction ReduceJSCreateClosure(Node* node);
Reduction ReduceJSCreateLiteralArray(Node* node);
......
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