summaryrefslogtreecommitdiff
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.cc836
1 files changed, 696 insertions, 140 deletions
diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc
index 1bf59adb4a..6b545c2853 100644
--- a/deps/v8/src/compiler/js-call-reducer.cc
+++ b/deps/v8/src/compiler/js-call-reducer.cc
@@ -9,17 +9,20 @@
#include "src/builtins/builtins-utils.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
-#include "src/compilation-dependencies.h"
#include "src/compiler/access-builder.h"
+#include "src/compiler/access-info.h"
#include "src/compiler/allocation-builder.h"
+#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
+#include "src/compiler/property-access-builder.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/type-cache.h"
#include "src/feedback-vector-inl.h"
#include "src/ic/call-optimization.h"
#include "src/objects-inl.h"
+#include "src/objects/arguments-inl.h"
#include "src/vector-slot-pair.h"
namespace v8 {
@@ -247,8 +250,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(value, effect)) {
- if (!NodeProperties::CanBeNullOrUndefined(value, effect)) {
+ if (NodeProperties::CanBePrimitive(isolate(), value, effect)) {
+ if (!NodeProperties::CanBeNullOrUndefined(isolate(), value, effect)) {
// Turn the {node} into a {JSToObject} call if we know that
// the {value} cannot be null or undefined.
NodeProperties::ReplaceValueInputs(node, value);
@@ -289,7 +292,8 @@ 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(arguments_list, effect)) {
+ if (!NodeProperties::CanBeNullOrUndefined(isolate(), arguments_list,
+ effect)) {
// Massage the value inputs appropriately.
node->ReplaceInput(0, target);
node->ReplaceInput(1, this_argument);
@@ -401,7 +405,8 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
// definitely a constructor or not a constructor.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), 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();
@@ -426,18 +431,18 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
isolate());
if (descriptors->number_of_descriptors() < 2) return NoChange();
if (descriptors->GetKey(JSFunction::kLengthDescriptorIndex) !=
- isolate()->heap()->length_string()) {
+ ReadOnlyRoots(isolate()).length_string()) {
return NoChange();
}
- if (!descriptors->GetValue(JSFunction::kLengthDescriptorIndex)
+ if (!descriptors->GetStrongValue(JSFunction::kLengthDescriptorIndex)
->IsAccessorInfo()) {
return NoChange();
}
if (descriptors->GetKey(JSFunction::kNameDescriptorIndex) !=
- isolate()->heap()->name_string()) {
+ ReadOnlyRoots(isolate()).name_string()) {
return NoChange();
}
- if (!descriptors->GetValue(JSFunction::kNameDescriptorIndex)
+ if (!descriptors->GetStrongValue(JSFunction::kNameDescriptorIndex)
->IsAccessorInfo()) {
return NoChange();
}
@@ -451,7 +456,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
: native_context()->bound_function_without_constructor_map(),
isolate());
if (map->prototype() != *prototype) {
- map = Map::TransitionToPrototype(map, prototype);
+ map = Map::TransitionToPrototype(isolate(), map, prototype);
}
// Make sure we can rely on the {receiver_maps}.
@@ -562,7 +567,8 @@ Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
// Try to determine the {object} map.
ZoneHandleSet<Map> object_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(object, effect, &object_maps);
+ NodeProperties::InferReceiverMaps(isolate(), object, effect,
+ &object_maps);
if (result != NodeProperties::kNoReceiverMaps) {
Handle<Map> candidate_map = object_maps[0];
Handle<Object> candidate_prototype(candidate_map->prototype(), isolate());
@@ -588,7 +594,8 @@ Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
}
if (result == NodeProperties::kUnreliableReceiverMaps) {
for (size_t i = 0; i < object_maps.size(); ++i) {
- dependencies()->AssumeMapStable(object_maps[i]);
+ dependencies()->DependOnStableMap(
+ MapRef(js_heap_broker(), object_maps[i]));
}
}
Node* value = jsgraph()->Constant(candidate_prototype);
@@ -721,7 +728,8 @@ 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(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), 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();
@@ -855,9 +863,8 @@ Reduction JSCallReducer::ReduceReflectGet(Node* node) {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kGetProperty);
auto call_descriptor = Linkage::GetStubCallDescriptor(
- isolate(), graph()->zone(), callable.descriptor(), 0,
- CallDescriptor::kNeedsFrameState, Operator::kNoProperties,
- MachineType::AnyTagged(), 1);
+ graph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNeedsFrameState, Operator::kNoProperties);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
vtrue = etrue = if_true =
graph()->NewNode(common()->Call(call_descriptor), stub_code, target,
@@ -962,8 +969,8 @@ Reduction JSCallReducer::ReduceReflectHas(Node* node) {
return Changed(vtrue);
}
-bool CanInlineArrayIteratingBuiltin(Handle<Map> receiver_map) {
- Isolate* const isolate = receiver_map->GetIsolate();
+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);
@@ -1016,7 +1023,8 @@ Reduction JSCallReducer::ReduceArrayForEach(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// By ensuring that {kind} is object or double, we can be polymorphic
@@ -1027,7 +1035,7 @@ Reduction JSCallReducer::ReduceArrayForEach(Node* node,
}
for (Handle<Map> receiver_map : receiver_maps) {
ElementsKind next_kind = receiver_map->elements_kind();
- if (!CanInlineArrayIteratingBuiltin(receiver_map)) {
+ if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map)) {
return NoChange();
}
if (!IsFastElementsKind(next_kind)) {
@@ -1043,7 +1051,8 @@ Reduction JSCallReducer::ReduceArrayForEach(Node* node,
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -1204,12 +1213,14 @@ Reduction JSCallReducer::ReduceArrayReduce(Node* node,
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), 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(receiver_map)) return NoChange();
+ if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map))
+ return NoChange();
if (!UnionElementsKindUptoSize(&kind, receiver_map->elements_kind()))
return NoChange();
}
@@ -1225,7 +1236,8 @@ Reduction JSCallReducer::ReduceArrayReduce(Node* node,
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -1478,7 +1490,8 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// Ensure that any changes to the Array species constructor cause deopt.
@@ -1487,13 +1500,15 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
const ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(receiver_map)) return NoChange();
+ 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();
}
- dependencies()->AssumePropertyCell(factory()->array_species_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
Handle<JSFunction> handle_constructor(
JSFunction::cast(
@@ -1618,10 +1633,12 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
&check_fail, &control);
}
- Handle<Map> double_map(Map::cast(
- native_context()->get(Context::ArrayMapIndex(HOLEY_DOUBLE_ELEMENTS))));
+ 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))));
+ 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);
@@ -1678,7 +1695,8 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// And ensure that any changes to the Array species constructor cause deopt.
@@ -1689,7 +1707,7 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
const ElementsKind packed_kind = GetPackedElementsKind(kind);
for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(receiver_map)) {
+ if (!CanInlineArrayIteratingBuiltin(isolate(), receiver_map)) {
return NoChange();
}
// We can handle different maps, as long as their elements kind are the
@@ -1697,10 +1715,12 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
if (receiver_map->elements_kind() != kind) return NoChange();
}
- dependencies()->AssumePropertyCell(factory()->array_species_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
Handle<Map> initial_map(
- Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)));
+ Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)),
+ isolate());
Node* k = jsgraph()->ZeroConstant();
Node* to = jsgraph()->ZeroConstant();
@@ -1724,7 +1744,8 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
ab.Store(AccessBuilder::ForJSArrayLength(packed_kind),
jsgraph()->ZeroConstant());
for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
- ab.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
+ ab.Store(AccessBuilder::ForJSObjectInObjectProperty(
+ MapRef(js_heap_broker(), initial_map), i),
jsgraph()->UndefinedConstant());
}
a = effect = ab.Finish();
@@ -1952,7 +1973,8 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
const ElementsKind kind = receiver_maps[0]->elements_kind();
@@ -1963,7 +1985,8 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
}
for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(receiver_map)) return NoChange();
+ 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();
@@ -1971,7 +1994,8 @@ Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -2269,7 +2293,8 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// And ensure that any changes to the Array species constructor cause deopt.
@@ -2278,13 +2303,15 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
const ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(receiver_map)) return NoChange();
+ 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();
}
- dependencies()->AssumePropertyCell(factory()->array_species_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
// If we have unreliable maps, we need a map check.
if (result == NodeProperties::kUnreliableReceiverMaps) {
@@ -2525,7 +2552,7 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
}
Handle<Map> receiver_map;
- if (!NodeProperties::GetMapWitness(node).ToHandle(&receiver_map))
+ if (!NodeProperties::GetMapWitness(isolate(), node).ToHandle(&receiver_map))
return NoChange();
if (receiver_map->instance_type() != JS_ARRAY_TYPE) return NoChange();
@@ -2537,8 +2564,8 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
: GetCallableForArrayIncludes(receiver_map->elements_kind(),
isolate());
CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
- isolate(), graph()->zone(), callable.descriptor(), 0,
- CallDescriptor::kNoFlags, Operator::kEliminatable);
+ graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
+ Operator::kEliminatable);
// The stub expects the following arguments: the receiver array, its elements,
// the search_element, the array length, and the index to start searching
// from.
@@ -2605,7 +2632,8 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
: jsgraph()->UndefinedConstant();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
// And ensure that any changes to the Array species constructor cause deopt.
@@ -2616,13 +2644,15 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
const ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> receiver_map : receiver_maps) {
- if (!CanInlineArrayIteratingBuiltin(receiver_map)) return NoChange();
+ 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();
}
- dependencies()->AssumePropertyCell(factory()->array_species_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->array_species_protector()));
Node* k = jsgraph()->ZeroConstant();
@@ -2824,7 +2854,7 @@ Reduction JSCallReducer::ReduceCallApiFunction(
Node* control = NodeProperties::GetControlInput(node);
Handle<FunctionTemplateInfo> function_template_info(
- FunctionTemplateInfo::cast(shared->function_data()));
+ 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
@@ -2835,7 +2865,8 @@ Reduction JSCallReducer::ReduceCallApiFunction(
// callback based on those.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), 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];
@@ -2852,7 +2883,7 @@ Reduction JSCallReducer::ReduceCallApiFunction(
}
// See if we can constant-fold the compatible receiver checks.
- CallOptimization call_optimization(function_template_info);
+ CallOptimization call_optimization(isolate(), function_template_info);
if (!call_optimization.is_simple_api_call()) return NoChange();
CallOptimization::HolderLookup lookup;
Handle<JSObject> api_holder =
@@ -2869,7 +2900,8 @@ 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()->AssumeMapStable(receiver_maps[i]);
+ dependencies()->DependOnStableMap(
+ MapRef(js_heap_broker(), receiver_maps[i]));
}
}
@@ -2886,13 +2918,12 @@ Reduction JSCallReducer::ReduceCallApiFunction(
Handle<CallHandlerInfo> call_handler_info(
CallHandlerInfo::cast(function_template_info->call_code()), isolate());
Handle<Object> data(call_handler_info->data(), isolate());
- CallApiCallbackStub stub(isolate(), argc);
- CallInterfaceDescriptor cid = stub.GetCallInterfaceDescriptor();
+ Callable call_api_callback = CodeFactory::CallApiCallback(isolate(), argc);
+ CallInterfaceDescriptor cid = call_api_callback.descriptor();
auto call_descriptor = Linkage::GetStubCallDescriptor(
- isolate(), graph()->zone(), cid,
+ graph()->zone(), cid,
cid.GetStackParameterCount() + argc + 1 /* implicit receiver */,
- CallDescriptor::kNeedsFrameState, Operator::kNoProperties,
- MachineType::AnyTagged(), 1, Linkage::kNoContext);
+ CallDescriptor::kNeedsFrameState);
ApiFunction api_function(v8::ToCData<Address>(call_handler_info->callback()));
Node* holder = lookup == CallOptimization::kHolderFound
? jsgraph()->HeapConstant(api_holder)
@@ -2900,7 +2931,7 @@ Reduction JSCallReducer::ReduceCallApiFunction(
ExternalReference function_reference = ExternalReference::Create(
&api_function, ExternalReference::DIRECT_API_CALL);
node->InsertInput(graph()->zone(), 0,
- jsgraph()->HeapConstant(stub.GetCode()));
+ jsgraph()->HeapConstant(call_api_callback.code()));
node->ReplaceInput(1, context);
node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(data));
node->InsertInput(graph()->zone(), 3, holder);
@@ -3040,7 +3071,8 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
// that no one messed with the %ArrayIteratorPrototype%.next method.
if (node->opcode() == IrOpcode::kJSCallWithSpread ||
node->opcode() == IrOpcode::kJSConstructWithSpread) {
- dependencies()->AssumePropertyCell(factory()->array_iterator_protector());
+ dependencies()->DependOnProtector(PropertyCellRef(
+ js_heap_broker(), factory()->array_iterator_protector()));
}
// Remove the {arguments_list} input from the {node}.
@@ -3249,7 +3281,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
// Update the JSCall operator on {node}.
ConvertReceiverMode const convert_mode =
- NodeProperties::CanBeNullOrUndefined(bound_this, effect)
+ NodeProperties::CanBeNullOrUndefined(isolate(), bound_this, effect)
? ConvertReceiverMode::kAny
: ConvertReceiverMode::kNotNullOrUndefined;
NodeProperties::ChangeOp(
@@ -3273,15 +3305,14 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return NoChange();
}
- Handle<Object> feedback(nexus.GetFeedback(), isolate());
- if (feedback->IsWeakCell()) {
+ HeapObject* heap_object;
+ if (nexus.GetFeedback()->ToWeakHeapObject(&heap_object)) {
+ Handle<HeapObject> feedback(heap_object, isolate());
// Check if we want to use CallIC feedback here.
if (!ShouldUseCallICFeedback(target)) return NoChange();
- Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
- if (cell->value()->IsCallable()) {
- Node* target_function =
- jsgraph()->Constant(handle(cell->value(), isolate()));
+ if (feedback->IsCallable()) {
+ Node* target_function = jsgraph()->Constant(feedback);
// Check that the {target} is still the {target_function}.
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
@@ -3408,6 +3439,54 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceArrayBufferViewAccessor(
node, JS_DATA_VIEW_TYPE,
AccessBuilder::ForJSArrayBufferViewByteOffset());
+ case Builtins::kDataViewPrototypeGetUint8:
+ return ReduceDataViewPrototypeGet(node,
+ ExternalArrayType::kExternalUint8Array);
+ case Builtins::kDataViewPrototypeGetInt8:
+ return ReduceDataViewPrototypeGet(node,
+ ExternalArrayType::kExternalInt8Array);
+ case Builtins::kDataViewPrototypeGetUint16:
+ return ReduceDataViewPrototypeGet(
+ node, ExternalArrayType::kExternalUint16Array);
+ case Builtins::kDataViewPrototypeGetInt16:
+ return ReduceDataViewPrototypeGet(node,
+ ExternalArrayType::kExternalInt16Array);
+ case Builtins::kDataViewPrototypeGetUint32:
+ return ReduceDataViewPrototypeGet(
+ node, ExternalArrayType::kExternalUint32Array);
+ case Builtins::kDataViewPrototypeGetInt32:
+ return ReduceDataViewPrototypeGet(node,
+ ExternalArrayType::kExternalInt32Array);
+ case Builtins::kDataViewPrototypeGetFloat32:
+ return ReduceDataViewPrototypeGet(
+ node, ExternalArrayType::kExternalFloat32Array);
+ case Builtins::kDataViewPrototypeGetFloat64:
+ return ReduceDataViewPrototypeGet(
+ node, ExternalArrayType::kExternalFloat64Array);
+ case Builtins::kDataViewPrototypeSetUint8:
+ return ReduceDataViewPrototypeSet(node,
+ ExternalArrayType::kExternalUint8Array);
+ case Builtins::kDataViewPrototypeSetInt8:
+ return ReduceDataViewPrototypeSet(node,
+ ExternalArrayType::kExternalInt8Array);
+ case Builtins::kDataViewPrototypeSetUint16:
+ return ReduceDataViewPrototypeSet(
+ node, ExternalArrayType::kExternalUint16Array);
+ case Builtins::kDataViewPrototypeSetInt16:
+ return ReduceDataViewPrototypeSet(node,
+ ExternalArrayType::kExternalInt16Array);
+ case Builtins::kDataViewPrototypeSetUint32:
+ return ReduceDataViewPrototypeSet(
+ node, ExternalArrayType::kExternalUint32Array);
+ case Builtins::kDataViewPrototypeSetInt32:
+ return ReduceDataViewPrototypeSet(node,
+ ExternalArrayType::kExternalInt32Array);
+ case Builtins::kDataViewPrototypeSetFloat32:
+ return ReduceDataViewPrototypeSet(
+ node, ExternalArrayType::kExternalFloat32Array);
+ case Builtins::kDataViewPrototypeSetFloat64:
+ return ReduceDataViewPrototypeSet(
+ node, ExternalArrayType::kExternalFloat64Array);
case Builtins::kTypedArrayPrototypeByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE,
@@ -3507,6 +3586,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceMapPrototypeGet(node);
case Builtins::kMapPrototypeHas:
return ReduceMapPrototypeHas(node);
+ case Builtins::kRegExpPrototypeTest:
+ return ReduceRegExpPrototypeTest(node);
case Builtins::kReturnReceiver:
return ReduceReturnReceiver(node);
case Builtins::kStringPrototypeIndexOf:
@@ -3646,13 +3727,15 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
return NoChange();
}
- Handle<Object> feedback(nexus.GetFeedback(), isolate());
- if (feedback->IsAllocationSite()) {
+ HeapObject* feedback_object;
+ if (nexus.GetFeedback()->ToStrongHeapObject(&feedback_object) &&
+ feedback_object->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 = Handle<AllocationSite>::cast(feedback);
+ Handle<AllocationSite> site(AllocationSite::cast(feedback_object),
+ isolate());
// Retrieve the Array function from the {node}.
Node* array_function = jsgraph()->HeapConstant(
@@ -3674,12 +3757,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
NodeProperties::ReplaceValueInput(node, array_function, 1);
NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
return Changed(node);
- } else if (feedback->IsWeakCell() &&
+ } else if (nexus.GetFeedback()->ToWeakHeapObject(&feedback_object) &&
!HeapObjectMatcher(new_target).HasValue()) {
- Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
- if (cell->value()->IsConstructor()) {
- Node* new_target_feedback =
- jsgraph()->Constant(handle(cell->value(), isolate()));
+ 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(),
@@ -4206,20 +4288,17 @@ Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node,
namespace {
// TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
-bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
+bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
DCHECK(!jsarray_map->is_dictionary_map());
- Isolate* isolate = jsarray_map->GetIsolate();
Handle<Name> length_string = isolate->factory()->length_string();
DescriptorArray* descriptors = jsarray_map->instance_descriptors();
- int number =
- descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
+ int number = descriptors->Search(*length_string, *jsarray_map);
DCHECK_NE(DescriptorArray::kNotFound, number);
return descriptors->GetDetails(number).IsReadOnly();
}
// TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
-bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
- Isolate* const isolate = receiver_map->GetIsolate();
+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);
@@ -4227,7 +4306,7 @@ bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
IsFastElementsKind(receiver_map->elements_kind()) &&
!receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
- !IsReadOnlyLengthDescriptor(receiver_map);
+ !IsReadOnlyLengthDescriptor(isolate, receiver_map);
}
} // namespace
@@ -4250,20 +4329,23 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
// Try to determine the {receiver} map(s).
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), 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(receiver_map)) return NoChange();
+ if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
+ return NoChange();
if (!UnionElementsKindUptoPackedness(&kind, receiver_map->elements_kind()))
return NoChange();
}
// Install code dependencies on the {receiver} global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_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.
@@ -4359,13 +4441,15 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), 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(receiver_map)) return NoChange();
+ 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)
@@ -4375,7 +4459,8 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
}
// Install code dependencies on the {receiver} global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_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.
@@ -4475,13 +4560,15 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), 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(receiver_map)) return NoChange();
+ 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)
@@ -4491,7 +4578,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
}
// Install code dependencies on the {receiver} global array protector cell.
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_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.
@@ -4685,7 +4773,8 @@ 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(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
for (Handle<Map> receiver_map : receiver_maps) {
@@ -4705,14 +4794,14 @@ Reduction JSCallReducer::ReduceArrayIterator(Node* node, IterationKind kind) {
namespace {
-bool InferIteratedObjectMaps(Node* iterator,
+bool InferIteratedObjectMaps(Isolate* isolate, 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(iterated_object, effect,
+ NodeProperties::InferReceiverMaps(isolate, iterated_object, effect,
iterated_object_maps);
return result != NodeProperties::kNoReceiverMaps;
}
@@ -4739,7 +4828,7 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
// Try to infer the [[IteratedObject]] maps from the {iterator}.
ZoneHandleSet<Map> iterated_object_maps;
- if (!InferIteratedObjectMaps(iterator, &iterated_object_maps)) {
+ if (!InferIteratedObjectMaps(isolate(), iterator, &iterated_object_maps)) {
return NoChange();
}
DCHECK_NE(0, iterated_object_maps.size());
@@ -4759,7 +4848,7 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
}
} else {
for (Handle<Map> iterated_object_map : iterated_object_maps) {
- if (!CanInlineArrayIteratingBuiltin(iterated_object_map)) {
+ if (!CanInlineArrayIteratingBuiltin(isolate(), iterated_object_map)) {
return NoChange();
}
if (!UnionElementsKindUptoSize(&elements_kind,
@@ -4771,7 +4860,8 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
// Install code dependency on the array protector for holey arrays.
if (IsHoleyElementsKind(elements_kind)) {
- dependencies()->AssumePropertyCell(factory()->no_elements_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->no_elements_protector()));
}
// Load the (current) {iterated_object} from the {iterator}; this might be
@@ -4795,8 +4885,8 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
if (isolate()->IsArrayBufferNeuteringIntact()) {
// Add a code dependency so we are deoptimized in case an ArrayBuffer
// gets neutered.
- dependencies()->AssumePropertyCell(
- factory()->array_buffer_neutering_protector());
+ dependencies()->DependOnProtector(PropertyCellRef(
+ js_heap_broker(), factory()->array_buffer_neutering_protector()));
} else {
// Deoptimize if the array buffer was neutered.
Node* buffer = effect = graph()->NewNode(
@@ -5164,7 +5254,7 @@ Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
- if (NodeProperties::HasInstanceTypeWitness(receiver, effect,
+ if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
JS_STRING_ITERATOR_TYPE)) {
Node* string = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
@@ -5255,10 +5345,10 @@ Reduction JSCallReducer::ReduceStringPrototypeConcat(
Callable const callable =
CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
- auto call_descriptor = Linkage::GetStubCallDescriptor(
- isolate(), graph()->zone(), callable.descriptor(), 0,
- CallDescriptor::kNeedsFrameState,
- Operator::kNoDeopt | Operator::kNoWrite);
+ auto call_descriptor =
+ Linkage::GetStubCallDescriptor(graph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNeedsFrameState,
+ Operator::kNoDeopt | Operator::kNoWrite);
// TODO(turbofan): Massage the FrameState of the {node} here once we
// have an artificial builtin frame type, so that it looks like the
@@ -5281,7 +5371,8 @@ Reduction JSCallReducer::ReduceAsyncFunctionPromiseCreate(Node* node) {
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
// Install a code dependency on the promise hook protector cell.
- dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
// Morph this {node} into a JSCreatePromise node.
RelaxControls(node);
@@ -5296,8 +5387,8 @@ Reduction JSCallReducer::ReduceAsyncFunctionPromiseRelease(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
- // Install a code dependency on the promise hook protector cell.
- dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
+ 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).
@@ -5352,11 +5443,11 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
// Only handle builtins Promises, not subclasses.
if (target != new_target) return NoChange();
- // Add a code dependency on the promise hook protector.
- dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
Handle<SharedFunctionInfo> promise_shared(
- handle(native_context()->promise_function()->shared()));
+ handle(native_context()->promise_function()->shared(), isolate()));
// Insert a construct stub frame into the chain of frame states. This will
// reconstruct the proper frame when deoptimizing within the constructor.
@@ -5510,8 +5601,8 @@ Reduction JSCallReducer::ReducePromiseInternalConstructor(Node* node) {
// Check that promises aren't being observed through (debug) hooks.
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
- // Install a code dependency on the promise hook protector cell.
- dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
// Create a new pending promise.
Node* value = effect =
@@ -5589,7 +5680,8 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
// Check if we know something about {receiver} already.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
@@ -5602,8 +5694,8 @@ Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
}
}
- // Add a code dependency on the necessary protectors.
- dependencies()->AssumePropertyCell(factory()->promise_then_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_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.
@@ -5617,7 +5709,8 @@ 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()));
+ Node* target =
+ jsgraph()->Constant(handle(native_context()->promise_then(), isolate()));
NodeProperties::ReplaceValueInput(node, target, 0);
NodeProperties::ReplaceEffectInput(node, effect);
for (; arity > 1; --arity) node->RemoveInput(3);
@@ -5664,7 +5757,8 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
// Check if we know something about {receiver} already.
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
@@ -5677,10 +5771,12 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
}
}
- // Add a code dependency on the necessary protectors.
- dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
- dependencies()->AssumePropertyCell(factory()->promise_then_protector());
- dependencies()->AssumePropertyCell(factory()->promise_species_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_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()));
// If the {receiver_maps} aren't reliable, we need to repeat the
// map check here, guarded by the CALL_IC.
@@ -5765,7 +5861,8 @@ 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()));
+ Node* target =
+ jsgraph()->Constant(handle(native_context()->promise_then(), isolate()));
NodeProperties::ReplaceValueInput(node, target, 0);
NodeProperties::ReplaceEffectInput(node, effect);
NodeProperties::ReplaceControlInput(node, control);
@@ -5813,7 +5910,8 @@ 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(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (infer_receiver_maps_result == NodeProperties::kNoReceiverMaps) {
return NoChange();
}
@@ -5828,9 +5926,10 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
}
}
- // Add a code dependency on the necessary protectors.
- dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
- dependencies()->AssumePropertyCell(factory()->promise_species_protector());
+ dependencies()->DependOnProtector(
+ PropertyCellRef(js_heap_broker(), factory()->promise_hook_protector()));
+ dependencies()->DependOnProtector(PropertyCellRef(
+ js_heap_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.
@@ -5880,7 +5979,8 @@ 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(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (infer_receiver_maps_result == NodeProperties::kNoReceiverMaps) {
return NoChange();
}
@@ -6075,7 +6175,8 @@ Reduction JSCallReducer::ReduceMapPrototypeGet(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
Node* key = NodeProperties::GetValueInput(node, 2);
- if (!NodeProperties::HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE))
+ if (!NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ JS_MAP_TYPE))
return NoChange();
Node* table = effect = graph()->NewNode(
@@ -6119,7 +6220,8 @@ Reduction JSCallReducer::ReduceMapPrototypeHas(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
Node* key = NodeProperties::GetValueInput(node, 2);
- if (!NodeProperties::HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE))
+ if (!NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ JS_MAP_TYPE))
return NoChange();
Node* table = effect = graph()->NewNode(
@@ -6159,7 +6261,8 @@ Reduction JSCallReducer::ReduceCollectionIteration(
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (NodeProperties::HasInstanceTypeWitness(
- receiver, effect, InstanceTypeForCollectionKind(collection_kind))) {
+ isolate(), receiver, effect,
+ InstanceTypeForCollectionKind(collection_kind))) {
Node* js_create_iterator = effect = graph()->NewNode(
javascript()->CreateCollectionIterator(collection_kind, iteration_kind),
receiver, context, effect, control);
@@ -6176,7 +6279,8 @@ Reduction JSCallReducer::ReduceCollectionPrototypeSize(
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (NodeProperties::HasInstanceTypeWitness(
- receiver, effect, InstanceTypeForCollectionKind(collection_kind))) {
+ isolate(), receiver, effect,
+ InstanceTypeForCollectionKind(collection_kind))) {
Node* table = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
receiver, effect, control);
@@ -6216,7 +6320,8 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
InstanceType receiver_instance_type;
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
- NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
+ NodeProperties::InferReceiverMaps(isolate(), receiver, effect,
+ &receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, receiver_maps.size());
receiver_instance_type = receiver_maps[0]->instance_type();
@@ -6268,8 +6373,8 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kOrderedHashTableHealIndex);
auto call_descriptor = Linkage::GetStubCallDescriptor(
- isolate(), graph()->zone(), callable.descriptor(), 0,
- CallDescriptor::kNoFlags, Operator::kEliminatable);
+ graph()->zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
+ Operator::kEliminatable);
index = effect =
graph()->NewNode(common()->Call(call_descriptor),
jsgraph()->HeapConstant(callable.code()), table, index,
@@ -6491,7 +6596,8 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- if (NodeProperties::HasInstanceTypeWitness(receiver, effect, instance_type)) {
+ if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ instance_type)) {
// Load the {receiver}s field.
Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
receiver, effect, control);
@@ -6500,16 +6606,15 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
if (isolate()->IsArrayBufferNeuteringIntact()) {
// Add a code dependency so we are deoptimized in case an ArrayBuffer
// gets neutered.
- dependencies()->AssumePropertyCell(
- factory()->array_buffer_neutering_protector());
+ dependencies()->DependOnProtector(PropertyCellRef(
+ js_heap_broker(), factory()->array_buffer_neutering_protector()));
} else {
// Check if the {receiver}s buffer was neutered.
- Node* receiver_buffer = effect = graph()->NewNode(
+ Node* buffer = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
receiver, effect, control);
- Node* check = effect =
- graph()->NewNode(simplified()->ArrayBufferWasNeutered(),
- receiver_buffer, effect, control);
+ Node* check = effect = graph()->NewNode(
+ simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
// Default to zero if the {receiver}s buffer was neutered.
value = graph()->NewNode(
@@ -6523,6 +6628,361 @@ Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
return NoChange();
}
+namespace {
+int ExternalArrayElementSize(const ExternalArrayType element_type) {
+ switch (element_type) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return size;
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+ default:
+ UNREACHABLE();
+#undef TYPED_ARRAY_CASE
+ }
+}
+} // namespace
+
+Reduction JSCallReducer::ReduceDataViewPrototypeGet(
+ Node* node, ExternalArrayType element_type) {
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* receiver = NodeProperties::GetValueInput(node, 1);
+
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node);
+
+ CallParameters const& p = CallParametersOf(node->op());
+
+ Node* offset = node->op()->ValueInputCount() > 2
+ ? NodeProperties::GetValueInput(node, 2)
+ : jsgraph()->ZeroConstant();
+
+ Node* is_little_endian = node->op()->ValueInputCount() > 3
+ ? NodeProperties::GetValueInput(node, 3)
+ : jsgraph()->FalseConstant();
+
+ // Only do stuff if the {receiver} is really a DataView.
+ if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ JS_DATA_VIEW_TYPE)) {
+ // Check that the {offset} is a positive Smi.
+ offset = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
+ offset, effect, control);
+
+ Node* is_positive = graph()->NewNode(simplified()->NumberLessThanOrEqual(),
+ jsgraph()->ZeroConstant(), offset);
+
+ effect = graph()->NewNode(
+ simplified()->CheckIf(DeoptimizeReason::kNotASmi, p.feedback()),
+ is_positive, effect, control);
+
+ // Coerce {is_little_endian} to boolean.
+ is_little_endian =
+ graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
+
+ // Get the underlying buffer and check that it has not been neutered.
+ Node* buffer = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
+ receiver, effect, control);
+
+ Node* check_neutered = effect = graph()->NewNode(
+ simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
+ Node* branch_neutered = graph()->NewNode(
+ common()->Branch(BranchHint::kFalse), check_neutered, control);
+
+ // Raise an error if it was neuteured.
+ Node* if_true_neutered =
+ graph()->NewNode(common()->IfTrue(), branch_neutered);
+ Node* etrue_neutered = effect;
+ {
+ if_true_neutered = etrue_neutered = graph()->NewNode(
+ javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
+ jsgraph()->Constant(MessageTemplate::kDetachedOperation),
+ jsgraph()->HeapConstant(
+ factory()->NewStringFromAsciiChecked("DataView.prototype.get")),
+ context, frame_state, etrue_neutered, if_true_neutered);
+ }
+
+ // Otherwise, proceed.
+ Node* if_false_neutered =
+ graph()->NewNode(common()->IfFalse(), branch_neutered);
+ Node* efalse_neutered = effect;
+
+ // Get the byte offset and byte length of the {receiver}.
+ Node* byte_offset = efalse_neutered =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferViewByteOffset()),
+ receiver, efalse_neutered, if_false_neutered);
+
+ Node* byte_length = efalse_neutered =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferViewByteLength()),
+ receiver, efalse_neutered, if_false_neutered);
+
+ // The end offset is the offset plus the element size
+ // of the type that we want to load.
+ int element_size = ExternalArrayElementSize(element_type);
+ Node* end_offset = graph()->NewNode(simplified()->NumberAdd(), offset,
+ jsgraph()->Constant(element_size));
+
+ // We need to check that {end_offset} <= {byte_length}, ie
+ // throw a RangeError if {byte_length} < {end_offset}.
+ Node* check_range = graph()->NewNode(simplified()->NumberLessThan(),
+ byte_length, end_offset);
+ Node* branch_range = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+ check_range, if_false_neutered);
+
+ Node* if_true_range = graph()->NewNode(common()->IfTrue(), branch_range);
+ Node* etrue_range = efalse_neutered;
+ {
+ if_true_range = etrue_range = graph()->NewNode(
+ javascript()->CallRuntime(Runtime::kThrowRangeError, 2),
+ jsgraph()->Constant(MessageTemplate::kInvalidDataViewAccessorOffset),
+ jsgraph()->HeapConstant(
+ factory()->NewStringFromAsciiChecked("DataView.prototype.get")),
+ context, frame_state, etrue_range, if_true_range);
+ }
+
+ Node* if_false_range = graph()->NewNode(common()->IfFalse(), branch_range);
+ Node* efalse_range = efalse_neutered;
+ Node* vfalse_range;
+ {
+ // Get the buffer's backing store.
+ Node* backing_store = efalse_range =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferBackingStore()),
+ buffer, efalse_range, if_false_range);
+
+ // Compute the buffer index at which we'll read.
+ Node* buffer_index =
+ graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
+
+ // Perform the load.
+ vfalse_range = efalse_range =
+ graph()->NewNode(simplified()->LoadDataViewElement(element_type),
+ buffer, backing_store, buffer_index,
+ is_little_endian, efalse_range, if_false_range);
+ }
+
+ // Rewire potential exception edges.
+ Node* on_exception = nullptr;
+ if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
+ // Create appropriate {IfException} and {IfSuccess} nodes.
+ Node* extrue_neutered = graph()->NewNode(
+ common()->IfException(), etrue_neutered,
+ if_true_neutered); // We threw because the array was neutered.
+ if_true_neutered =
+ graph()->NewNode(common()->IfSuccess(), if_true_neutered);
+
+ Node* extrue_range =
+ graph()->NewNode(common()->IfException(), etrue_range,
+ if_true_range); // We threw because out of bounds.
+ if_true_range = graph()->NewNode(common()->IfSuccess(), if_true_range);
+
+ // We can't throw in LoadDataViewElement(),
+ // so we don't need to handle that path here.
+
+ // Join the exception edges.
+ Node* merge =
+ graph()->NewNode(common()->Merge(2), extrue_neutered, extrue_range);
+ Node* ephi = graph()->NewNode(common()->EffectPhi(2), extrue_neutered,
+ extrue_range, merge);
+ Node* phi =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ extrue_neutered, extrue_range, merge);
+ ReplaceWithValue(on_exception, phi, ephi, merge);
+ }
+
+ // Connect the throwing paths to end.
+ if_true_neutered =
+ graph()->NewNode(common()->Throw(), etrue_neutered, if_true_neutered);
+ NodeProperties::MergeControlToEnd(graph(), common(), if_true_neutered);
+ if_true_range =
+ graph()->NewNode(common()->Throw(), etrue_range, if_true_range);
+ NodeProperties::MergeControlToEnd(graph(), common(), if_true_range);
+
+ // Continue on the regular path.
+ ReplaceWithValue(node, vfalse_range, efalse_range, if_false_range);
+ return Changed(vfalse_range);
+ }
+
+ return NoChange();
+}
+Reduction JSCallReducer::ReduceDataViewPrototypeSet(
+ Node* node, ExternalArrayType element_type) {
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* receiver = NodeProperties::GetValueInput(node, 1);
+
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node);
+
+ CallParameters const& p = CallParametersOf(node->op());
+
+ Node* offset = node->op()->ValueInputCount() > 2
+ ? NodeProperties::GetValueInput(node, 2)
+ : jsgraph()->ZeroConstant();
+
+ Node* value = node->op()->ValueInputCount() > 3
+ ? NodeProperties::GetValueInput(node, 3)
+ : jsgraph()->ZeroConstant();
+
+ Node* is_little_endian = node->op()->ValueInputCount() > 4
+ ? NodeProperties::GetValueInput(node, 4)
+ : jsgraph()->FalseConstant();
+
+ // Only do stuff if the {receiver} is really a DataView.
+ if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ JS_DATA_VIEW_TYPE)) {
+ // Check that the {offset} is a positive Smi.
+ offset = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
+ offset, effect, control);
+
+ Node* is_positive = graph()->NewNode(simplified()->NumberLessThanOrEqual(),
+ jsgraph()->ZeroConstant(), offset);
+
+ effect = graph()->NewNode(
+ simplified()->CheckIf(DeoptimizeReason::kNotASmi, p.feedback()),
+ is_positive, effect, control);
+
+ // Coerce {is_little_endian} to boolean.
+ is_little_endian =
+ graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
+
+ // Coerce {value} to Number.
+ value = effect = graph()->NewNode(
+ simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
+ p.feedback()),
+ value, effect, control);
+
+ // Get the underlying buffer and check that it has not been neutered.
+ Node* buffer = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
+ receiver, effect, control);
+
+ Node* check_neutered = effect = graph()->NewNode(
+ simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
+ Node* branch_neutered = graph()->NewNode(
+ common()->Branch(BranchHint::kFalse), check_neutered, control);
+
+ // Raise an error if it was neuteured.
+ Node* if_true_neutered =
+ graph()->NewNode(common()->IfTrue(), branch_neutered);
+ Node* etrue_neutered = effect;
+ {
+ if_true_neutered = etrue_neutered = graph()->NewNode(
+ javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
+ jsgraph()->Constant(MessageTemplate::kDetachedOperation),
+ jsgraph()->HeapConstant(
+ factory()->NewStringFromAsciiChecked("DataView.prototype.set")),
+ context, frame_state, etrue_neutered, if_true_neutered);
+ }
+
+ // Otherwise, proceed.
+ Node* if_false_neutered =
+ graph()->NewNode(common()->IfFalse(), branch_neutered);
+ Node* efalse_neutered = effect;
+
+ // Get the byte offset and byte length of the {receiver}.
+ Node* byte_offset = efalse_neutered =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferViewByteOffset()),
+ receiver, efalse_neutered, if_false_neutered);
+
+ Node* byte_length = efalse_neutered =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferViewByteLength()),
+ receiver, efalse_neutered, if_false_neutered);
+
+ // The end offset is the offset plus the element size
+ // of the type that we want to store.
+ int element_size = ExternalArrayElementSize(element_type);
+ Node* end_offset = graph()->NewNode(simplified()->NumberAdd(), offset,
+ jsgraph()->Constant(element_size));
+
+ // We need to check that {end_offset} <= {byte_length}, ie
+ // throw a RangeError if {byte_length} < {end_offset}.
+ Node* check_range = graph()->NewNode(simplified()->NumberLessThan(),
+ byte_length, end_offset);
+ Node* branch_range = graph()->NewNode(common()->Branch(BranchHint::kFalse),
+ check_range, if_false_neutered);
+
+ Node* if_true_range = graph()->NewNode(common()->IfTrue(), branch_range);
+ Node* etrue_range = efalse_neutered;
+ {
+ if_true_range = etrue_range = graph()->NewNode(
+ javascript()->CallRuntime(Runtime::kThrowRangeError, 2),
+ jsgraph()->Constant(MessageTemplate::kInvalidDataViewAccessorOffset),
+ jsgraph()->HeapConstant(
+ factory()->NewStringFromAsciiChecked("DataView.prototype.set")),
+ context, frame_state, etrue_range, if_true_range);
+ }
+
+ Node* if_false_range = graph()->NewNode(common()->IfFalse(), branch_range);
+ Node* efalse_range = efalse_neutered;
+ Node* vfalse_range = jsgraph()->UndefinedConstant(); // Return value.
+ {
+ // Get the buffer's backing store.
+ Node* backing_store = efalse_range =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayBufferBackingStore()),
+ buffer, efalse_range, if_false_range);
+
+ // Compute the buffer index at which we'll write.
+ Node* buffer_index =
+ graph()->NewNode(simplified()->NumberAdd(), offset, byte_offset);
+
+ // Perform the store.
+ efalse_range =
+ graph()->NewNode(simplified()->StoreDataViewElement(element_type),
+ buffer, backing_store, buffer_index, value,
+ is_little_endian, efalse_range, if_false_range);
+ }
+
+ // Rewire potential exception edges.
+ Node* on_exception = nullptr;
+ if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
+ // Create appropriate {IfException} and {IfSuccess} nodes.
+ Node* extrue_neutered = graph()->NewNode(
+ common()->IfException(), etrue_neutered,
+ if_true_neutered); // We threw because the array was neutered.
+ if_true_neutered =
+ graph()->NewNode(common()->IfSuccess(), if_true_neutered);
+
+ Node* extrue_range =
+ graph()->NewNode(common()->IfException(), etrue_range,
+ if_true_range); // We threw because out of bounds.
+ if_true_range = graph()->NewNode(common()->IfSuccess(), if_true_range);
+
+ // We can't throw in StoreDataViewElement(),
+ // so we don't need to handle that path here.
+
+ // Join the exception edges.
+ Node* merge =
+ graph()->NewNode(common()->Merge(2), extrue_neutered, extrue_range);
+ Node* ephi = graph()->NewNode(common()->EffectPhi(2), extrue_neutered,
+ extrue_range, merge);
+ Node* phi =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ extrue_neutered, extrue_range, merge);
+ ReplaceWithValue(on_exception, phi, ephi, merge);
+ }
+
+ // Connect the throwing paths to end.
+ if_true_neutered =
+ graph()->NewNode(common()->Throw(), etrue_neutered, if_true_neutered);
+ NodeProperties::MergeControlToEnd(graph(), common(), if_true_neutered);
+ if_true_range =
+ graph()->NewNode(common()->Throw(), etrue_range, if_true_range);
+ NodeProperties::MergeControlToEnd(graph(), common(), if_true_range);
+
+ // Continue on the regular path.
+ ReplaceWithValue(node, vfalse_range, efalse_range, if_false_range);
+ return Changed(vfalse_range);
+ }
+
+ return NoChange();
+}
+
// ES6 section 18.2.2 isFinite ( number )
Reduction JSCallReducer::ReduceGlobalIsFinite(Node* node) {
CallParameters const& p = CallParametersOf(node->op());
@@ -6578,7 +7038,8 @@ Reduction JSCallReducer::ReduceDatePrototypeGetTime(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- if (NodeProperties::HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) {
+ if (NodeProperties::HasInstanceTypeWitness(isolate(), receiver, effect,
+ JS_DATE_TYPE)) {
Node* value = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
effect, control);
@@ -6626,6 +7087,101 @@ Reduction JSCallReducer::ReduceNumberParseInt(Node* node) {
return Changed(node);
}
+Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
+ if (FLAG_force_slow_path) return NoChange();
+ if (node->op()->ValueInputCount() < 3) return NoChange();
+ CallParameters const& p = CallParametersOf(node->op());
+ if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
+ return NoChange();
+ }
+
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* regexp = NodeProperties::GetValueInput(node, 1);
+
+ // Check if we know something about the {regexp}.
+ ZoneHandleSet<Map> regexp_maps;
+ NodeProperties::InferReceiverMapsResult result =
+ NodeProperties::InferReceiverMaps(isolate(), regexp, effect,
+ &regexp_maps);
+
+ bool need_map_check = false;
+ switch (result) {
+ case NodeProperties::kNoReceiverMaps:
+ return NoChange();
+ case NodeProperties::kUnreliableReceiverMaps:
+ need_map_check = true;
+ break;
+ case NodeProperties::kReliableReceiverMaps:
+ break;
+ }
+
+ for (auto map : regexp_maps) {
+ if (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());
+ 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();
+
+ PropertyAccessBuilder access_builder(jsgraph(), js_heap_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);
+ }
+
+ if (need_map_check) {
+ effect =
+ graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
+ regexp_maps, p.feedback()),
+ regexp, effect, control);
+ }
+
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node);
+ Node* search = NodeProperties::GetValueInput(node, 2);
+ Node* search_string = effect = graph()->NewNode(
+ simplified()->CheckString(p.feedback()), search, effect, control);
+
+ Node* lastIndex = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSRegExpLastIndex()), regexp,
+ effect, control);
+
+ Node* lastIndexSmi = effect = graph()->NewNode(
+ simplified()->CheckSmi(p.feedback()), lastIndex, effect, control);
+
+ Node* is_positive = graph()->NewNode(simplified()->NumberLessThanOrEqual(),
+ jsgraph()->ZeroConstant(), lastIndexSmi);
+
+ effect = graph()->NewNode(
+ simplified()->CheckIf(DeoptimizeReason::kNotASmi, p.feedback()),
+ is_positive, effect, control);
+
+ node->ReplaceInput(0, regexp);
+ node->ReplaceInput(1, search_string);
+ node->ReplaceInput(2, context);
+ node->ReplaceInput(3, frame_state);
+ node->ReplaceInput(4, effect);
+ node->ReplaceInput(5, control);
+ node->TrimInputCount(6);
+ NodeProperties::ChangeOp(node, javascript()->RegExpTest());
+ return Changed(node);
+}
+
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }