[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}
This commit is contained in:
parent
dfedad42ab
commit
1d0b7bd28a
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user