diff options
Diffstat (limited to 'deps/v8/src/compiler/js-native-context-specialization.cc')
-rw-r--r-- | deps/v8/src/compiler/js-native-context-specialization.cc | 649 |
1 files changed, 396 insertions, 253 deletions
diff --git a/deps/v8/src/compiler/js-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc index d449e72367..c78970f0c9 100644 --- a/deps/v8/src/compiler/js-native-context-specialization.cc +++ b/deps/v8/src/compiler/js-native-context-specialization.cc @@ -21,6 +21,7 @@ #include "src/feedback-vector.h" #include "src/field-index-inl.h" #include "src/isolate-inl.h" +#include "src/objects/heap-number.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" #include "src/objects/templates.h" @@ -39,40 +40,35 @@ namespace compiler { namespace { -bool HasNumberMaps(MapHandles const& maps) { +bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) { for (auto map : maps) { - if (map->instance_type() == HEAP_NUMBER_TYPE) return true; + MapRef map_ref(broker, map); + if (map_ref.IsHeapNumberMap()) return true; } return false; } -bool HasOnlyJSArrayMaps(MapHandles const& maps) { +bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) { for (auto map : maps) { - if (!map->IsJSArrayMap()) return false; + MapRef map_ref(broker, map); + if (!map_ref.IsJSArrayMap()) return false; } return true; } } // namespace -struct JSNativeContextSpecialization::ScriptContextTableLookupResult { - Handle<Context> context; - bool immutable; - int index; -}; - JSNativeContextSpecialization::JSNativeContextSpecialization( - Editor* editor, JSGraph* jsgraph, JSHeapBroker* js_heap_broker, Flags flags, + Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker, Flags flags, Handle<Context> native_context, CompilationDependencies* dependencies, Zone* zone, Zone* shared_zone) : AdvancedReducer(editor), jsgraph_(jsgraph), - js_heap_broker_(js_heap_broker), + broker_(broker), flags_(flags), global_object_(native_context->global_object(), jsgraph->isolate()), global_proxy_(JSGlobalProxy::cast(native_context->global_proxy()), jsgraph->isolate()), - native_context_(js_heap_broker, native_context), dependencies_(dependencies), zone_(zone), shared_zone_(shared_zone), @@ -82,6 +78,12 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) { switch (node->opcode()) { case IrOpcode::kJSAdd: return ReduceJSAdd(node); + case IrOpcode::kJSAsyncFunctionEnter: + return ReduceJSAsyncFunctionEnter(node); + case IrOpcode::kJSAsyncFunctionReject: + return ReduceJSAsyncFunctionReject(node); + case IrOpcode::kJSAsyncFunctionResolve: + return ReduceJSAsyncFunctionResolve(node); case IrOpcode::kJSGetSuperConstructor: return ReduceJSGetSuperConstructor(node); case IrOpcode::kJSInstanceOf: @@ -153,7 +155,7 @@ Reduction JSNativeContextSpecialization::ReduceJSToString(Node* node) { Reduction reduction; HeapObjectMatcher matcher(input); - if (matcher.HasValue() && matcher.Ref(js_heap_broker()).IsString()) { + if (matcher.HasValue() && matcher.Ref(broker()).IsString()) { reduction = Changed(input); // JSToString(x:string) => x ReplaceWithValue(node, reduction.replacement()); return reduction; @@ -186,10 +188,10 @@ JSNativeContextSpecialization::CreateDelayedStringConstant(Node* node) { return new (shared_zone()) NumberToStringConstant(number_matcher.Value()); } else { HeapObjectMatcher matcher(node); - if (matcher.HasValue() && matcher.Ref(js_heap_broker()).IsString()) { - StringRef s = matcher.Ref(js_heap_broker()).AsString(); + if (matcher.HasValue() && matcher.Ref(broker()).IsString()) { + StringRef s = matcher.Ref(broker()).AsString(); return new (shared_zone()) - StringLiteral(s.object<String>(), static_cast<size_t>(s.length())); + StringLiteral(s.object(), static_cast<size_t>(s.length())); } else { UNREACHABLE(); } @@ -208,6 +210,114 @@ bool IsStringConstant(JSHeapBroker* broker, Node* node) { } } +Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionEnter( + Node* node) { + DCHECK_EQ(IrOpcode::kJSAsyncFunctionEnter, node->opcode()); + Node* closure = NodeProperties::GetValueInput(node, 0); + Node* receiver = NodeProperties::GetValueInput(node, 1); + Node* context = NodeProperties::GetContextInput(node); + Node* frame_state = NodeProperties::GetFrameStateInput(node); + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange(); + + // Install a code dependency on the promise hook protector cell. + dependencies()->DependOnProtector( + PropertyCellRef(broker(), factory()->promise_hook_protector())); + + // Create the promise for the async function. + Node* promise = effect = + graph()->NewNode(javascript()->CreatePromise(), context, effect); + + // Create the JSAsyncFunctionObject based on the SharedFunctionInfo + // extracted from the top-most frame in {frame_state}. + Handle<SharedFunctionInfo> shared = + FrameStateInfoOf(frame_state->op()).shared_info().ToHandleChecked(); + DCHECK(shared->is_compiled()); + int register_count = shared->internal_formal_parameter_count() + + shared->GetBytecodeArray()->register_count(); + Node* value = effect = + graph()->NewNode(javascript()->CreateAsyncFunctionObject(register_count), + closure, receiver, promise, context, effect, control); + ReplaceWithValue(node, value, effect, control); + return Replace(value); +} + +Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionReject( + Node* node) { + DCHECK_EQ(IrOpcode::kJSAsyncFunctionReject, node->opcode()); + Node* async_function_object = NodeProperties::GetValueInput(node, 0); + Node* reason = NodeProperties::GetValueInput(node, 1); + Node* context = NodeProperties::GetContextInput(node); + Node* frame_state = NodeProperties::GetFrameStateInput(node); + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange(); + + // Install a code dependency on the promise hook protector cell. + dependencies()->DependOnProtector( + PropertyCellRef(broker(), factory()->promise_hook_protector())); + + // Load the promise from the {async_function_object}. + Node* promise = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForJSAsyncFunctionObjectPromise()), + async_function_object, effect, control); + + // Create a nested frame state inside the current method's most-recent + // {frame_state} that will ensure that lazy deoptimizations at this + // point will still return the {promise} instead of the result of the + // JSRejectPromise operation (which yields undefined). + Node* parameters[] = {promise}; + frame_state = CreateStubBuiltinContinuationFrameState( + jsgraph(), Builtins::kAsyncFunctionLazyDeoptContinuation, context, + parameters, arraysize(parameters), frame_state, + ContinuationFrameStateMode::LAZY); + + // Disable the additional debug event for the rejection since a + // debug event already happend for the exception that got us here. + Node* debug_event = jsgraph()->FalseConstant(); + effect = graph()->NewNode(javascript()->RejectPromise(), promise, reason, + debug_event, context, frame_state, effect, control); + ReplaceWithValue(node, promise, effect, control); + return Replace(promise); +} + +Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionResolve( + Node* node) { + DCHECK_EQ(IrOpcode::kJSAsyncFunctionResolve, node->opcode()); + Node* async_function_object = NodeProperties::GetValueInput(node, 0); + Node* value = NodeProperties::GetValueInput(node, 1); + Node* context = NodeProperties::GetContextInput(node); + Node* frame_state = NodeProperties::GetFrameStateInput(node); + Node* effect = NodeProperties::GetEffectInput(node); + Node* control = NodeProperties::GetControlInput(node); + if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange(); + + // Install a code dependency on the promise hook protector cell. + dependencies()->DependOnProtector( + PropertyCellRef(broker(), factory()->promise_hook_protector())); + + // Load the promise from the {async_function_object}. + Node* promise = effect = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForJSAsyncFunctionObjectPromise()), + async_function_object, effect, control); + + // Create a nested frame state inside the current method's most-recent + // {frame_state} that will ensure that lazy deoptimizations at this + // point will still return the {promise} instead of the result of the + // JSResolvePromise operation (which yields undefined). + Node* parameters[] = {promise}; + frame_state = CreateStubBuiltinContinuationFrameState( + jsgraph(), Builtins::kAsyncFunctionLazyDeoptContinuation, context, + parameters, arraysize(parameters), frame_state, + ContinuationFrameStateMode::LAZY); + + effect = graph()->NewNode(javascript()->ResolvePromise(), promise, value, + context, frame_state, effect, control); + ReplaceWithValue(node, promise, effect, control); + return Replace(promise); +} + Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) { // TODO(turbofan): This has to run together with the inlining and // native context specialization to be able to leverage the string @@ -218,8 +328,8 @@ Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) { Node* const lhs = node->InputAt(0); Node* const rhs = node->InputAt(1); - base::Optional<size_t> lhs_len = GetMaxStringLength(js_heap_broker(), lhs); - base::Optional<size_t> rhs_len = GetMaxStringLength(js_heap_broker(), rhs); + base::Optional<size_t> lhs_len = GetMaxStringLength(broker(), lhs); + base::Optional<size_t> rhs_len = GetMaxStringLength(broker(), rhs); if (!lhs_len || !rhs_len) { return NoChange(); } @@ -227,8 +337,7 @@ Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) { // Fold into DelayedStringConstant if at least one of the parameters is a // string constant and the addition won't throw due to too long result. if (*lhs_len + *rhs_len <= String::kMaxLength && - (IsStringConstant(js_heap_broker(), lhs) || - IsStringConstant(js_heap_broker(), rhs))) { + (IsStringConstant(broker(), lhs) || IsStringConstant(broker(), rhs))) { const StringConstantBase* left = CreateDelayedStringConstant(lhs); const StringConstantBase* right = CreateDelayedStringConstant(rhs); const StringConstantBase* cons = @@ -250,8 +359,10 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor( // Check if the input is a known JSFunction. HeapObjectMatcher m(constructor); if (!m.HasValue()) return NoChange(); - JSFunctionRef function = m.Ref(js_heap_broker()).AsJSFunction(); + JSFunctionRef function = m.Ref(broker()).AsJSFunction(); MapRef function_map = function.map(); + // TODO(neis): Remove SerializePrototype call once brokerization is complete. + function_map.SerializePrototype(); ObjectRef function_prototype = function_map.prototype(); // We can constant-fold the super constructor access if the @@ -292,60 +403,53 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { } Handle<Map> receiver_map(receiver->map(), isolate()); - // Compute property access info for @@hasInstance on {receiver}. + // Compute property access info for @@hasInstance on the constructor. PropertyAccessInfo access_info; - AccessInfoFactory access_info_factory(js_heap_broker(), dependencies(), - native_context().object<Context>(), - graph()->zone()); + AccessInfoFactory access_info_factory( + broker(), dependencies(), native_context().object(), graph()->zone()); if (!access_info_factory.ComputePropertyAccessInfo( receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad, &access_info)) { return NoChange(); } + DCHECK_EQ(access_info.receiver_maps().size(), 1); + DCHECK_EQ(access_info.receiver_maps()[0].address(), receiver_map.address()); - PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(), - dependencies()); + PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); if (access_info.IsNotFound()) { // If there's no @@hasInstance handler, the OrdinaryHasInstance operation - // takes over, but that requires the {receiver} to be callable. - if (receiver->IsCallable()) { - // Determine actual holder and perform prototype chain checks. - Handle<JSObject> holder; - if (access_info.holder().ToHandle(&holder)) { - dependencies()->DependOnStablePrototypeChains( - js_heap_broker(), native_context().object<Context>(), - access_info.receiver_maps(), holder); - } - - // Check that {constructor} is actually {receiver}. - constructor = access_builder.BuildCheckValue(constructor, &effect, - control, receiver); + // takes over, but that requires the constructor to be callable. + if (!receiver_map->is_callable()) return NoChange(); - // Monomorphic property access. - access_builder.BuildCheckMaps(constructor, &effect, control, - access_info.receiver_maps()); - - // Lower to OrdinaryHasInstance(C, O). - NodeProperties::ReplaceValueInput(node, constructor, 0); - NodeProperties::ReplaceValueInput(node, object, 1); - NodeProperties::ReplaceEffectInput(node, effect); - NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); - Reduction const reduction = ReduceJSOrdinaryHasInstance(node); - return reduction.Changed() ? reduction : Changed(node); - } - } else if (access_info.IsDataConstant() || - access_info.IsDataConstantField()) { // Determine actual holder and perform prototype chain checks. Handle<JSObject> holder; if (access_info.holder().ToHandle(&holder)) { dependencies()->DependOnStablePrototypeChains( - js_heap_broker(), native_context().object<Context>(), - access_info.receiver_maps(), holder); - } else { - holder = receiver; + broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder)); } + // Monomorphic property access. + constructor = + access_builder.BuildCheckHeapObject(constructor, &effect, control); + access_builder.BuildCheckMaps(constructor, &effect, control, + access_info.receiver_maps()); + + // Lower to OrdinaryHasInstance(C, O). + NodeProperties::ReplaceValueInput(node, constructor, 0); + NodeProperties::ReplaceValueInput(node, object, 1); + NodeProperties::ReplaceEffectInput(node, effect); + NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); + Reduction const reduction = ReduceJSOrdinaryHasInstance(node); + return reduction.Changed() ? reduction : Changed(node); + } + + if (access_info.IsDataConstant() || access_info.IsDataConstantField()) { + // Determine actual holder. + Handle<JSObject> holder; + bool found_on_proto = access_info.holder().ToHandle(&holder); + if (!found_on_proto) holder = receiver; + Handle<Object> constant; if (access_info.IsDataConstant()) { DCHECK(!FLAG_track_constant_fields); @@ -353,12 +457,30 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { } else { DCHECK(FLAG_track_constant_fields); DCHECK(access_info.IsDataConstantField()); - // The value must be callable therefore tagged. - DCHECK(CanBeTaggedPointer(access_info.field_representation())); FieldIndex field_index = access_info.field_index(); constant = JSObject::FastPropertyAt(holder, Representation::Tagged(), field_index); + if (!constant->IsCallable()) { + return NoChange(); + } + + // Install dependency on constness. Unfortunately, access_info does not + // track descriptor index, so we have to search for it. + MapRef holder_map(broker(), handle(holder->map(), isolate())); + Handle<DescriptorArray> descriptors( + holder_map.object()->instance_descriptors(), isolate()); + int descriptor_index = descriptors->Search( + *(factory()->has_instance_symbol()), *(holder_map.object())); + CHECK_NE(descriptor_index, DescriptorArray::kNotFound); + holder_map.SerializeOwnDescriptors(); + dependencies()->DependOnFieldType(holder_map, descriptor_index); } + + if (found_on_proto) { + dependencies()->DependOnStablePrototypeChains( + broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder)); + } + DCHECK(constant->IsCallable()); // Check that {constructor} is actually {receiver}. @@ -409,7 +531,7 @@ JSNativeContextSpecialization::InferHasInPrototypeChain( Node* receiver, Node* effect, Handle<HeapObject> prototype) { ZoneHandleSet<Map> receiver_maps; NodeProperties::InferReceiverMapsResult result = - NodeProperties::InferReceiverMaps(isolate(), receiver, effect, + NodeProperties::InferReceiverMaps(broker(), receiver, effect, &receiver_maps); if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain; @@ -507,7 +629,7 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance( // Optimize if we currently know the "prototype" property. if (m.Value()->IsJSFunction()) { - JSFunctionRef function = m.Ref(js_heap_broker()).AsJSFunction(); + JSFunctionRef function = m.Ref(broker()).AsJSFunction(); // TODO(neis): This is a temporary hack needed because the copy reducer // runs only after this pass. function.Serialize(); @@ -541,18 +663,21 @@ Reduction JSNativeContextSpecialization::ReduceJSPromiseResolve(Node* node) { Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); + if (!isolate()->IsPromiseHookProtectorIntact()) { + return NoChange(); + } + // Check if the {constructor} is the %Promise% function. HeapObjectMatcher m(constructor); if (!m.HasValue() || - !m.Ref(js_heap_broker()) - .equals(js_heap_broker()->native_context().promise_function())) { + !m.Ref(broker()).equals(broker()->native_context().promise_function())) { return NoChange(); } // Check if we know something about the {value}. ZoneHandleSet<Map> value_maps; NodeProperties::InferReceiverMapsResult result = - NodeProperties::InferReceiverMaps(isolate(), value, effect, &value_maps); + NodeProperties::InferReceiverMaps(broker(), value, effect, &value_maps); if (result == NodeProperties::kNoReceiverMaps) return NoChange(); DCHECK_NE(0, value_maps.size()); @@ -561,6 +686,10 @@ Reduction JSNativeContextSpecialization::ReduceJSPromiseResolve(Node* node) { if (value_map->IsJSPromiseMap()) return NoChange(); } + // Install a code dependency on the promise hook protector cell. + dependencies()->DependOnProtector( + PropertyCellRef(broker(), factory()->promise_hook_protector())); + // Create a %Promise% instance and resolve it with {value}. Node* promise = effect = graph()->NewNode(javascript()->CreatePromise(), context, effect); @@ -582,16 +711,23 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) { // Check if we know something about the {resolution}. ZoneHandleSet<Map> resolution_maps; NodeProperties::InferReceiverMapsResult result = - NodeProperties::InferReceiverMaps(isolate(), resolution, effect, + NodeProperties::InferReceiverMaps(broker(), resolution, effect, &resolution_maps); - if (result != NodeProperties::kReliableReceiverMaps) return NoChange(); + if (result == NodeProperties::kNoReceiverMaps) return NoChange(); DCHECK_NE(0, resolution_maps.size()); + // When the {resolution_maps} information is unreliable, we can + // still optimize if all individual {resolution_maps} are stable. + if (result == NodeProperties::kUnreliableReceiverMaps) { + for (Handle<Map> resolution_map : resolution_maps) { + if (!resolution_map->is_stable()) return NoChange(); + } + } + // Compute property access info for "then" on {resolution}. PropertyAccessInfo access_info; - AccessInfoFactory access_info_factory(js_heap_broker(), dependencies(), - native_context().object<Context>(), - graph()->zone()); + AccessInfoFactory access_info_factory( + broker(), dependencies(), native_context().object(), graph()->zone()); if (!access_info_factory.ComputePropertyAccessInfo( MapHandles(resolution_maps.begin(), resolution_maps.end()), factory()->then_string(), AccessMode::kLoad, &access_info)) { @@ -601,15 +737,20 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) { // We can further optimize the case where {resolution} // definitely doesn't have a "then" property. if (!access_info.IsNotFound()) return NoChange(); - PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(), - dependencies()); + PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); // Add proper dependencies on the {resolution}s [[Prototype]]s. Handle<JSObject> holder; if (access_info.holder().ToHandle(&holder)) { dependencies()->DependOnStablePrototypeChains( - js_heap_broker(), native_context().object<Context>(), - access_info.receiver_maps(), holder); + broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder)); + } + + // Add stability dependencies on the {resolution_maps}. + if (result == NodeProperties::kUnreliableReceiverMaps) { + for (Handle<Map> resolution_map : resolution_maps) { + dependencies()->DependOnStableMap(MapRef(broker(), resolution_map)); + } } // Simply fulfill the {promise} with the {resolution}. @@ -716,13 +857,15 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( if (property_details.cell_type() != PropertyCellType::kMutable || property_details.IsConfigurable()) { dependencies()->DependOnGlobalProperty( - PropertyCellRef(js_heap_broker(), property_cell)); + PropertyCellRef(broker(), property_cell)); } // Load from constant/undefined global property can be constant-folded. if (property_details.cell_type() == PropertyCellType::kConstant || property_details.cell_type() == PropertyCellType::kUndefined) { value = jsgraph()->Constant(property_cell_value); + CHECK( + !property_cell_value.is_identical_to(factory()->the_hole_value())); } else { // Load from constant type cell can benefit from type feedback. MaybeHandle<Map> map; @@ -738,9 +881,8 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( representation = MachineRepresentation::kTaggedPointer; } else { MapRef property_cell_value_map( - js_heap_broker(), - handle(HeapObject::cast(*property_cell_value)->map(), - isolate())); + broker(), handle(HeapObject::cast(*property_cell_value)->map(), + isolate())); property_cell_value_type = Type::For(property_cell_value_map); representation = MachineRepresentation::kTaggedPointer; @@ -749,7 +891,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( // mutated without the cell state being updated. if (property_cell_value_map.is_stable()) { dependencies()->DependOnStableMap(property_cell_value_map); - map = property_cell_value_map.object<Map>(); + map = property_cell_value_map.object(); } } } @@ -771,7 +913,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( // Record a code dependency on the cell, and just deoptimize if the new // value doesn't match the previous value stored inside the cell. dependencies()->DependOnGlobalProperty( - PropertyCellRef(js_heap_broker(), property_cell)); + PropertyCellRef(broker(), property_cell)); Node* check = graph()->NewNode(simplified()->ReferenceEqual(), value, jsgraph()->Constant(property_cell_value)); @@ -785,7 +927,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( // values' type doesn't match the type of the previous value in the // cell. dependencies()->DependOnGlobalProperty( - PropertyCellRef(js_heap_broker(), property_cell)); + PropertyCellRef(broker(), property_cell)); Type property_cell_value_type; MachineRepresentation representation = MachineRepresentation::kTagged; if (property_cell_value->IsHeapObject()) { @@ -795,7 +937,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( Handle<HeapObject>::cast(property_cell_value)->map(), isolate()); DCHECK(property_cell_value_map->is_stable()); dependencies()->DependOnStableMap( - MapRef(js_heap_broker(), property_cell_value_map)); + MapRef(broker(), property_cell_value_map)); // Check that the {value} is a HeapObject. value = effect = graph()->NewNode(simplified()->CheckHeapObject(), @@ -827,7 +969,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( // Record a code dependency on the cell, and just deoptimize if the // property ever becomes read-only. dependencies()->DependOnGlobalProperty( - PropertyCellRef(js_heap_broker(), property_cell)); + PropertyCellRef(broker(), property_cell)); effect = graph()->NewNode( simplified()->StoreField(ForPropertyCellValue( MachineRepresentation::kTagged, Type::NonInternal(), @@ -844,7 +986,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess( Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) { DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); - NameRef name(js_heap_broker(), LoadGlobalParametersOf(node->op()).name()); + NameRef name(broker(), LoadGlobalParametersOf(node->op()).name()); Node* effect = NodeProperties::GetEffectInput(node); // Try to lookup the name on the script context table first (lexical scoping). @@ -865,13 +1007,13 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) { } // Lookup the {name} on the global object instead. - return ReduceGlobalAccess(node, nullptr, nullptr, name.object<Name>(), + return ReduceGlobalAccess(node, nullptr, nullptr, name.object(), AccessMode::kLoad); } Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode()); - NameRef name(js_heap_broker(), StoreGlobalParametersOf(node->op()).name()); + NameRef name(broker(), StoreGlobalParametersOf(node->op()).name()); Node* value = NodeProperties::GetValueInput(node, 0); Node* effect = NodeProperties::GetEffectInput(node); Node* control = NodeProperties::GetControlInput(node); @@ -894,7 +1036,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { } // Lookup the {name} on the global object instead. - return ReduceGlobalAccess(node, nullptr, value, name.object<Name>(), + return ReduceGlobalAccess(node, nullptr, value, name.object(), AccessMode::kStore); } @@ -918,11 +1060,11 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( if (receiver_maps.size() == 1) { Handle<Map> receiver_map = receiver_maps.front(); if (receiver_map->IsJSGlobalProxyMap()) { - Object* maybe_constructor = receiver_map->GetConstructor(); + Object maybe_constructor = receiver_map->GetConstructor(); // Detached global proxies have |null| as their constructor. if (maybe_constructor->IsJSFunction() && JSFunction::cast(maybe_constructor)->native_context() == - *native_context().object<Context>()) { + *native_context().object()) { return ReduceGlobalAccess(node, receiver, value, name, access_mode, index); } @@ -930,9 +1072,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( } // Compute property access infos for the receiver maps. - AccessInfoFactory access_info_factory(js_heap_broker(), dependencies(), - native_context().object<Context>(), - graph()->zone()); + AccessInfoFactory access_info_factory( + broker(), dependencies(), native_context().object(), graph()->zone()); ZoneVector<PropertyAccessInfo> access_infos(zone()); if (!access_info_factory.ComputePropertyAccessInfos( receiver_maps, name, access_mode, &access_infos)) { @@ -958,8 +1099,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( if_exceptions = &if_exception_nodes; } - PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(), - dependencies()); + PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); // Check for the monomorphic cases. if (access_infos.size() == 1) { @@ -970,7 +1110,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( &receiver, &effect, control) && !access_builder.TryBuildNumberCheck(access_info.receiver_maps(), &receiver, &effect, control)) { - if (HasNumberMaps(access_info.receiver_maps())) { + if (HasNumberMaps(broker(), access_info.receiver_maps())) { // We need to also let Smi {receiver}s through in this case, so // we construct a diamond, guarded by the Sminess of the {receiver} // and if {receiver} is not a Smi just emit a sequence of map checks. @@ -1015,7 +1155,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( // Check if {receiver} may be a number. bool receiverissmi_possible = false; for (PropertyAccessInfo const& access_info : access_infos) { - if (HasNumberMaps(access_info.receiver_maps())) { + if (HasNumberMaps(broker(), access_info.receiver_maps())) { receiverissmi_possible = true; break; } @@ -1079,7 +1219,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( } // The Number case requires special treatment to also deal with Smis. - if (HasNumberMaps(receiver_maps)) { + if (HasNumberMaps(broker(), receiver_maps)) { // Join this check with the "receiver is smi" check above. DCHECK_NOT_NULL(receiverissmi_effect); DCHECK_NOT_NULL(receiverissmi_control); @@ -1206,15 +1346,16 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); NamedAccess const& p = NamedAccessOf(node->op()); Node* const receiver = NodeProperties::GetValueInput(node, 0); - Node* const value = jsgraph()->Dead(); // Check if we have a constant receiver. HeapObjectMatcher m(receiver); if (m.HasValue()) { - if (m.Value()->IsJSFunction() && - p.name().is_identical_to(factory()->prototype_string())) { + ObjectRef object = m.Ref(broker()); + NameRef name(broker(), p.name()); + if (object.IsJSFunction() && + name.equals(ObjectRef(broker(), factory()->prototype_string()))) { // Optimize "prototype" property of functions. - JSFunctionRef function = m.Ref(js_heap_broker()).AsJSFunction(); + JSFunctionRef function = object.AsJSFunction(); // TODO(neis): This is a temporary hack needed because the copy reducer // runs only after this pass. function.Serialize(); @@ -1228,11 +1369,10 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { Node* value = jsgraph()->Constant(prototype); ReplaceWithValue(node, value); return Replace(value); - } else if (m.Value()->IsString() && - p.name().is_identical_to(factory()->length_string())) { + } else if (object.IsString() && + name.equals(ObjectRef(broker(), factory()->length_string()))) { // Constant-fold "length" property on constant strings. - Handle<String> string = Handle<String>::cast(m.Value()); - Node* value = jsgraph()->Constant(string->length()); + Node* value = jsgraph()->Constant(object.AsString().length()); ReplaceWithValue(node, value); return Replace(value); } @@ -1243,7 +1383,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot()); // Try to lower the named access based on the {receiver_maps}. - return ReduceNamedAccessFromNexus(node, value, nexus, p.name(), + return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, p.name(), AccessMode::kLoad); } @@ -1307,9 +1447,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( } else { // Retrieve the native context from the given {node}. // Compute element access infos for the receiver maps. - AccessInfoFactory access_info_factory(js_heap_broker(), dependencies(), - native_context().object<Context>(), - graph()->zone()); + AccessInfoFactory access_info_factory( + broker(), dependencies(), native_context().object(), graph()->zone()); ZoneVector<ElementAccessInfo> access_infos(zone()); if (!access_info_factory.ComputeElementAccessInfos( receiver_maps, access_mode, &access_infos)) { @@ -1333,7 +1472,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ZoneVector<Handle<Map>> prototype_maps(zone()); for (ElementAccessInfo const& access_info : access_infos) { for (Handle<Map> receiver_map : access_info.receiver_maps()) { - // If the {receiver_map} has a prototype and it's elements backing + // If the {receiver_map} has a prototype and its elements backing // store is either holey, or we have a potentially growing store, // then we need to check that all prototypes have stable maps with // fast elements (and we need to guard against changes to that below). @@ -1356,14 +1495,12 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( // Install dependencies on the relevant prototype maps. for (Handle<Map> prototype_map : prototype_maps) { - dependencies()->DependOnStableMap( - MapRef(js_heap_broker(), prototype_map)); + dependencies()->DependOnStableMap(MapRef(broker(), prototype_map)); } } // Ensure that {receiver} is a heap object. - PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(), - dependencies()); + PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control); // Check for the monomorphic case. @@ -1512,77 +1649,83 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( // Optimize the case where we load from a constant {receiver}. if (access_mode == AccessMode::kLoad) { HeapObjectMatcher mreceiver(receiver); - if (mreceiver.HasValue() && !mreceiver.Value()->IsTheHole(isolate()) && - !mreceiver.Value()->IsNullOrUndefined(isolate())) { - // Check whether we're accessing a known element on the {receiver} - // that is non-configurable, non-writable (i.e. the {receiver} was - // frozen using Object.freeze). - NumberMatcher mindex(index); - if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32 - 1.0)) { - LookupIterator it(isolate(), mreceiver.Value(), - static_cast<uint32_t>(mindex.Value()), - LookupIterator::OWN); - if (it.state() == LookupIterator::DATA) { - if (it.IsReadOnly() && !it.IsConfigurable()) { - // We can safely constant-fold the {index} access to {receiver}, - // since the element is non-configurable, non-writable and thus - // cannot change anymore. - value = jsgraph()->Constant(it.GetDataValue()); - ReplaceWithValue(node, value, effect, control); - return Replace(value); - } - - // Check if the {receiver} is a known constant with a copy-on-write - // backing store, and whether {index} is within the appropriate - // bounds. In that case we can constant-fold the access and only - // check that the {elements} didn't change. This is sufficient as - // the backing store of a copy-on-write JSArray is defensively copied - // whenever the length or the elements (might) change. - // - // What's interesting here is that we don't need to map check the - // {receiver}, since JSArray's will always have their elements in - // the backing store. - if (mreceiver.Value()->IsJSArray()) { - Handle<JSArray> array = Handle<JSArray>::cast(mreceiver.Value()); - if (array->elements()->IsCowArray()) { - Node* elements = effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForJSObjectElements()), - receiver, effect, control); - Handle<FixedArray> array_elements( - FixedArray::cast(array->elements()), isolate()); - Node* check = - graph()->NewNode(simplified()->ReferenceEqual(), elements, - jsgraph()->HeapConstant(array_elements)); - effect = graph()->NewNode( - simplified()->CheckIf( - DeoptimizeReason::kCowArrayElementsChanged), - check, effect, control); + if (mreceiver.HasValue()) { + HeapObjectRef receiver_ref = mreceiver.Ref(broker()).AsHeapObject(); + if (receiver_ref.map().oddball_type() != OddballType::kHole && + receiver_ref.map().oddball_type() != OddballType::kNull && + receiver_ref.map().oddball_type() != OddballType::kUndefined) { + // Check whether we're accessing a known element on the {receiver} + // that is non-configurable, non-writable (i.e. the {receiver} was + // frozen using Object.freeze). + NumberMatcher mindex(index); + if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32 - 1.0)) { + LookupIterator it(isolate(), receiver_ref.object(), + static_cast<uint32_t>(mindex.Value()), + LookupIterator::OWN); + if (it.state() == LookupIterator::DATA) { + if (it.IsReadOnly() && !it.IsConfigurable()) { + // We can safely constant-fold the {index} access to {receiver}, + // since the element is non-configurable, non-writable and thus + // cannot change anymore. value = jsgraph()->Constant(it.GetDataValue()); ReplaceWithValue(node, value, effect, control); return Replace(value); } + + // Check if the {receiver} is a known constant with a copy-on-write + // backing store, and whether {index} is within the appropriate + // bounds. In that case we can constant-fold the access and only + // check that the {elements} didn't change. This is sufficient as + // the backing store of a copy-on-write JSArray is defensively + // copied whenever the length or the elements (might) change. + // + // What's interesting here is that we don't need to map check the + // {receiver}, since JSArray's will always have their elements in + // the backing store. + if (receiver_ref.IsJSArray()) { + Handle<JSArray> array = receiver_ref.AsJSArray().object(); + if (array->elements()->IsCowArray()) { + Node* elements = effect = + graph()->NewNode(simplified()->LoadField( + AccessBuilder::ForJSObjectElements()), + receiver, effect, control); + Handle<FixedArray> array_elements( + FixedArray::cast(array->elements()), isolate()); + Node* check = + graph()->NewNode(simplified()->ReferenceEqual(), elements, + jsgraph()->HeapConstant(array_elements)); + effect = graph()->NewNode( + simplified()->CheckIf( + DeoptimizeReason::kCowArrayElementsChanged), + check, effect, control); + value = jsgraph()->Constant(it.GetDataValue()); + ReplaceWithValue(node, value, effect, control); + return Replace(value); + } + } } } - } - // For constant Strings we can eagerly strength-reduce the keyed - // accesses using the known length, which doesn't change. - if (mreceiver.Value()->IsString()) { - Handle<String> string = Handle<String>::cast(mreceiver.Value()); - - // We can only assume that the {index} is a valid array index if the IC - // is in element access mode and not MEGAMORPHIC, otherwise there's no - // guard for the bounds check below. - if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) { - // Ensure that {index} is less than {receiver} length. - Node* length = jsgraph()->Constant(string->length()); - - // Load the single character string from {receiver} or yield undefined - // if the {index} is out of bounds (depending on the {load_mode}). - value = BuildIndexedStringLoad(receiver, index, length, &effect, - &control, load_mode); - ReplaceWithValue(node, value, effect, control); - return Replace(value); + // For constant Strings we can eagerly strength-reduce the keyed + // accesses using the known length, which doesn't change. + if (receiver_ref.IsString()) { + // We can only assume that the {index} is a valid array index if the + // IC is in element access mode and not MEGAMORPHIC, otherwise there's + // no guard for the bounds check below. + if (nexus.ic_state() != MEGAMORPHIC && + nexus.GetKeyType() == ELEMENT) { + // Ensure that {index} is less than {receiver} length. + Node* length = + jsgraph()->Constant(receiver_ref.AsString().length()); + + // Load the single character string from {receiver} or yield + // undefined if the {index} is out of bounds (depending on the + // {load_mode}). + value = BuildIndexedStringLoad(receiver, index, length, &effect, + &control, load_mode); + ReplaceWithValue(node, value, effect, control); + return Replace(value); + } } } } @@ -1604,26 +1747,26 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( // Optimize access for constant {index}. HeapObjectMatcher mindex(index); - if (mindex.HasValue() && mindex.Value()->IsPrimitive()) { - // Keyed access requires a ToPropertyKey on the {index} first before - // looking up the property on the object (see ES6 section 12.3.2.1). - // We can only do this for non-observable ToPropertyKey invocations, - // so we limit the constant indices to primitives at this point. - Handle<Name> name; - if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) { - uint32_t array_index; - if (name->AsArrayIndex(&array_index)) { - // Use the constant array index. + if (mindex.HasValue()) { + ObjectRef name = mindex.Ref(broker()); + if (name.IsSymbol()) { + return ReduceNamedAccess(node, value, receiver_maps, + name.AsName().object(), access_mode); + } + if (name.IsInternalizedString()) { + uint32_t array_index = name.AsInternalizedString().array_index(); + if (array_index != InternalizedStringRef::kNotAnArrayIndex) { index = jsgraph()->Constant(static_cast<double>(array_index)); } else { - name = factory()->InternalizeName(name); - return ReduceNamedAccess(node, value, receiver_maps, name, access_mode); + return ReduceNamedAccess(node, value, receiver_maps, + name.AsName().object(), access_mode); } } } // Check if we have feedback for a named access. - if (Name* name = nexus.FindFirstName()) { + Name name = nexus.FindFirstName(); + if (!name.is_null()) { return ReduceNamedAccess(node, value, receiver_maps, handle(name, isolate()), access_mode, index); } else if (nexus.GetKeyType() != ELEMENT) { @@ -1885,7 +2028,7 @@ Node* JSNativeContextSpecialization::InlineApiCall( // Only setters have a value. int const argc = value == nullptr ? 0 : 1; // The stub always expects the receiver as the first param on the stack. - Callable call_api_callback = CodeFactory::CallApiCallback(isolate(), argc); + Callable call_api_callback = CodeFactory::CallApiCallback(isolate()); CallInterfaceDescriptor call_interface_descriptor = call_api_callback.descriptor(); auto call_descriptor = Linkage::GetStubCallDescriptor( @@ -1903,16 +2046,17 @@ Node* JSNativeContextSpecialization::InlineApiCall( // Add CallApiCallbackStub's register argument as well. Node* context = jsgraph()->Constant(native_context()); - Node* inputs[10] = {code, context, data, holder, function_reference, - receiver}; - int index = 6 + argc; + Node* inputs[11] = { + code, context, function_reference, jsgraph()->Constant(argc), data, + holder, receiver}; + int index = 7 + argc; inputs[index++] = frame_state; inputs[index++] = *effect; inputs[index++] = *control; // This needs to stay here because of the edge case described in // http://crbug.com/675648. if (value != nullptr) { - inputs[6] = value; + inputs[7] = value; } return *effect = *control = @@ -1926,12 +2070,10 @@ JSNativeContextSpecialization::BuildPropertyLoad( PropertyAccessInfo const& access_info) { // Determine actual holder and perform prototype chain checks. Handle<JSObject> holder; - PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(), - dependencies()); + PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); if (access_info.holder().ToHandle(&holder)) { dependencies()->DependOnStablePrototypeChains( - js_heap_broker(), native_context().object<Context>(), - access_info.receiver_maps(), holder); + broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder)); } // Generate the actual property access. @@ -1986,13 +2128,11 @@ JSNativeContextSpecialization::BuildPropertyStore( PropertyAccessInfo const& access_info, AccessMode access_mode) { // Determine actual holder and perform prototype chain checks. Handle<JSObject> holder; - PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(), - dependencies()); + PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); if (access_info.holder().ToHandle(&holder)) { DCHECK_NE(AccessMode::kStoreInLiteral, access_mode); dependencies()->DependOnStablePrototypeChains( - js_heap_broker(), native_context().object<Context>(), - access_info.receiver_maps(), holder); + broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder)); } DCHECK(!access_info.IsNotFound()); @@ -2152,7 +2292,7 @@ JSNativeContextSpecialization::BuildPropertyStore( // Reallocate the properties {storage}. storage = effect = BuildExtendPropertiesBackingStore( - original_map, storage, effect, control); + MapRef(broker(), original_map), storage, effect, control); // Perform the actual store. effect = graph()->NewNode(simplified()->StoreField(field_access), @@ -2201,8 +2341,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( DCHECK_EQ(MONOMORPHIC, nexus.ic_state()); - Map* map = nexus.FindFirstMap(); - if (map == nullptr) { + Map map = nexus.FindFirstMap(); + if (map.is_null()) { // Maps are weakly held in the type feedback vector, we may not have one. return NoChange(); } @@ -2211,14 +2351,13 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( if (!Map::TryUpdate(isolate(), receiver_map).ToHandle(&receiver_map)) return NoChange(); - Handle<Name> cached_name = - handle(Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()), - isolate()); + Handle<Name> cached_name( + Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()), + isolate()); PropertyAccessInfo access_info; - AccessInfoFactory access_info_factory(js_heap_broker(), dependencies(), - native_context().object<Context>(), - graph()->zone()); + AccessInfoFactory access_info_factory( + broker(), dependencies(), native_context().object(), graph()->zone()); if (!access_info_factory.ComputePropertyAccessInfo( receiver_map, cached_name, AccessMode::kStoreInLiteral, &access_info)) { @@ -2230,8 +2369,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( Node* control = NodeProperties::GetControlInput(node); // Monomorphic property access. - PropertyAccessBuilder access_builder(jsgraph(), js_heap_broker(), - dependencies()); + PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies()); receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control); access_builder.BuildCheckMaps(receiver, &effect, control, access_info.receiver_maps()); @@ -2305,7 +2443,7 @@ Reduction JSNativeContextSpecialization::ReduceJSToObject(Node* node) { ZoneHandleSet<Map> receiver_maps; NodeProperties::InferReceiverMapsResult result = - NodeProperties::InferReceiverMaps(isolate(), receiver, effect, + NodeProperties::InferReceiverMaps(broker(), receiver, effect, &receiver_maps); if (result == NodeProperties::kNoReceiverMaps) return NoChange(); @@ -2332,12 +2470,14 @@ ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) { UNREACHABLE(); } -MaybeHandle<JSTypedArray> GetTypedArrayConstant(Node* receiver) { +base::Optional<JSTypedArrayRef> GetTypedArrayConstant(JSHeapBroker* broker, + Node* receiver) { HeapObjectMatcher m(receiver); - if (!m.HasValue()) return MaybeHandle<JSTypedArray>(); - if (!m.Value()->IsJSTypedArray()) return MaybeHandle<JSTypedArray>(); - Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(m.Value()); - if (typed_array->is_on_heap()) return MaybeHandle<JSTypedArray>(); + if (!m.HasValue()) return base::nullopt; + ObjectRef object = m.Ref(broker); + if (!object.IsJSTypedArray()) return base::nullopt; + JSTypedArrayRef typed_array = object.AsJSTypedArray(); + if (typed_array.is_on_heap()) return base::nullopt; return typed_array; } @@ -2362,19 +2502,20 @@ JSNativeContextSpecialization::BuildElementAccess( // Check if we can constant-fold information about the {receiver} (i.e. // for asm.js-like code patterns). - Handle<JSTypedArray> typed_array; - if (GetTypedArrayConstant(receiver).ToHandle(&typed_array)) { - buffer = jsgraph()->HeapConstant(typed_array->GetBuffer()); + base::Optional<JSTypedArrayRef> typed_array = + GetTypedArrayConstant(broker(), receiver); + if (typed_array.has_value()) { + typed_array->Serialize(); + buffer = jsgraph()->Constant(typed_array->buffer()); length = jsgraph()->Constant(static_cast<double>(typed_array->length_value())); // Load the (known) base and external pointer for the {receiver}. The - // {external_pointer} might be invalid if the {buffer} was neutered, so + // {external_pointer} might be invalid if the {buffer} was detached, so // we need to make sure that any access is properly guarded. base_pointer = jsgraph()->ZeroConstant(); - external_pointer = jsgraph()->PointerConstant( - FixedTypedArrayBase::cast(typed_array->elements()) - ->external_pointer()); + external_pointer = + jsgraph()->PointerConstant(typed_array->elements_external_pointer()); } else { // Load the {receiver}s length. length = effect = graph()->NewNode( @@ -2412,15 +2553,15 @@ JSNativeContextSpecialization::BuildElementAccess( elements, effect, control); } - // See if we can skip the neutering check. - if (isolate()->IsArrayBufferNeuteringIntact()) { + // See if we can skip the detaching check. + if (isolate()->IsArrayBufferDetachingIntact()) { // Add a code dependency so we are deoptimized in case an ArrayBuffer - // gets neutered. + // gets detached. dependencies()->DependOnProtector(PropertyCellRef( - js_heap_broker(), factory()->array_buffer_neutering_protector())); + broker(), factory()->array_buffer_detaching_protector())); } else { - // Deopt if the {buffer} was neutered. - // Note: A neutered buffer leads to megamorphic feedback. + // Deopt if the {buffer} was detached. + // Note: A detached buffer leads to megamorphic feedback. Node* buffer_bit_field = effect = graph()->NewNode( simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), buffer, effect, control); @@ -2428,10 +2569,10 @@ JSNativeContextSpecialization::BuildElementAccess( simplified()->NumberEqual(), graph()->NewNode( simplified()->NumberBitwiseAnd(), buffer_bit_field, - jsgraph()->Constant(JSArrayBuffer::WasNeuteredBit::kMask)), + jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)), jsgraph()->ZeroConstant()); effect = graph()->NewNode( - simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered), + simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached), check, effect, control); } @@ -2572,7 +2713,7 @@ JSNativeContextSpecialization::BuildElementAccess( } // Check if the {receiver} is a JSArray. - bool receiver_is_jsarray = HasOnlyJSArrayMaps(receiver_maps); + bool receiver_is_jsarray = HasOnlyJSArrayMaps(broker(), receiver_maps); // Load the length of the {receiver}. Node* length = effect = @@ -2829,7 +2970,7 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad( if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS && isolate()->IsNoElementsProtectorIntact()) { dependencies()->DependOnProtector( - PropertyCellRef(js_heap_broker(), factory()->no_elements_protector())); + PropertyCellRef(broker(), factory()->no_elements_protector())); // Ensure that the {index} is a valid String length. index = *effect = graph()->NewNode( @@ -2880,7 +3021,7 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad( } Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( - Handle<Map> map, Node* properties, Node* effect, Node* control) { + const MapRef& map, Node* properties, Node* effect, Node* control) { // TODO(bmeurer/jkummerow): Property deletions can undo map transitions // while keeping the backing store around, meaning that even though the // map might believe that objects have no unused property fields, there @@ -2890,9 +3031,9 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( // difficult for escape analysis to get rid of the backing stores used // for intermediate states of chains of property additions. That makes // it unclear what the best approach is here. - DCHECK_EQ(0, map->UnusedPropertyFields()); + DCHECK_EQ(0, map.UnusedPropertyFields()); // Compute the length of the old {properties} and the new properties. - int length = map->NextFreePropertyIndex() - map->GetInObjectProperties(); + int length = map.NextFreePropertyIndex() - map.GetInObjectProperties(); int new_length = length + JSObject::kFieldsAdded; // Collect the field values from the {properties}. ZoneVector<Node*> values(zone()); @@ -2961,16 +3102,17 @@ Node* JSNativeContextSpecialization::BuildCheckEqualsName(Handle<Name> name, bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( MapHandles const& receiver_maps) { - // Check if all {receiver_maps} either have one of the initial Array.prototype + // Check if all {receiver_maps} have one of the initial Array.prototype // or Object.prototype objects as their prototype (in any of the current // native contexts, as the global Array protector works isolate-wide). - for (Handle<Map> receiver_map : receiver_maps) { - DisallowHeapAllocation no_gc; - Object* const receiver_prototype = receiver_map->prototype(); - if (!isolate()->IsInAnyContext(receiver_prototype, - Context::INITIAL_ARRAY_PROTOTYPE_INDEX) && - !isolate()->IsInAnyContext(receiver_prototype, - Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) { + for (Handle<Map> map : receiver_maps) { + MapRef receiver_map(broker(), map); + // TODO(neis): Remove SerializePrototype call once brokerization is + // complete. + receiver_map.SerializePrototype(); + ObjectRef receiver_prototype = receiver_map.prototype(); + if (!receiver_prototype.IsJSObject() || + !broker()->IsArrayOrObjectPrototype(receiver_prototype.AsJSObject())) { return false; } } @@ -2979,7 +3121,7 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( if (!isolate()->IsNoElementsProtectorIntact()) return false; dependencies()->DependOnProtector( - PropertyCellRef(js_heap_broker(), factory()->no_elements_protector())); + PropertyCellRef(broker(), factory()->no_elements_protector())); return true; } @@ -3027,7 +3169,7 @@ bool JSNativeContextSpecialization::InferReceiverMaps( Node* receiver, Node* effect, MapHandles* receiver_maps) { ZoneHandleSet<Map> maps; NodeProperties::InferReceiverMapsResult result = - NodeProperties::InferReceiverMaps(isolate(), receiver, effect, &maps); + NodeProperties::InferReceiverMaps(broker(), receiver, effect, &maps); if (result == NodeProperties::kReliableReceiverMaps) { for (size_t i = 0; i < maps.size(); ++i) { receiver_maps->push_back(maps[i]); @@ -3037,7 +3179,8 @@ bool JSNativeContextSpecialization::InferReceiverMaps( // For untrusted receiver maps, we can still use the information // if the maps are stable. for (size_t i = 0; i < maps.size(); ++i) { - if (!maps[i]->is_stable()) return false; + MapRef map(broker(), maps[i]); + if (!map.is_stable()) return false; } for (size_t i = 0; i < maps.size(); ++i) { receiver_maps->push_back(maps[i]); |