summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-typed-lowering.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-typed-lowering.cc')
-rw-r--r--deps/v8/src/compiler/js-typed-lowering.cc231
1 files changed, 129 insertions, 102 deletions
diff --git a/deps/v8/src/compiler/js-typed-lowering.cc b/deps/v8/src/compiler/js-typed-lowering.cc
index 7b3728428b..9be71cbd27 100644
--- a/deps/v8/src/compiler/js-typed-lowering.cc
+++ b/deps/v8/src/compiler/js-typed-lowering.cc
@@ -51,6 +51,7 @@ class JSBinopReduction final {
case CompareOperationHint::kSymbol:
case CompareOperationHint::kBigInt:
case CompareOperationHint::kReceiver:
+ case CompareOperationHint::kReceiverOrNullOrUndefined:
case CompareOperationHint::kInternalizedString:
break;
}
@@ -71,6 +72,13 @@ class JSBinopReduction final {
BothInputsMaybe(Type::Receiver());
}
+ bool IsReceiverOrNullOrUndefinedCompareOperation() {
+ DCHECK_EQ(1, node_->op()->EffectOutputCount());
+ return (CompareOperationHintOf(node_->op()) ==
+ CompareOperationHint::kReceiverOrNullOrUndefined) &&
+ BothInputsMaybe(Type::ReceiverOrNullOrUndefined());
+ }
+
bool IsStringCompareOperation() {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
return (CompareOperationHintOf(node_->op()) ==
@@ -94,7 +102,7 @@ class JSBinopReduction final {
if (BothInputsAre(Type::String()) ||
BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString) {
HeapObjectBinopMatcher m(node_);
- JSHeapBroker* broker = lowering_->js_heap_broker();
+ JSHeapBroker* broker = lowering_->broker();
if (m.right().HasValue() && m.right().Ref(broker).IsString()) {
StringRef right_string = m.right().Ref(broker).AsString();
if (right_string.length() >= ConsString::kMinLength) return true;
@@ -122,6 +130,15 @@ class JSBinopReduction final {
update_effect(left_input);
}
+ // Inserts a CheckReceiverOrNullOrUndefined for the left input.
+ void CheckLeftInputToReceiverOrNullOrUndefined() {
+ Node* left_input =
+ graph()->NewNode(simplified()->CheckReceiverOrNullOrUndefined(), left(),
+ effect(), control());
+ node_->ReplaceInput(0, left_input);
+ update_effect(left_input);
+ }
+
// Checks that both inputs are Receiver, and if we don't know
// statically that one side is already a Receiver, insert a
// CheckReceiver node.
@@ -137,6 +154,22 @@ class JSBinopReduction final {
}
}
+ // Checks that both inputs are Receiver, Null or Undefined and if
+ // we don't know statically that one side is already a Receiver,
+ // Null or Undefined, insert CheckReceiverOrNullOrUndefined nodes.
+ void CheckInputsToReceiverOrNullOrUndefined() {
+ if (!left_type().Is(Type::ReceiverOrNullOrUndefined())) {
+ CheckLeftInputToReceiverOrNullOrUndefined();
+ }
+ if (!right_type().Is(Type::ReceiverOrNullOrUndefined())) {
+ Node* right_input =
+ graph()->NewNode(simplified()->CheckReceiverOrNullOrUndefined(),
+ right(), effect(), control());
+ node_->ReplaceInput(1, right_input);
+ update_effect(right_input);
+ }
+ }
+
// Inserts a CheckSymbol for the left input.
void CheckLeftInputToSymbol() {
Node* left_input = graph()->NewNode(simplified()->CheckSymbol(), left(),
@@ -310,31 +343,6 @@ class JSBinopReduction final {
UNREACHABLE();
}
- const Operator* NumberOpFromSpeculativeNumberOp() {
- switch (node_->opcode()) {
- case IrOpcode::kSpeculativeNumberEqual:
- return simplified()->NumberEqual();
- case IrOpcode::kSpeculativeNumberLessThan:
- return simplified()->NumberLessThan();
- case IrOpcode::kSpeculativeNumberLessThanOrEqual:
- return simplified()->NumberLessThanOrEqual();
- case IrOpcode::kSpeculativeNumberAdd:
- // Handled by ReduceSpeculativeNumberAdd.
- UNREACHABLE();
- case IrOpcode::kSpeculativeNumberSubtract:
- return simplified()->NumberSubtract();
- case IrOpcode::kSpeculativeNumberMultiply:
- return simplified()->NumberMultiply();
- case IrOpcode::kSpeculativeNumberDivide:
- return simplified()->NumberDivide();
- case IrOpcode::kSpeculativeNumberModulus:
- return simplified()->NumberModulus();
- default:
- break;
- }
- UNREACHABLE();
- }
-
bool LeftInputIs(Type t) { return left_type().Is(t); }
bool RightInputIs(Type t) { return right_type().Is(t); }
@@ -414,12 +422,12 @@ class JSBinopReduction final {
// - relax effects from generic but not-side-effecting operations
JSTypedLowering::JSTypedLowering(Editor* editor, JSGraph* jsgraph,
- JSHeapBroker* js_heap_broker, Zone* zone)
+ JSHeapBroker* broker, Zone* zone)
: AdvancedReducer(editor),
jsgraph_(jsgraph),
- js_heap_broker_(js_heap_broker),
- empty_string_type_(Type::HeapConstant(
- js_heap_broker, factory()->empty_string(), graph()->zone())),
+ broker_(broker),
+ empty_string_type_(Type::HeapConstant(broker, factory()->empty_string(),
+ graph()->zone())),
pointer_comparable_type_(
Type::Union(Type::Oddball(),
Type::Union(Type::SymbolOrReceiver(), empty_string_type_,
@@ -427,21 +435,6 @@ JSTypedLowering::JSTypedLowering(Editor* editor, JSGraph* jsgraph,
graph()->zone())),
type_cache_(TypeCache::Get()) {}
-Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
- JSBinopReduction r(this, node);
- NumberOperationHint hint = NumberOperationHintOf(node->op());
- if ((hint == NumberOperationHint::kNumber ||
- hint == NumberOperationHint::kNumberOrOddball) &&
- r.BothInputsAre(Type::PlainPrimitive()) &&
- r.NeitherInputCanBe(Type::StringOrReceiver())) {
- // SpeculativeNumberAdd(x:-string, y:-string) =>
- // NumberAdd(ToNumber(x), ToNumber(y))
- r.ConvertInputsToNumber();
- return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
- }
- return NoChange();
-}
-
Reduction JSTypedLowering::ReduceJSBitwiseNot(Node* node) {
Node* input = NodeProperties::GetValueInput(node, 0);
Type input_type = NodeProperties::GetType(input);
@@ -569,7 +562,9 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
Node* length =
graph()->NewNode(simplified()->NumberAdd(), left_length, right_length);
- if (isolate()->IsStringLengthOverflowIntact()) {
+ CellRef string_length_protector(broker(),
+ factory()->string_length_protector());
+ if (string_length_protector.value().AsSmi() == Isolate::kProtectorValid) {
// We can just deoptimize if the {length} is out-of-bounds. Besides
// generating a shorter code sequence than the version below, this
// has the additional benefit of not holding on to the lazy {frame_state}
@@ -613,7 +608,7 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
}
control = graph()->NewNode(common()->IfTrue(), branch);
length = effect =
- graph()->NewNode(common()->TypeGuard(type_cache_.kStringLengthType),
+ graph()->NewNode(common()->TypeGuard(type_cache_->kStringLengthType),
length, effect, control);
}
@@ -670,22 +665,6 @@ Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
return NoChange();
}
-Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
- JSBinopReduction r(this, node);
- NumberOperationHint hint = NumberOperationHintOf(node->op());
- if ((hint == NumberOperationHint::kNumber ||
- hint == NumberOperationHint::kNumberOrOddball) &&
- r.BothInputsAre(Type::NumberOrUndefinedOrNullOrBoolean())) {
- // We intentionally do this only in the Number and NumberOrOddball hint case
- // because simplified lowering of these speculative ops may do some clever
- // reductions in the other cases.
- r.ConvertInputsToNumber();
- return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),
- Type::Number());
- }
- return NoChange();
-}
-
Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::PlainPrimitive())) {
@@ -708,15 +687,6 @@ Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
return NoChange();
}
-Reduction JSTypedLowering::ReduceSpeculativeNumberComparison(Node* node) {
- JSBinopReduction r(this, node);
- if (r.BothInputsAre(Type::Signed32()) ||
- r.BothInputsAre(Type::Unsigned32())) {
- return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp());
- }
- return NoChange();
-}
-
Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::String())) {
@@ -819,6 +789,46 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node) {
} else if (r.IsReceiverCompareOperation()) {
r.CheckInputsToReceiver();
return r.ChangeToPureOperator(simplified()->ReferenceEqual());
+ } else if (r.IsReceiverOrNullOrUndefinedCompareOperation()) {
+ // Check that both inputs are Receiver, Null or Undefined.
+ r.CheckInputsToReceiverOrNullOrUndefined();
+
+ // If one side is known to be a detectable receiver now, we
+ // can simply perform reference equality here, since this
+ // known detectable receiver is going to only match itself.
+ if (r.OneInputIs(Type::DetectableReceiver())) {
+ return r.ChangeToPureOperator(simplified()->ReferenceEqual());
+ }
+
+ // Known that both sides are Receiver, Null or Undefined, the
+ // abstract equality operation can be performed like this:
+ //
+ // if ObjectIsUndetectable(left)
+ // then ObjectIsUndetectable(right)
+ // else ReferenceEqual(left, right)
+ //
+ Node* left = r.left();
+ Node* right = r.right();
+ Node* effect = r.effect();
+ Node* control = r.control();
+
+ Node* check = graph()->NewNode(simplified()->ObjectIsUndetectable(), left);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
+
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* vtrue = graph()->NewNode(simplified()->ObjectIsUndetectable(), right);
+
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* vfalse =
+ graph()->NewNode(simplified()->ReferenceEqual(), left, right);
+
+ control = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ Node* value =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vtrue, vfalse, control);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
} else if (r.IsStringCompareOperation()) {
r.CheckInputsToString();
return r.ChangeToPureOperator(simplified()->StringEqual());
@@ -879,6 +889,13 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node) {
// both sides refer to the same Receiver.
r.CheckLeftInputToReceiver();
return r.ChangeToPureOperator(simplified()->ReferenceEqual());
+ } else if (r.IsReceiverOrNullOrUndefinedCompareOperation()) {
+ // For strict equality, it's enough to know that one input is a Receiver,
+ // Null or Undefined, as a strict equality comparison with a Receiver,
+ // Null or Undefined can only yield true if both sides refer to the same
+ // instance.
+ r.CheckLeftInputToReceiverOrNullOrUndefined();
+ return r.ChangeToPureOperator(simplified()->ReferenceEqual());
} else if (r.IsStringCompareOperation()) {
r.CheckInputsToString();
return r.ChangeToPureOperator(simplified()->StringEqual());
@@ -906,7 +923,7 @@ Reduction JSTypedLowering::ReduceJSToName(Node* node) {
Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
Node* input = NodeProperties::GetValueInput(node, 0);
Type input_type = NodeProperties::GetType(input);
- if (input_type.Is(type_cache_.kIntegerOrMinusZero)) {
+ if (input_type.Is(type_cache_->kIntegerOrMinusZero)) {
if (input_type.IsNone() || input_type.Max() <= 0.0) {
input = jsgraph()->ZeroConstant();
} else if (input_type.Min() >= kMaxSafeInteger) {
@@ -933,8 +950,8 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
if (input_type.Is(Type::String())) {
HeapObjectMatcher m(input);
- if (m.HasValue() && m.Ref(js_heap_broker()).IsString()) {
- StringRef input_value = m.Ref(js_heap_broker()).AsString();
+ if (m.HasValue() && m.Ref(broker()).IsString()) {
+ StringRef input_value = m.Ref(broker()).AsString();
double number;
ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(number, input_value.ToNumber());
return Replace(jsgraph()->Constant(number));
@@ -1107,8 +1124,8 @@ Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 0);
Type receiver_type = NodeProperties::GetType(receiver);
- NameRef name(js_heap_broker(), NamedAccessOf(node->op()).name());
- NameRef length_str(js_heap_broker(), factory()->length_string());
+ NameRef name(broker(), NamedAccessOf(node->op()).name());
+ NameRef length_str(broker(), factory()->length_string());
// Optimize "length" property of strings.
if (name.equals(length_str) && receiver_type.Is(Type::String())) {
Node* value = graph()->NewNode(simplified()->StringLength(), receiver);
@@ -1541,7 +1558,7 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
// Patch {node} to an indirect call via the {function}s construct stub.
bool use_builtin_construct_stub = shared.construct_as_builtin();
- CodeRef code(js_heap_broker(),
+ CodeRef code(broker(),
use_builtin_construct_stub
? BUILTIN_CODE(isolate(), JSBuiltinsConstructStub)
: BUILTIN_CODE(isolate(), JSConstructStubGeneric));
@@ -1625,22 +1642,27 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
if (IsClassConstructor(shared.kind())) return NoChange();
- // Load the context from the {target}.
- Node* context = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
- effect, control);
- NodeProperties::ReplaceContextInput(node, context);
-
- // Check if we need to convert the {receiver}.
+ // Check if we need to convert the {receiver}, but bailout if it would
+ // require data from a foreign native context.
if (is_sloppy(shared.language_mode()) && !shared.native() &&
!receiver_type.Is(Type::Receiver())) {
- Node* global_proxy = jsgraph()->Constant(function.global_proxy());
+ if (!function.native_context().equals(broker()->native_context())) {
+ return NoChange();
+ }
+ Node* global_proxy =
+ jsgraph()->Constant(function.native_context().global_proxy_object());
receiver = effect =
graph()->NewNode(simplified()->ConvertReceiver(convert_mode),
receiver, global_proxy, effect, control);
NodeProperties::ReplaceValueInput(node, receiver, 1);
}
+ // Load the context from the {target}.
+ Node* context = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
+ effect, control);
+ NodeProperties::ReplaceContextInput(node, context);
+
// Update the effect dependency for the {node}.
NodeProperties::ReplaceEffectInput(node, effect);
@@ -2205,9 +2227,9 @@ Reduction JSTypedLowering::ReduceJSParseInt(Node* node) {
Type radix_type = NodeProperties::GetType(radix);
// We need kTenOrUndefined and kZeroOrUndefined because
// the type representing {0,10} would become the range 1-10.
- if (value_type.Is(type_cache_.kSafeInteger) &&
- (radix_type.Is(type_cache_.kTenOrUndefined) ||
- radix_type.Is(type_cache_.kZeroOrUndefined))) {
+ if (value_type.Is(type_cache_->kSafeInteger) &&
+ (radix_type.Is(type_cache_->kTenOrUndefined) ||
+ radix_type.Is(type_cache_->kZeroOrUndefined))) {
// Number.parseInt(a:safe-integer) -> a
// Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
// Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
@@ -2217,6 +2239,22 @@ Reduction JSTypedLowering::ReduceJSParseInt(Node* node) {
return NoChange();
}
+Reduction JSTypedLowering::ReduceJSResolvePromise(Node* node) {
+ DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
+ Node* resolution = NodeProperties::GetValueInput(node, 1);
+ Type resolution_type = NodeProperties::GetType(resolution);
+ // We can strength-reduce JSResolvePromise to JSFulfillPromise
+ // if the {resolution} is known to be a primitive, as in that
+ // case we don't perform the implicit chaining (via "then").
+ if (resolution_type.Is(Type::Primitive())) {
+ // JSResolvePromise(p,v:primitive) -> JSFulfillPromise(p,v)
+ node->RemoveInput(3); // frame state
+ NodeProperties::ChangeOp(node, javascript()->FulfillPromise());
+ return Changed(node);
+ }
+ return NoChange();
+}
+
Reduction JSTypedLowering::Reduce(Node* node) {
DisallowHeapAccess no_heap_access;
@@ -2308,23 +2346,12 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSGeneratorRestoreRegister(node);
case IrOpcode::kJSGeneratorRestoreInputOrDebugPos:
return ReduceJSGeneratorRestoreInputOrDebugPos(node);
- // TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
- // fooling anyone. Consider moving this into a separate reducer.
- case IrOpcode::kSpeculativeNumberAdd:
- return ReduceSpeculativeNumberAdd(node);
- case IrOpcode::kSpeculativeNumberSubtract:
- case IrOpcode::kSpeculativeNumberMultiply:
- case IrOpcode::kSpeculativeNumberDivide:
- case IrOpcode::kSpeculativeNumberModulus:
- return ReduceSpeculativeNumberBinop(node);
- case IrOpcode::kSpeculativeNumberEqual:
- case IrOpcode::kSpeculativeNumberLessThan:
- case IrOpcode::kSpeculativeNumberLessThanOrEqual:
- return ReduceSpeculativeNumberComparison(node);
case IrOpcode::kJSObjectIsArray:
return ReduceObjectIsArray(node);
case IrOpcode::kJSParseInt:
return ReduceJSParseInt(node);
+ case IrOpcode::kJSResolvePromise:
+ return ReduceJSResolvePromise(node);
default:
break;
}