Commit 11d5d09c authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Initial support for constructor call inlining.

This implements a first version of support for constructor call inlining
in the inlining machinery. For now we can only inline calls where the
actual constructor and the original constructor coincide (i.e. no super
constructor calls). Note that the target of a super constructor call is
loaded with a runtime call, so there is no way for it to be constant
promoted at the moment.

R=bmeurer@chromium.org
BUG=v8:4544
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31954}
parent dd0ba4d1
...@@ -3215,7 +3215,8 @@ Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) { ...@@ -3215,7 +3215,8 @@ Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) {
const Operator* op = const Operator* op =
javascript()->CallRuntime(Runtime::kGetOriginalConstructor, 0); javascript()->CallRuntime(Runtime::kGetOriginalConstructor, 0);
Node* object = NewNode(op); Node* object = NewNode(op);
PrepareFrameState(object, BailoutId::None()); // TODO(4544): Bailout id only needed for JavaScriptFrame::Summarize.
PrepareFrameState(object, BailoutId::FunctionContext());
// Assign the object to the {new.target} variable. This should never lazy // Assign the object to the {new.target} variable. This should never lazy
// deopt, so it is fine to send invalid bailout id. // deopt, so it is fine to send invalid bailout id.
......
...@@ -551,6 +551,11 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( ...@@ -551,6 +551,11 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
shared_info_id, shared_info_id,
static_cast<unsigned int>(descriptor->parameters_count())); static_cast<unsigned int>(descriptor->parameters_count()));
break; break;
case FrameStateType::kConstructStub:
translation->BeginConstructStubFrame(
shared_info_id,
static_cast<unsigned int>(descriptor->parameters_count()));
break;
} }
for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) { for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) {
......
...@@ -54,6 +54,9 @@ std::ostream& operator<<(std::ostream& os, FrameStateType type) { ...@@ -54,6 +54,9 @@ std::ostream& operator<<(std::ostream& os, FrameStateType type) {
case FrameStateType::kArgumentsAdaptor: case FrameStateType::kArgumentsAdaptor:
os << "ARGUMENTS_ADAPTOR"; os << "ARGUMENTS_ADAPTOR";
break; break;
case FrameStateType::kConstructStub:
os << "CONSTRUCT_STUB";
break;
} }
return os; return os;
} }
......
...@@ -77,7 +77,8 @@ class OutputFrameStateCombine { ...@@ -77,7 +77,8 @@ class OutputFrameStateCombine {
// The type of stack frame that a FrameState node represents. // The type of stack frame that a FrameState node represents.
enum class FrameStateType { enum class FrameStateType {
kJavaScriptFunction, // Represents an unoptimized JavaScriptFrame. kJavaScriptFunction, // Represents an unoptimized JavaScriptFrame.
kArgumentsAdaptor // Represents an ArgumentsAdaptorFrame. kArgumentsAdaptor, // Represents an ArgumentsAdaptorFrame.
kConstructStub // Represents a ConstructStubFrame.
}; };
......
...@@ -456,7 +456,12 @@ void JSGenericLowering::LowerJSLoadDynamic(Node* node) { ...@@ -456,7 +456,12 @@ void JSGenericLowering::LowerJSLoadDynamic(Node* node) {
} }
void JSGenericLowering::LowerJSCreate(Node* node) { UNIMPLEMENTED(); } void JSGenericLowering::LowerJSCreate(Node* node) {
// TODO(4544): The duplication of the constructor function is only valid if
// actual constructor and original constructor coincide. Fix this!
node->InsertInput(zone(), 1, node->InputAt(0)); // Duplicate constructor.
ReplaceWithRuntimeCall(node, Runtime::kNewObject);
}
void JSGenericLowering::LowerJSCreateArguments(Node* node) { void JSGenericLowering::LowerJSCreateArguments(Node* node) {
......
...@@ -13,7 +13,7 @@ namespace internal { ...@@ -13,7 +13,7 @@ namespace internal {
namespace compiler { namespace compiler {
Reduction JSInliningHeuristic::Reduce(Node* node) { Reduction JSInliningHeuristic::Reduce(Node* node) {
if (node->opcode() != IrOpcode::kJSCallFunction) return NoChange(); if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
// Check if we already saw that {node} before, and if so, just skip it. // Check if we already saw that {node} before, and if so, just skip it.
if (seen_.find(node->id()) != seen_.end()) return NoChange(); if (seen_.find(node->id()) != seen_.end()) return NoChange();
...@@ -26,7 +26,7 @@ Reduction JSInliningHeuristic::Reduce(Node* node) { ...@@ -26,7 +26,7 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
// Functions marked with %SetForceInlineFlag are immediately inlined. // Functions marked with %SetForceInlineFlag are immediately inlined.
if (function->shared()->force_inline()) { if (function->shared()->force_inline()) {
return inliner_.ReduceJSCallFunction(node, function); return inliner_.ReduceJSCall(node, function);
} }
// Handling of special inlining modes right away: // Handling of special inlining modes right away:
...@@ -36,7 +36,7 @@ Reduction JSInliningHeuristic::Reduce(Node* node) { ...@@ -36,7 +36,7 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
case kRestrictedInlining: case kRestrictedInlining:
return NoChange(); return NoChange();
case kStressInlining: case kStressInlining:
return inliner_.ReduceJSCallFunction(node, function); return inliner_.ReduceJSCall(node, function);
case kGeneralInlining: case kGeneralInlining:
break; break;
} }
...@@ -67,19 +67,22 @@ Reduction JSInliningHeuristic::Reduce(Node* node) { ...@@ -67,19 +67,22 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
// Stop inlinining once the maximum allowed level is reached. // Stop inlinining once the maximum allowed level is reached.
int level = 0; int level = 0;
for (Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); for (Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
frame_state->opcode() == IrOpcode::kFrameState; frame_state->opcode() == IrOpcode::kFrameState;
frame_state = NodeProperties::GetFrameStateInput(frame_state, 0)) { frame_state = NodeProperties::GetFrameStateInput(frame_state, 0)) {
if (++level > FLAG_max_inlining_levels) return NoChange(); if (++level > FLAG_max_inlining_levels) return NoChange();
} }
// Gather feedback on how often this call site has been hit before. // Gather feedback on how often this call site has been hit before.
CallFunctionParameters p = CallFunctionParametersOf(node->op());
int calls = -1; // Same default as CallICNexus::ExtractCallCount. int calls = -1; // Same default as CallICNexus::ExtractCallCount.
// TODO(turbofan): We also want call counts for constructor calls.
if (node->opcode() == IrOpcode::kJSCallFunction) {
CallFunctionParameters p = CallFunctionParametersOf(node->op());
if (p.feedback().IsValid()) { if (p.feedback().IsValid()) {
CallICNexus nexus(p.feedback().vector(), p.feedback().slot()); CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
calls = nexus.ExtractCallCount(); calls = nexus.ExtractCallCount();
} }
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Everything above this line is part of the inlining heuristic. // Everything above this line is part of the inlining heuristic.
...@@ -99,7 +102,7 @@ void JSInliningHeuristic::Finalize() { ...@@ -99,7 +102,7 @@ void JSInliningHeuristic::Finalize() {
if (cumulative_count_ > FLAG_max_inlined_nodes_cumulative) break; if (cumulative_count_ > FLAG_max_inlined_nodes_cumulative) break;
auto i = candidates_.begin(); auto i = candidates_.begin();
Candidate const& candidate = *i; Candidate const& candidate = *i;
inliner_.ReduceJSCallFunction(candidate.node, candidate.function); inliner_.ReduceJSCall(candidate.node, candidate.function);
cumulative_count_ += candidate.function->shared()->ast_node_count(); cumulative_count_ += candidate.function->shared()->ast_node_count();
candidates_.erase(i); candidates_.erase(i);
} }
......
...@@ -34,36 +34,47 @@ namespace compiler { ...@@ -34,36 +34,47 @@ namespace compiler {
} while (false) } while (false)
// Provides convenience accessors for calls to JS functions. // Provides convenience accessors for the common layout of nodes having either
class JSCallFunctionAccessor { // the {JSCallFunction} or the {JSCallConstruct} operator.
class JSCallAccessor {
public: public:
explicit JSCallFunctionAccessor(Node* call) : call_(call) { explicit JSCallAccessor(Node* call) : call_(call) {
DCHECK_EQ(IrOpcode::kJSCallFunction, call->opcode()); DCHECK(call->opcode() == IrOpcode::kJSCallFunction ||
call->opcode() == IrOpcode::kJSCallConstruct);
} }
Node* jsfunction() { return call_->InputAt(0); } Node* target() {
// Both, {JSCallFunction} and {JSCallConstruct}, have same layout here.
Node* receiver() { return call_->InputAt(1); } return call_->InputAt(0);
}
Node* formal_argument(size_t index) { Node* receiver() {
DCHECK(index < formal_arguments()); DCHECK_EQ(IrOpcode::kJSCallFunction, call_->opcode());
return call_->InputAt(static_cast<int>(2 + index)); return call_->InputAt(1);
} }
size_t formal_arguments() { Node* original_constructor() {
// {value_inputs} includes jsfunction and receiver. DCHECK_EQ(IrOpcode::kJSCallConstruct, call_->opcode());
size_t value_inputs = call_->op()->ValueInputCount(); return call_->InputAt(formal_arguments() + 1);
DCHECK_GE(call_->InputCount(), 2);
return value_inputs - 2;
} }
Node* frame_state_before() { Node* frame_state_before() {
DCHECK_EQ(IrOpcode::kJSCallFunction, call_->opcode());
return NodeProperties::GetFrameStateInput(call_, 1); return NodeProperties::GetFrameStateInput(call_, 1);
} }
Node* frame_state_after() { Node* frame_state_after() {
// Both, {JSCallFunction} and {JSCallConstruct}, have frame state after.
return NodeProperties::GetFrameStateInput(call_, 0); return NodeProperties::GetFrameStateInput(call_, 0);
} }
int formal_arguments() {
// Both, {JSCallFunction} and {JSCallConstruct}, have two extra inputs:
// - JSCallConstruct: Includes target function and original constructor.
// - JSCallFunction: Includes target function and receiver.
return call_->op()->ValueInputCount() - 2;
}
private: private:
Node* call_; Node* call_;
}; };
...@@ -227,12 +238,13 @@ Reduction JSInliner::InlineCall(Node* call, Node* context, Node* frame_state, ...@@ -227,12 +238,13 @@ Reduction JSInliner::InlineCall(Node* call, Node* context, Node* frame_state,
} }
Node* JSInliner::CreateArgumentsAdaptorFrameState( Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
JSCallFunctionAccessor* call, Handle<SharedFunctionInfo> shared_info) { int parameter_count,
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared) {
const FrameStateFunctionInfo* state_info = const FrameStateFunctionInfo* state_info =
jsgraph_->common()->CreateFrameStateFunctionInfo( jsgraph_->common()->CreateFrameStateFunctionInfo(
FrameStateType::kArgumentsAdaptor, frame_state_type, parameter_count + 1, 0, shared,
static_cast<int>(call->formal_arguments()) + 1, 0, shared_info,
CALL_MAINTAINS_NATIVE_CONTEXT); CALL_MAINTAINS_NATIVE_CONTEXT);
const Operator* op = jsgraph_->common()->FrameState( const Operator* op = jsgraph_->common()->FrameState(
...@@ -240,36 +252,37 @@ Node* JSInliner::CreateArgumentsAdaptorFrameState( ...@@ -240,36 +252,37 @@ Node* JSInliner::CreateArgumentsAdaptorFrameState(
const Operator* op0 = jsgraph_->common()->StateValues(0); const Operator* op0 = jsgraph_->common()->StateValues(0);
Node* node0 = jsgraph_->graph()->NewNode(op0); Node* node0 = jsgraph_->graph()->NewNode(op0);
NodeVector params(local_zone_); NodeVector params(local_zone_);
params.push_back(call->receiver()); for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
for (size_t argument = 0; argument != call->formal_arguments(); ++argument) { params.push_back(node->InputAt(1 + parameter));
params.push_back(call->formal_argument(argument));
} }
const Operator* op_param = const Operator* op_param =
jsgraph_->common()->StateValues(static_cast<int>(params.size())); jsgraph_->common()->StateValues(static_cast<int>(params.size()));
Node* params_node = jsgraph_->graph()->NewNode( Node* params_node = jsgraph_->graph()->NewNode(
op_param, static_cast<int>(params.size()), &params.front()); op_param, static_cast<int>(params.size()), &params.front());
return jsgraph_->graph()->NewNode( return jsgraph_->graph()->NewNode(op, params_node, node0, node0,
op, params_node, node0, node0, jsgraph_->UndefinedConstant(), jsgraph_->UndefinedConstant(),
call->jsfunction(), call->frame_state_after()); node->InputAt(0), outer_frame_state);
} }
Reduction JSInliner::Reduce(Node* node) { Reduction JSInliner::Reduce(Node* node) {
if (node->opcode() != IrOpcode::kJSCallFunction) return NoChange(); if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
JSCallFunctionAccessor call(node); // This reducer can handle both normal function calls as well a constructor
HeapObjectMatcher match(call.jsfunction()); // calls whenever the target is a constant function object, as follows:
// - JSCallFunction(target:constant, receiver, args...)
// - JSCallConstruct(target:constant, args..., new.target)
HeapObjectMatcher match(node->InputAt(0));
if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange();
Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
return ReduceJSCallFunction(node, function); return ReduceJSCall(node, function);
} }
Reduction JSInliner::ReduceJSCallFunction(Node* node, Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
Handle<JSFunction> function) { DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); JSCallAccessor call(node);
JSCallFunctionAccessor call(node);
if (!function->shared()->IsInlineable()) { if (!function->shared()->IsInlineable()) {
// Function must be inlineable. // Function must be inlineable.
...@@ -359,7 +372,7 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node, ...@@ -359,7 +372,7 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
// In strong mode, in case of too few arguments we need to throw a TypeError // In strong mode, in case of too few arguments we need to throw a TypeError
// so we must not inline this call. // so we must not inline this call.
size_t parameter_count = info.literal()->parameter_count(); int parameter_count = info.literal()->parameter_count();
if (is_strong(info.language_mode()) && if (is_strong(info.language_mode()) &&
call.formal_arguments() < parameter_count) { call.formal_arguments() < parameter_count) {
TRACE("Not inlining %s into %s because too few arguments for strong mode\n", TRACE("Not inlining %s into %s because too few arguments for strong mode\n",
...@@ -425,12 +438,6 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node, ...@@ -425,12 +438,6 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
graph_reducer.ReduceGraph(); graph_reducer.ReduceGraph();
} }
// The inlinee specializes to the context from the JSFunction object.
// TODO(turbofan): We might want to load the context from the JSFunction at
// runtime in case we only know the SharedFunctionInfo once we have dynamic
// type feedback in the compiler.
Node* context = jsgraph_->Constant(handle(function->context()));
CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); CopyVisitor visitor(&graph, jsgraph_->graph(), &zone);
visitor.CopyGraph(); visitor.CopyGraph();
...@@ -438,13 +445,60 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node, ...@@ -438,13 +445,60 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
Node* end = visitor.GetCopy(graph.end()); Node* end = visitor.GetCopy(graph.end());
Node* frame_state = call.frame_state_after(); Node* frame_state = call.frame_state_after();
// Insert nodes around the call that model the behavior required for a
// constructor dispatch and turn the constructor call into a regular call.
// This models the behavior usually accomplished by our {JSConstructStub}.
// Note that the context has to be the callers context (input to call node).
if (node->opcode() == IrOpcode::kJSCallConstruct) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* context = NodeProperties::GetContextInput(node);
Node* create = jsgraph_->graph()->NewNode(jsgraph_->javascript()->Create(),
call.target(), context, effect);
NodeProperties::ReplaceEffectInput(node, create);
// TODO(4544): For now {JSCreate} requires the actual constructor to
// coincide with the original constructor. Adapt JSGenericLowering to fix.
// Also Runtime_GetOriginalConstructor depends on this for now. Fix as well!
CHECK_EQ(call.target(), call.original_constructor());
// TODO(4544): For derived constructors we should not allocate an implicit
// receiver and also the return value should not be checked afterwards.
CHECK(!IsClassConstructor(function->shared()->kind()));
// Swizzle the inputs of the {JSCallConstruct} node to look like inputs to
// any {JSCallFunction} node so that the rest of the inlining machinery
// behaves as if we were dealing with a regular function invocation.
node->RemoveInput(call.formal_arguments() + 1); // Drop new.target.
node->InsertInput(jsgraph_->graph()->zone(), 1, create);
// Insert a check of the return value to determine whether the return value
// or the implicit receiver should be selected as a result of the call.
Node* check = jsgraph_->graph()->NewNode(
jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsSpecObject, 1),
node, context, node, start);
Node* select = jsgraph_->graph()->NewNode(
jsgraph_->common()->Select(kMachAnyTagged), check, node, create);
NodeProperties::ReplaceUses(node, select, check, node, node);
NodeProperties::ReplaceValueInput(select, node, 1);
NodeProperties::ReplaceValueInput(check, node, 0);
NodeProperties::ReplaceEffectInput(check, node);
// Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor.
frame_state = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(),
FrameStateType::kConstructStub, info.shared_info());
}
// The inlinee specializes to the context from the JSFunction object.
// TODO(turbofan): We might want to load the context from the JSFunction at
// runtime in case we only know the SharedFunctionInfo once we have dynamic
// type feedback in the compiler.
Node* context = jsgraph_->Constant(handle(function->context()));
// Insert a JSConvertReceiver node for sloppy callees. Note that the context // Insert a JSConvertReceiver node for sloppy callees. Note that the context
// passed into this node has to be the callees context (loaded above). Note // passed into this node has to be the callees context (loaded above). Note
// that the frame state passed to the JSConvertReceiver must be the frame // that the frame state passed to the JSConvertReceiver must be the frame
// state _before_ the call; it is not necessary to fiddle with the receiver // state _before_ the call; it is not necessary to fiddle with the receiver
// in that frame state tho, as the conversion of the receiver can be repeated // in that frame state tho, as the conversion of the receiver can be repeated
// any number of times, it's not observable. // any number of times, it's not observable.
if (is_sloppy(info.language_mode()) && !function->shared()->native()) { if (node->opcode() == IrOpcode::kJSCallFunction &&
is_sloppy(info.language_mode()) && !function->shared()->native()) {
const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* convert = jsgraph_->graph()->NewNode( Node* convert = jsgraph_->graph()->NewNode(
...@@ -457,10 +511,11 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node, ...@@ -457,10 +511,11 @@ Reduction JSInliner::ReduceJSCallFunction(Node* node,
// Insert argument adaptor frame if required. The callees formal parameter // Insert argument adaptor frame if required. The callees formal parameter
// count (i.e. value outputs of start node minus target, receiver, num args // count (i.e. value outputs of start node minus target, receiver, num args
// and context) have to match the number of arguments passed to the call. // and context) have to match the number of arguments passed to the call.
DCHECK_EQ(static_cast<int>(parameter_count), DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 4);
start->op()->ValueOutputCount() - 4);
if (call.formal_arguments() != parameter_count) { if (call.formal_arguments() != parameter_count) {
frame_state = CreateArgumentsAdaptorFrameState(&call, info.shared_info()); frame_state = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(),
FrameStateType::kArgumentsAdaptor, info.shared_info());
} }
return InlineCall(node, context, frame_state, start, end); return InlineCall(node, context, frame_state, start, end);
......
...@@ -16,9 +16,6 @@ class CompilationInfo; ...@@ -16,9 +16,6 @@ class CompilationInfo;
namespace compiler { namespace compiler {
// Forward declarations.
class JSCallFunctionAccessor;
// The JSInliner provides the core graph inlining machinery. Note that this // The JSInliner provides the core graph inlining machinery. Note that this
// class only deals with the mechanics of how to inline one graph into another, // class only deals with the mechanics of how to inline one graph into another,
// heuristics that decide what and how much to inline are beyond its scope. // heuristics that decide what and how much to inline are beyond its scope.
...@@ -36,15 +33,17 @@ class JSInliner final : public AdvancedReducer { ...@@ -36,15 +33,17 @@ class JSInliner final : public AdvancedReducer {
// Can be used by inlining heuristics or by testing code directly, without // Can be used by inlining heuristics or by testing code directly, without
// using the above generic reducer interface of the inlining machinery. // using the above generic reducer interface of the inlining machinery.
Reduction ReduceJSCallFunction(Node* node, Handle<JSFunction> function); Reduction ReduceJSCall(Node* node, Handle<JSFunction> function);
private: private:
Zone* local_zone_; Zone* local_zone_;
CompilationInfo* info_; CompilationInfo* info_;
JSGraph* jsgraph_; JSGraph* jsgraph_;
Node* CreateArgumentsAdaptorFrameState( Node* CreateArtificialFrameState(Node* node, Node* outer_frame_state,
JSCallFunctionAccessor* call, Handle<SharedFunctionInfo> shared_info); int parameter_count,
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared);
Reduction InlineCall(Node* call, Node* context, Node* frame_state, Reduction InlineCall(Node* call, Node* context, Node* frame_state,
Node* start, Node* end); Node* start, Node* end);
......
...@@ -363,7 +363,7 @@ const CreateClosureParameters& CreateClosureParametersOf(const Operator* op) { ...@@ -363,7 +363,7 @@ const CreateClosureParameters& CreateClosureParametersOf(const Operator* op) {
V(ToName, Operator::kNoProperties, 1, 1) \ V(ToName, Operator::kNoProperties, 1, 1) \
V(ToObject, Operator::kNoProperties, 1, 1) \ V(ToObject, Operator::kNoProperties, 1, 1) \
V(Yield, Operator::kNoProperties, 1, 1) \ V(Yield, Operator::kNoProperties, 1, 1) \
V(Create, Operator::kEliminatable, 0, 1) \ V(Create, Operator::kEliminatable, 1, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \ V(HasProperty, Operator::kNoProperties, 2, 1) \
V(TypeOf, Operator::kEliminatable, 1, 1) \ V(TypeOf, Operator::kEliminatable, 1, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \ V(InstanceOf, Operator::kNoProperties, 2, 1) \
......
...@@ -230,6 +230,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) { ...@@ -230,6 +230,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kNewClosure: case Runtime::kNewClosure:
case Runtime::kNewClosure_Tenured: case Runtime::kNewClosure_Tenured:
case Runtime::kNewFunctionContext: case Runtime::kNewFunctionContext:
case Runtime::kNewObject:
case Runtime::kPushBlockContext: case Runtime::kPushBlockContext:
case Runtime::kPushCatchContext: case Runtime::kPushCatchContext:
case Runtime::kReThrow: case Runtime::kReThrow:
...@@ -244,6 +245,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) { ...@@ -244,6 +245,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kInlineDefaultConstructorCallSuper: case Runtime::kInlineDefaultConstructorCallSuper:
case Runtime::kInlineGetCallerJSFunction: case Runtime::kInlineGetCallerJSFunction:
case Runtime::kInlineGetPrototype: case Runtime::kInlineGetPrototype:
case Runtime::kInlineIsConstructCall:
case Runtime::kInlineRegExpExec: case Runtime::kInlineRegExpExec:
case Runtime::kInlineSubString: case Runtime::kInlineSubString:
case Runtime::kInlineToInteger: case Runtime::kInlineToInteger:
......
...@@ -373,6 +373,11 @@ class IrOpcode { ...@@ -373,6 +373,11 @@ class IrOpcode {
return kIfTrue <= value && value <= kIfDefault; return kIfTrue <= value && value <= kIfDefault;
} }
// Returns true if opcode can be inlined.
static bool IsInlineeOpcode(Value value) {
return value == kJSCallConstruct || value == kJSCallFunction;
}
// Returns true if opcode for comparison operator. // Returns true if opcode for comparison operator.
static bool IsComparisonOpcode(Value value) { static bool IsComparisonOpcode(Value value) {
return (kJSEqual <= value && value <= kJSGreaterThanOrEqual) || return (kJSEqual <= value && value <= kJSGreaterThanOrEqual) ||
......
...@@ -570,9 +570,17 @@ RUNTIME_FUNCTION(Runtime_GetOriginalConstructor) { ...@@ -570,9 +570,17 @@ RUNTIME_FUNCTION(Runtime_GetOriginalConstructor) {
DCHECK(args.length() == 0); DCHECK(args.length() == 0);
JavaScriptFrameIterator it(isolate); JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = it.frame(); JavaScriptFrame* frame = it.frame();
// Currently we don't inline [[Construct]] calls. // TODO(4544): Currently we never inline any [[Construct]] calls where the
return frame->IsConstructor() && !frame->HasInlinedFrames() // actual constructor differs from the original constructor. Fix this soon!
? frame->GetOriginalConstructor() if (frame->HasInlinedFrames()) {
HandleScope scope(isolate);
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
it.frame()->Summarize(&frames);
FrameSummary& summary = frames.last();
return summary.is_constructor() ? Object::cast(*summary.function())
: isolate->heap()->undefined_value();
}
return frame->IsConstructor() ? frame->GetOriginalConstructor()
: isolate->heap()->undefined_value(); : isolate->heap()->undefined_value();
} }
...@@ -590,11 +598,13 @@ RUNTIME_FUNCTION(Runtime_ConvertReceiver) { ...@@ -590,11 +598,13 @@ RUNTIME_FUNCTION(Runtime_ConvertReceiver) {
RUNTIME_FUNCTION(Runtime_IsConstructCall) { RUNTIME_FUNCTION(Runtime_IsConstructCall) {
SealHandleScope shs(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 0); DCHECK(args.length() == 0);
JavaScriptFrameIterator it(isolate); JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = it.frame(); List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
return isolate->heap()->ToBoolean(frame->IsConstructor()); it.frame()->Summarize(&frames);
FrameSummary& summary = frames.last();
return isolate->heap()->ToBoolean(summary.is_constructor());
} }
......
...@@ -138,8 +138,14 @@ ...@@ -138,8 +138,14 @@
'debug-stepout-scope-part2': [PASS, NO_VARIANTS], 'debug-stepout-scope-part2': [PASS, NO_VARIANTS],
'debug-stepout-scope-part3': [PASS, NO_VARIANTS], 'debug-stepout-scope-part3': [PASS, NO_VARIANTS],
'es6/debug-evaluate-blockscopes': [PASS, NO_VARIANTS], 'es6/debug-evaluate-blockscopes': [PASS, NO_VARIANTS],
# issue 4055: # Issue 4055: Scope chain length observed by debugger is off.
'es6/generators-debug-scopes': [PASS, NO_VARIANTS], 'es6/generators-debug-scopes': [PASS, NO_VARIANTS],
# Issue 4544: Stepping in inlined constructors is borked.
'es6/debug-promises/throw-in-constructor': [PASS, NO_VARIANTS],
'es6/debug-step-into-constructor': [PASS, NO_VARIANTS],
# TODO(4544): Investigate why assumptions about fast properties break.
'fast-prototype': [PASS, NO_VARIANTS],
# TODO(titzer): --always-opt incorrectly disables CrankShaft soft deopt points # TODO(titzer): --always-opt incorrectly disables CrankShaft soft deopt points
'result-table-min': [PASS, NO_VARIANTS], 'result-table-min': [PASS, NO_VARIANTS],
......
...@@ -78,7 +78,7 @@ const SharedOperator kSharedOperators[] = { ...@@ -78,7 +78,7 @@ const SharedOperator kSharedOperators[] = {
SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2), SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2),
SHARED(Create, Operator::kEliminatable, 0, 0, 1, 0, 1, 1, 0), SHARED(Create, Operator::kEliminatable, 1, 0, 1, 0, 1, 1, 0),
SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(TypeOf, Operator::kEliminatable, 1, 0, 1, 0, 1, 1, 0), SHARED(TypeOf, Operator::kEliminatable, 1, 0, 1, 0, 1, 1, 0),
SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
......
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