Commit ed0a8599 authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

Reland "[runtime] Optimise paired instance type checks"

This is a reland of 92edf9a1

Introduce map handle again to prevent corruption.

Drive-by-fix:
Make some PropertyDetails and Representation methods constexpr.

Original change's description:
> [runtime] Optimise paired instance type checks
>
> Clang doesn't optimise over handle derefs. Change the ValueSerializer
> and the JsonStringifier to use InstanceType directly for checks.
> This CL squeezes another 1.5% of JSON.stringify in local benchmarks.
>
> Drive-by-fix:
> - Avoid a few more derefs in the JsonStringifier
> - Make JsonStringifier::SerializeJSArray a bit more readable
>
> Change-Id: I37626a6d92a8d9275611a4e6d1d908f2e0c6d43b
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3247637
> Commit-Queue: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#77697}

Change-Id: I8915a82aab6dd7966223a4d7a8dd1363258b7c81
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3260512
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77735}
parent cce7154d
This diff is collapsed.
......@@ -104,16 +104,22 @@ class Representation {
kNumRepresentations
};
Representation() : kind_(kNone) {}
constexpr Representation() : kind_(kNone) {}
static Representation None() { return Representation(kNone); }
static Representation Tagged() { return Representation(kTagged); }
static Representation Smi() { return Representation(kSmi); }
static Representation Double() { return Representation(kDouble); }
static Representation HeapObject() { return Representation(kHeapObject); }
static Representation WasmValue() { return Representation(kWasmValue); }
static constexpr Representation None() { return Representation(kNone); }
static constexpr Representation Tagged() { return Representation(kTagged); }
static constexpr Representation Smi() { return Representation(kSmi); }
static constexpr Representation Double() { return Representation(kDouble); }
static constexpr Representation HeapObject() {
return Representation(kHeapObject);
}
static constexpr Representation WasmValue() {
return Representation(kWasmValue);
}
static Representation FromKind(Kind kind) { return Representation(kind); }
static constexpr Representation FromKind(Kind kind) {
return Representation(kind);
}
bool Equals(const Representation& other) const {
return kind_ == other.kind_;
......@@ -190,14 +196,14 @@ class Representation {
return kTaggedSize;
}
Kind kind() const { return static_cast<Kind>(kind_); }
bool IsNone() const { return kind_ == kNone; }
bool IsWasmValue() const { return kind_ == kWasmValue; }
bool IsTagged() const { return kind_ == kTagged; }
bool IsSmi() const { return kind_ == kSmi; }
bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
bool IsDouble() const { return kind_ == kDouble; }
bool IsHeapObject() const { return kind_ == kHeapObject; }
constexpr Kind kind() const { return static_cast<Kind>(kind_); }
constexpr bool IsNone() const { return kind_ == kNone; }
constexpr bool IsWasmValue() const { return kind_ == kWasmValue; }
constexpr bool IsTagged() const { return kind_ == kTagged; }
constexpr bool IsSmi() const { return kind_ == kSmi; }
constexpr bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
constexpr bool IsDouble() const { return kind_ == kDouble; }
constexpr bool IsHeapObject() const { return kind_ == kHeapObject; }
const char* Mnemonic() const {
switch (kind_) {
......@@ -218,7 +224,7 @@ class Representation {
}
private:
explicit Representation(Kind k) : kind_(k) {}
explicit constexpr Representation(Kind k) : kind_(k) {}
// Make sure kind fits in int8.
STATIC_ASSERT(kNumRepresentations <= (1 << kBitsPerByte));
......@@ -254,42 +260,43 @@ enum class PropertyCellType {
class PropertyDetails {
public:
// Property details for global dictionary properties.
PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
PropertyCellType cell_type, int dictionary_index = 0) {
value_ = KindField::encode(kind) |
LocationField::encode(PropertyLocation::kField) |
AttributesField::encode(attributes) |
// We track PropertyCell constness via PropertyCellTypeField,
// so we set ConstnessField to kMutable to simplify DCHECKs related
// to non-global property constness tracking.
ConstnessField::encode(PropertyConstness::kMutable) |
DictionaryStorageField::encode(dictionary_index) |
PropertyCellTypeField::encode(cell_type);
}
constexpr PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
PropertyCellType cell_type,
int dictionary_index = 0)
: value_(KindField::encode(kind) |
LocationField::encode(PropertyLocation::kField) |
AttributesField::encode(attributes) |
// We track PropertyCell constness via PropertyCellTypeField,
// so we set ConstnessField to kMutable to simplify DCHECKs
// related to non-global property constness tracking.
ConstnessField::encode(PropertyConstness::kMutable) |
DictionaryStorageField::encode(dictionary_index) |
PropertyCellTypeField::encode(cell_type)) {}
// Property details for dictionary mode properties/elements.
PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
PropertyConstness constness, int dictionary_index = 0) {
value_ = KindField::encode(kind) |
LocationField::encode(PropertyLocation::kField) |
AttributesField::encode(attributes) |
ConstnessField::encode(constness) |
DictionaryStorageField::encode(dictionary_index) |
PropertyCellTypeField::encode(PropertyCellType::kNoCell);
}
constexpr PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
PropertyConstness constness,
int dictionary_index = 0)
: value_(KindField::encode(kind) |
LocationField::encode(PropertyLocation::kField) |
AttributesField::encode(attributes) |
ConstnessField::encode(constness) |
DictionaryStorageField::encode(dictionary_index) |
PropertyCellTypeField::encode(PropertyCellType::kNoCell)) {}
// Property details for fast mode properties.
PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
PropertyLocation location, PropertyConstness constness,
Representation representation, int field_index = 0) {
value_ = KindField::encode(kind) | AttributesField::encode(attributes) |
LocationField::encode(location) |
ConstnessField::encode(constness) |
RepresentationField::encode(EncodeRepresentation(representation)) |
FieldIndexField::encode(field_index);
}
static PropertyDetails Empty(
constexpr PropertyDetails(PropertyKind kind, PropertyAttributes attributes,
PropertyLocation location,
PropertyConstness constness,
Representation representation, int field_index = 0)
: value_(
KindField::encode(kind) | AttributesField::encode(attributes) |
LocationField::encode(location) |
ConstnessField::encode(constness) |
RepresentationField::encode(EncodeRepresentation(representation)) |
FieldIndexField::encode(field_index)) {}
static constexpr PropertyDetails Empty(
PropertyCellType cell_type = PropertyCellType::kNoCell) {
return PropertyDetails(kData, NONE, cell_type);
}
......@@ -336,7 +343,7 @@ class PropertyDetails {
explicit inline PropertyDetails(Smi smi);
inline Smi AsSmi() const;
static uint8_t EncodeRepresentation(Representation representation) {
static constexpr uint8_t EncodeRepresentation(Representation representation) {
return representation.kind();
}
......
......@@ -1005,12 +1005,12 @@ class V8_EXPORT_PRIVATE FlatStringReader : public Relocatable {
inline base::uc32 Get(int index) const;
template <typename Char>
inline Char Get(int index) const;
int length() { return length_; }
int length() const { return length_; }
private:
Handle<String> str_;
bool is_one_byte_;
int length_;
int const length_;
const void* start_;
};
......
......@@ -413,7 +413,8 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
}
DCHECK(object->IsHeapObject());
switch (HeapObject::cast(*object).map().instance_type()) {
InstanceType instance_type = HeapObject::cast(*object).map().instance_type();
switch (instance_type) {
case ODDBALL_TYPE:
WriteOddball(Oddball::cast(*object));
return ThrowIfOutOfMemory();
......@@ -433,7 +434,7 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object);
if (!id_map_.Find(view) && !treat_array_buffer_views_as_host_objects_) {
Handle<JSArrayBuffer> buffer(
view->IsJSTypedArray()
InstanceTypeChecker::IsJSTypedArray(instance_type)
? Handle<JSTypedArray>::cast(view)->GetBuffer()
: handle(JSArrayBuffer::cast(view->buffer()), isolate_));
if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>();
......@@ -441,10 +442,10 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
return WriteJSReceiver(view);
}
default:
if (object->IsString()) {
if (InstanceTypeChecker::IsString(instance_type)) {
WriteString(Handle<String>::cast(object));
return ThrowIfOutOfMemory();
} else if (object->IsJSReceiver()) {
} else if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
return WriteJSReceiver(Handle<JSReceiver>::cast(object));
} else {
ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
......@@ -664,6 +665,7 @@ Maybe<bool> ValueSerializer::WriteJSObjectSlow(Handle<JSObject> object) {
}
Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
PtrComprCageBase cage_base(isolate_);
uint32_t length = 0;
bool valid_length = array->length().ToArrayLength(&length);
DCHECK(valid_length);
......@@ -675,7 +677,7 @@ Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
// existed (as only indices which were enumerable own properties at this point
// should be serialized).
const bool should_serialize_densely =
array->HasFastElements() && !array->HasHoleyElements();
array->HasFastElements(cage_base) && !array->HasHoleyElements(cage_base);
if (should_serialize_densely) {
DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength));
......@@ -685,35 +687,36 @@ Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
// Fast paths. Note that PACKED_ELEMENTS in particular can bail due to the
// structure of the elements changing.
switch (array->GetElementsKind()) {
switch (array->GetElementsKind(cage_base)) {
case PACKED_SMI_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(array->elements()),
isolate_);
for (; i < length; i++) WriteSmi(Smi::cast(elements->get(i)));
DisallowGarbageCollection no_gc;
FixedArray elements = FixedArray::cast(array->elements());
for (i = 0; i < length; i++)
WriteSmi(Smi::cast(elements.get(cage_base, i)));
break;
}
case PACKED_DOUBLE_ELEMENTS: {
// Elements are empty_fixed_array, not a FixedDoubleArray, if the array
// is empty. No elements to encode in this case anyhow.
if (length == 0) break;
Handle<FixedDoubleArray> elements(
FixedDoubleArray::cast(array->elements()), isolate_);
for (; i < length; i++) {
DisallowGarbageCollection no_gc;
FixedDoubleArray elements = FixedDoubleArray::cast(array->elements());
for (i = 0; i < length; i++) {
WriteTag(SerializationTag::kDouble);
WriteDouble(elements->get_scalar(i));
WriteDouble(elements.get_scalar(i));
}
break;
}
case PACKED_ELEMENTS: {
Handle<Object> old_length(array->length(), isolate_);
Handle<Object> old_length(array->length(cage_base), isolate_);
for (; i < length; i++) {
if (array->length() != *old_length ||
array->GetElementsKind() != PACKED_ELEMENTS) {
if (array->length(cage_base) != *old_length ||
array->GetElementsKind(cage_base) != PACKED_ELEMENTS) {
// Fall back to slow path.
break;
}
Handle<Object> element(FixedArray::cast(array->elements()).get(i),
isolate_);
Handle<Object> element(
FixedArray::cast(array->elements()).get(cage_base, i), isolate_);
if (!WriteObject(element).FromMaybe(false)) return Nothing<bool>();
}
break;
......
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