aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-call-reducer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-call-reducer.cc')
-rw-r--r--deps/v8/src/compiler/js-call-reducer.cc1358
1 files changed, 664 insertions, 694 deletions
diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc
index 5b04731a64..d16e38a458 100644
--- a/deps/v8/src/compiler/js-call-reducer.cc
+++ b/deps/v8/src/compiler/js-call-reducer.cc
@@ -5,10 +5,9 @@
#include "src/compiler/js-call-reducer.h"
#include "src/api-inl.h"
-#include "src/builtins/builtins-promise-gen.h"
+#include "src/builtins/builtins-promise.h"
#include "src/builtins/builtins-utils.h"
#include "src/code-factory.h"
-#include "src/code-stubs.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/access-info.h"
#include "src/compiler/allocation-builder.h"
@@ -253,8 +252,8 @@ Reduction JSCallReducer::ReduceObjectConstructor(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
// We can fold away the Object(x) call if |x| is definitely not a primitive.
- if (NodeProperties::CanBePrimitive(isolate(), value, effect)) {
- if (!NodeProperties::CanBeNullOrUndefined(isolate(), value, effect)) {
+ if (NodeProperties::CanBePrimitive(broker(), value, effect)) {
+ if (!NodeProperties::CanBeNullOrUndefined(broker(), value, effect)) {
// Turn the {node} into a {JSToObject} call if we know that
// the {value} cannot be null or undefined.
NodeProperties::ReplaceValueInputs(node, value);
@@ -295,7 +294,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
// If {arguments_list} cannot be null or undefined, we don't need
// to expand this {node} to control-flow.
- if (!NodeProperties::CanBeNullOrUndefined(isolate(), arguments_list,
+ if (!NodeProperties::CanBeNullOrUndefined(broker(), arguments_list,
effect)) {
// Massage the value inputs appropriately.
node->ReplaceInput(0, target);
@@ -408,30 +407,37 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
// definitely a constructor or not a constructor.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
- bool const is_constructor = receiver_maps[0]->is_constructor();
- Handle<Object> const prototype(receiver_maps[0]->prototype(), isolate());
- for (Handle<Map> const receiver_map : receiver_maps) {
+ MapRef first_receiver_map(broker(), receiver_maps[0]);
+ bool const is_constructor = first_receiver_map.is_constructor();
+ first_receiver_map.SerializePrototype();
+ ObjectRef const prototype = first_receiver_map.prototype();
+ for (Handle<Map> const map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+
// Check for consistency among the {receiver_maps}.
STATIC_ASSERT(LAST_TYPE == LAST_FUNCTION_TYPE);
- if (receiver_map->prototype() != *prototype) return NoChange();
- if (receiver_map->is_constructor() != is_constructor) return NoChange();
- if (receiver_map->instance_type() < FIRST_FUNCTION_TYPE) return NoChange();
+ receiver_map.SerializePrototype();
+ if (!receiver_map.prototype().equals(prototype) ||
+ receiver_map.is_constructor() != is_constructor ||
+ receiver_map.instance_type() < FIRST_FUNCTION_TYPE) {
+ return NoChange();
+ }
// Disallow binding of slow-mode functions. We need to figure out
// whether the length and name property are in the original state.
- if (receiver_map->is_dictionary_map()) return NoChange();
+ if (receiver_map.is_dictionary_map()) return NoChange();
// Check whether the length and name properties are still present
// as AccessorInfo objects. In that case, their values can be
// recomputed even if the actual value of the object changes.
// This mirrors the checks done in builtins-function-gen.cc at
// runtime otherwise.
- Handle<DescriptorArray> descriptors(receiver_map->instance_descriptors(),
- isolate());
+ Handle<DescriptorArray> descriptors(
+ receiver_map.object()->instance_descriptors(), isolate());
if (descriptors->number_of_descriptors() < 2) return NoChange();
if (descriptors->GetKey(JSFunction::kLengthDescriptorIndex) !=
ReadOnlyRoots(isolate()).length_string()) {
@@ -451,16 +457,12 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
}
}
- // Setup the map for the resulting JSBoundFunction with the
- // correct instance {prototype}.
- Handle<Map> map(
- is_constructor
- ? native_context()->bound_function_with_constructor_map()
- : native_context()->bound_function_without_constructor_map(),
- isolate());
- if (map->prototype() != *prototype) {
- map = Map::TransitionToPrototype(isolate(), map, prototype);
- }
+ // Choose the map for the resulting JSBoundFunction (but bail out in case of a
+ // custom prototype).
+ MapRef map = is_constructor
+ ? native_context().bound_function_with_constructor_map()
+ : native_context().bound_function_without_constructor_map();
+ if (!map.prototype().equals(prototype)) return NoChange();
// Make sure we can rely on the {receiver_maps}.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -481,8 +483,9 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
inputs[2 + arity + 0] = context;
inputs[2 + arity + 1] = effect;
inputs[2 + arity + 2] = control;
- Node* value = effect = graph()->NewNode(
- javascript()->CreateBoundFunction(arity, map), input_count, inputs);
+ Node* value = effect =
+ graph()->NewNode(javascript()->CreateBoundFunction(arity, map.object()),
+ input_count, inputs);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
@@ -500,8 +503,8 @@ Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
Node* context;
HeapObjectMatcher m(target);
if (m.HasValue()) {
- Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
- context = jsgraph()->HeapConstant(handle(function->context(), isolate()));
+ JSFunctionRef function = m.Ref(broker()).AsJSFunction();
+ context = jsgraph()->Constant(function.context());
} else {
context = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
@@ -570,18 +573,19 @@ Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
// Try to determine the {object} map.
ZoneHandleSet<Map> object_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), object, effect,
- &object_maps);
+ NodeProperties::InferReceiverMaps(broker(), object, effect, &object_maps);
if (result != NodeProperties::kNoReceiverMaps) {
- Handle<Map> candidate_map = object_maps[0];
- Handle<Object> candidate_prototype(candidate_map->prototype(), isolate());
+ MapRef candidate_map(broker(), object_maps[0]);
+ candidate_map.SerializePrototype();
+ ObjectRef candidate_prototype = candidate_map.prototype();
// Check if we can constant-fold the {candidate_prototype}.
for (size_t i = 0; i < object_maps.size(); ++i) {
- Handle<Map> object_map = object_maps[i];
- if (object_map->IsSpecialReceiverMap() ||
- object_map->has_hidden_prototype() ||
- object_map->prototype() != *candidate_prototype) {
+ MapRef object_map(broker(), object_maps[i]);
+ object_map.SerializePrototype();
+ if (IsSpecialReceiverInstanceType(object_map.instance_type()) ||
+ object_map.has_hidden_prototype() ||
+ !object_map.prototype().equals(candidate_prototype)) {
// We exclude special receivers, like JSProxy or API objects that
// might require access checks here; we also don't want to deal
// with hidden prototypes at this point.
@@ -589,16 +593,15 @@ Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
}
// The above check also excludes maps for primitive values, which is
// important because we are not applying [[ToObject]] here as expected.
- DCHECK(!object_map->IsPrimitiveMap() && object_map->IsJSReceiverMap());
+ DCHECK(!object_map.IsPrimitiveMap() && object_map.IsJSReceiverMap());
if (result == NodeProperties::kUnreliableReceiverMaps &&
- !object_map->is_stable()) {
+ !object_map.is_stable()) {
return NoChange();
}
}
if (result == NodeProperties::kUnreliableReceiverMaps) {
for (size_t i = 0; i < object_maps.size(); ++i) {
- dependencies()->DependOnStableMap(
- MapRef(js_heap_broker(), object_maps[i]));
+ dependencies()->DependOnStableMap(MapRef(broker(), object_maps[i]));
}
}
Node* value = jsgraph()->Constant(candidate_prototype);
@@ -731,11 +734,12 @@ Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) {
// the ToObject step of Object.prototype.isPrototypeOf is a no-op).
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
- for (size_t i = 0; i < receiver_maps.size(); ++i) {
- if (!receiver_maps[i]->IsJSReceiverMap()) return NoChange();
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.IsJSReceiverMap()) return NoChange();
}
// We don't check whether {value} is a proper JSReceiver here explicitly,
@@ -852,10 +856,10 @@ Reduction JSCallReducer::ReduceReflectGet(Node* node) {
{
if_false = efalse = graph()->NewNode(
javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
- jsgraph()->Constant(MessageTemplate::kCalledOnNonObject),
- jsgraph()->HeapConstant(
- factory()->NewStringFromAsciiChecked("Reflect.get")),
- context, frame_state, efalse, if_false);
+ jsgraph()->Constant(
+ static_cast<int>(MessageTemplate::kCalledOnNonObject)),
+ jsgraph()->HeapConstant(factory()->ReflectGet_string()), context,
+ frame_state, efalse, if_false);
}
// Otherwise just use the existing GetPropertyStub.
@@ -929,10 +933,10 @@ Reduction JSCallReducer::ReduceReflectHas(Node* node) {
{
if_false = efalse = graph()->NewNode(
javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
- jsgraph()->Constant(MessageTemplate::kCalledOnNonObject),
- jsgraph()->HeapConstant(
- factory()->NewStringFromAsciiChecked("Reflect.has")),
- context, frame_state, efalse, if_false);
+ jsgraph()->Constant(
+ static_cast<int>(MessageTemplate::kCalledOnNonObject)),
+ jsgraph()->HeapConstant(factory()->ReflectHas_string()), context,
+ frame_state, efalse, if_false);
}
// Otherwise just use the existing {JSHasProperty} logic.
@@ -973,17 +977,6 @@ Reduction JSCallReducer::ReduceReflectHas(Node* node) {
return Changed(vtrue);
}
-bool CanInlineArrayIteratingBuiltin(Isolate* isolate,
- Handle<Map> receiver_map) {
- if (!receiver_map->prototype()->IsJSArray()) return false;
- Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
- isolate);
- return receiver_map->instance_type() == JS_ARRAY_TYPE &&
- IsFastElementsKind(receiver_map->elements_kind()) &&
- isolate->IsNoElementsProtectorIntact() &&
- isolate->IsAnyInitialArrayPrototype(receiver_prototype);
-}
-
Node* JSCallReducer::WireInLoopStart(Node* k, Node** control, Node** effect) {
Node* loop = *control =
graph()->NewNode(common()->Loop(2), *control, *control);
@@ -1002,8 +995,50 @@ void JSCallReducer::WireInLoopEnd(Node* loop, Node* eloop, Node* vloop, Node* k,
eloop->ReplaceInput(1, effect);
}
-Reduction JSCallReducer::ReduceArrayForEach(Node* node,
- Handle<SharedFunctionInfo> shared) {
+namespace {
+bool CanInlineArrayIteratingBuiltin(JSHeapBroker* broker,
+ ZoneHandleSet<Map> receiver_maps,
+ ElementsKind* kind_return) {
+ DCHECK_NE(0, receiver_maps.size());
+ *kind_return = MapRef(broker, receiver_maps[0]).elements_kind();
+ for (auto receiver_map : receiver_maps) {
+ MapRef map(broker, receiver_map);
+ if (!map.supports_fast_array_iteration() ||
+ !UnionElementsKindUptoSize(kind_return, map.elements_kind())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CanInlineArrayResizingBuiltin(JSHeapBroker* broker,
+ ZoneHandleSet<Map> receiver_maps,
+ ElementsKind* kind_return,
+ bool builtin_is_push = false) {
+ DCHECK_NE(0, receiver_maps.size());
+ *kind_return = MapRef(broker, receiver_maps[0]).elements_kind();
+ for (auto receiver_map : receiver_maps) {
+ MapRef map(broker, receiver_map);
+ if (!map.supports_fast_array_resize()) return false;
+ if (builtin_is_push) {
+ if (!UnionElementsKindUptoPackedness(kind_return, map.elements_kind())) {
+ return false;
+ }
+ } else {
+ // TODO(turbofan): We should also handle fast holey double elements once
+ // we got the hole NaN mess sorted out in TurboFan/V8.
+ if (map.elements_kind() == HOLEY_DOUBLE_ELEMENTS ||
+ !UnionElementsKindUptoSize(kind_return, map.elements_kind())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+} // namespace
+
+Reduction JSCallReducer::ReduceArrayForEach(
+ Node* node, const SharedFunctionInfoRef& shared) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1026,36 +1061,19 @@ Reduction JSCallReducer::ReduceArrayForEach(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
- // By ensuring that {kind} is object or double, we can be polymorphic
- // on different elements kinds.
- ElementsKind kind = receiver_maps[0]->elements_kind();
- if (IsSmiElementsKind(kind)) {
- kind = FastSmiToObjectElementsKind(kind);
- }
- for (Handle<Map> receiver_map : receiver_maps) {
- ElementsKind next_kind = receiver_map->elements_kind();
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map)) {
- return NoChange();
- }
- if (!IsFastElementsKind(next_kind)) {
- return NoChange();
- }
- if (IsDoubleElementsKind(kind) != IsDoubleElementsKind(next_kind)) {
- return NoChange();
- }
- if (IsHoleyElementsKind(next_kind)) {
- kind = GetHoleyElementsKind(kind);
- }
+ ElementsKind kind;
+ if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -1180,6 +1198,11 @@ Reduction JSCallReducer::ReduceArrayForEach(Node* node,
control = if_false;
effect = eloop;
+ // Introduce proper LoopExit and LoopExitEffect nodes to mark
+ // {loop} as a candidate for loop peeling (crbug.com/v8/8273).
+ control = graph()->NewNode(common()->LoopExit(), control, loop);
+ effect = graph()->NewNode(common()->LoopExitEffect(), effect, control);
+
// Wire up the branch for the case when IsCallable fails for the callback.
// Since {check_throw} is an unconditional throw, it's impossible to
// return a successful completion. Therefore, we simply connect the successful
@@ -1192,9 +1215,9 @@ Reduction JSCallReducer::ReduceArrayForEach(Node* node,
return Replace(jsgraph()->UndefinedConstant());
}
-Reduction JSCallReducer::ReduceArrayReduce(Node* node,
- ArrayReduceDirection direction,
- Handle<SharedFunctionInfo> shared) {
+Reduction JSCallReducer::ReduceArrayReduce(
+ Node* node, ArrayReduceDirection direction,
+ const SharedFunctionInfoRef& shared) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1216,16 +1239,13 @@ Reduction JSCallReducer::ReduceArrayReduce(Node* node,
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
- ElementsKind kind = receiver_maps[0]->elements_kind();
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
- return NoChange();
- if (!UnionElementsKindUptoSize(&kind, receiver_map->elements_kind()))
- return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
std::function<Node*(Node*)> hole_check = [this, kind](Node* element) {
@@ -1240,7 +1260,7 @@ Reduction JSCallReducer::ReduceArrayReduce(Node* node,
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -1470,7 +1490,7 @@ Reduction JSCallReducer::ReduceArrayReduce(Node* node,
}
Reduction JSCallReducer::ReduceArrayMap(Node* node,
- Handle<SharedFunctionInfo> shared) {
+ const SharedFunctionInfoRef& shared) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1493,37 +1513,28 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// Ensure that any changes to the Array species constructor cause deopt.
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
- const ElementsKind kind = receiver_maps[0]->elements_kind();
-
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
- return NoChange();
- // We can handle different maps, as long as their elements kind are the
- // same.
- if (receiver_map->elements_kind() != kind) return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
if (IsHoleyElementsKind(kind)) {
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
}
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
-
- Handle<JSFunction> handle_constructor(
- JSFunction::cast(
- native_context()->GetInitialJSArrayMap(kind)->GetConstructor()),
- isolate());
- Node* array_constructor = jsgraph()->HeapConstant(handle_constructor);
+ PropertyCellRef(broker(), factory()->array_species_protector()));
+ Node* array_constructor = jsgraph()->Constant(
+ native_context().GetInitialJSArrayMap(kind).GetConstructor());
Node* k = jsgraph()->ZeroConstant();
@@ -1643,15 +1654,12 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
// The array {a} should be HOLEY_SMI_ELEMENTS because we'd only come into this
// loop if the input array length is non-zero, and "new Array({x > 0})" always
// produces a HOLEY array.
- Handle<Map> double_map(Map::cast(native_context()->get(
- Context::ArrayMapIndex(HOLEY_DOUBLE_ELEMENTS))),
- isolate());
- Handle<Map> fast_map(
- Map::cast(native_context()->get(Context::ArrayMapIndex(HOLEY_ELEMENTS))),
- isolate());
- effect = graph()->NewNode(
- simplified()->TransitionAndStoreElement(double_map, fast_map), a, k,
- callback_value, effect, control);
+ MapRef holey_double_map =
+ native_context().GetInitialJSArrayMap(HOLEY_DOUBLE_ELEMENTS);
+ MapRef holey_map = native_context().GetInitialJSArrayMap(HOLEY_ELEMENTS);
+ effect = graph()->NewNode(simplified()->TransitionAndStoreElement(
+ holey_double_map.object(), holey_map.object()),
+ a, k, callback_value, effect, control);
if (IsHoleyElementsKind(kind)) {
Node* after_call_and_store_control = control;
@@ -1682,8 +1690,8 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
return Replace(a);
}
-Reduction JSCallReducer::ReduceArrayFilter(Node* node,
- Handle<SharedFunctionInfo> shared) {
+Reduction JSCallReducer::ReduceArrayFilter(
+ Node* node, const SharedFunctionInfoRef& shared) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1705,37 +1713,30 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// And ensure that any changes to the Array species constructor cause deopt.
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
- const ElementsKind kind = receiver_maps[0]->elements_kind();
+ ElementsKind kind;
+ if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
+ }
+
// The output array is packed (filter doesn't visit holes).
const ElementsKind packed_kind = GetPackedElementsKind(kind);
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map)) {
- return NoChange();
- }
- // We can handle different maps, as long as their elements kind are the
- // same.
- if (receiver_map->elements_kind() != kind) return NoChange();
- }
-
if (IsHoleyElementsKind(kind)) {
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
}
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
+ PropertyCellRef(broker(), factory()->array_species_protector()));
- Handle<Map> initial_map(
- Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)),
- isolate());
+ MapRef initial_map = native_context().GetInitialJSArrayMap(packed_kind);
Node* k = jsgraph()->ZeroConstant();
Node* to = jsgraph()->ZeroConstant();
@@ -1751,16 +1752,15 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
Node* a; // Construct the output array.
{
AllocationBuilder ab(jsgraph(), effect, control);
- ab.Allocate(initial_map->instance_size(), NOT_TENURED, Type::Array());
+ ab.Allocate(initial_map.instance_size(), NOT_TENURED, Type::Array());
ab.Store(AccessBuilder::ForMap(), initial_map);
Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
ab.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array);
ab.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
ab.Store(AccessBuilder::ForJSArrayLength(packed_kind),
jsgraph()->ZeroConstant());
- for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
- ab.Store(AccessBuilder::ForJSObjectInObjectProperty(
- MapRef(js_heap_broker(), initial_map), i),
+ for (int i = 0; i < initial_map.GetInObjectProperties(); ++i) {
+ ab.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
jsgraph()->UndefinedConstant());
}
a = effect = ab.Finish();
@@ -1947,7 +1947,7 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
}
Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
- Handle<SharedFunctionInfo> shared) {
+ const SharedFunctionInfoRef& shared) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1988,24 +1988,19 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
- const ElementsKind kind = receiver_maps[0]->elements_kind();
-
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
- return NoChange();
- // We can handle different maps, as long as their elements kind are the
- // same.
- if (receiver_map->elements_kind() != kind) return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -2140,10 +2135,16 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
Node* if_not_found_value = (variant == ArrayFindVariant::kFind)
? jsgraph()->UndefinedConstant()
: jsgraph()->MinusOneConstant();
- Node* return_value =
+ Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
if_found_return_value, if_not_found_value, control);
+ // Introduce proper LoopExit/LoopExitEffect/LoopExitValue to mark
+ // {loop} as a candidate for loop peeling (crbug.com/v8/8273).
+ control = graph()->NewNode(common()->LoopExit(), control, loop);
+ effect = graph()->NewNode(common()->LoopExitEffect(), effect, control);
+ value = graph()->NewNode(common()->LoopExitValue(), value, control);
+
// Wire up the branch for the case when IsCallable fails for the callback.
// Since {check_throw} is an unconditional throw, it's impossible to
// return a successful completion. Therefore, we simply connect the successful
@@ -2152,8 +2153,8 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
graph()->NewNode(common()->Throw(), check_throw, check_fail);
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
- ReplaceWithValue(node, return_value, effect, control);
- return Replace(return_value);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
}
Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node** control,
@@ -2174,10 +2175,10 @@ Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node** control,
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), a, etrue,
if_true);
- DCHECK(TypeCache::Get().kFixedDoubleArrayLengthType.Is(
- TypeCache::Get().kFixedArrayLengthType));
+ DCHECK(TypeCache::Get()->kFixedDoubleArrayLengthType.Is(
+ TypeCache::Get()->kFixedArrayLengthType));
Node* checked_to = etrue = graph()->NewNode(
- common()->TypeGuard(TypeCache::Get().kFixedArrayLengthType), to, etrue,
+ common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), to, etrue,
if_true);
Node* elements_length = etrue = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), elements,
@@ -2226,8 +2227,9 @@ void JSCallReducer::WireInCallbackIsCallableCheck(
*check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
*check_throw = *check_fail = graph()->NewNode(
javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
- jsgraph()->Constant(MessageTemplate::kCalledNonCallable), fncallback,
- context, check_frame_state, effect, *check_fail);
+ jsgraph()->Constant(
+ static_cast<int>(MessageTemplate::kCalledNonCallable)),
+ fncallback, context, check_frame_state, effect, *check_fail);
*control = graph()->NewNode(common()->IfTrue(), check_branch);
}
@@ -2280,7 +2282,7 @@ Node* JSCallReducer::SafeLoadElement(ElementsKind kind, Node* receiver,
}
Reduction JSCallReducer::ReduceArrayEvery(Node* node,
- Handle<SharedFunctionInfo> shared) {
+ const SharedFunctionInfoRef& shared) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -2302,30 +2304,25 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// And ensure that any changes to the Array species constructor cause deopt.
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
- const ElementsKind kind = receiver_maps[0]->elements_kind();
-
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
- return NoChange();
- // We can handle different maps, as long as their elements kind are the
- // same.
- if (receiver_map->elements_kind() != kind) return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
if (IsHoleyElementsKind(kind)) {
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
}
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
+ PropertyCellRef(broker(), factory()->array_species_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -2488,10 +2485,16 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
control = graph()->NewNode(common()->Merge(2), if_false, if_false_callback);
effect =
graph()->NewNode(common()->EffectPhi(2), eloop, efalse_callback, control);
- Node* return_value = graph()->NewNode(
+ Node* value = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2),
jsgraph()->TrueConstant(), jsgraph()->FalseConstant(), control);
+ // Introduce proper LoopExit/LoopExitEffect/LoopExitValue to mark
+ // {loop} as a candidate for loop peeling (crbug.com/v8/8273).
+ control = graph()->NewNode(common()->LoopExit(), control, loop);
+ effect = graph()->NewNode(common()->LoopExitEffect(), effect, control);
+ value = graph()->NewNode(common()->LoopExitValue(), value, control);
+
// Wire up the branch for the case when IsCallable fails for the callback.
// Since {check_throw} is an unconditional throw, it's impossible to
// return a successful completion. Therefore, we simply connect the successful
@@ -2500,8 +2503,8 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
graph()->NewNode(common()->Throw(), check_throw, check_fail);
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
- ReplaceWithValue(node, return_value, effect, control);
- return Replace(return_value);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
}
namespace {
@@ -2562,23 +2565,23 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
return NoChange();
}
- Handle<Map> receiver_map;
- if (!NodeProperties::GetMapWitness(isolate(), node).ToHandle(&receiver_map))
+ Handle<Map> map;
+ if (!NodeProperties::GetMapWitness(broker(), node).ToHandle(&map))
return NoChange();
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
- return NoChange();
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.supports_fast_array_iteration()) return NoChange();
- if (IsHoleyElementsKind(receiver_map->elements_kind())) {
+ ElementsKind const elements_kind = receiver_map.elements_kind();
+ if (IsHoleyElementsKind(elements_kind)) {
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
}
Callable const callable =
search_variant == SearchVariant::kIndexOf
- ? GetCallableForArrayIndexOf(receiver_map->elements_kind(), isolate())
- : GetCallableForArrayIncludes(receiver_map->elements_kind(),
- isolate());
+ ? GetCallableForArrayIndexOf(elements_kind, isolate())
+ : GetCallableForArrayIncludes(elements_kind, isolate());
CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(),
callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
@@ -2596,8 +2599,7 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
Node* length = effect = graph()->NewNode(
- simplified()->LoadField(
- AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
+ simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)),
receiver, effect, control);
Node* new_from_index = jsgraph()->ZeroConstant();
if (node->op()->ValueInputCount() >= 4) {
@@ -2627,7 +2629,7 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
}
Reduction JSCallReducer::ReduceArraySome(Node* node,
- Handle<SharedFunctionInfo> shared) {
+ const SharedFunctionInfoRef& shared) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -2649,32 +2651,25 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// And ensure that any changes to the Array species constructor cause deopt.
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
- if (receiver_maps.size() == 0) return NoChange();
-
- const ElementsKind kind = receiver_maps[0]->elements_kind();
-
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
- return NoChange();
- // We can handle different maps, as long as their elements kind are the
- // same.
- if (receiver_map->elements_kind() != kind) return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
if (IsHoleyElementsKind(kind)) {
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
}
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
+ PropertyCellRef(broker(), factory()->array_species_protector()));
Node* k = jsgraph()->ZeroConstant();
@@ -2844,10 +2839,16 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
control = graph()->NewNode(common()->Merge(2), if_false, if_true_callback);
effect =
graph()->NewNode(common()->EffectPhi(2), eloop, etrue_callback, control);
- Node* return_value = graph()->NewNode(
+ Node* value = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2),
jsgraph()->FalseConstant(), jsgraph()->TrueConstant(), control);
+ // Introduce proper LoopExit/LoopExitEffect/LoopExitValue to mark
+ // {loop} as a candidate for loop peeling (crbug.com/v8/8273).
+ control = graph()->NewNode(common()->LoopExit(), control, loop);
+ effect = graph()->NewNode(common()->LoopExitEffect(), effect, control);
+ value = graph()->NewNode(common()->LoopExitValue(), value, control);
+
// Wire up the branch for the case when IsCallable fails for the callback.
// Since {check_throw} is an unconditional throw, it's impossible to
// return a successful completion. Therefore, we simply connect the successful
@@ -2856,48 +2857,44 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
graph()->NewNode(common()->Throw(), check_throw, check_fail);
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
- ReplaceWithValue(node, return_value, effect, control);
- return Replace(return_value);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
}
Reduction JSCallReducer::ReduceCallApiFunction(
- Node* node, Handle<SharedFunctionInfo> shared) {
+ Node* node, const SharedFunctionInfoRef& shared) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
int const argc = static_cast<int>(p.arity()) - 2;
Node* target = NodeProperties::GetValueInput(node, 0);
- Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined)
- ? jsgraph()->HeapConstant(global_proxy())
- : NodeProperties::GetValueInput(node, 1);
+ Node* receiver =
+ (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined)
+ ? jsgraph()->Constant(native_context().global_proxy_object())
+ : NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Handle<FunctionTemplateInfo> function_template_info(
- FunctionTemplateInfo::cast(shared->function_data()), isolate());
-
- // CallApiCallbackStub expects the target in a register, so we count it out,
- // and counts the receiver as an implicit argument, so we count the receiver
- // out too.
- if (argc > CallApiCallbackStub::kArgMax) return NoChange();
+ FunctionTemplateInfo::cast(shared.object()->function_data()), isolate());
// Infer the {receiver} maps, and check if we can inline the API function
// callback based on those.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
- for (size_t i = 0; i < receiver_maps.size(); ++i) {
- Handle<Map> receiver_map = receiver_maps[i];
- if (!receiver_map->IsJSObjectMap() ||
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.IsJSObjectMap() ||
(!function_template_info->accept_any_receiver() &&
- receiver_map->is_access_check_needed())) {
+ receiver_map.is_access_check_needed())) {
return NoChange();
}
// In case of unreliable {receiver} information, the {receiver_maps}
// must all be stable in order to consume the information.
if (result == NodeProperties::kUnreliableReceiverMaps) {
- if (!receiver_map->is_stable()) return NoChange();
+ if (!receiver_map.is_stable()) return NoChange();
}
}
@@ -2918,9 +2915,9 @@ Reduction JSCallReducer::ReduceCallApiFunction(
// Install stability dependencies for unreliable {receiver_maps}.
if (result == NodeProperties::kUnreliableReceiverMaps) {
- for (size_t i = 0; i < receiver_maps.size(); ++i) {
- dependencies()->DependOnStableMap(
- MapRef(js_heap_broker(), receiver_maps[i]));
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ dependencies()->DependOnStableMap(receiver_map);
}
}
@@ -2937,7 +2934,7 @@ Reduction JSCallReducer::ReduceCallApiFunction(
Handle<CallHandlerInfo> call_handler_info(
CallHandlerInfo::cast(function_template_info->call_code()), isolate());
Handle<Object> data(call_handler_info->data(), isolate());
- Callable call_api_callback = CodeFactory::CallApiCallback(isolate(), argc);
+ Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
CallInterfaceDescriptor cid = call_api_callback.descriptor();
auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), cid,
@@ -2952,13 +2949,14 @@ Reduction JSCallReducer::ReduceCallApiFunction(
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(call_api_callback.code()));
node->ReplaceInput(1, context);
- node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data));
- node->InsertInput(graph()->zone(), 3, holder);
- node->InsertInput(graph()->zone(), 4,
+ node->InsertInput(graph()->zone(), 2,
jsgraph()->ExternalConstant(function_reference));
- node->ReplaceInput(5, receiver);
- node->RemoveInput(6 + argc); // Remove context input.
- node->ReplaceInput(7 + argc, effect); // Update effect input.
+ node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(argc));
+ node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(data));
+ node->InsertInput(graph()->zone(), 5, holder);
+ node->ReplaceInput(6, receiver);
+ node->RemoveInput(7 + argc); // Remove context input.
+ node->ReplaceInput(8 + argc, effect); // Update effect input.
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
return Changed(node);
}
@@ -3018,8 +3016,9 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
FieldAccess const& access = FieldAccessOf(user->op());
if (access.offset == JSArray::kLengthOffset) {
// Ignore uses for arguments#length.
- STATIC_ASSERT(JSArray::kLengthOffset ==
- JSArgumentsObjectWithLength::kLengthOffset);
+ STATIC_ASSERT(
+ static_cast<int>(JSArray::kLengthOffset) ==
+ static_cast<int>(JSArgumentsObjectWithLength::kLengthOffset));
continue;
} else if (access.offset == JSObject::kElementsOffset) {
// Ignore safe uses for arguments#elements.
@@ -3066,10 +3065,15 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list);
FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
int start_index = 0;
- // Determine the formal parameter count;
- Handle<SharedFunctionInfo> shared;
- if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
- int formal_parameter_count = shared->internal_formal_parameter_count();
+
+ int formal_parameter_count;
+ {
+ Handle<SharedFunctionInfo> shared;
+ if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
+ formal_parameter_count = SharedFunctionInfoRef(broker(), shared)
+ .internal_formal_parameter_count();
+ }
+
if (type == CreateArgumentsType::kMappedArguments) {
// Mapped arguments (sloppy mode) that are aliased can only be handled
// here if there's no side-effect between the {node} and the {arg_array}.
@@ -3090,8 +3094,8 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
// that no one messed with the %ArrayIteratorPrototype%.next method.
if (node->opcode() == IrOpcode::kJSCallWithSpread ||
node->opcode() == IrOpcode::kJSConstructWithSpread) {
- dependencies()->DependOnProtector(PropertyCellRef(
- js_heap_broker(), factory()->array_iterator_protector()));
+ dependencies()->DependOnProtector(
+ PropertyCellRef(broker(), factory()->array_iterator_protector()));
}
// Remove the {arguments_list} input from the {node}.
@@ -3146,10 +3150,10 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
Node* check_branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
- Node* check_throw = check_fail =
- graph()->NewNode(javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
- jsgraph()->Constant(MessageTemplate::kNotConstructor),
- new_target, context, frame_state, effect, check_fail);
+ Node* check_throw = check_fail = graph()->NewNode(
+ javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
+ jsgraph()->Constant(static_cast<int>(MessageTemplate::kNotConstructor)),
+ new_target, context, frame_state, effect, check_fail);
control = graph()->NewNode(common()->IfTrue(), check_branch);
NodeProperties::ReplaceControlInput(node, control);
@@ -3211,6 +3215,13 @@ bool ShouldUseCallICFeedback(Node* node) {
return true;
}
+base::Optional<HeapObjectRef> GetHeapObjectFeedback(
+ JSHeapBroker* broker, const FeedbackNexus& nexus) {
+ HeapObject object;
+ if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
+ return HeapObjectRef(broker, handle(object, broker->isolate()));
+}
+
} // namespace
Reduction JSCallReducer::ReduceJSCall(Node* node) {
@@ -3225,40 +3236,45 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
// Try to specialize JSCall {node}s with constant {target}s.
HeapObjectMatcher m(target);
if (m.HasValue()) {
- if (m.Value()->IsJSFunction()) {
- Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
+ ObjectRef target_ref = m.Ref(broker());
+ if (target_ref.IsJSFunction()) {
+ JSFunctionRef function = target_ref.AsJSFunction();
+ function.Serialize();
// Don't inline cross native context.
- if (function->native_context() != *native_context()) return NoChange();
-
- return ReduceJSCall(node, handle(function->shared(), isolate()));
- } else if (m.Value()->IsJSBoundFunction()) {
- Handle<JSBoundFunction> function =
- Handle<JSBoundFunction>::cast(m.Value());
- Handle<JSReceiver> bound_target_function(
- function->bound_target_function(), isolate());
- Handle<Object> bound_this(function->bound_this(), isolate());
- Handle<FixedArray> bound_arguments(function->bound_arguments(),
- isolate());
+ if (!function.native_context().equals(native_context())) {
+ return NoChange();
+ }
+
+ return ReduceJSCall(node, function.shared());
+ } else if (target_ref.IsJSBoundFunction()) {
+ JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
+ function.Serialize();
+
+ ObjectRef bound_this = function.bound_this();
ConvertReceiverMode const convert_mode =
- (bound_this->IsNullOrUndefined(isolate()))
+ bound_this.IsNullOrUndefined()
? ConvertReceiverMode::kNullOrUndefined
: ConvertReceiverMode::kNotNullOrUndefined;
+
// Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
NodeProperties::ReplaceValueInput(
- node, jsgraph()->Constant(bound_target_function), 0);
+ node, jsgraph()->Constant(function.bound_target_function()), 0);
NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
1);
+
// Insert the [[BoundArguments]] for {node}.
- for (int i = 0; i < bound_arguments->length(); ++i) {
- node->InsertInput(
- graph()->zone(), i + 2,
- jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
+ FixedArrayRef bound_arguments = function.bound_arguments();
+ for (int i = 0; i < bound_arguments.length(); ++i) {
+ node->InsertInput(graph()->zone(), i + 2,
+ jsgraph()->Constant(bound_arguments.get(i)));
arity++;
}
+
NodeProperties::ChangeOp(
node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
convert_mode));
+
// Try to further reduce the JSCall {node}.
Reduction const reduction = ReduceJSCall(node);
return reduction.Changed() ? reduction : Changed(node);
@@ -3275,7 +3291,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
// the {target} must have the same native context as the call site.
if (target->opcode() == IrOpcode::kJSCreateClosure) {
CreateClosureParameters const& p = CreateClosureParametersOf(target->op());
- return ReduceJSCall(node, p.shared_info());
+ return ReduceJSCall(node, SharedFunctionInfoRef(broker(), p.shared_info()));
}
// If {target} is the result of a JSCreateBoundFunction operation,
@@ -3300,7 +3316,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
// Update the JSCall operator on {node}.
ConvertReceiverMode const convert_mode =
- NodeProperties::CanBeNullOrUndefined(isolate(), bound_this, effect)
+ NodeProperties::CanBeNullOrUndefined(broker(), bound_this, effect)
? ConvertReceiverMode::kAny
: ConvertReceiverMode::kNotNullOrUndefined;
NodeProperties::ChangeOp(
@@ -3324,44 +3340,41 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return NoChange();
}
- HeapObject* heap_object;
- if (nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object)) {
- Handle<HeapObject> feedback(heap_object, isolate());
- // Check if we want to use CallIC feedback here.
- if (!ShouldUseCallICFeedback(target)) return NoChange();
-
- if (feedback->IsCallable()) {
- Node* target_function = jsgraph()->Constant(feedback);
+ base::Optional<HeapObjectRef> feedback =
+ GetHeapObjectFeedback(broker(), nexus);
+ if (feedback.has_value() && ShouldUseCallICFeedback(target) &&
+ feedback->map().is_callable()) {
+ Node* target_function = jsgraph()->Constant(*feedback);
- // Check that the {target} is still the {target_function}.
- Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
- target_function);
- effect = graph()->NewNode(
- simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
- effect, control);
+ // Check that the {target} is still the {target_function}.
+ Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
+ target_function);
+ effect = graph()->NewNode(
+ simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
+ effect, control);
- // Specialize the JSCall node to the {target_function}.
- NodeProperties::ReplaceValueInput(node, target_function, 0);
- NodeProperties::ReplaceEffectInput(node, effect);
+ // Specialize the JSCall node to the {target_function}.
+ NodeProperties::ReplaceValueInput(node, target_function, 0);
+ NodeProperties::ReplaceEffectInput(node, effect);
- // Try to further reduce the JSCall {node}.
- Reduction const reduction = ReduceJSCall(node);
- return reduction.Changed() ? reduction : Changed(node);
- }
+ // Try to further reduce the JSCall {node}.
+ Reduction const reduction = ReduceJSCall(node);
+ return reduction.Changed() ? reduction : Changed(node);
}
+
return NoChange();
}
Reduction JSCallReducer::ReduceJSCall(Node* node,
- Handle<SharedFunctionInfo> shared) {
+ const SharedFunctionInfoRef& shared) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* target = NodeProperties::GetValueInput(node, 0);
// Do not reduce calls to functions with break points.
- if (shared->HasBreakInfo()) return NoChange();
+ if (shared.HasBreakInfo()) return NoChange();
// Raise a TypeError if the {target} is a "classConstructor".
- if (IsClassConstructor(shared->kind())) {
+ if (IsClassConstructor(shared.kind())) {
NodeProperties::ReplaceValueInputs(node, target);
NodeProperties::ChangeOp(
node, javascript()->CallRuntime(
@@ -3372,7 +3385,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
// Check for known builtin functions.
int builtin_id =
- shared->HasBuiltinId() ? shared->builtin_id() : Builtins::kNoBuiltinId;
+ shared.HasBuiltinId() ? shared.builtin_id() : Builtins::kNoBuiltinId;
switch (builtin_id) {
case Builtins::kArrayConstructor:
return ReduceArrayConstructor(node);
@@ -3642,17 +3655,13 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
case Builtins::kStringIteratorPrototypeNext:
return ReduceStringIteratorPrototypeNext(node);
case Builtins::kStringPrototypeConcat:
- return ReduceStringPrototypeConcat(node, shared);
+ return ReduceStringPrototypeConcat(node);
case Builtins::kTypedArrayPrototypeEntries:
return ReduceArrayIterator(node, IterationKind::kEntries);
case Builtins::kTypedArrayPrototypeKeys:
return ReduceArrayIterator(node, IterationKind::kKeys);
case Builtins::kTypedArrayPrototypeValues:
return ReduceArrayIterator(node, IterationKind::kValues);
- case Builtins::kAsyncFunctionPromiseCreate:
- return ReduceAsyncFunctionPromiseCreate(node);
- case Builtins::kAsyncFunctionPromiseRelease:
- return ReduceAsyncFunctionPromiseRelease(node);
case Builtins::kPromiseInternalConstructor:
return ReducePromiseInternalConstructor(node);
case Builtins::kPromiseInternalReject:
@@ -3665,6 +3674,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReducePromisePrototypeFinally(node);
case Builtins::kPromisePrototypeThen:
return ReducePromisePrototypeThen(node);
+ case Builtins::kPromiseResolveTrampoline:
+ return ReducePromiseResolveTrampoline(node);
case Builtins::kMapPrototypeEntries:
return ReduceCollectionIteration(node, CollectionKind::kMap,
IterationKind::kEntries);
@@ -3702,7 +3713,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
break;
}
- if (!FLAG_runtime_stats && shared->IsApiFunction()) {
+ if (!FLAG_runtime_stats && shared.object()->IsApiFunction()) {
return ReduceCallApiFunction(node, shared);
}
return NoChange();
@@ -3750,19 +3761,16 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
return NoChange();
}
- HeapObject* feedback_object;
- if (nexus.GetFeedback()->GetHeapObjectIfStrong(&feedback_object) &&
- feedback_object->IsAllocationSite()) {
+ base::Optional<HeapObjectRef> feedback =
+ GetHeapObjectFeedback(broker(), nexus);
+ if (feedback.has_value() && feedback->IsAllocationSite()) {
// 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
// implementation in Ignition.
- Handle<AllocationSite> site(AllocationSite::cast(feedback_object),
- isolate());
- // Retrieve the Array function from the {node}.
- Node* array_function = jsgraph()->HeapConstant(
- handle(native_context()->array_function(), isolate()));
+ Node* array_function =
+ jsgraph()->Constant(native_context().array_function());
// Check that the {target} is still the {array_function}.
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
@@ -3778,40 +3786,42 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
node, NodeProperties::GetValueInput(node, i), i + 1);
}
NodeProperties::ReplaceValueInput(node, array_function, 1);
- NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
+ NodeProperties::ChangeOp(
+ node, javascript()->CreateArray(
+ arity, feedback->AsAllocationSite().object()));
return Changed(node);
- } else if (nexus.GetFeedback()->GetHeapObjectIfWeak(&feedback_object) &&
- !HeapObjectMatcher(new_target).HasValue()) {
- Handle<HeapObject> object(feedback_object, isolate());
- if (object->IsConstructor()) {
- Node* new_target_feedback = jsgraph()->Constant(object);
-
- // Check that the {new_target} is still the {new_target_feedback}.
- Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
- new_target, new_target_feedback);
- effect = graph()->NewNode(
- simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
- effect, control);
-
- // Specialize the JSConstruct node to the {new_target_feedback}.
- NodeProperties::ReplaceValueInput(node, new_target_feedback, arity + 1);
- NodeProperties::ReplaceEffectInput(node, effect);
- if (target == new_target) {
- NodeProperties::ReplaceValueInput(node, new_target_feedback, 0);
- }
+ } else if (feedback.has_value() &&
+ !HeapObjectMatcher(new_target).HasValue() &&
+ feedback->map().is_constructor()) {
+ Node* new_target_feedback = jsgraph()->Constant(*feedback);
+
+ // Check that the {new_target} is still the {new_target_feedback}.
+ Node* check = graph()->NewNode(simplified()->ReferenceEqual(), new_target,
+ new_target_feedback);
+ effect = graph()->NewNode(
+ simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
+ effect, control);
- // Try to further reduce the JSConstruct {node}.
- Reduction const reduction = ReduceJSConstruct(node);
- return reduction.Changed() ? reduction : Changed(node);
+ // Specialize the JSConstruct node to the {new_target_feedback}.
+ NodeProperties::ReplaceValueInput(node, new_target_feedback, arity + 1);
+ NodeProperties::ReplaceEffectInput(node, effect);
+ if (target == new_target) {
+ NodeProperties::ReplaceValueInput(node, new_target_feedback, 0);
}
+
+ // Try to further reduce the JSConstruct {node}.
+ Reduction const reduction = ReduceJSConstruct(node);
+ return reduction.Changed() ? reduction : Changed(node);
}
}
// Try to specialize JSConstruct {node}s with constant {target}s.
HeapObjectMatcher m(target);
if (m.HasValue()) {
+ HeapObjectRef target_ref = m.Ref(broker()).AsHeapObject();
+
// Raise a TypeError if the {target} is not a constructor.
- if (!m.Value()->IsConstructor()) {
+ if (!target_ref.map().is_constructor()) {
NodeProperties::ReplaceValueInputs(node, target);
NodeProperties::ChangeOp(node,
javascript()->CallRuntime(
@@ -3819,31 +3829,33 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
return Changed(node);
}
- if (m.Value()->IsJSFunction()) {
- Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
+ if (target_ref.IsJSFunction()) {
+ JSFunctionRef function = target_ref.AsJSFunction();
+ function.Serialize();
// Do not reduce constructors with break points.
- if (function->shared()->HasBreakInfo()) return NoChange();
+ if (function.shared().HasBreakInfo()) return NoChange();
// Don't inline cross native context.
- if (function->native_context() != *native_context()) return NoChange();
+ if (!function.native_context().equals(native_context())) {
+ return NoChange();
+ }
// Check for known builtin functions.
- int builtin_id = function->shared()->HasBuiltinId()
- ? function->shared()->builtin_id()
+ int builtin_id = function.shared().HasBuiltinId()
+ ? function.shared().builtin_id()
: Builtins::kNoBuiltinId;
switch (builtin_id) {
case Builtins::kArrayConstructor: {
// TODO(bmeurer): Deal with Array subclasses here.
- Handle<AllocationSite> site;
// Turn the {node} into a {JSCreateArray} call.
for (int i = arity; i > 0; --i) {
NodeProperties::ReplaceValueInput(
node, NodeProperties::GetValueInput(node, i), i + 1);
}
NodeProperties::ReplaceValueInput(node, new_target, 1);
- NodeProperties::ChangeOp(node,
- javascript()->CreateArray(arity, site));
+ NodeProperties::ChangeOp(
+ node, javascript()->CreateArray(arity, Handle<AllocationSite>()));
return Changed(node);
}
case Builtins::kObjectConstructor: {
@@ -3858,7 +3870,8 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
// the value parameter is ignored, which is only the case if
// the {new_target} and {target} are definitely not identical.
HeapObjectMatcher mnew_target(new_target);
- if (mnew_target.HasValue() && *mnew_target.Value() != *function) {
+ if (mnew_target.HasValue() &&
+ !mnew_target.Ref(broker()).equals(function)) {
// Drop the value inputs.
for (int i = arity; i > 0; --i) node->RemoveInput(i);
NodeProperties::ChangeOp(node, javascript()->Create());
@@ -3869,18 +3882,16 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
case Builtins::kPromiseConstructor:
return ReducePromiseConstructor(node);
case Builtins::kTypedArrayConstructor:
- return ReduceTypedArrayConstructor(
- node, handle(function->shared(), isolate()));
+ return ReduceTypedArrayConstructor(node, function.shared());
default:
break;
}
- } else if (m.Value()->IsJSBoundFunction()) {
- Handle<JSBoundFunction> function =
- Handle<JSBoundFunction>::cast(m.Value());
- Handle<JSReceiver> bound_target_function(
- function->bound_target_function(), isolate());
- Handle<FixedArray> bound_arguments(function->bound_arguments(),
- isolate());
+ } else if (target_ref.IsJSBoundFunction()) {
+ JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
+ function.Serialize();
+
+ ObjectRef bound_target_function = function.bound_target_function();
+ FixedArrayRef bound_arguments = function.bound_arguments();
// Patch {node} to use [[BoundTargetFunction]].
NodeProperties::ReplaceValueInput(
@@ -3898,10 +3909,9 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
arity + 1);
// Insert the [[BoundArguments]] for {node}.
- for (int i = 0; i < bound_arguments->length(); ++i) {
- node->InsertInput(
- graph()->zone(), i + 1,
- jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
+ for (int i = 0; i < bound_arguments.length(); ++i) {
+ node->InsertInput(graph()->zone(), i + 1,
+ jsgraph()->Constant(bound_arguments.get(i)));
arity++;
}
@@ -4308,32 +4318,6 @@ Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node,
return Changed(node);
}
-namespace {
-
-// TODO(turbofan): This was copied from old compiler, might be too restrictive.
-bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
- DCHECK(!jsarray_map->is_dictionary_map());
- Handle<Name> length_string = isolate->factory()->length_string();
- DescriptorArray* descriptors = jsarray_map->instance_descriptors();
- int number = descriptors->Search(*length_string, *jsarray_map);
- DCHECK_NE(DescriptorArray::kNotFound, number);
- return descriptors->GetDetails(number).IsReadOnly();
-}
-
-// TODO(turbofan): This was copied from old compiler, might be too restrictive.
-bool CanInlineArrayResizeOperation(Isolate* isolate, Handle<Map> receiver_map) {
- if (!receiver_map->prototype()->IsJSArray()) return false;
- Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
- isolate);
- return receiver_map->instance_type() == JS_ARRAY_TYPE &&
- IsFastElementsKind(receiver_map->elements_kind()) &&
- !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
- isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
- !IsReadOnlyLengthDescriptor(isolate, receiver_map);
-}
-
-} // namespace
-
// ES6 section 22.1.3.18 Array.prototype.push ( )
Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
@@ -4342,33 +4326,25 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
return NoChange();
}
- if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
-
int const num_values = node->op()->ValueInputCount() - 2;
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- // Try to determine the {receiver} map(s).
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
- ElementsKind kind = receiver_maps[0]->elements_kind();
-
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
- return NoChange();
- if (!UnionElementsKindUptoPackedness(&kind, receiver_map->elements_kind()))
- return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kind, true)) {
+ return NoChange();
}
- // Install code dependencies on the {receiver} global array protector cell.
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
@@ -4456,34 +4432,24 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
return NoChange();
}
- if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
-
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
- ElementsKind kind = receiver_maps[0]->elements_kind();
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
- return NoChange();
- // TODO(turbofan): Extend this to also handle fast holey double elements
- // once we got the hole NaN mess sorted out in TurboFan/V8.
- if (receiver_map->elements_kind() == HOLEY_DOUBLE_ELEMENTS)
- return NoChange();
- if (!UnionElementsKindUptoSize(&kind, receiver_map->elements_kind()))
- return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
- // Install code dependencies on the {receiver} global array protector cell.
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
@@ -4573,7 +4539,6 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
return NoChange();
}
- if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
Node* target = NodeProperties::GetValueInput(node, 0);
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* context = NodeProperties::GetContextInput(node);
@@ -4583,26 +4548,18 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
- ElementsKind kind = receiver_maps[0]->elements_kind();
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
- return NoChange();
- // TODO(turbofan): Extend this to also handle fast holey double elements
- // once we got the hole NaN mess sorted out in TurboFan/V8.
- if (receiver_map->elements_kind() == HOLEY_DOUBLE_ELEMENTS)
- return NoChange();
- if (!UnionElementsKindUptoSize(&kind, receiver_map->elements_kind()))
- return NoChange();
+ ElementsKind kind;
+ if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kind)) {
+ return NoChange();
}
- // Install code dependencies on the {receiver} global array protector cell.
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
@@ -4771,51 +4728,60 @@ Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
return NoChange();
}
- int arity = static_cast<int>(p.arity() - 2);
- // Here we only optimize for cloning, that is when slice is called
- // without arguments, or with a single argument that is the constant 0.
- if (arity >= 2) return NoChange();
- if (arity == 1) {
- NumberMatcher m(NodeProperties::GetValueInput(node, 2));
- if (!m.HasValue()) return NoChange();
- if (m.Value() != 0) return NoChange();
- }
-
Node* receiver = NodeProperties::GetValueInput(node, 1);
+ Node* start = node->op()->ValueInputCount() > 2
+ ? NodeProperties::GetValueInput(node, 2)
+ : jsgraph()->ZeroConstant();
+ Node* end = node->op()->ValueInputCount() > 3
+ ? NodeProperties::GetValueInput(node, 3)
+ : jsgraph()->UndefinedConstant();
+ Node* context = NodeProperties::GetContextInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- // Try to determine the {receiver} map.
+ // Optimize for the case where we simply clone the {receiver},
+ // i.e. when the {start} is zero and the {end} is undefined
+ // (meaning it will be set to {receiver}s "length" property).
+ if (!NumberMatcher(start).Is(0) ||
+ !HeapObjectMatcher(end).Is(factory()->undefined_value())) {
+ return NoChange();
+ }
+
+ // Try to determine the {receiver} maps.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
- // Ensure that any changes to the Array species constructor cause deopt.
+ // We cannot optimize unless the Array[@@species] lookup chain is intact.
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
- dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
+ // Check that the maps are of JSArray (and more).
+ // TODO(turbofan): Consider adding special case for the common pattern
+ // `slice.call(arguments)`, for example jQuery makes heavy use of that.
bool can_be_holey = false;
- // Check that the maps are of JSArray (and more)
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
- return NoChange();
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.supports_fast_array_iteration()) return NoChange();
- if (IsHoleyElementsKind(receiver_map->elements_kind())) can_be_holey = true;
+ if (IsHoleyElementsKind(receiver_map.elements_kind())) {
+ can_be_holey = true;
+ }
}
+ // Install code dependency on the Array[@@species] protector.
+ dependencies()->DependOnProtector(
+ PropertyCellRef(broker(), factory()->array_species_protector()));
+
// Install code dependency on the array protector for holey arrays.
if (can_be_holey) {
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
}
- // If we have unreliable maps, we need a map check.
- // This is actually redundant due to how JSNativeContextSpecialization
- // reduces the load of slice, but we do it here nevertheless for consistency
- // and robustness.
+ // If we have unreliable maps, we need a map check, as there might be
+ // side-effects caused by the evaluation of the {node}s parameters.
if (result == NodeProperties::kUnreliableReceiverMaps) {
effect =
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
@@ -4823,8 +4789,12 @@ Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
receiver, effect, control);
}
- Node* context = NodeProperties::GetContextInput(node);
-
+ // TODO(turbofan): We can do even better here, either adding a CloneArray
+ // simplified operator, whose output type indicates that it's an Array,
+ // saving subsequent checks, or yet better, by introducing new operators
+ // CopySmiOrObjectElements / CopyDoubleElements and inlining the JSArray
+ // allocation in here. That way we'd even get escape analysis and scalar
+ // replacement to help in some cases.
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kCloneFastJSArray);
auto call_descriptor = Linkage::GetStubCallDescriptor(
@@ -4876,12 +4846,13 @@ Reduction JSCallReducer::ReduceArrayIterator(Node* node, IterationKind kind) {
// Check if we know that {receiver} is a valid JSReceiver.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!receiver_map->IsJSReceiverMap()) return NoChange();
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.IsJSReceiverMap()) return NoChange();
}
// Morph the {node} into a JSCreateArrayIterator with the given {kind}.
@@ -4897,14 +4868,14 @@ Reduction JSCallReducer::ReduceArrayIterator(Node* node, IterationKind kind) {
namespace {
-bool InferIteratedObjectMaps(Isolate* isolate, Node* iterator,
+bool InferIteratedObjectMaps(JSHeapBroker* broker, Node* iterator,
ZoneHandleSet<Map>* iterated_object_maps) {
DCHECK_EQ(IrOpcode::kJSCreateArrayIterator, iterator->opcode());
Node* iterated_object = NodeProperties::GetValueInput(iterator, 0);
Node* effect = NodeProperties::GetEffectInput(iterator);
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate, iterated_object, effect,
+ NodeProperties::InferReceiverMaps(broker, iterated_object, effect,
iterated_object_maps);
return result != NodeProperties::kNoReceiverMaps;
}
@@ -4931,40 +4902,37 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
// Try to infer the [[IteratedObject]] maps from the {iterator}.
ZoneHandleSet<Map> iterated_object_maps;
- if (!InferIteratedObjectMaps(isolate(), iterator, &iterated_object_maps)) {
+ if (!InferIteratedObjectMaps(broker(), iterator, &iterated_object_maps)) {
return NoChange();
}
DCHECK_NE(0, iterated_object_maps.size());
// Check that various {iterated_object_maps} have compatible elements kinds.
- ElementsKind elements_kind = iterated_object_maps[0]->elements_kind();
+ ElementsKind elements_kind =
+ MapRef(broker(), iterated_object_maps[0]).elements_kind();
if (IsFixedTypedArrayElementsKind(elements_kind)) {
// TurboFan doesn't support loading from BigInt typed arrays yet.
if (elements_kind == BIGUINT64_ELEMENTS ||
elements_kind == BIGINT64_ELEMENTS) {
return NoChange();
}
- for (Handle<Map> iterated_object_map : iterated_object_maps) {
- if (iterated_object_map->elements_kind() != elements_kind) {
+ for (Handle<Map> map : iterated_object_maps) {
+ MapRef iterated_object_map(broker(), map);
+ if (iterated_object_map.elements_kind() != elements_kind) {
return NoChange();
}
}
} else {
- for (Handle<Map> iterated_object_map : iterated_object_maps) {
- if (!CanInlineArrayIteratingBuiltin(isolate(), iterated_object_map)) {
- return NoChange();
- }
- if (!UnionElementsKindUptoSize(&elements_kind,
- iterated_object_map->elements_kind())) {
- return NoChange();
- }
+ if (!CanInlineArrayIteratingBuiltin(broker(), iterated_object_maps,
+ &elements_kind)) {
+ return NoChange();
}
}
// Install code dependency on the array protector for holey arrays.
if (IsHoleyElementsKind(elements_kind)) {
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
+ PropertyCellRef(broker(), factory()->no_elements_protector()));
}
// Load the (current) {iterated_object} from the {iterator}.
@@ -4980,14 +4948,14 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
iterated_object, effect, control);
if (IsFixedTypedArrayElementsKind(elements_kind)) {
- // See if we can skip the neutering check.
- if (isolate()->IsArrayBufferNeuteringIntact()) {
+ // See if we can skip the detaching check.
+ if (isolate()->IsArrayBufferDetachingIntact()) {
// Add a code dependency so we are deoptimized in case an ArrayBuffer
- // gets neutered.
+ // gets detached.
dependencies()->DependOnProtector(PropertyCellRef(
- js_heap_broker(), factory()->array_buffer_neutering_protector()));
+ broker(), factory()->array_buffer_detaching_protector()));
} else {
- // Bail out if the {iterated_object}s JSArrayBuffer was neutered.
+ // Bail out if the {iterated_object}s JSArrayBuffer was detached.
Node* buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
iterated_object, effect, control);
@@ -4998,10 +4966,10 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
simplified()->NumberEqual(),
graph()->NewNode(
simplified()->NumberBitwiseAnd(), buffer_bit_field,
- jsgraph()->Constant(JSArrayBuffer::WasNeuteredBit::kMask)),
+ jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
jsgraph()->ZeroConstant());
effect = graph()->NewNode(
- simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered,
+ simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
p.feedback()),
check, effect, control);
}
@@ -5013,11 +4981,11 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
// latter case we even know that it's a Smi in UnsignedSmall range.
FieldAccess index_access = AccessBuilder::ForJSArrayIteratorNextIndex();
if (IsFixedTypedArrayElementsKind(elements_kind)) {
- index_access.type = TypeCache::Get().kJSTypedArrayLengthType;
+ index_access.type = TypeCache::Get()->kJSTypedArrayLengthType;
index_access.machine_type = MachineType::TaggedSigned();
index_access.write_barrier_kind = kNoWriteBarrier;
} else {
- index_access.type = TypeCache::Get().kJSArrayLengthType;
+ index_access.type = TypeCache::Get()->kJSArrayLengthType;
}
Node* index = effect = graph()->NewNode(simplified()->LoadField(index_access),
iterator, effect, control);
@@ -5373,7 +5341,7 @@ Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
- if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ if (NodeProperties::HasInstanceTypeWitness(broker(), receiver, effect,
JS_STRING_ITERATOR_TYPE)) {
Node* string = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
@@ -5438,8 +5406,7 @@ Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
}
// ES #sec-string.prototype.concat
-Reduction JSCallReducer::ReduceStringPrototypeConcat(
- Node* node, Handle<SharedFunctionInfo> shared) {
+Reduction JSCallReducer::ReduceStringPrototypeConcat(Node* node) {
if (node->op()->ValueInputCount() < 2 || node->op()->ValueInputCount() > 3) {
return NoChange();
}
@@ -5479,46 +5446,13 @@ Reduction JSCallReducer::ReduceStringPrototypeConcat(
return Replace(value);
}
-Reduction JSCallReducer::ReduceAsyncFunctionPromiseCreate(Node* node) {
- DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
- Node* context = NodeProperties::GetContextInput(node);
- Node* effect = NodeProperties::GetEffectInput(node);
- if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
-
- // Install a code dependency on the promise hook protector cell.
- dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
-
- // Morph this {node} into a JSCreatePromise node.
- RelaxControls(node);
- node->ReplaceInput(0, context);
- node->ReplaceInput(1, effect);
- node->TrimInputCount(2);
- NodeProperties::ChangeOp(node, javascript()->CreatePromise());
- return Changed(node);
-}
-
-Reduction JSCallReducer::ReduceAsyncFunctionPromiseRelease(Node* node) {
- DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
- if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
-
- dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
-
- // The AsyncFunctionPromiseRelease builtin is a no-op as long as neither
- // the debugger is active nor any promise hook has been installed (ever).
- Node* value = jsgraph()->UndefinedConstant();
- ReplaceWithValue(node, value);
- return Replace(value);
-}
-
Node* JSCallReducer::CreateArtificialFrameState(
Node* node, Node* outer_frame_state, int parameter_count,
BailoutId bailout_id, FrameStateType frame_state_type,
- Handle<SharedFunctionInfo> shared, Node* context) {
+ const SharedFunctionInfoRef& shared, Node* context) {
const FrameStateFunctionInfo* state_info =
- common()->CreateFrameStateFunctionInfo(frame_state_type,
- parameter_count + 1, 0, shared);
+ common()->CreateFrameStateFunctionInfo(
+ frame_state_type, parameter_count + 1, 0, shared.object());
const Operator* op = common()->FrameState(
bailout_id, OutputFrameStateCombine::Ignore(), state_info);
@@ -5562,16 +5496,16 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
if (target != new_target) return NoChange();
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
+ PropertyCellRef(broker(), factory()->promise_hook_protector()));
- Handle<SharedFunctionInfo> promise_shared(
- handle(native_context()->promise_function()->shared(), isolate()));
+ SharedFunctionInfoRef promise_shared =
+ native_context().promise_function().shared();
// Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor.
// For the frame state, we only provide the executor parameter, even if more
// arugments were passed. This is not observable from JS.
- DCHECK_EQ(1, promise_shared->internal_formal_parameter_count());
+ DCHECK_EQ(1, promise_shared.internal_formal_parameter_count());
Node* constructor_frame_state = CreateArtificialFrameState(
node, outer_frame_state, 1, BailoutId::ConstructStubInvoke(),
FrameStateType::kConstructStub, promise_shared, context);
@@ -5604,45 +5538,42 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
// 8. CreatePromiseResolvingFunctions
// Allocate a promise context for the closures below.
- Node* promise_context = effect =
- graph()->NewNode(javascript()->CreateFunctionContext(
- handle(native_context()->scope_info(), isolate()),
- PromiseBuiltinsAssembler::kPromiseContextLength -
- Context::MIN_CONTEXT_SLOTS,
- FUNCTION_SCOPE),
- context, effect, control);
- effect =
- graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
- PromiseBuiltinsAssembler::kPromiseSlot)),
- promise_context, promise, effect, control);
+ Node* promise_context = effect = graph()->NewNode(
+ javascript()->CreateFunctionContext(
+ handle(native_context().object()->scope_info(), isolate()),
+ PromiseBuiltins::kPromiseContextLength - Context::MIN_CONTEXT_SLOTS,
+ FUNCTION_SCOPE),
+ context, effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(
+ AccessBuilder::ForContextSlot(PromiseBuiltins::kPromiseSlot)),
+ promise_context, promise, effect, control);
effect = graph()->NewNode(
- simplified()->StoreField(AccessBuilder::ForContextSlot(
- PromiseBuiltinsAssembler::kAlreadyResolvedSlot)),
+ simplified()->StoreField(
+ AccessBuilder::ForContextSlot(PromiseBuiltins::kAlreadyResolvedSlot)),
promise_context, jsgraph()->FalseConstant(), effect, control);
effect = graph()->NewNode(
- simplified()->StoreField(AccessBuilder::ForContextSlot(
- PromiseBuiltinsAssembler::kDebugEventSlot)),
+ simplified()->StoreField(
+ AccessBuilder::ForContextSlot(PromiseBuiltins::kDebugEventSlot)),
promise_context, jsgraph()->TrueConstant(), effect, control);
// Allocate the closure for the resolve case.
- Handle<SharedFunctionInfo> resolve_shared(
- native_context()->promise_capability_default_resolve_shared_fun(),
- isolate());
- Node* resolve = effect =
- graph()->NewNode(javascript()->CreateClosure(
- resolve_shared, factory()->many_closures_cell(),
- handle(resolve_shared->GetCode(), isolate())),
- promise_context, effect, control);
+ SharedFunctionInfoRef resolve_shared =
+ native_context().promise_capability_default_resolve_shared_fun();
+ Node* resolve = effect = graph()->NewNode(
+ javascript()->CreateClosure(
+ resolve_shared.object(), factory()->many_closures_cell(),
+ handle(resolve_shared.object()->GetCode(), isolate())),
+ promise_context, effect, control);
// Allocate the closure for the reject case.
- Handle<SharedFunctionInfo> reject_shared(
- native_context()->promise_capability_default_reject_shared_fun(),
- isolate());
- Node* reject = effect =
- graph()->NewNode(javascript()->CreateClosure(
- reject_shared, factory()->many_closures_cell(),
- handle(reject_shared->GetCode(), isolate())),
- promise_context, effect, control);
+ SharedFunctionInfoRef reject_shared =
+ native_context().promise_capability_default_reject_shared_fun();
+ Node* reject = effect = graph()->NewNode(
+ javascript()->CreateClosure(
+ reject_shared.object(), factory()->many_closures_cell(),
+ handle(reject_shared.object()->GetCode(), isolate())),
+ promise_context, effect, control);
const std::vector<Node*> checkpoint_parameters_continuation(
{jsgraph()->UndefinedConstant() /* receiver */, promise, reject});
@@ -5720,7 +5651,7 @@ Reduction JSCallReducer::ReducePromiseInternalConstructor(Node* node) {
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
+ PropertyCellRef(broker(), factory()->promise_hook_protector()));
// Create a new pending promise.
Node* value = effect =
@@ -5798,22 +5729,25 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
// Check if we know something about {receiver} already.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
// Check whether all {receiver_maps} are JSPromise maps and
// have the initial Promise.prototype as their [[Prototype]].
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!receiver_map->IsJSPromiseMap()) return NoChange();
- if (receiver_map->prototype() != native_context()->promise_prototype()) {
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.IsJSPromiseMap()) return NoChange();
+ receiver_map.SerializePrototype();
+ if (!receiver_map.prototype().equals(
+ native_context().promise_prototype())) {
return NoChange();
}
}
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_then_protector()));
+ PropertyCellRef(broker(), factory()->promise_then_protector()));
// If the {receiver_maps} aren't reliable, we need to repeat the
// map check here, guarded by the CALL_IC.
@@ -5827,8 +5761,7 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
// Massage the {node} to call "then" instead by first removing all inputs
// following the onRejected parameter, and then filling up the parameters
// to two inputs from the left with undefined.
- Node* target =
- jsgraph()->Constant(handle(native_context()->promise_then(), isolate()));
+ Node* target = jsgraph()->Constant(native_context().promise_then());
NodeProperties::ReplaceValueInput(node, target, 0);
NodeProperties::ReplaceEffectInput(node, effect);
for (; arity > 1; --arity) node->RemoveInput(3);
@@ -5875,26 +5808,29 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
// Check if we know something about {receiver} already.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
// Check whether all {receiver_maps} are JSPromise maps and
// have the initial Promise.prototype as their [[Prototype]].
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!receiver_map->IsJSPromiseMap()) return NoChange();
- if (receiver_map->prototype() != native_context()->promise_prototype()) {
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.IsJSPromiseMap()) return NoChange();
+ receiver_map.SerializePrototype();
+ if (!receiver_map.prototype().equals(
+ native_context().promise_prototype())) {
return NoChange();
}
}
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
+ PropertyCellRef(broker(), factory()->promise_hook_protector()));
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_then_protector()));
- dependencies()->DependOnProtector(PropertyCellRef(
- js_heap_broker(), factory()->promise_species_protector()));
+ PropertyCellRef(broker(), factory()->promise_then_protector()));
+ dependencies()->DependOnProtector(
+ PropertyCellRef(broker(), factory()->promise_species_protector()));
// If the {receiver_maps} aren't reliable, we need to repeat the
// map check here, guarded by the CALL_IC.
@@ -5916,44 +5852,44 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
Node* catch_true;
Node* then_true;
{
- Node* context = jsgraph()->HeapConstant(native_context());
- Node* constructor = jsgraph()->HeapConstant(
- handle(native_context()->promise_function(), isolate()));
+ Node* context = jsgraph()->Constant(native_context());
+ Node* constructor =
+ jsgraph()->Constant(native_context().promise_function());
// Allocate shared context for the closures below.
context = etrue = graph()->NewNode(
javascript()->CreateFunctionContext(
- handle(native_context()->scope_info(), isolate()),
- PromiseBuiltinsAssembler::kPromiseFinallyContextLength -
+ handle(native_context().object()->scope_info(), isolate()),
+ PromiseBuiltins::kPromiseFinallyContextLength -
Context::MIN_CONTEXT_SLOTS,
FUNCTION_SCOPE),
context, etrue, if_true);
- etrue =
- graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
- PromiseBuiltinsAssembler::kOnFinallySlot)),
- context, on_finally, etrue, if_true);
- etrue =
- graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
- PromiseBuiltinsAssembler::kConstructorSlot)),
- context, constructor, etrue, if_true);
+ etrue = graph()->NewNode(
+ simplified()->StoreField(
+ AccessBuilder::ForContextSlot(PromiseBuiltins::kOnFinallySlot)),
+ context, on_finally, etrue, if_true);
+ etrue = graph()->NewNode(
+ simplified()->StoreField(
+ AccessBuilder::ForContextSlot(PromiseBuiltins::kConstructorSlot)),
+ context, constructor, etrue, if_true);
// Allocate the closure for the reject case.
- Handle<SharedFunctionInfo> catch_finally(
- native_context()->promise_catch_finally_shared_fun(), isolate());
- catch_true = etrue =
- graph()->NewNode(javascript()->CreateClosure(
- catch_finally, factory()->many_closures_cell(),
- handle(catch_finally->GetCode(), isolate())),
- context, etrue, if_true);
+ SharedFunctionInfoRef catch_finally =
+ native_context().promise_catch_finally_shared_fun();
+ catch_true = etrue = graph()->NewNode(
+ javascript()->CreateClosure(
+ catch_finally.object(), factory()->many_closures_cell(),
+ handle(catch_finally.object()->GetCode(), isolate())),
+ context, etrue, if_true);
// Allocate the closure for the fulfill case.
- Handle<SharedFunctionInfo> then_finally(
- native_context()->promise_then_finally_shared_fun(), isolate());
- then_true = etrue =
- graph()->NewNode(javascript()->CreateClosure(
- then_finally, factory()->many_closures_cell(),
- handle(then_finally->GetCode(), isolate())),
- context, etrue, if_true);
+ SharedFunctionInfoRef then_finally =
+ native_context().promise_then_finally_shared_fun();
+ then_true = etrue = graph()->NewNode(
+ javascript()->CreateClosure(
+ then_finally.object(), factory()->many_closures_cell(),
+ handle(then_finally.object()->GetCode(), isolate())),
+ context, etrue, if_true);
}
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
@@ -5979,8 +5915,7 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
// Massage the {node} to call "then" instead by first removing all inputs
// following the onFinally parameter, and then replacing the only parameter
// input with the {on_finally} value.
- Node* target =
- jsgraph()->Constant(handle(native_context()->promise_then(), isolate()));
+ Node* target = jsgraph()->Constant(native_context().promise_then());
NodeProperties::ReplaceValueInput(node, target, 0);
NodeProperties::ReplaceEffectInput(node, effect);
NodeProperties::ReplaceControlInput(node, control);
@@ -6028,7 +5963,7 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
// Check if we know something about {receiver} already.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult infer_receiver_maps_result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (infer_receiver_maps_result == NodeProperties::kNoReceiverMaps) {
return NoChange();
@@ -6037,17 +5972,20 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
// Check whether all {receiver_maps} are JSPromise maps and
// have the initial Promise.prototype as their [[Prototype]].
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!receiver_map->IsJSPromiseMap()) return NoChange();
- if (receiver_map->prototype() != native_context()->promise_prototype()) {
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.IsJSPromiseMap()) return NoChange();
+ receiver_map.SerializePrototype();
+ if (!receiver_map.prototype().equals(
+ native_context().promise_prototype())) {
return NoChange();
}
}
dependencies()->DependOnProtector(
- PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
- dependencies()->DependOnProtector(PropertyCellRef(
- js_heap_broker(), factory()->promise_species_protector()));
+ PropertyCellRef(broker(), factory()->promise_hook_protector()));
+ dependencies()->DependOnProtector(
+ PropertyCellRef(broker(), factory()->promise_species_protector()));
// If the {receiver_maps} aren't reliable, we need to repeat the
// map check here, guarded by the CALL_IC.
@@ -6078,6 +6016,18 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
result = effect = graph()->NewNode(
javascript()->PerformPromiseThen(), receiver, on_fulfilled, on_rejected,
result, context, frame_state, effect, control);
+
+ // At this point we know that {result} is going to have the
+ // initial Promise map, since even if {PerformPromiseThen}
+ // above called into the host rejection tracker, the {result}
+ // doesn't escape to user JavaScript. So bake this information
+ // into the graph such that subsequent passes can use the
+ // information for further optimizations.
+ MapRef result_map = native_context().promise_function().initial_map();
+ effect = graph()->NewNode(
+ simplified()->MapGuard(ZoneHandleSet<Map>(result_map.object())), result,
+ effect, control);
+
ReplaceWithValue(node, result, effect, control);
return Replace(result);
}
@@ -6097,7 +6047,7 @@ Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
// Check if we know something about {receiver} already.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult infer_receiver_maps_result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (infer_receiver_maps_result == NodeProperties::kNoReceiverMaps) {
return NoChange();
@@ -6105,8 +6055,9 @@ Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
DCHECK_NE(0, receiver_maps.size());
// Only reduce when all {receiver_maps} are JSReceiver maps.
- for (Handle<Map> receiver_map : receiver_maps) {
- if (!receiver_map->IsJSReceiverMap()) return NoChange();
+ for (Handle<Map> map : receiver_maps) {
+ MapRef receiver_map(broker(), map);
+ if (!receiver_map.IsJSReceiverMap()) return NoChange();
}
// Morph the {node} into a JSPromiseResolve operation.
@@ -6123,7 +6074,7 @@ Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
// ES #sec-typedarray-constructors
Reduction JSCallReducer::ReduceTypedArrayConstructor(
- Node* node, Handle<SharedFunctionInfo> shared) {
+ Node* node, const SharedFunctionInfoRef& shared) {
DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
ConstructParameters const& p = ConstructParametersOf(node->op());
int arity = static_cast<int>(p.arity() - 2);
@@ -6293,7 +6244,7 @@ Reduction JSCallReducer::ReduceMapPrototypeGet(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
Node* key = NodeProperties::GetValueInput(node, 2);
- if (!NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ if (!NodeProperties::HasInstanceTypeWitness(broker(), receiver, effect,
JS_MAP_TYPE))
return NoChange();
@@ -6338,7 +6289,7 @@ Reduction JSCallReducer::ReduceMapPrototypeHas(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
Node* key = NodeProperties::GetValueInput(node, 2);
- if (!NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ if (!NodeProperties::HasInstanceTypeWitness(broker(), receiver, effect,
JS_MAP_TYPE))
return NoChange();
@@ -6379,7 +6330,7 @@ Reduction JSCallReducer::ReduceCollectionIteration(
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (NodeProperties::HasInstanceTypeWitness(
- isolate(), receiver, effect,
+ broker(), receiver, effect,
InstanceTypeForCollectionKind(collection_kind))) {
Node* js_create_iterator = effect = graph()->NewNode(
javascript()->CreateCollectionIterator(collection_kind, iteration_kind),
@@ -6397,14 +6348,14 @@ Reduction JSCallReducer::ReduceCollectionPrototypeSize(
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (NodeProperties::HasInstanceTypeWitness(
- isolate(), receiver, effect,
+ broker(), receiver, effect,
InstanceTypeForCollectionKind(collection_kind))) {
Node* table = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
receiver, effect, control);
Node* value = effect = graph()->NewNode(
simplified()->LoadField(
- AccessBuilder::ForOrderedHashTableBaseNumberOfElements()),
+ AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()),
table, effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
@@ -6438,7 +6389,7 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
InstanceType receiver_instance_type;
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
@@ -6471,7 +6422,7 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
receiver, effect, control);
Node* next_table = effect =
graph()->NewNode(simplified()->LoadField(
- AccessBuilder::ForOrderedHashTableBaseNextTable()),
+ AccessBuilder::ForOrderedHashMapOrSetNextTable()),
table, effect, control);
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), next_table);
control =
@@ -6500,7 +6451,7 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
jsgraph()->NoContextConstant(), effect);
index = effect = graph()->NewNode(
- common()->TypeGuard(TypeCache::Get().kFixedArrayLengthType), index,
+ common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), index,
effect, control);
// Update the {index} and {table} on the {receiver}.
@@ -6540,15 +6491,15 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
// Compute the currently used capacity.
Node* number_of_buckets = effect = graph()->NewNode(
simplified()->LoadField(
- AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets()),
+ AccessBuilder::ForOrderedHashMapOrSetNumberOfBuckets()),
table, effect, control);
Node* number_of_elements = effect = graph()->NewNode(
simplified()->LoadField(
- AccessBuilder::ForOrderedHashTableBaseNumberOfElements()),
+ AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()),
table, effect, control);
Node* number_of_deleted_elements = effect = graph()->NewNode(
simplified()->LoadField(
- AccessBuilder::ForOrderedHashTableBaseNumberOfDeletedElements()),
+ AccessBuilder::ForOrderedHashMapOrSetNumberOfDeletedElements()),
table, effect, control);
Node* used_capacity =
graph()->NewNode(simplified()->NumberAdd(), number_of_elements,
@@ -6564,7 +6515,7 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);
Node* index = effect = graph()->NewNode(
- common()->TypeGuard(TypeCache::Get().kFixedArrayLengthType), iloop,
+ common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), iloop,
eloop, control);
{
Node* check0 = graph()->NewNode(simplified()->NumberLessThan(), index,
@@ -6590,6 +6541,8 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
Node* etrue0 = effect;
{
// Load the key of the entry.
+ STATIC_ASSERT(OrderedHashMap::HashTableStartIndex() ==
+ OrderedHashSet::HashTableStartIndex());
Node* entry_start_position = graph()->NewNode(
simplified()->NumberAdd(),
graph()->NewNode(
@@ -6597,7 +6550,7 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
graph()->NewNode(simplified()->NumberMultiply(), index,
jsgraph()->Constant(entry_size)),
number_of_buckets),
- jsgraph()->Constant(OrderedHashTableBase::kHashTableStartIndex));
+ jsgraph()->Constant(OrderedHashMap::HashTableStartIndex()));
Node* entry_key = etrue0 = graph()->NewNode(
simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
table, entry_start_position, etrue0, if_true0);
@@ -6716,20 +6669,20 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ if (NodeProperties::HasInstanceTypeWitness(broker(), receiver, effect,
instance_type)) {
// Load the {receiver}s field.
Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
receiver, effect, control);
- // See if we can skip the neutering check.
- if (isolate()->IsArrayBufferNeuteringIntact()) {
+ // See if we can skip the detaching check.
+ if (isolate()->IsArrayBufferDetachingIntact()) {
// Add a code dependency so we are deoptimized in case an ArrayBuffer
- // gets neutered.
+ // gets detached.
dependencies()->DependOnProtector(PropertyCellRef(
- js_heap_broker(), factory()->array_buffer_neutering_protector()));
+ broker(), factory()->array_buffer_detaching_protector()));
} else {
- // Check whether {receiver}s JSArrayBuffer was neutered.
+ // Check whether {receiver}s JSArrayBuffer was detached.
Node* buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
receiver, effect, control);
@@ -6740,11 +6693,11 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
simplified()->NumberEqual(),
graph()->NewNode(
simplified()->NumberBitwiseAnd(), buffer_bit_field,
- jsgraph()->Constant(JSArrayBuffer::WasNeuteredBit::kMask)),
+ jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
jsgraph()->ZeroConstant());
// TODO(turbofan): Ideally we would bail out here if the {receiver}s
- // JSArrayBuffer was neutered, but there's no way to guard against
+ // JSArrayBuffer was detached, but there's no way to guard against
// deoptimization loops right now, since the JSCall {node} is usually
// created from a LOAD_IC inlining, and so there's no CALL_IC slot
// from which we could use the speculation bit.
@@ -6802,68 +6755,57 @@ Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access,
}
// Only do stuff if the {receiver} is really a DataView.
- if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ if (NodeProperties::HasInstanceTypeWitness(broker(), receiver, effect,
JS_DATA_VIEW_TYPE)) {
+ Node* byte_offset;
+
// Check that the {offset} is within range for the {receiver}.
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
// We only deal with DataViews here whose [[ByteLength]] is at least
- // {element_size} and less than 2^31-{element_size}.
- Handle<JSDataView> dataview = Handle<JSDataView>::cast(m.Value());
- if (dataview->byte_length() < element_size ||
- dataview->byte_length() - element_size > kMaxInt) {
- return NoChange();
- }
-
- // The {receiver}s [[ByteOffset]] must be within Unsigned31 range.
- if (dataview->byte_offset() > kMaxInt) {
- return NoChange();
- }
+ // {element_size}, as for all other DataViews it'll be out-of-bounds.
+ JSDataViewRef dataview = m.Ref(broker()).AsJSDataView();
+ if (dataview.byte_length() < element_size) return NoChange();
// Check that the {offset} is within range of the {byte_length}.
Node* byte_length =
- jsgraph()->Constant(dataview->byte_length() - (element_size - 1));
+ jsgraph()->Constant(dataview.byte_length() - (element_size - 1));
offset = effect =
graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
byte_length, effect, control);
- // Add the [[ByteOffset]] to compute the effective offset.
- Node* byte_offset = jsgraph()->Constant(dataview->byte_offset());
- offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
+ // Load the [[ByteOffset]] from the {dataview}.
+ byte_offset = jsgraph()->Constant(dataview.byte_offset());
} else {
// We only deal with DataViews here that have Smi [[ByteLength]]s.
Node* byte_length = effect =
graph()->NewNode(simplified()->LoadField(
AccessBuilder::ForJSArrayBufferViewByteLength()),
receiver, effect, control);
- byte_length = effect = graph()->NewNode(
- simplified()->CheckSmi(p.feedback()), byte_length, effect, control);
+
+ if (element_size > 1) {
+ // For non-byte accesses we also need to check that the {offset}
+ // plus the {element_size}-1 fits within the given {byte_length}.
+ // So to keep this as a single check on the {offset}, we subtract
+ // the {element_size}-1 from the {byte_length} here (clamped to
+ // positive safe integer range), and perform a check against that
+ // with the {offset} below.
+ byte_length = graph()->NewNode(
+ simplified()->NumberMax(), jsgraph()->ZeroConstant(),
+ graph()->NewNode(simplified()->NumberSubtract(), byte_length,
+ jsgraph()->Constant(element_size - 1)));
+ }
// Check that the {offset} is within range of the {byte_length}.
offset = effect =
graph()->NewNode(simplified()->CheckBounds(p.feedback()), offset,
byte_length, effect, control);
- if (element_size > 0) {
- // For non-byte accesses we also need to check that the {offset}
- // plus the {element_size}-1 fits within the given {byte_length}.
- Node* end_offset =
- graph()->NewNode(simplified()->NumberAdd(), offset,
- jsgraph()->Constant(element_size - 1));
- effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
- end_offset, byte_length, effect, control);
- }
-
- // The {receiver}s [[ByteOffset]] also needs to be a (positive) Smi.
- Node* byte_offset = effect =
+ // Also load the [[ByteOffset]] from the {receiver}.
+ byte_offset = effect =
graph()->NewNode(simplified()->LoadField(
AccessBuilder::ForJSArrayBufferViewByteOffset()),
receiver, effect, control);
- byte_offset = effect = graph()->NewNode(
- simplified()->CheckSmi(p.feedback()), byte_offset, effect, control);
-
- // Compute the buffer index at which we'll read.
- offset = graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
}
// Coerce {is_little_endian} to boolean.
@@ -6878,18 +6820,18 @@ Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access,
value, effect, control);
}
- // Get the underlying buffer and check that it has not been neutered.
+ // Get the underlying buffer and check that it has not been detached.
Node* buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
receiver, effect, control);
- if (isolate()->IsArrayBufferNeuteringIntact()) {
+ if (isolate()->IsArrayBufferDetachingIntact()) {
// Add a code dependency so we are deoptimized in case an ArrayBuffer
- // gets neutered.
+ // gets detached.
dependencies()->DependOnProtector(PropertyCellRef(
- js_heap_broker(), factory()->array_buffer_neutering_protector()));
+ broker(), factory()->array_buffer_detaching_protector()));
} else {
- // Bail out if the {buffer} was neutered.
+ // Bail out if the {buffer} was detached.
Node* buffer_bit_field = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
buffer, effect, control);
@@ -6897,10 +6839,10 @@ Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access,
simplified()->NumberEqual(),
graph()->NewNode(
simplified()->NumberBitwiseAnd(), buffer_bit_field,
- jsgraph()->Constant(JSArrayBuffer::WasNeuteredBit::kMask)),
+ jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
jsgraph()->ZeroConstant());
effect = graph()->NewNode(
- simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered,
+ simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
p.feedback()),
check, effect, control);
}
@@ -6913,15 +6855,17 @@ Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access,
switch (access) {
case DataViewAccess::kGet:
// Perform the load.
- value = effect = graph()->NewNode(
- simplified()->LoadDataViewElement(element_type), buffer,
- backing_store, offset, is_little_endian, effect, control);
+ value = effect =
+ graph()->NewNode(simplified()->LoadDataViewElement(element_type),
+ buffer, backing_store, byte_offset, offset,
+ is_little_endian, effect, control);
break;
case DataViewAccess::kSet:
// Perform the store.
- effect = graph()->NewNode(
- simplified()->StoreDataViewElement(element_type), buffer,
- backing_store, offset, value, is_little_endian, effect, control);
+ effect =
+ graph()->NewNode(simplified()->StoreDataViewElement(element_type),
+ buffer, backing_store, byte_offset, offset, value,
+ is_little_endian, effect, control);
value = jsgraph()->UndefinedConstant();
break;
}
@@ -6989,7 +6933,7 @@ Reduction JSCallReducer::ReduceDatePrototypeGetTime(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ if (NodeProperties::HasInstanceTypeWitness(broker(), receiver, effect,
JS_DATE_TYPE)) {
Node* value = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
@@ -7053,8 +6997,7 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
// Check if we know something about the {regexp}.
ZoneHandleSet<Map> regexp_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(isolate(), regexp, effect,
- &regexp_maps);
+ NodeProperties::InferReceiverMaps(broker(), regexp, effect, &regexp_maps);
bool need_map_check = false;
switch (result) {
@@ -7068,31 +7011,63 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
}
for (auto map : regexp_maps) {
- if (map->instance_type() != JS_REGEXP_TYPE) return NoChange();
+ MapRef receiver_map(broker(), map);
+ if (receiver_map.instance_type() != JS_REGEXP_TYPE) return NoChange();
}
// Compute property access info for "exec" on {resolution}.
PropertyAccessInfo ai_exec;
- AccessInfoFactory access_info_factory(js_heap_broker(), dependencies(),
- native_context(), graph()->zone());
+ AccessInfoFactory access_info_factory(
+ broker(), dependencies(), native_context().object(), graph()->zone());
if (!access_info_factory.ComputePropertyAccessInfo(
MapHandles(regexp_maps.begin(), regexp_maps.end()),
factory()->exec_string(), AccessMode::kLoad, &ai_exec)) {
return NoChange();
}
// If "exec" has been modified on {regexp}, we can't do anything.
- if (!ai_exec.IsDataConstant()) return NoChange();
- Handle<Object> exec_on_proto = ai_exec.constant();
- if (*exec_on_proto != *isolate()->regexp_exec_function()) return NoChange();
+ if (ai_exec.IsDataConstant()) {
+ if (!ai_exec.constant().is_identical_to(
+ isolate()->regexp_exec_function())) {
+ return NoChange();
+ }
+ } else if (ai_exec.IsDataConstantField()) {
+ Handle<JSObject> holder;
+ // Do not reduce if the exec method is not on the prototype chain.
+ if (!ai_exec.holder().ToHandle(&holder)) return NoChange();
+
+ // Bail out if the exec method is not the original one.
+ Handle<Object> constant = JSObject::FastPropertyAt(
+ holder, Representation::Tagged(), ai_exec.field_index());
+ if (!constant.is_identical_to(isolate()->regexp_exec_function())) {
+ return NoChange();
+ }
+
+ // Protect the prototype chain from changes.
+ dependencies()->DependOnStablePrototypeChains(
+ broker(), ai_exec.receiver_maps(), JSObjectRef(broker(), holder));
+
+ // Protect the exec method change in the holder.
+ Handle<Object> exec_on_proto;
+ Handle<Map> holder_map(holder->map(), isolate());
+ Handle<DescriptorArray> descriptors(holder_map->instance_descriptors(),
+ isolate());
+ int descriptor_index =
+ descriptors->Search(*(factory()->exec_string()), *holder_map);
+ CHECK_NE(descriptor_index, DescriptorArray::kNotFound);
- PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(),
- dependencies());
+ dependencies()->DependOnFieldType(MapRef(broker(), holder_map),
+ descriptor_index);
+ } else {
+ return NoChange();
+ }
+
+ PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
// Add proper dependencies on the {regexp}s [[Prototype]]s.
Handle<JSObject> holder;
if (ai_exec.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
- js_heap_broker(), native_context(), ai_exec.receiver_maps(), holder);
+ broker(), ai_exec.receiver_maps(), JSObjectRef(broker(), holder));
}
if (need_map_check) {
@@ -7145,8 +7120,8 @@ Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
Node* frame_state = NodeProperties::GetFrameStateInput(node);
// Create the artificial frame state in the middle of the Number constructor.
- Handle<SharedFunctionInfo> shared_info(
- handle(native_context()->number_function()->shared(), isolate()));
+ SharedFunctionInfoRef shared_info =
+ native_context().number_function().shared();
Node* stack_parameters[] = {receiver};
int stack_parameter_count = arraysize(stack_parameters);
Node* continuation_frame_state =
@@ -7169,11 +7144,6 @@ Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
Factory* JSCallReducer::factory() const { return isolate()->factory(); }
-Handle<JSGlobalProxy> JSCallReducer::global_proxy() const {
- return handle(JSGlobalProxy::cast(native_context()->global_proxy()),
- isolate());
-}
-
CommonOperatorBuilder* JSCallReducer::common() const {
return jsgraph()->common();
}