diff options
Diffstat (limited to 'deps/v8/src/compiler/js-call-reducer.cc')
-rw-r--r-- | deps/v8/src/compiler/js-call-reducer.cc | 836 |
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, + ®exp_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(); } |