[compiler] Remove delayed string constants

StringConstantXXX were introduced when we switched to concurrent
compilation, as a way to build strings in Turbofan in a background
thread, without having to actually allocate them on the main heap
from the background. See https://crrev.com/c/1221807.

Now that we have local heaps, we can actually allocate strings from
the background, making StringConstantXXX useless.

Moreover, we would fold constant string concatenations into
ConsString, which sounds a bit dubious for performance. Now, small
constant string concatenations will be folded into SeqStrings, while
larger ones will remain ConsString, just to avoid the quadratic
worst-case.

Change-Id: I0479d16aa5691c9d774187c4cc0d03ff4fe2b4f9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3811291
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82381}
This commit is contained in:
Darius M 2022-08-09 18:31:12 +02:00 committed by V8 LUCI CQ
parent aff4d490ce
commit de04959f17
44 changed files with 263 additions and 414 deletions

View File

@ -1222,8 +1222,6 @@ filegroup(
"src/codegen/source-position-table.h",
"src/codegen/source-position.cc",
"src/codegen/source-position.h",
"src/codegen/string-constants.cc",
"src/codegen/string-constants.h",
"src/codegen/tick-counter.cc",
"src/codegen/tick-counter.h",
"src/codegen/tnode.cc",

View File

@ -2849,7 +2849,6 @@ v8_header_set("v8_internal_headers") {
"src/codegen/signature.h",
"src/codegen/source-position-table.h",
"src/codegen/source-position.h",
"src/codegen/string-constants.h",
"src/codegen/tick-counter.h",
"src/codegen/tnode.h",
"src/codegen/turbo-assembler.h",
@ -4416,7 +4415,6 @@ v8_source_set("v8_base_without_compiler") {
"src/codegen/safepoint-table.cc",
"src/codegen/source-position-table.cc",
"src/codegen/source-position.cc",
"src/codegen/string-constants.cc",
"src/codegen/tick-counter.cc",
"src/codegen/tnode.cc",
"src/codegen/turbo-assembler.cc",

View File

@ -45,7 +45,6 @@
#include "src/codegen/assembler-inl.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/string-constants.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/objects/objects-inl.h"
@ -398,15 +397,8 @@ Operand Operand::EmbeddedNumber(double value) {
int32_t smi;
if (DoubleToSmiInteger(value, &smi)) return Operand(Smi::FromInt(smi));
Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
result.is_heap_object_request_ = true;
result.value_.heap_object_request = HeapObjectRequest(value);
return result;
}
Operand Operand::EmbeddedStringConstant(const StringConstantBase* str) {
Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
result.is_heap_object_request_ = true;
result.value_.heap_object_request = HeapObjectRequest(str);
result.is_heap_number_request_ = true;
result.value_.heap_number_request = HeapNumberRequest(value);
return result;
}
@ -463,22 +455,12 @@ void NeonMemOperand::SetAlignment(int align) {
}
}
void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
for (auto& request : heap_object_requests_) {
Handle<HeapObject> object;
switch (request.kind()) {
case HeapObjectRequest::kHeapNumber:
object = isolate->factory()->NewHeapNumber<AllocationType::kOld>(
void Assembler::AllocateAndInstallRequestedHeapNumbers(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_number_requests_.empty());
for (auto& request : heap_number_requests_) {
Handle<HeapObject> object =
isolate->factory()->NewHeapNumber<AllocationType::kOld>(
request.heap_number());
break;
case HeapObjectRequest::kStringConstant: {
const StringConstantBase* str = request.string();
CHECK_NOT_NULL(str);
object = str->AllocateStringConstant(isolate);
break;
}
}
Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
Memory<Address>(constant_pool_entry_address(pc, 0 /* unused */)) =
object.address();
@ -585,7 +567,7 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc,
int code_comments_size = WriteCodeComments();
AllocateAndInstallRequestedHeapObjects(isolate);
AllocateAndInstallRequestedHeapNumbers(isolate);
// Set up code descriptor.
// TODO(jgruber): Reconsider how these offsets and sizes are maintained up to
@ -1214,8 +1196,8 @@ void Assembler::Move32BitImmediate(Register rd, const Operand& x,
}
} else {
int32_t immediate;
if (x.IsHeapObjectRequest()) {
RequestHeapObject(x.heap_object_request());
if (x.IsHeapNumberRequest()) {
RequestHeapNumber(x.heap_number_request());
immediate = 0;
} else {
immediate = x.immediate();

View File

@ -116,7 +116,6 @@ class V8_EXPORT_PRIVATE Operand {
explicit Operand(Register rm, ShiftOp shift_op, Register rs);
static Operand EmbeddedNumber(double number); // Smi or HeapNumber.
static Operand EmbeddedStringConstant(const StringConstantBase* str);
// Return true if this is a register operand.
bool IsRegister() const {
@ -148,21 +147,21 @@ class V8_EXPORT_PRIVATE Operand {
inline int32_t immediate() const {
DCHECK(IsImmediate());
DCHECK(!IsHeapObjectRequest());
DCHECK(!IsHeapNumberRequest());
return value_.immediate;
}
bool IsImmediate() const { return !rm_.is_valid(); }
HeapObjectRequest heap_object_request() const {
DCHECK(IsHeapObjectRequest());
return value_.heap_object_request;
HeapNumberRequest heap_number_request() const {
DCHECK(IsHeapNumberRequest());
return value_.heap_number_request;
}
bool IsHeapObjectRequest() const {
DCHECK_IMPLIES(is_heap_object_request_, IsImmediate());
DCHECK_IMPLIES(is_heap_object_request_,
bool IsHeapNumberRequest() const {
DCHECK_IMPLIES(is_heap_number_request_, IsImmediate());
DCHECK_IMPLIES(is_heap_number_request_,
rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT ||
rmode_ == RelocInfo::CODE_TARGET);
return is_heap_object_request_;
return is_heap_number_request_;
}
Register rm() const { return rm_; }
@ -176,10 +175,10 @@ class V8_EXPORT_PRIVATE Operand {
int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
union Value {
Value() {}
HeapObjectRequest heap_object_request; // if is_heap_object_request_
HeapNumberRequest heap_number_request; // if is_heap_number_request_
int32_t immediate; // otherwise
} value_; // valid if rm_ == no_reg
bool is_heap_object_request_ = false;
bool is_heap_number_request_ = false;
RelocInfo::Mode rmode_;
friend class Assembler;
@ -1344,7 +1343,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
void ConstantPoolAddEntry(int position, RelocInfo::Mode rmode,
intptr_t value);
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
void AllocateAndInstallRequestedHeapNumbers(Isolate* isolate);
int WriteCodeComments();

View File

@ -268,21 +268,21 @@ Operand::Operand(Register reg, Extend extend, unsigned shift_amount)
DCHECK(reg.Is64Bits() || ((extend != SXTX) && (extend != UXTX)));
}
bool Operand::IsHeapObjectRequest() const {
DCHECK_IMPLIES(heap_object_request_.has_value(), reg_ == NoReg);
DCHECK_IMPLIES(heap_object_request_.has_value(),
bool Operand::IsHeapNumberRequest() const {
DCHECK_IMPLIES(heap_number_request_.has_value(), reg_ == NoReg);
DCHECK_IMPLIES(heap_number_request_.has_value(),
immediate_.rmode() == RelocInfo::FULL_EMBEDDED_OBJECT ||
immediate_.rmode() == RelocInfo::CODE_TARGET);
return heap_object_request_.has_value();
return heap_number_request_.has_value();
}
HeapObjectRequest Operand::heap_object_request() const {
DCHECK(IsHeapObjectRequest());
return *heap_object_request_;
HeapNumberRequest Operand::heap_number_request() const {
DCHECK(IsHeapNumberRequest());
return *heap_number_request_;
}
bool Operand::IsImmediate() const {
return reg_ == NoReg && !IsHeapObjectRequest();
return reg_ == NoReg && !IsHeapNumberRequest();
}
bool Operand::IsShiftedRegister() const {
@ -319,11 +319,8 @@ Operand Operand::ToW() const {
return *this;
}
Immediate Operand::immediate_for_heap_object_request() const {
DCHECK((heap_object_request().kind() == HeapObjectRequest::kHeapNumber &&
immediate_.rmode() == RelocInfo::FULL_EMBEDDED_OBJECT) ||
(heap_object_request().kind() == HeapObjectRequest::kStringConstant &&
immediate_.rmode() == RelocInfo::FULL_EMBEDDED_OBJECT));
Immediate Operand::immediate_for_heap_number_request() const {
DCHECK(immediate_.rmode() == RelocInfo::FULL_EMBEDDED_OBJECT);
return immediate_;
}
@ -338,7 +335,7 @@ int64_t Operand::ImmediateValue() const {
}
RelocInfo::Mode Operand::ImmediateRMode() const {
DCHECK(IsImmediate() || IsHeapObjectRequest());
DCHECK(IsImmediate() || IsHeapNumberRequest());
return immediate_.rmode();
}

View File

@ -36,7 +36,6 @@
#include "src/codegen/arm64/assembler-arm64-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/codegen/safepoint-table.h"
#include "src/codegen/string-constants.h"
#include "src/execution/frame-constants.h"
namespace v8 {
@ -362,28 +361,15 @@ win64_unwindinfo::BuiltinUnwindInfo Assembler::GetUnwindInfo() const {
}
#endif
void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
for (auto& request : heap_object_requests_) {
void Assembler::AllocateAndInstallRequestedHeapNumbers(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_number_requests_.empty());
for (auto& request : heap_number_requests_) {
Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
switch (request.kind()) {
case HeapObjectRequest::kHeapNumber: {
Handle<HeapObject> object =
isolate->factory()->NewHeapNumber<AllocationType::kOld>(
request.heap_number());
EmbeddedObjectIndex index = AddEmbeddedObject(object);
set_embedded_object_index_referenced_from(pc, index);
break;
}
case HeapObjectRequest::kStringConstant: {
const StringConstantBase* str = request.string();
CHECK_NOT_NULL(str);
EmbeddedObjectIndex index =
AddEmbeddedObject(str->AllocateStringConstant(isolate));
set_embedded_object_index_referenced_from(pc, index);
break;
}
}
Handle<HeapObject> object =
isolate->factory()->NewHeapNumber<AllocationType::kOld>(
request.heap_number());
EmbeddedObjectIndex index = AddEmbeddedObject(object);
set_embedded_object_index_referenced_from(pc, index);
}
}
@ -405,7 +391,7 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc,
int code_comments_size = WriteCodeComments();
AllocateAndInstallRequestedHeapObjects(isolate);
AllocateAndInstallRequestedHeapNumbers(isolate);
// Set up code descriptor.
// TODO(jgruber): Reconsider how these offsets and sizes are maintained up to
@ -1321,23 +1307,16 @@ Operand Operand::EmbeddedNumber(double number) {
return Operand(Immediate(Smi::FromInt(smi)));
}
Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
result.heap_object_request_.emplace(number);
DCHECK(result.IsHeapObjectRequest());
return result;
}
Operand Operand::EmbeddedStringConstant(const StringConstantBase* str) {
Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
result.heap_object_request_.emplace(str);
DCHECK(result.IsHeapObjectRequest());
result.heap_number_request_.emplace(number);
DCHECK(result.IsHeapNumberRequest());
return result;
}
void Assembler::ldr(const CPURegister& rt, const Operand& operand) {
if (operand.IsHeapObjectRequest()) {
BlockPoolsScope no_pool_before_ldr_of_heap_object_request(this);
RequestHeapObject(operand.heap_object_request());
ldr(rt, operand.immediate_for_heap_object_request());
if (operand.IsHeapNumberRequest()) {
BlockPoolsScope no_pool_before_ldr_of_heap_number_request(this);
RequestHeapNumber(operand.heap_number_request());
ldr(rt, operand.immediate_for_heap_number_request());
} else {
ldr(rt, operand.immediate());
}
@ -4392,9 +4371,9 @@ void Assembler::near_call(int offset, RelocInfo::Mode rmode) {
bl(offset);
}
void Assembler::near_call(HeapObjectRequest request) {
void Assembler::near_call(HeapNumberRequest request) {
BlockPoolsScope no_pool_before_bl_instr(this);
RequestHeapObject(request);
RequestHeapNumber(request);
EmbeddedObjectIndex index = AddEmbeddedObject(Handle<CodeT>());
RecordRelocInfo(RelocInfo::CODE_TARGET, index, NO_POOL_ENTRY);
DCHECK(is_int32(index));

View File

@ -82,11 +82,10 @@ class Operand {
inline Operand(Register reg, Extend extend, unsigned shift_amount = 0);
static Operand EmbeddedNumber(double number); // Smi or HeapNumber.
static Operand EmbeddedStringConstant(const StringConstantBase* str);
inline bool IsHeapObjectRequest() const;
inline HeapObjectRequest heap_object_request() const;
inline Immediate immediate_for_heap_object_request() const;
inline bool IsHeapNumberRequest() const;
inline HeapNumberRequest heap_number_request() const;
inline Immediate immediate_for_heap_number_request() const;
// Implicit constructor for all int types, ExternalReference, and Smi.
template <typename T>
@ -120,7 +119,7 @@ class Operand {
bool NeedsRelocation(const Assembler* assembler) const;
private:
base::Optional<HeapObjectRequest> heap_object_request_;
base::Optional<HeapNumberRequest> heap_number_request_;
Immediate immediate_;
Register reg_;
Shift shift_;
@ -239,8 +238,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// instruction.
void near_call(int offset, RelocInfo::Mode rmode);
// Generate a BL immediate instruction with the corresponding relocation info
// for the input HeapObjectRequest.
void near_call(HeapObjectRequest request);
// for the input HeapNumberRequest.
void near_call(HeapNumberRequest request);
// Return the address in the constant pool of the code target address used by
// the branch/call instruction at pc.
@ -2757,7 +2756,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// the length of the label chain.
void DeleteUnresolvedBranchInfoForLabelTraverse(Label* label);
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
void AllocateAndInstallRequestedHeapNumbers(Isolate* isolate);
int WriteCodeComments();

View File

@ -39,7 +39,6 @@
#endif
#include "src/base/vector.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/string-constants.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/diagnostics/disassembler.h"
#include "src/execution/isolate.h"
@ -230,17 +229,10 @@ unsigned CpuFeatures::supported_ = 0;
unsigned CpuFeatures::icache_line_size_ = 0;
unsigned CpuFeatures::dcache_line_size_ = 0;
HeapObjectRequest::HeapObjectRequest(double heap_number, int offset)
: kind_(kHeapNumber), offset_(offset) {
value_.heap_number = heap_number;
DCHECK(!IsSmiDouble(value_.heap_number));
}
HeapObjectRequest::HeapObjectRequest(const StringConstantBase* string,
int offset)
: kind_(kStringConstant), offset_(offset) {
value_.string = string;
DCHECK_NOT_NULL(value_.string);
HeapNumberRequest::HeapNumberRequest(double heap_number, int offset)
: offset_(offset) {
value_ = heap_number;
DCHECK(!IsSmiDouble(value_));
}
// Platform specific but identical code for all the platforms.
@ -267,9 +259,9 @@ void Assembler::DataAlign(int m) {
}
}
void AssemblerBase::RequestHeapObject(HeapObjectRequest request) {
void AssemblerBase::RequestHeapNumber(HeapNumberRequest request) {
request.set_offset(pc_offset());
heap_object_requests_.push_front(request);
heap_number_requests_.push_front(request);
}
int AssemblerBase::AddCodeTarget(Handle<CodeT> target) {

View File

@ -70,7 +70,6 @@ class Isolate;
class SCTableReference;
class SourcePosition;
class StatsCounter;
class StringConstantBase;
// -----------------------------------------------------------------------------
// Optimization for far-jmp like instructions that can be replaced by shorter.
@ -103,23 +102,11 @@ class JumpOptimizationInfo {
size_t hash_code_ = 0u;
};
class HeapObjectRequest {
class HeapNumberRequest {
public:
explicit HeapObjectRequest(double heap_number, int offset = -1);
explicit HeapObjectRequest(const StringConstantBase* string, int offset = -1);
explicit HeapNumberRequest(double heap_number, int offset = -1);
enum Kind { kHeapNumber, kStringConstant };
Kind kind() const { return kind_; }
double heap_number() const {
DCHECK_EQ(kind(), kHeapNumber);
return value_.heap_number;
}
const StringConstantBase* string() const {
DCHECK_EQ(kind(), kStringConstant);
return value_.string;
}
double heap_number() const { return value_; }
// The code buffer offset at the time of the request.
int offset() const {
@ -133,13 +120,7 @@ class HeapObjectRequest {
}
private:
Kind kind_;
union {
double heap_number;
const StringConstantBase* string;
} value_;
double value_;
int offset_;
};
@ -388,7 +369,7 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced {
std::unique_ptr<AssemblerBuffer> buffer_;
// Cached from {buffer_->start()}, for faster access.
byte* buffer_start_;
std::forward_list<HeapObjectRequest> heap_object_requests_;
std::forward_list<HeapNumberRequest> heap_number_requests_;
// The program counter, which points into the buffer above and moves forward.
// TODO(jkummerow): This should probably have type {Address}.
byte* pc_;
@ -402,12 +383,12 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced {
}
}
// {RequestHeapObject} records the need for a future heap number allocation,
// {RequestHeapNumber} records the need for a future heap number allocation,
// code stub generation or string allocation. After code assembly, each
// platform's {Assembler::AllocateAndInstallRequestedHeapObjects} will
// platform's {Assembler::AllocateAndInstallRequestedHeapNumbers} will
// allocate these objects and place them where they are expected (determined
// by the pc offset associated with each request).
void RequestHeapObject(HeapObjectRequest request);
void RequestHeapNumber(HeapNumberRequest request);
bool ShouldRecordRelocInfo(RelocInfo::Mode rmode) const {
DCHECK(!RelocInfo::IsNoInfo(rmode));

View File

@ -120,8 +120,6 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(ShadowRealmImportValueFulfilledSFI, \
shadow_realm_import_value_fulfilled_sfi, \
ShadowRealmImportValueFulfilledSFI) \
V(SingleCharacterStringTable, single_character_string_table, \
SingleCharacterStringTable) \
V(StringIteratorProtector, string_iterator_protector, \
StringIteratorProtector) \
V(TypedArraySpeciesProtector, typed_array_species_protector, \
@ -210,6 +208,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(resolve_string, resolve_string, ResolveString) \
V(return_string, return_string, ReturnString) \
V(search_symbol, search_symbol, SearchSymbol) \
V(SingleCharacterStringTable, single_character_string_table, \
SingleCharacterStringTable) \
V(species_symbol, species_symbol, SpeciesSymbol) \
V(StaleRegister, stale_register, StaleRegister) \
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \

View File

@ -195,8 +195,8 @@ void Assembler::emit(const Immediate& x) {
return;
}
if (!RelocInfo::IsNoInfo(x.rmode_)) RecordRelocInfo(x.rmode_);
if (x.is_heap_object_request()) {
RequestHeapObject(x.heap_object_request());
if (x.is_heap_number_request()) {
RequestHeapNumber(x.heap_number_request());
emit(0);
return;
}

View File

@ -51,7 +51,6 @@
#include "src/base/cpu.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/string-constants.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/diagnostics/disassembler.h"
#include "src/init/v8.h"
@ -64,15 +63,8 @@ Immediate Immediate::EmbeddedNumber(double value) {
int32_t smi;
if (DoubleToSmiInteger(value, &smi)) return Immediate(Smi::FromInt(smi));
Immediate result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
result.is_heap_object_request_ = true;
result.value_.heap_object_request = HeapObjectRequest(value);
return result;
}
Immediate Immediate::EmbeddedStringConstant(const StringConstantBase* str) {
Immediate result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
result.is_heap_object_request_ = true;
result.value_.heap_object_request = HeapObjectRequest(str);
result.is_heap_number_request_ = true;
result.value_.heap_number_request = HeapNumberRequest(value);
return result;
}
@ -293,22 +285,12 @@ Register Operand::reg() const {
bool operator!=(Operand op, XMMRegister r) { return !op.is_reg(r); }
void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
for (auto& request : heap_object_requests_) {
Handle<HeapObject> object;
switch (request.kind()) {
case HeapObjectRequest::kHeapNumber:
object = isolate->factory()->NewHeapNumber<AllocationType::kOld>(
void Assembler::AllocateAndInstallRequestedHeapNumbers(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_number_requests_.empty());
for (auto& request : heap_number_requests_) {
Handle<HeapObject> object =
isolate->factory()->NewHeapNumber<AllocationType::kOld>(
request.heap_number());
break;
case HeapObjectRequest::kStringConstant: {
const StringConstantBase* str = request.string();
CHECK_NOT_NULL(str);
object = str->AllocateStringConstant(isolate);
break;
}
}
Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
WriteUnalignedValue(pc, object);
}
@ -353,7 +335,7 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc,
// that we are still not overlapping instructions and relocation info).
DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
AllocateAndInstallRequestedHeapObjects(isolate);
AllocateAndInstallRequestedHeapNumbers(isolate);
// Set up code descriptor.
// TODO(jgruber): Reconsider how these offsets and sizes are maintained up to

View File

@ -112,29 +112,28 @@ class Immediate {
: Immediate(static_cast<intptr_t>(value.ptr())) {}
static Immediate EmbeddedNumber(double number); // Smi or HeapNumber.
static Immediate EmbeddedStringConstant(const StringConstantBase* str);
static Immediate CodeRelativeOffset(Label* label) { return Immediate(label); }
bool is_heap_object_request() const {
DCHECK_IMPLIES(is_heap_object_request_,
bool is_heap_number_request() const {
DCHECK_IMPLIES(is_heap_number_request_,
rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT ||
rmode_ == RelocInfo::CODE_TARGET);
return is_heap_object_request_;
return is_heap_number_request_;
}
HeapObjectRequest heap_object_request() const {
DCHECK(is_heap_object_request());
return value_.heap_object_request;
HeapNumberRequest heap_number_request() const {
DCHECK(is_heap_number_request());
return value_.heap_number_request;
}
int immediate() const {
DCHECK(!is_heap_object_request());
DCHECK(!is_heap_number_request());
return value_.immediate;
}
bool is_embedded_object() const {
return !is_heap_object_request() &&
return !is_heap_number_request() &&
rmode() == RelocInfo::FULL_EMBEDDED_OBJECT;
}
@ -178,10 +177,10 @@ class Immediate {
union Value {
Value() {}
HeapObjectRequest heap_object_request;
HeapNumberRequest heap_number_request;
int immediate;
} value_;
bool is_heap_object_request_ = false;
bool is_heap_number_request_ = false;
RelocInfo::Mode rmode_;
friend class Operand;
@ -1766,7 +1765,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
bool is_optimizable_farjmp(int idx);
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
void AllocateAndInstallRequestedHeapNumbers(Isolate* isolate);
int WriteCodeComments();

View File

@ -1661,7 +1661,7 @@ void TurboAssembler::Move(Register dst, Register src) {
}
void TurboAssembler::Move(Register dst, const Immediate& src) {
if (!src.is_heap_object_request() && src.is_zero()) {
if (!src.is_heap_number_request() && src.is_zero()) {
xor_(dst, dst); // Shorter than mov of 32-bit immediate 0.
} else if (src.is_external_reference()) {
LoadAddress(dst, src.external_reference());
@ -1675,7 +1675,7 @@ void TurboAssembler::Move(Operand dst, const Immediate& src) {
// stack.
if (root_array_available() && options().isolate_independent_code) {
if (src.is_embedded_object() || src.is_external_reference() ||
src.is_heap_object_request()) {
src.is_heap_number_request()) {
Push(src);
pop(dst);
return;

View File

@ -20,7 +20,6 @@
#include "src/base/platform/wrappers.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/string-constants.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/flags/flags.h"
#include "src/init/v8.h"
@ -241,26 +240,14 @@ bool Operand::AddressUsesRegister(Register reg) const {
}
}
void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
for (auto& request : heap_object_requests_) {
void Assembler::AllocateAndInstallRequestedHeapNumbers(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_number_requests_.empty());
for (auto& request : heap_number_requests_) {
Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
switch (request.kind()) {
case HeapObjectRequest::kHeapNumber: {
Handle<HeapNumber> object =
isolate->factory()->NewHeapNumber<AllocationType::kOld>(
request.heap_number());
WriteUnalignedValue(pc, object);
break;
}
case HeapObjectRequest::kStringConstant: {
const StringConstantBase* str = request.string();
CHECK_NOT_NULL(str);
Handle<String> allocated = str->AllocateStringConstant(isolate);
WriteUnalignedValue(pc, allocated);
break;
}
}
Handle<HeapNumber> object =
isolate->factory()->NewHeapNumber<AllocationType::kOld>(
request.heap_number());
WriteUnalignedValue(pc, object);
}
}
@ -392,7 +379,7 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc,
// that we are still not overlapping instructions and relocation info.
DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
AllocateAndInstallRequestedHeapObjects(isolate);
AllocateAndInstallRequestedHeapNumbers(isolate);
// Set up code descriptor.
// TODO(jgruber): Reconsider how these offsets and sizes are maintained up to
@ -1696,15 +1683,7 @@ void Assembler::movq_heap_number(Register dst, double value) {
EnsureSpace ensure_space(this);
emit_rex(dst, kInt64Size);
emit(0xB8 | dst.low_bits());
RequestHeapObject(HeapObjectRequest(value));
emit(Immediate64(kNullAddress, RelocInfo::FULL_EMBEDDED_OBJECT));
}
void Assembler::movq_string(Register dst, const StringConstantBase* str) {
EnsureSpace ensure_space(this);
emit_rex(dst, kInt64Size);
emit(0xB8 | dst.low_bits());
RequestHeapObject(HeapObjectRequest(str));
RequestHeapNumber(HeapNumberRequest(value));
emit(Immediate64(kNullAddress, RelocInfo::FULL_EMBEDDED_OBJECT));
}

View File

@ -589,8 +589,6 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// move.
void movq_heap_number(Register dst, double value);
void movq_string(Register dst, const StringConstantBase* str);
// Loads a 64-bit immediate into a register, potentially using the constant
// pool.
void movq(Register dst, int64_t value) { movq(dst, Immediate64(value)); }
@ -2555,7 +2553,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
bool is_optimizable_farjmp(int idx);
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
void AllocateAndInstallRequestedHeapNumbers(Isolate* isolate);
int WriteCodeComments();

View File

@ -16,7 +16,6 @@
#include "src/codegen/interface-descriptors-inl.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/register-configuration.h"
#include "src/codegen/string-constants.h"
#include "src/codegen/x64/assembler-x64.h"
#include "src/codegen/x64/register-x64.h"
#include "src/common/globals.h"
@ -1988,12 +1987,6 @@ void TurboAssembler::Move(Operand dst, Handle<HeapObject> object,
movq(dst, kScratchRegister);
}
void TurboAssembler::MoveStringConstant(Register result,
const StringConstantBase* string,
RelocInfo::Mode rmode) {
movq_string(result, string);
}
void MacroAssembler::Drop(int stack_elements) {
if (stack_elements > 0) {
addq(rsp, Immediate(stack_elements * kSystemPointerSize));

View File

@ -24,8 +24,6 @@ namespace internal {
// Convenience for platform-independent signatures.
using MemOperand = Operand;
class StringConstantBase;
struct SmiIndex {
SmiIndex(Register index_register, ScaleFactor scale)
: reg(index_register), scale(scale) {}
@ -353,10 +351,6 @@ class V8_EXPORT_PRIVATE TurboAssembler
// Move src0 to dst0 and src1 to dst1, handling possible overlaps.
void MovePair(Register dst0, Register src0, Register dst1, Register src1);
void MoveStringConstant(
Register result, const StringConstantBase* string,
RelocInfo::Mode rmode = RelocInfo::FULL_EMBEDDED_OBJECT);
// Convert smi to word-size sign-extended value.
void SmiUntag(Register reg);
// Requires dst != src

View File

@ -138,9 +138,6 @@ class ArmOperandConverter final : public InstructionOperandConverter {
return Operand::EmbeddedNumber(constant.ToFloat64().value());
case Constant::kExternalReference:
return Operand(constant.ToExternalReference());
case Constant::kDelayedStringConstant:
return Operand::EmbeddedStringConstant(
constant.ToDelayedStringConstant());
case Constant::kInt64:
case Constant::kCompressedHeapObject:
case Constant::kHeapObject:

View File

@ -231,9 +231,6 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
case Constant::kCompressedHeapObject: // Fall through.
case Constant::kHeapObject:
return Operand(constant.ToHeapObject());
case Constant::kDelayedStringConstant:
return Operand::EmbeddedStringConstant(
constant.ToDelayedStringConstant());
case Constant::kRpoNumber:
UNREACHABLE(); // TODO(dcarney): RPO immediates on arm64.
}

View File

@ -8,7 +8,6 @@
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/optimized-compilation-info.h"
#include "src/codegen/string-constants.h"
#include "src/compiler/backend/code-generator-impl.h"
#include "src/compiler/globals.h"
#include "src/compiler/linkage.h"
@ -1286,10 +1285,6 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr,
DCHECK_EQ(MachineType::AnyTagged(), type);
literal = DeoptimizationLiteral(constant.ToHeapObject());
break;
case Constant::kDelayedStringConstant:
DCHECK_EQ(MachineRepresentation::kTagged, type.representation());
literal = DeoptimizationLiteral(constant.ToDelayedStringConstant());
break;
default:
UNREACHABLE();
}
@ -1330,9 +1325,6 @@ Handle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const {
case DeoptimizationLiteralKind::kNumber: {
return isolate->factory()->NewNumber(number_);
}
case DeoptimizationLiteralKind::kString: {
return string_->AllocateStringConstant(isolate);
}
case DeoptimizationLiteralKind::kInvalid: {
UNREACHABLE();
}

View File

@ -55,34 +55,26 @@ class InstructionOperandIterator {
size_t pos_;
};
enum class DeoptimizationLiteralKind { kObject, kNumber, kString, kInvalid };
enum class DeoptimizationLiteralKind { kObject, kNumber, kInvalid };
// Either a non-null Handle<Object>, a double or a StringConstantBase.
// Either a non-null Handle<Object> or a double.
class DeoptimizationLiteral {
public:
DeoptimizationLiteral()
: kind_(DeoptimizationLiteralKind::kInvalid),
object_(),
number_(0),
string_(nullptr) {}
: kind_(DeoptimizationLiteralKind::kInvalid), object_(), number_(0) {}
explicit DeoptimizationLiteral(Handle<Object> object)
: kind_(DeoptimizationLiteralKind::kObject), object_(object) {
CHECK(!object_.is_null());
}
explicit DeoptimizationLiteral(double number)
: kind_(DeoptimizationLiteralKind::kNumber), number_(number) {}
explicit DeoptimizationLiteral(const StringConstantBase* string)
: kind_(DeoptimizationLiteralKind::kString), string_(string) {}
Handle<Object> object() const { return object_; }
const StringConstantBase* string() const { return string_; }
bool operator==(const DeoptimizationLiteral& other) const {
return kind_ == other.kind_ && object_.equals(other.object_) &&
base::bit_cast<uint64_t>(number_) ==
base::bit_cast<uint64_t>(other.number_) &&
base::bit_cast<intptr_t>(string_) ==
base::bit_cast<intptr_t>(other.string_);
base::bit_cast<uint64_t>(other.number_);
}
Handle<Object> Reify(Isolate* isolate) const;
@ -101,7 +93,6 @@ class DeoptimizationLiteral {
Handle<Object> object_;
double number_ = 0;
const StringConstantBase* string_ = nullptr;
};
// These structs hold pc offsets for generated instructions and is only used

View File

@ -89,9 +89,6 @@ class IA32OperandConverter : public InstructionOperandConverter {
return Immediate(constant.ToHeapObject());
case Constant::kCompressedHeapObject:
break;
case Constant::kDelayedStringConstant:
return Immediate::EmbeddedStringConstant(
constant.ToDelayedStringConstant());
case Constant::kInt64:
break;
case Constant::kRpoNumber:

View File

@ -365,8 +365,6 @@ class OperandGenerator {
return Constant(HeapConstantOf(node->op()));
case IrOpcode::kCompressedHeapConstant:
return Constant(HeapConstantOf(node->op()), true);
case IrOpcode::kDelayedStringConstant:
return Constant(StringConstantBaseOf(node->op()));
case IrOpcode::kDeadValue: {
switch (DeadValueRepresentationOf(node->op())) {
case MachineRepresentation::kBit:

View File

@ -497,7 +497,6 @@ InstructionOperand OperandForDeopt(Isolate* isolate, OperandGenerator* g,
case IrOpcode::kInt64Constant:
case IrOpcode::kFloat32Constant:
case IrOpcode::kFloat64Constant:
case IrOpcode::kDelayedStringConstant:
return g->UseImmediate(input);
case IrOpcode::kNumberConstant:
if (rep == MachineRepresentation::kWord32) {
@ -1431,8 +1430,6 @@ void InstructionSelector::VisitNode(Node* node) {
if (!IsSmiDouble(value)) MarkAsTagged(node);
return VisitConstant(node);
}
case IrOpcode::kDelayedStringConstant:
return MarkAsTagged(node), VisitConstant(node);
case IrOpcode::kCall:
return VisitCall(node);
case IrOpcode::kDeoptimizeIf:

View File

@ -567,13 +567,6 @@ Handle<CodeT> Constant::ToCode() const {
return value;
}
const StringConstantBase* Constant::ToDelayedStringConstant() const {
DCHECK_EQ(kDelayedStringConstant, type());
const StringConstantBase* value =
base::bit_cast<StringConstantBase*>(static_cast<intptr_t>(value_));
return value;
}
std::ostream& operator<<(std::ostream& os, const Constant& constant) {
switch (constant.type()) {
case Constant::kInt32:
@ -591,9 +584,6 @@ std::ostream& operator<<(std::ostream& os, const Constant& constant) {
return os << Brief(*constant.ToHeapObject());
case Constant::kRpoNumber:
return os << "RPO" << constant.ToRpoNumber().ToInt();
case Constant::kDelayedStringConstant:
return os << "DelayedStringConstant: "
<< constant.ToDelayedStringConstant();
}
UNREACHABLE();
}

View File

@ -1110,8 +1110,7 @@ class V8_EXPORT_PRIVATE Constant final {
kExternalReference,
kCompressedHeapObject,
kHeapObject,
kRpoNumber,
kDelayedStringConstant
kRpoNumber
};
explicit Constant(int32_t v);
@ -1127,8 +1126,6 @@ class V8_EXPORT_PRIVATE Constant final {
: type_(is_compressed ? kCompressedHeapObject : kHeapObject),
value_(base::bit_cast<intptr_t>(obj)) {}
explicit Constant(RpoNumber rpo) : type_(kRpoNumber), value_(rpo.ToInt()) {}
explicit Constant(const StringConstantBase* str)
: type_(kDelayedStringConstant), value_(base::bit_cast<intptr_t>(str)) {}
explicit Constant(RelocatablePtrConstantInfo info);
Type type() const { return type_; }
@ -1185,7 +1182,6 @@ class V8_EXPORT_PRIVATE Constant final {
Handle<HeapObject> ToHeapObject() const;
Handle<CodeT> ToCode() const;
const StringConstantBase* ToDelayedStringConstant() const;
private:
Type type_;

View File

@ -5168,11 +5168,6 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
}
break;
}
case Constant::kDelayedStringConstant: {
const StringConstantBase* src_constant = src.ToDelayedStringConstant();
__ MoveStringConstant(dst, src_constant);
break;
}
case Constant::kRpoNumber:
UNREACHABLE(); // TODO(dcarney): load of labels on x64.
}

View File

@ -273,7 +273,7 @@ TNode<Number> CodeAssembler::NumberConstant(double value) {
} else {
// We allocate the heap number constant eagerly at this point instead of
// deferring allocation to code generation
// (see AllocateAndInstallRequestedHeapObjects) since that makes it easier
// (see AllocateAndInstallRequestedHeapNumbers) since that makes it easier
// to generate constant lookups for embedded builtins.
return UncheckedCast<Number>(HeapConstant(
isolate()->factory()->NewHeapNumberForCodeAssembler(value)));

View File

@ -91,13 +91,6 @@ DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const op) {
return OpParameter<DeoptimizeParameters>(op);
}
const Operator* CommonOperatorBuilder::DelayedStringConstant(
const StringConstantBase* str) {
return zone()->New<Operator1<const StringConstantBase*>>(
IrOpcode::kDelayedStringConstant, Operator::kPure,
"DelayedStringConstant", 0, 0, 0, 1, 0, 0, str);
}
bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
return lhs.representation() == rhs.representation() &&
lhs.hint() == rhs.hint();
@ -1242,11 +1235,6 @@ Handle<HeapObject> HeapConstantOf(const Operator* op) {
return OpParameter<Handle<HeapObject>>(op);
}
const StringConstantBase* StringConstantBaseOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kDelayedStringConstant, op->opcode());
return OpParameter<const StringConstantBase*>(op);
}
const char* StaticAssertSourceOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kStaticAssert, op->opcode());
return OpParameter<const char*>(op);

View File

@ -8,7 +8,6 @@
#include "src/base/compiler-specific.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/reloc-info.h"
#include "src/codegen/string-constants.h"
#include "src/common/globals.h"
#include "src/compiler/feedback-source.h"
#include "src/compiler/frame-states.h"
@ -20,8 +19,6 @@
namespace v8 {
namespace internal {
class StringConstantBase;
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchHint);
namespace compiler {
@ -413,9 +410,6 @@ const FrameStateInfo& FrameStateInfoOf(const Operator* op)
V8_EXPORT_PRIVATE Handle<HeapObject> HeapConstantOf(const Operator* op)
V8_WARN_UNUSED_RESULT;
const StringConstantBase* StringConstantBaseOf(const Operator* op)
V8_WARN_UNUSED_RESULT;
const char* StaticAssertSourceOf(const Operator* op);
class SLVerifierHintParameters final {
@ -559,8 +553,6 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
const wasm::FunctionSig* signature);
#endif // V8_ENABLE_WEBASSEMBLY
const Operator* DelayedStringConstant(const StringConstantBase* str);
private:
Zone* zone() const { return zone_; }

View File

@ -4,24 +4,30 @@
#include "src/compiler/js-native-context-specialization.h"
#include "src/base/logging.h"
#include "src/base/optional.h"
#include "src/builtins/accessors.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/string-constants.h"
#include "src/common/globals.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/access-info.h"
#include "src/compiler/allocation-builder-inl.h"
#include "src/compiler/allocation-builder.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h"
#include "src/compiler/map-inference.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/property-access-builder.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/type-cache.h"
#include "src/handles/handles.h"
#include "src/heap/factory.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/heap-number.h"
#include "src/objects/string.h"
namespace v8 {
namespace internal {
@ -118,13 +124,13 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
return NoChange();
}
// If {node} is a HeapConstant<String>, return the String's length. If {node} is
// a number, return the maximum size that a stringified number can have.
// Otherwise, we can't easily convert {node} into a String, and we return
// nullopt.
// static
base::Optional<size_t> JSNativeContextSpecialization::GetMaxStringLength(
JSHeapBroker* broker, Node* node) {
if (node->opcode() == IrOpcode::kDelayedStringConstant) {
return StringConstantBaseOf(node->op())->GetMaxStringConstantLength();
}
HeapObjectMatcher matcher(node);
if (matcher.HasResolvedValue() && matcher.Ref(broker).IsString()) {
StringRef input = matcher.Ref(broker).AsString();
@ -144,11 +150,10 @@ base::Optional<size_t> JSNativeContextSpecialization::GetMaxStringLength(
Reduction JSNativeContextSpecialization::ReduceJSToString(Node* node) {
DCHECK_EQ(IrOpcode::kJSToString, node->opcode());
Node* const input = node->InputAt(0);
Reduction reduction;
HeapObjectMatcher matcher(input);
if (matcher.HasResolvedValue() && matcher.Ref(broker()).IsString()) {
reduction = Changed(input); // JSToString(x:string) => x
Reduction reduction = Changed(input); // JSToString(x:string) => x
ReplaceWithValue(node, reduction.replacement());
return reduction;
}
@ -159,46 +164,50 @@ Reduction JSNativeContextSpecialization::ReduceJSToString(Node* node) {
// regressions and the stronger optimization should be re-implemented.
NumberMatcher number_matcher(input);
if (number_matcher.HasResolvedValue()) {
const StringConstantBase* base = shared_zone()->New<NumberToStringConstant>(
number_matcher.ResolvedValue());
reduction =
Replace(graph()->NewNode(common()->DelayedStringConstant(base)));
ReplaceWithValue(node, reduction.replacement());
return reduction;
Handle<Object> num_obj =
broker()
->local_isolate_or_isolate()
->factory()
->NewNumber<AllocationType::kOld>(number_matcher.ResolvedValue());
Handle<String> num_str =
broker()->local_isolate_or_isolate()->factory()->NumberToString(
num_obj);
Node* reduced = graph()->NewNode(
common()->HeapConstant(broker()->CanonicalPersistentHandle(num_str)));
ReplaceWithValue(node, reduced);
return Replace(reduced);
}
return NoChange();
}
base::Optional<const StringConstantBase*>
JSNativeContextSpecialization::CreateDelayedStringConstant(Node* node) {
if (node->opcode() == IrOpcode::kDelayedStringConstant) {
return StringConstantBaseOf(node->op());
// Return a String from {node}, which should be either a HeapConstant<String>
// (in which case we return the String), or a number (in which case we convert
// it to a String).
Handle<String> JSNativeContextSpecialization::CreateStringConstant(Node* node) {
DCHECK(IrOpcode::IsConstantOpcode(node->opcode()));
NumberMatcher number_matcher(node);
if (number_matcher.HasResolvedValue()) {
Handle<Object> num_obj =
broker()
->local_isolate_or_isolate()
->factory()
->NewNumber<AllocationType::kOld>(number_matcher.ResolvedValue());
return broker()->local_isolate_or_isolate()->factory()->NumberToString(
num_obj);
} else {
NumberMatcher number_matcher(node);
if (number_matcher.HasResolvedValue()) {
return shared_zone()->New<NumberToStringConstant>(
number_matcher.ResolvedValue());
HeapObjectMatcher matcher(node);
if (matcher.HasResolvedValue() && matcher.Ref(broker()).IsString()) {
return matcher.Ref(broker()).AsString().object();
} else {
HeapObjectMatcher matcher(node);
if (matcher.HasResolvedValue() && matcher.Ref(broker()).IsString()) {
StringRef s = matcher.Ref(broker()).AsString();
if (!s.length().has_value()) return base::nullopt;
return shared_zone()->New<StringLiteral>(
s.object(), static_cast<size_t>(s.length().value()));
} else {
UNREACHABLE();
}
UNREACHABLE();
}
}
}
namespace {
bool IsStringConstant(JSHeapBroker* broker, Node* node) {
if (node->opcode() == IrOpcode::kDelayedStringConstant) {
return true;
}
HeapObjectMatcher matcher(node);
return matcher.HasResolvedValue() && matcher.Ref(broker).IsString();
}
@ -310,6 +319,82 @@ Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionResolve(
return Replace(promise);
}
namespace {
// Concatenates {left} and {right}. The result is fairly similar to creating a
// new ConsString with {left} and {right} and then flattening it, which we don't
// do because String::Flatten does not support background threads. Rather than
// implementing a full String::Flatten for background threads, we prefered to
// implement this Concatenate function, which, unlike String::Flatten, doesn't
// need to replace ConsStrings by ThinStrings.
Handle<String> Concatenate(Handle<String> left, Handle<String> right,
JSHeapBroker* broker) {
if (left->length() == 0) return right;
if (right->length() == 0) return left;
// Repeated concatenations have a quadratic cost (eg, "s+=a;s+=b;s+=c;...").
// Rather than doing static analysis to determine how many concatenations we
// there are and how many uses the result of each concatenation have, we
// generate ConsString when the result of the concatenation would have more
// than {kConstantStringFlattenMaxSize} characters, and flattened SeqString
// otherwise.
// TODO(dmercadier): ideally, we would like to get rid of this constant, and
// always flatten. This requires some care to avoid the quadratic worst-case.
constexpr int32_t kConstantStringFlattenMaxSize = 100;
int32_t length = left->length() + right->length();
if (length > kConstantStringFlattenMaxSize) {
return broker->local_isolate_or_isolate()
->factory()
->NewConsString(left, right, AllocationType::kOld)
.ToHandleChecked();
}
// If one of the string is not in readonly space, then we need a
// SharedStringAccessGuardIfNeeded before accessing its content.
bool require_guard = SharedStringAccessGuardIfNeeded::IsNeeded(
*left, broker->local_isolate_or_isolate()) ||
SharedStringAccessGuardIfNeeded::IsNeeded(
*right, broker->local_isolate_or_isolate());
SharedStringAccessGuardIfNeeded access_guard(
require_guard ? broker->local_isolate_or_isolate() : nullptr);
if (left->IsOneByteRepresentation() && right->IsOneByteRepresentation()) {
// {left} and {right} are 1-byte ==> the result will be 1-byte.
Handle<SeqOneByteString> flat =
broker->local_isolate_or_isolate()
->factory()
->NewRawOneByteString(length, AllocationType::kOld)
.ToHandleChecked();
DisallowGarbageCollection no_gc;
String::WriteToFlat(*left, flat->GetChars(no_gc, access_guard), 0,
left->length(), GetPtrComprCageBase(*left),
access_guard);
String::WriteToFlat(
*right, flat->GetChars(no_gc, access_guard) + left->length(), 0,
right->length(), GetPtrComprCageBase(*right), access_guard);
return flat;
} else {
// One (or both) of {left} and {right} is 2-byte ==> the result will be
// 2-byte.
Handle<SeqTwoByteString> flat =
broker->local_isolate_or_isolate()
->factory()
->NewRawTwoByteString(length, AllocationType::kOld)
.ToHandleChecked();
DisallowGarbageCollection no_gc;
String::WriteToFlat(*left, flat->GetChars(no_gc, access_guard), 0,
left->length(), GetPtrComprCageBase(*left),
access_guard);
String::WriteToFlat(
*right, flat->GetChars(no_gc, access_guard) + left->length(), 0,
right->length(), GetPtrComprCageBase(*right), access_guard);
return flat;
}
}
} // namespace
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
@ -322,24 +407,19 @@ Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) {
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();
}
if (!lhs_len || !rhs_len) return NoChange();
// 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.
// Fold 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(broker(), lhs) || IsStringConstant(broker(), rhs))) {
base::Optional<const StringConstantBase*> left =
CreateDelayedStringConstant(lhs);
if (!left.has_value()) return NoChange();
base::Optional<const StringConstantBase*> right =
CreateDelayedStringConstant(rhs);
if (!right.has_value()) return NoChange();
const StringConstantBase* cons =
shared_zone()->New<StringCons>(left.value(), right.value());
Handle<String> left = CreateStringConstant(lhs);
Handle<String> right = CreateStringConstant(rhs);
Handle<String> concatenated = Concatenate(left, right, broker());
Node* reduced = graph()->NewNode(common()->HeapConstant(
broker()->CanonicalPersistentHandle(concatenated)));
Node* reduced = graph()->NewNode(common()->DelayedStringConstant(cons));
ReplaceWithValue(node, reduced);
return Replace(reduced);
}

View File

@ -18,7 +18,6 @@ namespace internal {
class Factory;
class JSGlobalObject;
class JSGlobalProxy;
class StringConstantBase;
namespace compiler {
@ -125,8 +124,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Reduction ReduceJSLoadPropertyWithEnumeratedKey(Node* node);
base::Optional<const StringConstantBase*> CreateDelayedStringConstant(
Node* node);
Handle<String> CreateStringConstant(Node* node);
// A triple of nodes that represents a continuation.
class ValueEffectControl final {

View File

@ -212,7 +212,6 @@ class MachineRepresentationInferrer {
MachineRepresentation::kTaggedPointer;
break;
case IrOpcode::kNumberConstant:
case IrOpcode::kDelayedStringConstant:
case IrOpcode::kChangeBitToTagged:
case IrOpcode::kIfException:
case IrOpcode::kOsrValue:

View File

@ -421,7 +421,6 @@
V(ConvertReceiver) \
V(ConvertTaggedHoleToUndefined) \
V(DateNow) \
V(DelayedStringConstant) \
V(EnsureWritableFastElements) \
V(FastApiCall) \
V(FindOrderedHashMapEntry) \

View File

@ -399,7 +399,6 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
// Eagerly fold representation changes for constants.
switch (node->opcode()) {
case IrOpcode::kHeapConstant:
case IrOpcode::kDelayedStringConstant:
if (use_info.type_check() == TypeCheckKind::kBigInt) break;
return node; // No change necessary.
case IrOpcode::kInt32Constant:
@ -512,7 +511,6 @@ Node* RepresentationChanger::GetTaggedRepresentationFor(
switch (node->opcode()) {
case IrOpcode::kNumberConstant:
case IrOpcode::kHeapConstant:
case IrOpcode::kDelayedStringConstant:
return node; // No change necessary.
case IrOpcode::kInt32Constant:
case IrOpcode::kFloat64Constant:

View File

@ -2161,7 +2161,6 @@ class RepresentationSelector {
return;
}
case IrOpcode::kHeapConstant:
case IrOpcode::kDelayedStringConstant:
return VisitLeaf<T>(node, MachineRepresentation::kTaggedPointer);
case IrOpcode::kPointerConstant: {
VisitLeaf<T>(node, MachineType::PointerRepresentation());

View File

@ -322,9 +322,6 @@ OpIndex GraphBuilder::Process(
case IrOpcode::kExternalConstant:
return assembler.Constant(ConstantOp::Kind::kExternal,
OpParameter<ExternalReference>(op));
case IrOpcode::kDelayedStringConstant:
return assembler.Constant(ConstantOp::Kind::kDelayedString,
StringConstantBaseOf(op));
case IrOpcode::kWord32And:
return assembler.BitwiseAnd(Map(node->InputAt(0)), Map(node->InputAt(1)),

View File

@ -232,9 +232,6 @@ void ConstantOp::PrintOptions(std::ostream& os) const {
case Kind::kCompressedHeapObject:
os << "compressed heap object: " << handle();
break;
case Kind::kDelayedString:
os << delayed_string();
break;
}
os << "]";
}

View File

@ -27,7 +27,6 @@
namespace v8::internal {
class HeapObject;
class StringConstantBase;
} // namespace v8::internal
namespace v8::internal::compiler {
class CallDescriptor;
@ -867,8 +866,7 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
kTaggedIndex,
kExternal,
kHeapObject,
kCompressedHeapObject,
kDelayedString
kCompressedHeapObject
};
Kind kind;
@ -878,14 +876,12 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
double float64;
ExternalReference external;
Handle<HeapObject> handle;
const StringConstantBase* string;
Storage(uint64_t integral = 0) : integral(integral) {}
Storage(double constant) : float64(constant) {}
Storage(float constant) : float32(constant) {}
Storage(ExternalReference constant) : external(constant) {}
Storage(Handle<HeapObject> constant) : handle(constant) {}
Storage(const StringConstantBase* constant) : string(constant) {}
} storage;
static constexpr OpProperties properties = OpProperties::Pure();
@ -905,7 +901,6 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
return MachineType::PointerRepresentation();
case Kind::kHeapObject:
case Kind::kNumber:
case Kind::kDelayedString:
return MachineRepresentation::kTagged;
case Kind::kCompressedHeapObject:
return MachineRepresentation::kCompressed;
@ -971,11 +966,6 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
return storage.handle;
}
const StringConstantBase* delayed_string() const {
DCHECK(kind == Kind::kDelayedString);
return storage.string;
}
bool IsZero() const {
switch (kind) {
case Kind::kWord32:
@ -990,7 +980,6 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kExternal:
case Kind::kHeapObject:
case Kind::kCompressedHeapObject:
case Kind::kDelayedString:
UNREACHABLE();
}
}
@ -1009,7 +998,6 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kExternal:
case Kind::kHeapObject:
case Kind::kCompressedHeapObject:
case Kind::kDelayedString:
UNREACHABLE();
}
}
@ -1044,8 +1032,6 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kHeapObject:
case Kind::kCompressedHeapObject:
return base::hash_combine(kind, storage.handle.address());
case Kind::kDelayedString:
return base::hash_combine(kind, storage.string);
}
}
bool operator==(const ConstantOp& other) const {
@ -1075,8 +1061,6 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kHeapObject:
case Kind::kCompressedHeapObject:
return storage.handle.address() == other.storage.handle.address();
case Kind::kDelayedString:
return storage.string == other.storage.string;
}
}
};

View File

@ -771,8 +771,6 @@ Node* ScheduleBuilder::ProcessOperation(const ConstantOp& op) {
return AddNode(common.Float64Constant(op.float64()), {});
case ConstantOp::Kind::kFloat32:
return AddNode(common.Float32Constant(op.float32()), {});
case ConstantOp::Kind::kDelayedString:
return AddNode(common.DelayedStringConstant(op.delayed_string()), {});
}
}
Node* ScheduleBuilder::ProcessOperation(const LoadOp& op) {

View File

@ -2361,10 +2361,6 @@ Type Typer::Visitor::TypeNewArgumentsElements(Node* node) {
Type Typer::Visitor::TypeNewConsString(Node* node) { return Type::String(); }
Type Typer::Visitor::TypeDelayedStringConstant(Node* node) {
return Type::String();
}
Type Typer::Visitor::TypeFindOrderedHashMapEntry(Node* node) {
return Type::Range(-1.0, FixedArray::kMaxLength, zone());
}

View File

@ -1276,9 +1276,6 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckValueInputIs(node, 2, Type::String());
CheckTypeIs(node, Type::String());
break;
case IrOpcode::kDelayedStringConstant:
CheckTypeIs(node, Type::String());
break;
case IrOpcode::kAllocate:
CheckValueInputIs(node, 0, Type::PlainNumber());
break;

View File

@ -45,19 +45,35 @@ class V8_NODISCARD SharedStringAccessGuardIfNeeded {
// Slow version which gets the isolate from the String.
explicit SharedStringAccessGuardIfNeeded(String str) {
Isolate* isolate = GetIsolateIfNeeded(str);
if (isolate != nullptr)
if (isolate != nullptr) {
mutex_guard.emplace(isolate->internalized_string_access());
}
}
static SharedStringAccessGuardIfNeeded NotNeeded() {
return SharedStringAccessGuardIfNeeded();
}
#ifdef DEBUG
static bool IsNeeded(String str) {
return GetIsolateIfNeeded(str) != nullptr;
static bool IsNeeded(String str, LocalIsolate* local_isolate) {
return IsNeeded(local_isolate) && IsNeeded(str, false);
}
static bool IsNeeded(String str, bool check_local_heap = true) {
if (check_local_heap) {
LocalHeap* local_heap = LocalHeap::Current();
if (!local_heap || local_heap->is_main_thread()) {
// Don't acquire the lock for the main thread.
return false;
}
}
if (ReadOnlyHeap::Contains(str)) {
// Don't acquire lock for strings in ReadOnlySpace.
return false;
}
return true;
}
#endif
static bool IsNeeded(LocalIsolate* local_isolate) {
// TODO(leszeks): Remove the nullptr check for local_isolate.
@ -75,16 +91,7 @@ class V8_NODISCARD SharedStringAccessGuardIfNeeded {
// Returns the Isolate from the String if we need it for the lock.
static Isolate* GetIsolateIfNeeded(String str) {
LocalHeap* local_heap = LocalHeap::Current();
// Don't acquire the lock for the main thread.
if (!local_heap || local_heap->is_main_thread()) return nullptr;
#ifdef V8_COMPRESS_POINTERS_IN_ISOLATE_CAGE
// We don't need to guard when the string is in RO space. When compressing
// pointers in a per-Isolate cage, GetIsolateFromHeapObject always returns
// an Isolate, even for objects in RO space, so manually check.
if (ReadOnlyHeap::Contains(str)) return nullptr;
#endif
if (!IsNeeded(str)) return nullptr;
Isolate* isolate;
if (!GetIsolateFromHeapObject(str, &isolate)) {