Commit 97d106f4 authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[TurboFan] Optimize map checks with pointer compression

If pointer compression is on, it makes sense to embed the map as
a 32-bit constant, for direct comparison. No need to uncompress
the receiver map.

Bug: v8:8982
Change-Id: I285ca4d5b49b26536873776d298e18bcbf84b23e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1518182Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60313}
parent 55bbcc4c
......@@ -50,6 +50,17 @@ FieldAccess AccessBuilder::ForMap() {
return access;
}
// static
FieldAccess AccessBuilder::ForCompressedMap() {
FieldAccess access = {kTaggedBase, HeapObject::kMapOffset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
// We use MachineType::Uint32() for the compressed
// pointer load, because we want to examine it
// as a compressed pointer in map checks.
Type::OtherInternal(), MachineType::Uint32(),
kMapWriteBarrier, LoadSensitivity::kUnsafe};
return access;
}
// static
FieldAccess AccessBuilder::ForHeapNumberValue() {
......
......@@ -36,6 +36,8 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to HeapObject::map() field.
static FieldAccess ForMap();
static FieldAccess ForCompressedMap();
// Provides access to HeapNumber::value() field.
static FieldAccess ForHeapNumberValue();
......
......@@ -18,14 +18,22 @@
#include "src/objects/heap-number.h"
#include "src/objects/oddball.h"
#include "src/ptr-compr-inl.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
bool UsingCompressedPointers() { return kTaggedSize < kSystemPointerSize; }
} // namespace
EffectControlLinearizer::EffectControlLinearizer(
JSGraph* js_graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions, NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index)
MaskArrayIndexEnable mask_array_index,
std::vector<Handle<Map>>* embedded_maps)
: js_graph_(js_graph),
schedule_(schedule),
temp_zone_(temp_zone),
......@@ -33,7 +41,8 @@ EffectControlLinearizer::EffectControlLinearizer(
source_positions_(source_positions),
node_origins_(node_origins),
graph_assembler_(js_graph, nullptr, nullptr, temp_zone),
frame_state_zapper_(nullptr) {}
frame_state_zapper_(nullptr),
embedded_maps_(embedded_maps) {}
Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); }
CommonOperatorBuilder* EffectControlLinearizer::common() const {
......@@ -1524,11 +1533,27 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
auto done = __ MakeLabel();
// Load the current map of the {value}.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* value_map =
UsingCompressedPointers()
? __ LoadField(AccessBuilder::ForCompressedMap(), value)
: __ LoadField(AccessBuilder::ForMap(), value);
for (size_t i = 0; i < map_count; ++i) {
Node* map = __ HeapConstant(maps[i]);
Node* check = __ WordEqual(value_map, map);
Node* check;
if (UsingCompressedPointers()) {
// We need the dereference scope to embed the map pointer value as an
// int32. We don't visit the pointer.
AllowHandleDereference allow_map_dereference;
int32_t int32Map = static_cast<int32_t>(CompressTagged(maps[i]->ptr()));
Node* map = __ Int32Constant(int32Map);
check = __ Word32Equal(value_map, map);
this->embedded_maps()->push_back(maps[i]);
} else {
Node* map = __ HeapConstant(maps[i]);
check = __ WordEqual(value_map, map);
}
if (i == map_count - 1) {
__ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, p.feedback(), check,
frame_state, IsSafetyCheck::kCriticalSafetyCheck);
......@@ -1551,11 +1576,26 @@ Node* EffectControlLinearizer::LowerCompareMaps(Node* node) {
auto done = __ MakeLabel(MachineRepresentation::kBit);
// Load the current map of the {value}.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* value_map = UsingCompressedPointers()
? __ LoadField(AccessBuilder::ForCompressedMap(), value)
: __ LoadField(AccessBuilder::ForMap(), value);
for (size_t i = 0; i < map_count; ++i) {
Node* map = __ HeapConstant(maps[i]);
Node* check = __ WordEqual(value_map, map);
Node* check;
if (UsingCompressedPointers()) {
// We need the dereference scope to embed the map pointer value as an
// int32. We don't visit the pointer.
AllowHandleDereference allow_map_dereference;
int32_t int32Map = static_cast<int32_t>(CompressTagged(maps[i]->ptr()));
Node* map = __ Int32Constant(int32Map);
check = __ Word32Equal(value_map, map);
this->embedded_maps()->push_back(maps[i]);
} else {
Node* map = __ HeapConstant(maps[i]);
check = __ WordEqual(value_map, map);
}
auto next_map = __ MakeLabel();
auto passed = __ MakeLabel();
__ Branch(check, &passed, &next_map, IsSafetyCheck::kCriticalSafetyCheck);
......
......@@ -36,7 +36,8 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
EffectControlLinearizer(JSGraph* graph, Schedule* schedule, Zone* temp_zone,
SourcePositionTable* source_positions,
NodeOriginTable* node_origins,
MaskArrayIndexEnable mask_array_index);
MaskArrayIndexEnable mask_array_index,
std::vector<Handle<Map>>* embedded_maps);
void Run();
......@@ -232,6 +233,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
CommonOperatorBuilder* common() const;
SimplifiedOperatorBuilder* simplified() const;
MachineOperatorBuilder* machine() const;
std::vector<Handle<Map>>* embedded_maps() { return embedded_maps_; }
GraphAssembler* gasm() { return &graph_assembler_; }
......@@ -244,6 +246,10 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
NodeOriginTable* node_origins_;
GraphAssembler graph_assembler_;
Node* frame_state_zapper_; // For tracking down compiler::Node::New crashes.
// embedded_maps_ keeps track of maps we've embedded as Uint32 constants.
// We do this in order to notify the garbage collector at code-gen time.
std::vector<Handle<Map>>* embedded_maps_;
};
} // namespace compiler
......
......@@ -289,6 +289,7 @@ class PipelineData {
Zone* codegen_zone() const { return codegen_zone_; }
InstructionSequence* sequence() const { return sequence_; }
Frame* frame() const { return frame_; }
std::vector<Handle<Map>>* embedded_maps() { return &embedded_maps_; }
Zone* register_allocation_zone() const { return register_allocation_zone_; }
RegisterAllocationData* register_allocation_data() const {
......@@ -491,6 +492,10 @@ class PipelineData {
JSHeapBroker* broker_ = nullptr;
Frame* frame_ = nullptr;
// embedded_maps_ keeps track of maps we've embedded as Uint32 constants.
// We do this in order to notify the garbage collector at code-gen time.
std::vector<Handle<Map>> embedded_maps_;
// All objects in the following group of fields are allocated in
// register_allocation_zone_. They are all set to nullptr when the zone is
// destroyed.
......@@ -985,7 +990,7 @@ PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl(
void PipelineCompilationJob::RegisterWeakObjectsInOptimizedCode(
Handle<Code> code, Isolate* isolate) {
DCHECK(code->is_optimized_code());
std::vector<Handle<Map>> maps;
std::vector<Handle<Map>> retained_maps;
{
DisallowHeapAllocation no_gc;
int const mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
......@@ -996,14 +1001,23 @@ void PipelineCompilationJob::RegisterWeakObjectsInOptimizedCode(
Handle<HeapObject> object(HeapObject::cast(it.rinfo()->target_object()),
isolate);
if (object->IsMap()) {
maps.push_back(Handle<Map>::cast(object));
retained_maps.push_back(Handle<Map>::cast(object));
}
}
}
}
for (Handle<Map> map : maps) {
for (Handle<Map> map : retained_maps) {
isolate->heap()->AddRetainedMap(map);
}
// Additionally, gather embedded maps if we have any.
for (Handle<Map> map : *data_.embedded_maps()) {
if (code->IsWeakObjectInOptimizedCode(*map)) {
isolate->heap()->AddRetainedMap(map);
}
}
code->set_can_have_weak_objects(true);
}
......@@ -1378,7 +1392,7 @@ struct EffectControlLinearizationPhase {
// - introduce effect phis and rewire effects to get SSA again.
EffectControlLinearizer linearizer(
data->jsgraph(), schedule, temp_zone, data->source_positions(),
data->node_origins(), mask_array_index);
data->node_origins(), mask_array_index, data->embedded_maps());
linearizer.Run();
}
{
......
......@@ -5,7 +5,6 @@
#ifndef V8_PTR_COMPR_INL_H_
#define V8_PTR_COMPR_INL_H_
#if V8_TARGET_ARCH_64_BIT
#include "include/v8-internal.h"
#include "src/ptr-compr.h"
......@@ -13,6 +12,7 @@
namespace v8 {
namespace internal {
#if V8_TARGET_ARCH_64_BIT
// Compresses full-pointer representation of a tagged value to on-heap
// representation.
V8_INLINE Tagged_t CompressTagged(Address tagged) {
......@@ -58,9 +58,12 @@ STATIC_ASSERT(kPtrComprIsolateRootAlignment ==
#endif // V8_COMPRESS_POINTERS
} // namespace internal
} // namespace v8
#else
V8_INLINE Tagged_t CompressTagged(Address tagged) { UNREACHABLE(); }
#endif // V8_TARGET_ARCH_64_BIT
} // namespace internal
} // namespace v8
#endif // V8_PTR_COMPR_INL_H_
......@@ -5,10 +5,10 @@
#ifndef V8_PTR_COMPR_H_
#define V8_PTR_COMPR_H_
#if V8_TARGET_ARCH_64_BIT
#include "src/globals.h"
#if V8_TARGET_ARCH_64_BIT
namespace v8 {
namespace internal {
......
......@@ -40,6 +40,7 @@ class EffectControlLinearizerTest : public GraphTest {
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
SourcePositionTable* source_positions() { return source_positions_; }
NodeOriginTable* node_origins() { return node_origins_; }
std::vector<Handle<Map>>* maps() { return &maps_; }
private:
MachineOperatorBuilder machine_;
......@@ -48,6 +49,7 @@ class EffectControlLinearizerTest : public GraphTest {
JSGraph jsgraph_;
SourcePositionTable* source_positions_;
NodeOriginTable* node_origins_;
std::vector<Handle<Map>> maps_;
};
namespace {
......@@ -87,7 +89,7 @@ TEST_F(EffectControlLinearizerTest, SimpleLoad) {
// Run the state effect introducer.
EffectControlLinearizer introducer(
jsgraph(), &schedule, zone(), source_positions(), node_origins(),
EffectControlLinearizer::kDoNotMaskArrayIndex);
EffectControlLinearizer::kDoNotMaskArrayIndex, maps());
introducer.Run();
EXPECT_THAT(load,
......@@ -150,7 +152,7 @@ TEST_F(EffectControlLinearizerTest, DiamondLoad) {
// Run the state effect introducer.
EffectControlLinearizer introducer(
jsgraph(), &schedule, zone(), source_positions(), node_origins(),
EffectControlLinearizer::kDoNotMaskArrayIndex);
EffectControlLinearizer::kDoNotMaskArrayIndex, maps());
introducer.Run();
// The effect input to the return should be an effect phi with the
......@@ -218,7 +220,7 @@ TEST_F(EffectControlLinearizerTest, LoopLoad) {
// Run the state effect introducer.
EffectControlLinearizer introducer(
jsgraph(), &schedule, zone(), source_positions(), node_origins(),
EffectControlLinearizer::kDoNotMaskArrayIndex);
EffectControlLinearizer::kDoNotMaskArrayIndex, maps());
introducer.Run();
ASSERT_THAT(ret, IsReturn(load, load, if_true));
......@@ -282,7 +284,7 @@ TEST_F(EffectControlLinearizerTest, CloneBranch) {
EffectControlLinearizer introducer(
jsgraph(), &schedule, zone(), source_positions(), node_origins(),
EffectControlLinearizer::kDoNotMaskArrayIndex);
EffectControlLinearizer::kDoNotMaskArrayIndex, maps());
introducer.Run();
Capture<Node *> branch1_capture, branch2_capture;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment