diff options
Diffstat (limited to 'deps/v8/src/compiler/js-typed-lowering.cc')
-rw-r--r-- | deps/v8/src/compiler/js-typed-lowering.cc | 231 |
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; } |