summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-native-context-specialization.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-native-context-specialization.cc')
-rw-r--r--deps/v8/src/compiler/js-native-context-specialization.cc187
1 files changed, 137 insertions, 50 deletions
diff --git a/deps/v8/src/compiler/js-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc
index b2f8c567e2..35e0a551db 100644
--- a/deps/v8/src/compiler/js-native-context-specialization.cc
+++ b/deps/v8/src/compiler/js-native-context-specialization.cc
@@ -76,6 +76,10 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
return ReduceJSHasInPrototypeChain(node);
case IrOpcode::kJSOrdinaryHasInstance:
return ReduceJSOrdinaryHasInstance(node);
+ case IrOpcode::kJSPromiseResolve:
+ return ReduceJSPromiseResolve(node);
+ case IrOpcode::kJSResolvePromise:
+ return ReduceJSResolvePromise(node);
case IrOpcode::kJSLoadContext:
return ReduceJSLoadContext(node);
case IrOpcode::kJSLoadGlobal:
@@ -168,7 +172,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
if (m.HasValue() && m.Value()->IsJSObject()) {
receiver = Handle<JSObject>::cast(m.Value());
} else if (p.feedback().IsValid()) {
- InstanceOfICNexus nexus(p.feedback().vector(), p.feedback().slot());
+ FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) return NoChange();
} else {
return NoChange();
@@ -411,6 +415,87 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
return NoChange();
}
+// ES section #sec-promise-resolve
+Reduction JSNativeContextSpecialization::ReduceJSPromiseResolve(Node* node) {
+ DCHECK_EQ(IrOpcode::kJSPromiseResolve, node->opcode());
+ Node* constructor = NodeProperties::GetValueInput(node, 0);
+ Node* value = NodeProperties::GetValueInput(node, 1);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+
+ // Check if the {constructor} is the %Promise% function.
+ HeapObjectMatcher m(constructor);
+ if (!m.Is(handle(native_context()->promise_function()))) return NoChange();
+
+ // Check if we know something about the {value}.
+ ZoneHandleSet<Map> value_maps;
+ NodeProperties::InferReceiverMapsResult result =
+ NodeProperties::InferReceiverMaps(value, effect, &value_maps);
+ if (result == NodeProperties::kNoReceiverMaps) return NoChange();
+ DCHECK_NE(0, value_maps.size());
+
+ // Check that the {value} cannot be a JSPromise.
+ for (Handle<Map> const value_map : value_maps) {
+ if (value_map->IsJSPromiseMap()) return NoChange();
+ }
+
+ // Create a %Promise% instance and resolve it with {value}.
+ Node* promise = effect =
+ graph()->NewNode(javascript()->CreatePromise(), context, effect);
+ effect = graph()->NewNode(javascript()->ResolvePromise(), promise, value,
+ context, frame_state, effect, control);
+ ReplaceWithValue(node, promise, effect, control);
+ return Replace(promise);
+}
+
+// ES section #sec-promise-resolve-functions
+Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
+ DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
+ Node* promise = NodeProperties::GetValueInput(node, 0);
+ Node* resolution = NodeProperties::GetValueInput(node, 1);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+
+ // Check if we know something about the {resolution}.
+ ZoneHandleSet<Map> resolution_maps;
+ NodeProperties::InferReceiverMapsResult result =
+ NodeProperties::InferReceiverMaps(resolution, effect, &resolution_maps);
+ if (result != NodeProperties::kReliableReceiverMaps) return NoChange();
+ DCHECK_NE(0, resolution_maps.size());
+
+ // Compute property access info for "then" on {resolution}.
+ PropertyAccessInfo access_info;
+ AccessInfoFactory access_info_factory(dependencies(), native_context(),
+ graph()->zone());
+ if (!access_info_factory.ComputePropertyAccessInfo(
+ MapHandles(resolution_maps.begin(), resolution_maps.end()),
+ factory()->then_string(), AccessMode::kLoad, &access_info)) {
+ return NoChange();
+ }
+
+ // We can further optimize the case where {resolution}
+ // definitely doesn't have a "then" property.
+ if (!access_info.IsNotFound()) return NoChange();
+ PropertyAccessBuilder access_builder(jsgraph(), dependencies());
+
+ // Add proper dependencies on the {resolution}s [[Prototype]]s.
+ Handle<JSObject> holder;
+ if (access_info.holder().ToHandle(&holder)) {
+ access_builder.AssumePrototypesStable(native_context(),
+ access_info.receiver_maps(), holder);
+ }
+
+ // Simply fulfill the {promise} with the {resolution}.
+ Node* value = effect =
+ graph()->NewNode(javascript()->FulfillPromise(), promise, resolution,
+ context, effect, control);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
+}
+
Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
ContextAccess const& access = ContextAccessOf(node->op());
@@ -945,16 +1030,6 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
}
- // Check if the {nexus} reports type feedback for the IC.
- if (nexus.IsUninitialized()) {
- if (flags() & kBailoutOnUninitialized) {
- return ReduceSoftDeoptimize(
- node,
- DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
- }
- return NoChange();
- }
-
// Extract receiver maps from the IC using the {nexus}.
MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
@@ -967,6 +1042,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
}
return NoChange();
}
+ DCHECK(!nexus.IsUninitialized());
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccess(node, value, receiver_maps, name, access_mode);
@@ -1007,9 +1083,9 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
}
}
- // Extract receiver maps from the load IC using the LoadICNexus.
+ // Extract receiver maps from the load IC using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
- LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
+ FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
@@ -1022,9 +1098,9 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
NamedAccess const& p = NamedAccessOf(node->op());
Node* const value = NodeProperties::GetValueInput(node, 1);
- // Extract receiver maps from the store IC using the StoreICNexus.
+ // Extract receiver maps from the store IC using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
- StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
+ FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
@@ -1036,9 +1112,9 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
Node* const value = NodeProperties::GetValueInput(node, 1);
- // Extract receiver maps from the IC using the StoreOwnICNexus.
+ // Extract receiver maps from the IC using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
- StoreOwnICNexus nexus(p.feedback().vector(), p.feedback().slot());
+ FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the creation of a named property based on the {receiver_maps}.
return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
@@ -1264,9 +1340,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
return Replace(value);
}
-template <typename KeyedICNexus>
Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
- Node* node, Node* index, Node* value, KeyedICNexus const& nexus,
+ Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
AccessMode access_mode, KeyedAccessLoadMode load_mode,
KeyedAccessStoreMode store_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
@@ -1354,16 +1429,6 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
}
}
- // Check if the {nexus} reports type feedback for the IC.
- if (nexus.IsUninitialized()) {
- if (flags() & kBailoutOnUninitialized) {
- return ReduceSoftDeoptimize(
- node,
- DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
- }
- return NoChange();
- }
-
// Extract receiver maps from the {nexus}.
MapHandles receiver_maps;
if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
@@ -1376,6 +1441,7 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
}
return NoChange();
}
+ DCHECK(!nexus.IsUninitialized());
// Optimize access for constant {index}.
HeapObjectMatcher mindex(index);
@@ -1543,9 +1609,9 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
}
}
- // Extract receiver maps from the keyed load IC using the KeyedLoadICNexus.
+ // Extract receiver maps from the keyed load IC using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
- KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
+ FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Extract the keyed access load mode from the keyed load IC.
KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
@@ -1561,9 +1627,9 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
Node* const index = NodeProperties::GetValueInput(node, 1);
Node* const value = NodeProperties::GetValueInput(node, 2);
- // Extract receiver maps from the keyed store IC using the KeyedStoreICNexus.
+ // Extract receiver maps from the keyed store IC using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
- KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
+ FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Extract the keyed access store mode from the keyed store IC.
KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
@@ -1663,7 +1729,7 @@ Node* JSNativeContextSpecialization::InlineApiCall(
CallApiCallbackStub stub(isolate(), argc);
CallInterfaceDescriptor call_interface_descriptor =
stub.GetCallInterfaceDescriptor();
- CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
+ auto call_descriptor = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), call_interface_descriptor,
call_interface_descriptor.GetStackParameterCount() + argc +
1 /* implicit receiver */,
@@ -1960,8 +2026,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
if (!p.feedback().IsValid()) return NoChange();
- StoreDataPropertyInLiteralICNexus nexus(p.feedback().vector(),
- p.feedback().slot());
+ FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
if (nexus.IsUninitialized()) {
return NoChange();
}
@@ -2124,12 +2189,18 @@ JSNativeContextSpecialization::BuildElementAccess(
if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
- // Check that the {index} is a valid array index, we do the actual
- // bounds check below and just skip the store below if it's out of
+ // Only check that the {index} is in Signed32 range. We do the actual
+ // bounds check below and just skip the property access if it's out of
// bounds for the {receiver}.
index = effect = graph()->NewNode(
- simplified()->CheckBounds(VectorSlotPair()), index,
- jsgraph()->Constant(Smi::kMaxValue), effect, control);
+ simplified()->SpeculativeToNumber(NumberOperationHint::kSigned32,
+ VectorSlotPair()),
+ index, effect, control);
+
+ // Cast the {index} to Unsigned32 range, so that the bounds checks
+ // below are performed on unsigned values, which means that all the
+ // Negative32 values are treated as out-of-bounds.
+ index = graph()->NewNode(simplified()->NumberToUint32(), index);
} else {
// Check that the {index} is in the valid range for the {receiver}.
index = effect =
@@ -2193,10 +2264,10 @@ JSNativeContextSpecialization::BuildElementAccess(
case AccessMode::kStore: {
// Ensure that the {value} is actually a Number or an Oddball,
// and truncate it to a Number appropriately.
- value = effect =
- graph()->NewNode(simplified()->SpeculativeToNumber(
- NumberOperationHint::kNumberOrOddball),
- value, effect, control);
+ value = effect = graph()->NewNode(
+ simplified()->SpeculativeToNumber(
+ NumberOperationHint::kNumberOrOddball, VectorSlotPair()),
+ value, effect, control);
// Introduce the appropriate truncation for {value}. Currently we
// only need to do this for ClamedUint8Array {receiver}s, as the
@@ -2246,10 +2317,11 @@ JSNativeContextSpecialization::BuildElementAccess(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
effect, control);
- // Don't try to store to a copy-on-write backing store.
+ // Don't try to store to a copy-on-write backing store (unless supported by
+ // the store mode).
if (access_mode == AccessMode::kStore &&
IsSmiOrObjectElementsKind(elements_kind) &&
- store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
+ !IsCOWHandlingStoreMode(store_mode)) {
effect = graph()->NewNode(
simplified()->CheckMaps(
CheckMapsFlag::kNone,
@@ -2459,6 +2531,15 @@ JSNativeContextSpecialization::BuildElementAccess(
simplified()->MaybeGrowFastElements(mode, VectorSlotPair()),
receiver, elements, index, elements_length, effect, control);
+ // If we didn't grow {elements}, it might still be COW, in which case we
+ // copy it now.
+ if (IsSmiOrObjectElementsKind(elements_kind) &&
+ store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW) {
+ elements = effect =
+ graph()->NewNode(simplified()->EnsureWritableFastElements(),
+ receiver, elements, effect, control);
+ }
+
// Also update the "length" property if {receiver} is a JSArray.
if (receiver_is_jsarray) {
Node* check =
@@ -2524,13 +2605,16 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
graph()->NewNode(simplified()->MaskIndexWithBound(), index, length);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver,
- masked_index, if_true);
+ Node* etrue;
+ Node* vtrue = etrue = graph()->NewNode(
+ simplified()->StringCharAt(), receiver, masked_index, *effect, if_true);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = jsgraph()->UndefinedConstant();
*control = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ *effect =
+ graph()->NewNode(common()->EffectPhi(2), etrue, *effect, *control);
return graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue, vfalse, *control);
} else {
@@ -2543,8 +2627,10 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
graph()->NewNode(simplified()->MaskIndexWithBound(), index, length);
// Return the character from the {receiver} as single character string.
- return graph()->NewNode(simplified()->StringCharAt(), receiver,
- masked_index, *control);
+ Node* value = *effect =
+ graph()->NewNode(simplified()->StringCharAt(), receiver, masked_index,
+ *effect, *control);
+ return value;
}
}
@@ -2652,6 +2738,7 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
Node* receiver, Node* effect, FeedbackNexus const& nexus,
MapHandles* receiver_maps) {
DCHECK_EQ(0, receiver_maps->size());
+ if (nexus.IsUninitialized()) return true;
// See if we can infer a concrete type for the {receiver}.
if (InferReceiverMaps(receiver, effect, receiver_maps)) {
// We can assume that the {receiver} still has the inferred {receiver_maps}.