summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-native-context-specialization.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-native-context-specialization.cc')
-rw-r--r--deps/v8/src/compiler/js-native-context-specialization.cc649
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]);