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