Commit db5d8d19 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[nci] Adapt HasProperty, InstanceOf, CreateClosure

HasProperty and InstanceOf now both have a feedback vector input, and
collect feedback in generic lowering.

CreateClosure loads the feedback cell (in nci mode) instead of embedding
a heap constant.

Bug: v8:8888
Change-Id: Id479cda344684aeb5054f687b087c4fedeac05d8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2282530Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68711}
parent e63bae12
...@@ -671,6 +671,7 @@ namespace internal { ...@@ -671,6 +671,7 @@ namespace internal {
/* instanceof */ \ /* instanceof */ \
TFC(OrdinaryHasInstance, Compare) \ TFC(OrdinaryHasInstance, Compare) \
TFC(InstanceOf, Compare) \ TFC(InstanceOf, Compare) \
TFC(InstanceOf_WithFeedback, Compare_WithFeedback) \
\ \
/* for-in */ \ /* for-in */ \
TFS(ForInEnumerate, kReceiver) \ TFS(ForInEnumerate, kReceiver) \
......
...@@ -1156,6 +1156,18 @@ TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) { ...@@ -1156,6 +1156,18 @@ TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) {
Return(InstanceOf(object, callable, context)); Return(InstanceOf(object, callable, context));
} }
TF_BUILTIN(InstanceOf_WithFeedback, ObjectBuiltinsAssembler) {
TNode<Object> object = CAST(Parameter(Descriptor::kLeft));
TNode<Object> callable = CAST(Parameter(Descriptor::kRight));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<HeapObject> maybe_feedback_vector =
CAST(Parameter(Descriptor::kMaybeFeedbackVector));
TNode<UintPtrT> slot = UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot));
CollectInstanceOfFeedback(callable, context, maybe_feedback_vector, slot);
Return(InstanceOf(object, callable, context));
}
// ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) // ES6 section 7.3.19 OrdinaryHasInstance ( C, O )
TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) { TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) {
TNode<Object> constructor = CAST(Parameter(Descriptor::kLeft)); TNode<Object> constructor = CAST(Parameter(Descriptor::kLeft));
......
...@@ -1177,6 +1177,16 @@ FieldAccess AccessBuilder::ForFeedbackCellValue() { ...@@ -1177,6 +1177,16 @@ FieldAccess AccessBuilder::ForFeedbackCellValue() {
return access; return access;
} }
// static
FieldAccess AccessBuilder::ForFeedbackVectorClosureFeedbackCellArray() {
FieldAccess access = {
kTaggedBase, FeedbackVector::kClosureFeedbackCellArrayOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::Any(), MachineType::TaggedPointer(),
kFullWriteBarrier};
return access;
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -330,6 +330,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final ...@@ -330,6 +330,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to a FeedbackCell's value. // Provides access to a FeedbackCell's value.
static FieldAccess ForFeedbackCellValue(); static FieldAccess ForFeedbackCellValue();
// Provides access to a FeedbackVector fields.
static FieldAccess ForFeedbackVectorClosureFeedbackCellArray();
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessBuilder); DISALLOW_IMPLICIT_CONSTRUCTORS(AccessBuilder);
}; };
......
...@@ -80,6 +80,8 @@ class BytecodeGraphBuilder { ...@@ -80,6 +80,8 @@ class BytecodeGraphBuilder {
return feedback_vector_node_; return feedback_vector_node_;
} }
Node* BuildLoadFeedbackCell(int index);
// Builder for loading the a native context field. // Builder for loading the a native context field.
Node* BuildLoadNativeContextField(int index); Node* BuildLoadNativeContextField(int index);
...@@ -183,7 +185,6 @@ class BytecodeGraphBuilder { ...@@ -183,7 +185,6 @@ class BytecodeGraphBuilder {
void BuildUnaryOp(const Operator* op); void BuildUnaryOp(const Operator* op);
void BuildBinaryOp(const Operator* op); void BuildBinaryOp(const Operator* op);
void BuildBinaryOpWithImmediate(const Operator* op); void BuildBinaryOpWithImmediate(const Operator* op);
void BuildInstanceOf(const Operator* op);
void BuildCompareOp(const Operator* op); void BuildCompareOp(const Operator* op);
void BuildDelete(LanguageMode language_mode); void BuildDelete(LanguageMode language_mode);
void BuildCastOperator(const Operator* op); void BuildCastOperator(const Operator* op);
...@@ -1036,6 +1037,30 @@ Node* BytecodeGraphBuilder::BuildLoadFeedbackVector() { ...@@ -1036,6 +1037,30 @@ Node* BytecodeGraphBuilder::BuildLoadFeedbackVector() {
return vector; return vector;
} }
Node* BytecodeGraphBuilder::BuildLoadFeedbackCell(int index) {
if (native_context_independent()) {
Environment* env = environment();
Node* control = env->GetControlDependency();
Node* effect = env->GetEffectDependency();
// TODO(jgruber,v8:8888): Assumes that the feedback vector has been
// allocated.
Node* closure_feedback_cell_array = effect = graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForFeedbackVectorClosureFeedbackCellArray()),
feedback_vector_node(), effect, control);
Node* feedback_cell = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)),
closure_feedback_cell_array, effect, control);
env->UpdateEffectDependency(effect);
return feedback_cell;
} else {
return jsgraph()->Constant(feedback_vector().GetClosureFeedbackCell(index));
}
}
Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) { Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) {
Node* result = NewNode(javascript()->LoadContext(0, index, true)); Node* result = NewNode(javascript()->LoadContext(0, index, true));
NodeProperties::ReplaceContextInput(result, NodeProperties::ReplaceContextInput(result,
...@@ -2071,12 +2096,10 @@ void BytecodeGraphBuilder::VisitCreateClosure() { ...@@ -2071,12 +2096,10 @@ void BytecodeGraphBuilder::VisitCreateClosure() {
const Operator* op = javascript()->CreateClosure( const Operator* op = javascript()->CreateClosure(
shared_info.object(), shared_info.object(),
feedback_vector()
.GetClosureFeedbackCell(bytecode_iterator().GetIndexOperand(1))
.object(),
jsgraph()->isolate()->builtins()->builtin_handle(Builtins::kCompileLazy), jsgraph()->isolate()->builtins()->builtin_handle(Builtins::kCompileLazy),
allocation); allocation);
Node* closure = NewNode(op); Node* closure = NewNode(
op, BuildLoadFeedbackCell(bytecode_iterator().GetIndexOperand(1)));
environment()->BindAccumulator(closure); environment()->BindAccumulator(closure);
} }
...@@ -3067,29 +3090,6 @@ void BytecodeGraphBuilder::VisitGetSuperConstructor() { ...@@ -3067,29 +3090,6 @@ void BytecodeGraphBuilder::VisitGetSuperConstructor() {
Environment::kAttachFrameState); Environment::kAttachFrameState);
} }
void BytecodeGraphBuilder::BuildInstanceOf(const Operator* op) {
// TODO(jgruber, v8:8888): Treat InstanceOf like other compare ops.
DCHECK_EQ(op->opcode(), IrOpcode::kJSInstanceOf);
PrepareEagerCheckpoint();
Node* left =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* right = environment()->LookupAccumulator();
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(1);
JSTypeHintLowering::LoweringResult lowering =
TryBuildSimplifiedBinaryOp(op, left, right, slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
if (lowering.IsSideEffectFree()) {
node = lowering.value();
} else {
DCHECK(!lowering.Changed());
node = NewNode(op, left, right);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::BuildCompareOp(const Operator* op) { void BytecodeGraphBuilder::BuildCompareOp(const Operator* op) {
DCHECK(JSOperator::IsBinaryWithFeedback(op->opcode())); DCHECK(JSOperator::IsBinaryWithFeedback(op->opcode()));
PrepareEagerCheckpoint(); PrepareEagerCheckpoint();
...@@ -3172,8 +3172,9 @@ void BytecodeGraphBuilder::VisitTestIn() { ...@@ -3172,8 +3172,9 @@ void BytecodeGraphBuilder::VisitTestIn() {
} }
void BytecodeGraphBuilder::VisitTestInstanceOf() { void BytecodeGraphBuilder::VisitTestInstanceOf() {
int const slot_index = bytecode_iterator().GetIndexOperand(1); FeedbackSource feedback = CreateFeedbackSource(
BuildInstanceOf(javascript()->InstanceOf(CreateFeedbackSource(slot_index))); bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex));
BuildCompareOp(javascript()->InstanceOf(feedback));
} }
void BytecodeGraphBuilder::VisitTestUndetectable() { void BytecodeGraphBuilder::VisitTestUndetectable() {
......
...@@ -828,13 +828,13 @@ class PromiseBuiltinReducerAssembler : public JSCallReducerAssembler { ...@@ -828,13 +828,13 @@ class PromiseBuiltinReducerAssembler : public JSCallReducerAssembler {
TNode<JSFunction> CreateClosureFromBuiltinSharedFunctionInfo( TNode<JSFunction> CreateClosureFromBuiltinSharedFunctionInfo(
SharedFunctionInfoRef shared, TNode<Context> context) { SharedFunctionInfoRef shared, TNode<Context> context) {
DCHECK(shared.HasBuiltinId()); DCHECK(shared.HasBuiltinId());
Handle<FeedbackCell> feedback_cell =
isolate()->factory()->many_closures_cell();
Callable const callable = Builtins::CallableFor( Callable const callable = Builtins::CallableFor(
isolate(), static_cast<Builtins::Name>(shared.builtin_id())); isolate(), static_cast<Builtins::Name>(shared.builtin_id()));
return AddNode<JSFunction>(graph()->NewNode( return AddNode<JSFunction>(graph()->NewNode(
javascript()->CreateClosure(shared.object(), javascript()->CreateClosure(shared.object(), callable.code()),
isolate()->factory()->many_closures_cell(), HeapConstant(feedback_cell), context, effect(), control()));
callable.code()),
context, effect(), control()));
} }
void CallPromiseExecutor(TNode<Object> executor, TNode<JSFunction> resolve, void CallPromiseExecutor(TNode<Object> executor, TNode<JSFunction> resolve,
...@@ -3987,7 +3987,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) { ...@@ -3987,7 +3987,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
// the {target} must have the same native context as the call site. // the {target} must have the same native context as the call site.
// Same if the {target} is the result of a CheckClosure operation. // Same if the {target} is the result of a CheckClosure operation.
if (target->opcode() == IrOpcode::kJSCreateClosure) { if (target->opcode() == IrOpcode::kJSCreateClosure) {
CreateClosureParameters const& p = CreateClosureParametersOf(target->op()); CreateClosureParameters const& p = JSCreateClosureNode{target}.Parameters();
return ReduceJSCall(node, SharedFunctionInfoRef(broker(), p.shared_info())); return ReduceJSCall(node, SharedFunctionInfoRef(broker(), p.shared_info()));
} else if (target->opcode() == IrOpcode::kCheckClosure) { } else if (target->opcode() == IrOpcode::kCheckClosure) {
FeedbackCellRef cell(broker(), FeedbackCellOf(target->op())); FeedbackCellRef cell(broker(), FeedbackCellOf(target->op()));
...@@ -4495,8 +4495,12 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) { ...@@ -4495,8 +4495,12 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct); node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct);
} }
// TODO(jgruber,v8:8888): Remove the special case for native context
// independent codegen below once we control available feedback through
// this flag.
base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target(); base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
if (feedback_target.has_value() && feedback_target->IsAllocationSite()) { if (feedback_target.has_value() && feedback_target->IsAllocationSite() &&
!broker()->is_native_context_independent()) {
// The feedback is an AllocationSite, which means we have called the // The feedback is an AllocationSite, which means we have called the
// Array function and collected transition (and pretenuring) feedback // Array function and collected transition (and pretenuring) feedback
// for the resulting arrays. This has to be kept in sync with the // for the resulting arrays. This has to be kept in sync with the
...@@ -6341,12 +6345,13 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) { ...@@ -6341,12 +6345,13 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
Node* JSCallReducer::CreateClosureFromBuiltinSharedFunctionInfo( Node* JSCallReducer::CreateClosureFromBuiltinSharedFunctionInfo(
SharedFunctionInfoRef shared, Node* context, Node* effect, Node* control) { SharedFunctionInfoRef shared, Node* context, Node* effect, Node* control) {
DCHECK(shared.HasBuiltinId()); DCHECK(shared.HasBuiltinId());
Handle<FeedbackCell> feedback_cell =
isolate()->factory()->many_closures_cell();
Callable const callable = Builtins::CallableFor( Callable const callable = Builtins::CallableFor(
isolate(), static_cast<Builtins::Name>(shared.builtin_id())); isolate(), static_cast<Builtins::Name>(shared.builtin_id()));
return graph()->NewNode( return graph()->NewNode(
javascript()->CreateClosure( javascript()->CreateClosure(shared.object(), callable.code()),
shared.object(), factory()->many_closures_cell(), callable.code()), jsgraph()->HeapConstant(feedback_cell), context, effect, control);
context, effect, control);
} }
// ES section #sec-promise.prototype.finally // ES section #sec-promise.prototype.finally
......
...@@ -924,14 +924,14 @@ Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) { ...@@ -924,14 +924,14 @@ Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) {
} }
Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) { Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode()); JSCreateClosureNode n(node);
CreateClosureParameters const& p = CreateClosureParametersOf(node->op()); CreateClosureParameters const& p = n.Parameters();
SharedFunctionInfoRef shared(broker(), p.shared_info()); SharedFunctionInfoRef shared(broker(), p.shared_info());
FeedbackCellRef feedback_cell(broker(), p.feedback_cell()); FeedbackCellRef feedback_cell = n.GetFeedbackCellRefChecked(broker());
HeapObjectRef code(broker(), p.code()); HeapObjectRef code(broker(), p.code());
Node* effect = NodeProperties::GetEffectInput(node); Effect effect = n.effect();
Node* control = NodeProperties::GetControlInput(node); Control control = n.control();
Node* context = NodeProperties::GetContextInput(node); Node* context = n.context();
// Use inline allocation of closures only for instantiation sites that have // Use inline allocation of closures only for instantiation sites that have
// seen more than one instantiation, this simplifies the generated code and // seen more than one instantiation, this simplifies the generated code and
......
...@@ -200,6 +200,7 @@ DEF_BINARY_LOWERING(Subtract) ...@@ -200,6 +200,7 @@ DEF_BINARY_LOWERING(Subtract)
DEF_BINARY_LOWERING(Equal) DEF_BINARY_LOWERING(Equal)
DEF_BINARY_LOWERING(GreaterThan) DEF_BINARY_LOWERING(GreaterThan)
DEF_BINARY_LOWERING(GreaterThanOrEqual) DEF_BINARY_LOWERING(GreaterThanOrEqual)
DEF_BINARY_LOWERING(InstanceOf)
DEF_BINARY_LOWERING(LessThan) DEF_BINARY_LOWERING(LessThan)
DEF_BINARY_LOWERING(LessThanOrEqual) DEF_BINARY_LOWERING(LessThanOrEqual)
#undef DEF_BINARY_LOWERING #undef DEF_BINARY_LOWERING
...@@ -247,9 +248,17 @@ bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source, ...@@ -247,9 +248,17 @@ bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source,
} // namespace } // namespace
void JSGenericLowering::LowerJSHasProperty(Node* node) { void JSGenericLowering::LowerJSHasProperty(Node* node) {
// TODO(jgruber,v8:8888): Collect feedback. JSHasPropertyNode n(node);
node->RemoveInput(JSHasPropertyNode::FeedbackVectorIndex()); const PropertyAccess& p = n.Parameters();
ReplaceWithBuiltinCall(node, Builtins::kHasProperty); if (!p.feedback().IsValid()) {
node->RemoveInput(JSHasPropertyNode::FeedbackVectorIndex());
ReplaceWithBuiltinCall(node, Builtins::kHasProperty);
} else {
STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
n->InsertInput(zone(), 2,
jsgraph()->TaggedIndexConstant(p.feedback().index()));
ReplaceWithBuiltinCall(node, Builtins::kKeyedHasIC);
}
} }
void JSGenericLowering::LowerJSLoadProperty(Node* node) { void JSGenericLowering::LowerJSLoadProperty(Node* node) {
...@@ -471,11 +480,6 @@ void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) { ...@@ -471,11 +480,6 @@ void JSGenericLowering::LowerJSHasInPrototypeChain(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain); ReplaceWithRuntimeCall(node, Runtime::kHasInPrototypeChain);
} }
void JSGenericLowering::LowerJSInstanceOf(Node* node) {
// TODO(jgruber, v8:8888): Collect feedback.
ReplaceWithBuiltinCall(node, Builtins::kInstanceOf);
}
void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) { void JSGenericLowering::LowerJSOrdinaryHasInstance(Node* node) {
ReplaceWithBuiltinCall(node, Builtins::kOrdinaryHasInstance); ReplaceWithBuiltinCall(node, Builtins::kOrdinaryHasInstance);
} }
...@@ -570,12 +574,11 @@ void JSGenericLowering::LowerJSRegExpTest(Node* node) { ...@@ -570,12 +574,11 @@ void JSGenericLowering::LowerJSRegExpTest(Node* node) {
} }
void JSGenericLowering::LowerJSCreateClosure(Node* node) { void JSGenericLowering::LowerJSCreateClosure(Node* node) {
// TODO(jgruber,v8:8888): Load the feedback cell instead of embedding a JSCreateClosureNode n(node);
// (context-dependent) constant. CreateClosureParameters const& p = n.Parameters();
CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
Handle<SharedFunctionInfo> const shared_info = p.shared_info(); Handle<SharedFunctionInfo> const shared_info = p.shared_info();
STATIC_ASSERT(n.FeedbackCellIndex() == 0);
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info)); node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info));
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.feedback_cell()));
node->RemoveInput(4); // control node->RemoveInput(4); // control
// Use the FastNewClosure builtin only for functions allocated in new space. // Use the FastNewClosure builtin only for functions allocated in new space.
...@@ -586,7 +589,6 @@ void JSGenericLowering::LowerJSCreateClosure(Node* node) { ...@@ -586,7 +589,6 @@ void JSGenericLowering::LowerJSCreateClosure(Node* node) {
} }
} }
void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) { void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) {
const CreateFunctionContextParameters& parameters = const CreateFunctionContextParameters& parameters =
CreateFunctionContextParametersOf(node->op()); CreateFunctionContextParametersOf(node->op());
......
...@@ -74,7 +74,6 @@ Reduction JSHeapCopyReducer::Reduce(Node* node) { ...@@ -74,7 +74,6 @@ Reduction JSHeapCopyReducer::Reduce(Node* node) {
case IrOpcode::kJSCreateClosure: { case IrOpcode::kJSCreateClosure: {
CreateClosureParameters const& p = CreateClosureParametersOf(node->op()); CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
SharedFunctionInfoRef(broker(), p.shared_info()); SharedFunctionInfoRef(broker(), p.shared_info());
FeedbackCellRef(broker(), p.feedback_cell());
HeapObjectRef(broker(), p.code()); HeapObjectRef(broker(), p.code());
break; break;
} }
......
...@@ -124,8 +124,9 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions( ...@@ -124,8 +124,9 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions(
} }
if (m.IsJSCreateClosure()) { if (m.IsJSCreateClosure()) {
DCHECK(!out.functions[0].has_value()); DCHECK(!out.functions[0].has_value());
CreateClosureParameters const& p = CreateClosureParametersOf(m.op()); JSCreateClosureNode n(callee);
FeedbackCellRef feedback_cell(broker(), p.feedback_cell()); CreateClosureParameters const& p = n.Parameters();
FeedbackCellRef feedback_cell = n.GetFeedbackCellRefChecked(broker());
SharedFunctionInfoRef shared_info(broker(), p.shared_info()); SharedFunctionInfoRef shared_info(broker(), p.shared_info());
out.shared_info = shared_info; out.shared_info = shared_info;
if (feedback_cell.value().IsFeedbackVector() && if (feedback_cell.value().IsFeedbackVector() &&
......
...@@ -280,7 +280,8 @@ bool NeedsImplicitReceiver(SharedFunctionInfoRef shared_info) { ...@@ -280,7 +280,8 @@ bool NeedsImplicitReceiver(SharedFunctionInfoRef shared_info) {
base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
Node* node) { Node* node) {
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
HeapObjectMatcher match(node->InputAt(JSCallOrConstructNode::TargetIndex())); Node* target = node->InputAt(JSCallOrConstructNode::TargetIndex());
HeapObjectMatcher match(target);
// This reducer can handle both normal function calls as well a constructor // This reducer can handle both normal function calls as well a constructor
// calls whenever the target is a constant function object, as follows: // calls whenever the target is a constant function object, as follows:
...@@ -315,8 +316,8 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( ...@@ -315,8 +316,8 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
// - JSConstruct(JSCreateClosure[shared](context), // - JSConstruct(JSCreateClosure[shared](context),
// new.target, args..., vector) // new.target, args..., vector)
if (match.IsJSCreateClosure()) { if (match.IsJSCreateClosure()) {
CreateClosureParameters const& p = CreateClosureParametersOf(match.op()); JSCreateClosureNode n(target);
FeedbackCellRef cell(broker(), p.feedback_cell()); FeedbackCellRef cell = n.GetFeedbackCellRefChecked(broker());
return cell.shared_function_info(); return cell.shared_function_info();
} else if (match.IsCheckClosure()) { } else if (match.IsCheckClosure()) {
FeedbackCellRef cell(broker(), FeedbackCellOf(match.op())); FeedbackCellRef cell(broker(), FeedbackCellOf(match.op()));
...@@ -334,7 +335,8 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget( ...@@ -334,7 +335,8 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
FeedbackVectorRef JSInliner::DetermineCallContext(Node* node, FeedbackVectorRef JSInliner::DetermineCallContext(Node* node,
Node** context_out) { Node** context_out) {
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
HeapObjectMatcher match(node->InputAt(JSCallOrConstructNode::TargetIndex())); Node* target = node->InputAt(JSCallOrConstructNode::TargetIndex());
HeapObjectMatcher match(target);
if (match.HasValue() && match.Ref(broker()).IsJSFunction()) { if (match.HasValue() && match.Ref(broker()).IsJSFunction()) {
JSFunctionRef function = match.Ref(broker()).AsJSFunction(); JSFunctionRef function = match.Ref(broker()).AsJSFunction();
...@@ -347,11 +349,10 @@ FeedbackVectorRef JSInliner::DetermineCallContext(Node* node, ...@@ -347,11 +349,10 @@ FeedbackVectorRef JSInliner::DetermineCallContext(Node* node,
} }
if (match.IsJSCreateClosure()) { if (match.IsJSCreateClosure()) {
CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
// Load the feedback vector of the target by looking up its vector cell at // Load the feedback vector of the target by looking up its vector cell at
// the instantiation site (we only decide to inline if it's populated). // the instantiation site (we only decide to inline if it's populated).
FeedbackCellRef cell(broker(), p.feedback_cell()); JSCreateClosureNode n(target);
FeedbackCellRef cell = n.GetFeedbackCellRefChecked(broker());
// The inlinee uses the locally provided context at instantiation. // The inlinee uses the locally provided context at instantiation.
*context_out = NodeProperties::GetContextInput(match.node()); *context_out = NodeProperties::GetContextInput(match.node());
......
...@@ -376,14 +376,14 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor( ...@@ -376,14 +376,14 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
} }
Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); JSInstanceOfNode n(node);
FeedbackParameter const& p = FeedbackParameterOf(node->op()); FeedbackParameter const& p = n.Parameters();
Node* object = NodeProperties::GetValueInput(node, 0); Node* object = n.left();
Node* constructor = NodeProperties::GetValueInput(node, 1); Node* constructor = n.right();
Node* context = NodeProperties::GetContextInput(node); TNode<Object> context = n.context();
Node* effect = NodeProperties::GetEffectInput(node); FrameState frame_state = n.frame_state();
Node* frame_state = NodeProperties::GetFrameStateInput(node); Effect effect = n.effect();
Node* control = NodeProperties::GetControlInput(node); Control control = n.control();
// Check if the right hand side is a known {receiver}, or // Check if the right hand side is a known {receiver}, or
// we have feedback from the InstanceOfIC. // we have feedback from the InstanceOfIC.
...@@ -441,6 +441,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { ...@@ -441,6 +441,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
NodeProperties::ReplaceValueInput(node, constructor, 0); NodeProperties::ReplaceValueInput(node, constructor, 0);
NodeProperties::ReplaceValueInput(node, object, 1); NodeProperties::ReplaceValueInput(node, object, 1);
NodeProperties::ReplaceEffectInput(node, effect); NodeProperties::ReplaceEffectInput(node, effect);
STATIC_ASSERT(n.FeedbackVectorIndex() == 2);
node->RemoveInput(n.FeedbackVectorIndex());
NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
return Changed(node).FollowedBy(ReduceJSOrdinaryHasInstance(node)); return Changed(node).FollowedBy(ReduceJSOrdinaryHasInstance(node));
} }
...@@ -626,9 +628,14 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance( ...@@ -626,9 +628,14 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
JSReceiverRef bound_target_function = function.bound_target_function(); JSReceiverRef bound_target_function = function.bound_target_function();
NodeProperties::ReplaceValueInput(node, object, 0); Node* feedback = jsgraph()->UndefinedConstant();
NodeProperties::ReplaceValueInput(node, object,
JSInstanceOfNode::LeftIndex());
NodeProperties::ReplaceValueInput( NodeProperties::ReplaceValueInput(
node, jsgraph()->Constant(bound_target_function), 1); node, jsgraph()->Constant(bound_target_function),
JSInstanceOfNode::RightIndex());
node->InsertInput(zone(), JSInstanceOfNode::FeedbackVectorIndex(),
feedback);
NodeProperties::ChangeOp(node, javascript()->InstanceOf(FeedbackSource())); NodeProperties::ChangeOp(node, javascript()->InstanceOf(FeedbackSource()));
return Changed(node).FollowedBy(ReduceJSInstanceOf(node)); return Changed(node).FollowedBy(ReduceJSInstanceOf(node));
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/base/lazy-instance.h" #include "src/base/lazy-instance.h"
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "src/handles/handles-inl.h" #include "src/handles/handles-inl.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
...@@ -36,6 +37,13 @@ TNode<Oddball> UndefinedConstant(JSGraph* jsgraph) { ...@@ -36,6 +37,13 @@ TNode<Oddball> UndefinedConstant(JSGraph* jsgraph) {
} // namespace js_node_wrapper_utils } // namespace js_node_wrapper_utils
FeedbackCellRef JSCreateClosureNode::GetFeedbackCellRefChecked(
JSHeapBroker* broker) const {
HeapObjectMatcher m(feedback_cell());
CHECK(m.HasValue());
return FeedbackCellRef(broker, m.Value());
}
std::ostream& operator<<(std::ostream& os, CallFrequency const& f) { std::ostream& operator<<(std::ostream& os, CallFrequency const& f) {
if (f.IsUnknown()) return os << "unknown"; if (f.IsUnknown()) return os << "unknown";
return os << f.value(); return os << f.value();
...@@ -523,7 +531,6 @@ bool operator==(CreateClosureParameters const& lhs, ...@@ -523,7 +531,6 @@ bool operator==(CreateClosureParameters const& lhs,
CreateClosureParameters const& rhs) { CreateClosureParameters const& rhs) {
return lhs.allocation() == rhs.allocation() && return lhs.allocation() == rhs.allocation() &&
lhs.code().location() == rhs.code().location() && lhs.code().location() == rhs.code().location() &&
lhs.feedback_cell().location() == rhs.feedback_cell().location() &&
lhs.shared_info().location() == rhs.shared_info().location(); lhs.shared_info().location() == rhs.shared_info().location();
} }
...@@ -535,14 +542,13 @@ bool operator!=(CreateClosureParameters const& lhs, ...@@ -535,14 +542,13 @@ bool operator!=(CreateClosureParameters const& lhs,
size_t hash_value(CreateClosureParameters const& p) { size_t hash_value(CreateClosureParameters const& p) {
return base::hash_combine(p.allocation(), p.shared_info().location(), return base::hash_combine(p.allocation(), p.shared_info().location());
p.feedback_cell().location());
} }
std::ostream& operator<<(std::ostream& os, CreateClosureParameters const& p) { std::ostream& operator<<(std::ostream& os, CreateClosureParameters const& p) {
return os << p.allocation() << ", " << Brief(*p.shared_info()) << ", " return os << p.allocation() << ", " << Brief(*p.shared_info()) << ", "
<< Brief(*p.feedback_cell()) << ", " << Brief(*p.code()); << Brief(*p.code());
} }
...@@ -941,15 +947,6 @@ const Operator* JSOperatorBuilder::HasProperty(FeedbackSource const& feedback) { ...@@ -941,15 +947,6 @@ const Operator* JSOperatorBuilder::HasProperty(FeedbackSource const& feedback) {
access); // parameter access); // parameter
} }
const Operator* JSOperatorBuilder::InstanceOf(FeedbackSource const& feedback) {
FeedbackParameter parameter(feedback);
return new (zone()) Operator1<FeedbackParameter>( // --
IrOpcode::kJSInstanceOf, Operator::kNoProperties, // opcode
"JSInstanceOf", // name
2, 1, 1, 1, 1, 2, // counts
parameter); // parameter
}
const Operator* JSOperatorBuilder::ForInNext(ForInMode mode) { const Operator* JSOperatorBuilder::ForInNext(ForInMode mode) {
return new (zone()) Operator1<ForInMode>( // -- return new (zone()) Operator1<ForInMode>( // --
IrOpcode::kJSForInNext, Operator::kNoProperties, // opcode IrOpcode::kJSForInNext, Operator::kNoProperties, // opcode
...@@ -1188,14 +1185,15 @@ const Operator* JSOperatorBuilder::CreateBoundFunction(size_t arity, ...@@ -1188,14 +1185,15 @@ const Operator* JSOperatorBuilder::CreateBoundFunction(size_t arity,
} }
const Operator* JSOperatorBuilder::CreateClosure( const Operator* JSOperatorBuilder::CreateClosure(
Handle<SharedFunctionInfo> shared_info, Handle<FeedbackCell> feedback_cell, Handle<SharedFunctionInfo> shared_info, Handle<Code> code,
Handle<Code> code, AllocationType allocation) { AllocationType allocation) {
CreateClosureParameters parameters(shared_info, feedback_cell, code, static constexpr int kFeedbackCell = 1;
allocation); static constexpr int kArity = kFeedbackCell;
CreateClosureParameters parameters(shared_info, code, allocation);
return new (zone()) Operator1<CreateClosureParameters>( // -- return new (zone()) Operator1<CreateClosureParameters>( // --
IrOpcode::kJSCreateClosure, Operator::kEliminatable, // opcode IrOpcode::kJSCreateClosure, Operator::kEliminatable, // opcode
"JSCreateClosure", // name "JSCreateClosure", // name
0, 1, 1, 1, 1, 0, // counts kArity, 1, 1, 1, 1, 0, // counts
parameters); // parameter parameters); // parameter
} }
......
...@@ -40,7 +40,8 @@ struct JSOperatorGlobalCache; ...@@ -40,7 +40,8 @@ struct JSOperatorGlobalCache;
#define JS_BINOP_WITH_FEEDBACK(V) \ #define JS_BINOP_WITH_FEEDBACK(V) \
JS_ARITH_BINOP_LIST(V) \ JS_ARITH_BINOP_LIST(V) \
JS_BITWISE_BINOP_LIST(V) \ JS_BITWISE_BINOP_LIST(V) \
JS_COMPARE_BINOP_LIST(V) JS_COMPARE_BINOP_LIST(V) \
V(JSInstanceOf, InstanceOf)
// Predicates. // Predicates.
class JSOperator final : public AllStatic { class JSOperator final : public AllStatic {
...@@ -657,21 +658,15 @@ const CreateBoundFunctionParameters& CreateBoundFunctionParametersOf( ...@@ -657,21 +658,15 @@ const CreateBoundFunctionParameters& CreateBoundFunctionParametersOf(
class CreateClosureParameters final { class CreateClosureParameters final {
public: public:
CreateClosureParameters(Handle<SharedFunctionInfo> shared_info, CreateClosureParameters(Handle<SharedFunctionInfo> shared_info,
Handle<FeedbackCell> feedback_cell, Handle<Code> code, Handle<Code> code, AllocationType allocation)
AllocationType allocation) : shared_info_(shared_info), code_(code), allocation_(allocation) {}
: shared_info_(shared_info),
feedback_cell_(feedback_cell),
code_(code),
allocation_(allocation) {}
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
Handle<FeedbackCell> feedback_cell() const { return feedback_cell_; }
Handle<Code> code() const { return code_; } Handle<Code> code() const { return code_; }
AllocationType allocation() const { return allocation_; } AllocationType allocation() const { return allocation_; }
private: private:
Handle<SharedFunctionInfo> const shared_info_; Handle<SharedFunctionInfo> const shared_info_;
Handle<FeedbackCell> const feedback_cell_;
Handle<Code> const code_; Handle<Code> const code_;
AllocationType const allocation_; AllocationType const allocation_;
}; };
...@@ -863,8 +858,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final ...@@ -863,8 +858,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CreateCollectionIterator(CollectionKind, IterationKind); const Operator* CreateCollectionIterator(CollectionKind, IterationKind);
const Operator* CreateBoundFunction(size_t arity, Handle<Map> map); const Operator* CreateBoundFunction(size_t arity, Handle<Map> map);
const Operator* CreateClosure( const Operator* CreateClosure(
Handle<SharedFunctionInfo> shared_info, Handle<SharedFunctionInfo> shared_info, Handle<Code> code,
Handle<FeedbackCell> feedback_cell, Handle<Code> code,
AllocationType allocation = AllocationType::kYoung); AllocationType allocation = AllocationType::kYoung);
const Operator* CreateIterResultObject(); const Operator* CreateIterResultObject();
const Operator* CreateStringIterator(); const Operator* CreateStringIterator();
...@@ -1078,6 +1072,10 @@ class JSBinaryOpNode final : public JSNodeWrapperBase { ...@@ -1078,6 +1072,10 @@ class JSBinaryOpNode final : public JSNodeWrapperBase {
CONSTEXPR_DCHECK(JSOperator::IsBinaryWithFeedback(node->opcode())); CONSTEXPR_DCHECK(JSOperator::IsBinaryWithFeedback(node->opcode()));
} }
const FeedbackParameter& Parameters() const {
return FeedbackParameterOf(node()->op());
}
#define INPUTS(V) \ #define INPUTS(V) \
V(Left, left, 0, Object) \ V(Left, left, 0, Object) \
V(Right, right, 1, Object) \ V(Right, right, 1, Object) \
...@@ -1512,6 +1510,23 @@ class JSStoreInArrayLiteralNode final : public JSNodeWrapperBase { ...@@ -1512,6 +1510,23 @@ class JSStoreInArrayLiteralNode final : public JSNodeWrapperBase {
#undef INPUTS #undef INPUTS
}; };
class JSCreateClosureNode final : public JSNodeWrapperBase {
public:
explicit constexpr JSCreateClosureNode(Node* node) : JSNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kJSCreateClosure);
}
const CreateClosureParameters& Parameters() const {
return CreateClosureParametersOf(node()->op());
}
#define INPUTS(V) V(FeedbackCell, feedback_cell, 0, FeedbackCell)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
FeedbackCellRef GetFeedbackCellRefChecked(JSHeapBroker* broker) const;
};
#undef DEFINE_INPUT_ACCESSORS #undef DEFINE_INPUT_ACCESSORS
} // namespace compiler } // namespace compiler
......
...@@ -1735,7 +1735,7 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { ...@@ -1735,7 +1735,7 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
shared = function->shared(); shared = function->shared();
} else if (target->opcode() == IrOpcode::kJSCreateClosure) { } else if (target->opcode() == IrOpcode::kJSCreateClosure) {
CreateClosureParameters const& ccp = CreateClosureParameters const& ccp =
CreateClosureParametersOf(target->op()); JSCreateClosureNode{target}.Parameters();
shared = SharedFunctionInfoRef(broker(), ccp.shared_info()); shared = SharedFunctionInfoRef(broker(), ccp.shared_info());
} else if (target->opcode() == IrOpcode::kCheckClosure) { } else if (target->opcode() == IrOpcode::kCheckClosure) {
FeedbackCellRef cell(broker(), FeedbackCellOf(target->op())); FeedbackCellRef cell(broker(), FeedbackCellOf(target->op()));
......
...@@ -109,8 +109,8 @@ void PropertyAccessBuilder::BuildCheckMaps( ...@@ -109,8 +109,8 @@ void PropertyAccessBuilder::BuildCheckMaps(
*effect, control); *effect, control);
} }
Node* PropertyAccessBuilder::BuildCheckValue(Node* receiver, Node** effect, Node* PropertyAccessBuilder::BuildCheckValue(Node* receiver, Effect* effect,
Node* control, Control control,
Handle<HeapObject> value) { Handle<HeapObject> value) {
HeapObjectMatcher m(receiver); HeapObjectMatcher m(receiver);
if (m.Is(value)) return receiver; if (m.Is(value)) return receiver;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "src/codegen/machine-type.h" #include "src/codegen/machine-type.h"
#include "src/compiler/js-heap-broker.h" #include "src/compiler/js-heap-broker.h"
#include "src/compiler/node.h"
#include "src/handles/handles.h" #include "src/handles/handles.h"
#include "src/objects/map.h" #include "src/objects/map.h"
#include "src/zone/zone-containers.h" #include "src/zone/zone-containers.h"
...@@ -22,7 +23,6 @@ class CompilationDependencies; ...@@ -22,7 +23,6 @@ class CompilationDependencies;
class Graph; class Graph;
class JSGraph; class JSGraph;
class JSHeapBroker; class JSHeapBroker;
class Node;
class PropertyAccessInfo; class PropertyAccessInfo;
class SimplifiedOperatorBuilder; class SimplifiedOperatorBuilder;
...@@ -42,9 +42,18 @@ class PropertyAccessBuilder { ...@@ -42,9 +42,18 @@ class PropertyAccessBuilder {
ZoneVector<Handle<Map>> const& maps, Node** receiver, ZoneVector<Handle<Map>> const& maps, Node** receiver,
Node** effect, Node* control); Node** effect, Node* control);
// TODO(jgruber): Remove the untyped version once all uses are
// updated.
void BuildCheckMaps(Node* receiver, Node** effect, Node* control, void BuildCheckMaps(Node* receiver, Node** effect, Node* control,
ZoneVector<Handle<Map>> const& receiver_maps); ZoneVector<Handle<Map>> const& receiver_maps);
Node* BuildCheckValue(Node* receiver, Node** effect, Node* control, void BuildCheckMaps(Node* receiver, Effect* effect, Control control,
ZoneVector<Handle<Map>> const& receiver_maps) {
Node* e = *effect;
Node* c = control;
BuildCheckMaps(receiver, &e, c, receiver_maps);
*effect = e;
}
Node* BuildCheckValue(Node* receiver, Effect* effect, Control control,
Handle<HeapObject> value); Handle<HeapObject> value);
// Builds the actual load for data-field and data-constant-field // Builds the actual load for data-field and data-constant-field
......
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