Commit f8809072 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] @relaxedWrite annotation; generate Context C++ class/BodyDescr.

This CL lets Torque generate the Context C++ class and BodyDescriptor
for Context.
This requires two Torque changes:

- Allow @generateBodyDescriptor on @abstract classes, since all Context
  classes share the same BodyDescriptor.

- Add a new annotation @relaxedWrite, which makes C++ setters
  use WRITE_RELAXED_FIELD instead of WRITE_FIELD.
  Attention: As a side-effect, this CL disables using
    WRITE_RELAXED_FIELD by default for all non-array fields. If this
    causes problems, we should manually add @relaxedWrite to the
    corresponding fields.

Bug: v8:7793

Change-Id: I735b310bcb36a3612d86c22efa9c0bfc108d4ca6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2529453
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71123}
parent 4b71ac6b
...@@ -22,7 +22,6 @@ namespace internal { ...@@ -22,7 +22,6 @@ namespace internal {
V(Cell) \ V(Cell) \
V(Code) \ V(Code) \
V(CodeDataContainer) \ V(CodeDataContainer) \
V(Context) \
V(CoverageInfo) \ V(CoverageInfo) \
V(DataHandler) \ V(DataHandler) \
V(EmbedderDataArray) \ V(EmbedderDataArray) \
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#include "torque-generated/src/objects/contexts-tq-inl.inc"
OBJECT_CONSTRUCTORS_IMPL(ScriptContextTable, FixedArray) OBJECT_CONSTRUCTORS_IMPL(ScriptContextTable, FixedArray)
CAST_ACCESSOR(ScriptContextTable) CAST_ACCESSOR(ScriptContextTable)
...@@ -48,39 +50,20 @@ Context ScriptContextTable::get_context(int i) const { ...@@ -48,39 +50,20 @@ Context ScriptContextTable::get_context(int i) const {
return Context::cast(this->get(i + kFirstContextSlotIndex)); return Context::cast(this->get(i + kFirstContextSlotIndex));
} }
OBJECT_CONSTRUCTORS_IMPL(Context, HeapObject) TQ_OBJECT_CONSTRUCTORS_IMPL(Context)
NEVER_READ_ONLY_SPACE_IMPL(Context) NEVER_READ_ONLY_SPACE_IMPL(Context)
CAST_ACCESSOR(Context)
SMI_ACCESSORS(Context, length, kLengthOffset)
CAST_ACCESSOR(NativeContext) CAST_ACCESSOR(NativeContext)
Object Context::get(int index) const { V8_INLINE Object Context::get(int index) const { return elements(index); }
IsolateRoot isolate = GetIsolateForPtrCompr(*this); V8_INLINE Object Context::get(IsolateRoot isolate, int index) const {
return get(isolate, index); return elements(isolate, index);
} }
V8_INLINE void Context::set(int index, Object value) {
Object Context::get(IsolateRoot isolate, int index) const { set_elements(index, value);
DCHECK_LT(static_cast<unsigned>(index),
static_cast<unsigned>(this->length()));
return TaggedField<Object>::Relaxed_Load(isolate, *this,
OffsetOfElementAt(index));
} }
V8_INLINE void Context::set(int index, Object value, WriteBarrierMode mode) {
void Context::set(int index, Object value) { set_elements(index, value, mode);
DCHECK_LT(static_cast<unsigned>(index),
static_cast<unsigned>(this->length()));
int offset = OffsetOfElementAt(index);
RELAXED_WRITE_FIELD(*this, offset, value);
WRITE_BARRIER(*this, offset, value);
}
void Context::set(int index, Object value, WriteBarrierMode mode) {
DCHECK_LT(static_cast<unsigned>(index),
static_cast<unsigned>(this->length()));
int offset = OffsetOfElementAt(index);
RELAXED_WRITE_FIELD(*this, offset, value);
CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
} }
void Context::set_scope_info(ScopeInfo scope_info) { void Context::set_scope_info(ScopeInfo scope_info) {
......
...@@ -337,6 +337,8 @@ enum ContextLookupFlags { ...@@ -337,6 +337,8 @@ enum ContextLookupFlags {
V(RETAINED_MAPS, WeakArrayList, retained_maps) \ V(RETAINED_MAPS, WeakArrayList, retained_maps) \
V(OSR_CODE_CACHE_INDEX, WeakFixedArray, osr_code_cache) V(OSR_CODE_CACHE_INDEX, WeakFixedArray, osr_code_cache)
#include "torque-generated/src/objects/contexts-tq.inc"
// A table of all script contexts. Every loaded top-level script with top-level // A table of all script contexts. Every loaded top-level script with top-level
// lexical declarations contributes its ScriptContext into this table. // lexical declarations contributes its ScriptContext into this table.
// //
...@@ -428,15 +430,10 @@ class ScriptContextTable : public FixedArray { ...@@ -428,15 +430,10 @@ class ScriptContextTable : public FixedArray {
// Script contexts from all top-level scripts are gathered in // Script contexts from all top-level scripts are gathered in
// ScriptContextTable. // ScriptContextTable.
class Context : public HeapObject { class Context : public TorqueGeneratedContext<Context, HeapObject> {
public: public:
NEVER_READ_ONLY_SPACE NEVER_READ_ONLY_SPACE
DECL_CAST(Context)
// [length]: length of the context.
V8_INLINE int length() const;
V8_INLINE void set_length(int value);
// Setter and getter for elements. // Setter and getter for elements.
V8_INLINE Object get(int index) const; V8_INLINE Object get(int index) const;
V8_INLINE Object get(IsolateRoot isolate, int index) const; V8_INLINE Object get(IsolateRoot isolate, int index) const;
...@@ -448,15 +445,9 @@ class Context : public HeapObject { ...@@ -448,15 +445,9 @@ class Context : public HeapObject {
V8_INLINE Object synchronized_get(IsolateRoot isolate, int index) const; V8_INLINE Object synchronized_get(IsolateRoot isolate, int index) const;
V8_INLINE void synchronized_set(int index, Object value); V8_INLINE void synchronized_set(int index, Object value);
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, static const int kScopeInfoOffset = kElementsOffset;
TORQUE_GENERATED_CONTEXT_FIELDS)
static const int kScopeInfoOffset = kHeaderSize;
static const int kPreviousOffset = kScopeInfoOffset + kTaggedSize; static const int kPreviousOffset = kScopeInfoOffset + kTaggedSize;
// TODO(v8:8989): [torque] Support marker constants
/* TODO(ishell): remove this fixedArray-like header size. */
static const int kFixedArrayLikeHeaderSize = kScopeInfoOffset;
static const int kStartOfTaggedFieldsOffset = kScopeInfoOffset;
/* Header size. */ \ /* Header size. */ \
/* TODO(ishell): use this as header size once MIN_CONTEXT_SLOTS */ \ /* TODO(ishell): use this as header size once MIN_CONTEXT_SLOTS */ \
/* is removed in favour of offset-based access to common fields. */ \ /* is removed in favour of offset-based access to common fields. */ \
...@@ -467,7 +458,10 @@ class Context : public HeapObject { ...@@ -467,7 +458,10 @@ class Context : public HeapObject {
// Garbage collection support. // Garbage collection support.
V8_INLINE static constexpr int SizeFor(int length) { V8_INLINE static constexpr int SizeFor(int length) {
return kFixedArrayLikeHeaderSize + length * kTaggedSize; // TODO(v8:9287): This is a workaround for GCMole build failures.
int result = kElementsOffset + length * kTaggedSize;
DCHECK_EQ(TorqueGeneratedContext::SizeFor(length), result);
return result;
} }
// Code Generation support. // Code Generation support.
...@@ -477,7 +471,7 @@ class Context : public HeapObject { ...@@ -477,7 +471,7 @@ class Context : public HeapObject {
} }
// Offset of the element from the heap object pointer. // Offset of the element from the heap object pointer.
V8_INLINE static constexpr int SlotOffset(int index) { V8_INLINE static constexpr int SlotOffset(int index) {
return SizeFor(index) - kHeapObjectTag; return OffsetOfElementAt(index) - kHeapObjectTag;
} }
// Initializes the variable slots of the context. Lexical variables that need // Initializes the variable slots of the context. Lexical variables that need
...@@ -647,7 +641,7 @@ class Context : public HeapObject { ...@@ -647,7 +641,7 @@ class Context : public HeapObject {
DECL_PRINTER(Context) DECL_PRINTER(Context)
DECL_VERIFIER(Context) DECL_VERIFIER(Context)
using BodyDescriptor = FlexibleBodyDescriptor<kStartOfTaggedFieldsOffset>; class BodyDescriptor;
private: private:
#ifdef DEBUG #ifdef DEBUG
...@@ -655,7 +649,7 @@ class Context : public HeapObject { ...@@ -655,7 +649,7 @@ class Context : public HeapObject {
static bool IsBootstrappingOrValidParentContext(Object object, Context kid); static bool IsBootstrappingOrValidParentContext(Object object, Context kid);
#endif #endif
OBJECT_CONSTRUCTORS(Context, HeapObject); TQ_OBJECT_CONSTRUCTORS(Context)
}; };
class NativeContext : public Context { class NativeContext : public Context {
......
...@@ -3,12 +3,17 @@ ...@@ -3,12 +3,17 @@
// found in the LICENSE file. // found in the LICENSE file.
@abstract @abstract
extern class Context extends HeapObject { @export
@customCppClass
// We normally don't generate a BodyDescriptor for an abstact class, but here we
// do since all context classes share the same BodyDescriptor.
@generateBodyDescriptor
class Context extends HeapObject {
macro GetScopeInfo(): ScopeInfo { macro GetScopeInfo(): ScopeInfo {
return *ContextSlot(this, ContextSlot::SCOPE_INFO_INDEX); return *ContextSlot(this, ContextSlot::SCOPE_INFO_INDEX);
} }
const length: Smi; const length: Smi;
elements[length]: Object; @relaxedWrite elements[length]: Object;
} }
extern class AwaitContext extends Context generates 'TNode<Context>'; extern class AwaitContext extends Context generates 'TNode<Context>';
......
...@@ -38,7 +38,6 @@ enum InstanceType : uint16_t; ...@@ -38,7 +38,6 @@ enum InstanceType : uint16_t;
V(Cell) \ V(Cell) \
V(Code) \ V(Code) \
V(CodeDataContainer) \ V(CodeDataContainer) \
V(Context) \
V(DataHandler) \ V(DataHandler) \
V(EmbedderDataArray) \ V(EmbedderDataArray) \
V(EphemeronHashTable) \ V(EphemeronHashTable) \
......
...@@ -98,7 +98,6 @@ class ZoneForwardList; ...@@ -98,7 +98,6 @@ class ZoneForwardList;
V(CompilationCacheTable) \ V(CompilationCacheTable) \
V(ConsString) \ V(ConsString) \
V(Constructor) \ V(Constructor) \
V(Context) \
V(CoverageInfo) \ V(CoverageInfo) \
V(ClosureFeedbackCellArray) \ V(ClosureFeedbackCellArray) \
V(DataHandler) \ V(DataHandler) \
......
...@@ -18,7 +18,6 @@ extern class ConsString extends String { ...@@ -18,7 +18,6 @@ extern class ConsString extends String {
} }
@abstract @abstract
@generateBodyDescriptor
@doNotGenerateCast @doNotGenerateCast
extern class ExternalString extends String { extern class ExternalString extends String {
resource: ExternalPointer; resource: ExternalPointer;
......
...@@ -931,6 +931,7 @@ struct ClassFieldExpression { ...@@ -931,6 +931,7 @@ struct ClassFieldExpression {
bool weak; bool weak;
bool const_qualified; bool const_qualified;
bool generate_verify; bool generate_verify;
bool relaxed_write;
}; };
struct LabelAndTypes { struct LabelAndTypes {
......
...@@ -103,6 +103,8 @@ static const char* const ANNOTATION_EXPORT = "@export"; ...@@ -103,6 +103,8 @@ static const char* const ANNOTATION_EXPORT = "@export";
static const char* const ANNOTATION_DO_NOT_GENERATE_CAST = "@doNotGenerateCast"; static const char* const ANNOTATION_DO_NOT_GENERATE_CAST = "@doNotGenerateCast";
static const char* const ANNOTATION_USE_PARENT_TYPE_CHECKER = static const char* const ANNOTATION_USE_PARENT_TYPE_CHECKER =
"@useParentTypeChecker"; "@useParentTypeChecker";
// Generate C++ accessors with relaxed write semantics.
static const char* const ANNOTATION_RELAXED_WRITE = "@relaxedWrite";
inline bool IsConstexprName(const std::string& name) { inline bool IsConstexprName(const std::string& name) {
return name.substr(0, std::strlen(CONSTEXPR_TYPE_PREFIX)) == return name.substr(0, std::strlen(CONSTEXPR_TYPE_PREFIX)) ==
......
...@@ -3781,8 +3781,9 @@ void CppClassGenerator::GenerateClass() { ...@@ -3781,8 +3781,9 @@ void CppClassGenerator::GenerateClass() {
if (!index_fields.has_value()) { if (!index_fields.has_value()) {
hdr_ << " // SizeFor implementations not generated due to complex array " hdr_ << " // SizeFor implementations not generated due to complex array "
"lengths\n\n"; "lengths\n\n";
} else if (!type_->IsAbstract() && } else if (type_->ShouldGenerateBodyDescriptor() ||
!type_->IsSubtypeOf(TypeOracle::GetJSObjectType())) { (!type_->IsAbstract() &&
!type_->IsSubtypeOf(TypeOracle::GetJSObjectType()))) {
hdr_ << " V8_INLINE static constexpr int32_t SizeFor("; hdr_ << " V8_INLINE static constexpr int32_t SizeFor(";
bool first = true; bool first = true;
for (const Field& field : *index_fields) { for (const Field& field : *index_fields) {
...@@ -4060,12 +4061,15 @@ void CppClassGenerator::GenerateFieldAccessorForSmi(const Field& f) { ...@@ -4060,12 +4061,15 @@ void CppClassGenerator::GenerateFieldAccessorForSmi(const Field& f) {
inl_ << "int i, "; inl_ << "int i, ";
} }
inl_ << type << " value) {\n"; inl_ << type << " value) {\n";
const char* write_macro =
f.relaxed_write ? "RELAXED_WRITE_FIELD" : "WRITE_FIELD";
if (f.index) { if (f.index) {
GenerateBoundsDCheck(inl_, "i", type_, f); GenerateBoundsDCheck(inl_, "i", type_, f);
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n"; inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
inl_ << " WRITE_FIELD(*this, offset, Smi::FromInt(value));\n"; inl_ << " " << write_macro << "(*this, offset, Smi::FromInt(value));\n";
} else { } else {
inl_ << " WRITE_FIELD(*this, " << offset << ", Smi::FromInt(value));\n"; inl_ << " " << write_macro << "(*this, " << offset
<< ", Smi::FromInt(value));\n";
} }
inl_ << "}\n\n"; inl_ << "}\n\n";
} }
...@@ -4105,12 +4109,6 @@ void CppClassGenerator::GenerateFieldAccessorForTagged(const Field& f) { ...@@ -4105,12 +4109,6 @@ void CppClassGenerator::GenerateFieldAccessorForTagged(const Field& f) {
inl_ << type << " " << gen_name_ << "<D, P>::" << name inl_ << type << " " << gen_name_ << "<D, P>::" << name
<< "(IsolateRoot isolate" << (f.index ? ", int i" : "") << ") const {\n"; << "(IsolateRoot isolate" << (f.index ? ", int i" : "") << ") const {\n";
// TODO(tebbi): The distinction between relaxed and non-relaxed accesses here
// is pretty arbitrary and just tries to preserve what was there before.
// It currently doesn't really make a difference due to concurrent marking
// turning all loads and stores to be relaxed. We should probably drop the
// distinction at some point, even though in principle non-relaxed operations
// would give us TSAN protection.
if (f.index) { if (f.index) {
GenerateBoundsDCheck(inl_, "i", type_, f); GenerateBoundsDCheck(inl_, "i", type_, f);
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n"; inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
...@@ -4135,16 +4133,15 @@ void CppClassGenerator::GenerateFieldAccessorForTagged(const Field& f) { ...@@ -4135,16 +4133,15 @@ void CppClassGenerator::GenerateFieldAccessorForTagged(const Field& f) {
if (!type_check.empty()) { if (!type_check.empty()) {
inl_ << " SLOW_DCHECK(" << type_check << ");\n"; inl_ << " SLOW_DCHECK(" << type_check << ");\n";
} }
const char* write_macro =
strong_pointer ? (f.relaxed_write ? "RELAXED_WRITE_FIELD" : "WRITE_FIELD")
: "RELAXED_WRITE_WEAK_FIELD";
if (f.index) { if (f.index) {
GenerateBoundsDCheck(inl_, "i", type_, f); GenerateBoundsDCheck(inl_, "i", type_, f);
const char* write_macro =
strong_pointer ? "WRITE_FIELD" : "RELAXED_WRITE_WEAK_FIELD";
inl_ << " int offset = " << offset << " + i * kTaggedSize;\n"; inl_ << " int offset = " << offset << " + i * kTaggedSize;\n";
offset = "offset"; offset = "offset";
inl_ << " " << write_macro << "(*this, offset, value);\n"; inl_ << " " << write_macro << "(*this, offset, value);\n";
} else { } else {
const char* write_macro =
strong_pointer ? "RELAXED_WRITE_FIELD" : "RELAXED_WRITE_WEAK_FIELD";
inl_ << " " << write_macro << "(*this, " << offset << ", value);\n"; inl_ << " " << write_macro << "(*this, " << offset << ", value);\n";
} }
const char* write_barrier = strong_pointer ? "CONDITIONAL_WRITE_BARRIER" const char* write_barrier = strong_pointer ? "CONDITIONAL_WRITE_BARRIER"
......
...@@ -1939,9 +1939,11 @@ base::Optional<ParseResult> MakeAnnotation(ParseResultIterator* child_results) { ...@@ -1939,9 +1939,11 @@ base::Optional<ParseResult> MakeAnnotation(ParseResultIterator* child_results) {
} }
base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) { base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
AnnotationSet annotations(child_results, {ANNOTATION_NO_VERIFIER}, AnnotationSet annotations(child_results,
{ANNOTATION_NO_VERIFIER, ANNOTATION_RELAXED_WRITE},
{ANNOTATION_IF, ANNOTATION_IFNOT}); {ANNOTATION_IF, ANNOTATION_IFNOT});
bool generate_verify = !annotations.Contains(ANNOTATION_NO_VERIFIER); bool generate_verify = !annotations.Contains(ANNOTATION_NO_VERIFIER);
bool relaxed_write = annotations.Contains(ANNOTATION_RELAXED_WRITE);
std::vector<ConditionalAnnotation> conditions; std::vector<ConditionalAnnotation> conditions;
base::Optional<std::string> if_condition = base::Optional<std::string> if_condition =
annotations.GetStringParam(ANNOTATION_IF); annotations.GetStringParam(ANNOTATION_IF);
...@@ -1964,7 +1966,8 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) { ...@@ -1964,7 +1966,8 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
std::move(conditions), std::move(conditions),
weak, weak,
const_qualified, const_qualified,
generate_verify}}; generate_verify,
relaxed_write}};
} }
base::Optional<ParseResult> MakeStructField( base::Optional<ParseResult> MakeStructField(
......
...@@ -212,6 +212,7 @@ const StructType* TypeVisitor::ComputeType( ...@@ -212,6 +212,7 @@ const StructType* TypeVisitor::ComputeType(
offset.SingleValue(), offset.SingleValue(),
false, false,
field.const_qualified, field.const_qualified,
false,
false}; false};
auto optional_size = SizeOf(f.name_and_type.type); auto optional_size = SizeOf(f.name_and_type.type);
struct_type->RegisterField(f); struct_type->RegisterField(f);
...@@ -313,8 +314,7 @@ const ClassType* TypeVisitor::ComputeType( ...@@ -313,8 +314,7 @@ const ClassType* TypeVisitor::ComputeType(
Error("non-external classes must have defined layouts"); Error("non-external classes must have defined layouts");
} }
} }
flags = flags | ClassFlag::kGeneratePrint | ClassFlag::kGenerateVerify | flags = flags | ClassFlag::kGeneratePrint | ClassFlag::kGenerateVerify;
ClassFlag::kGenerateBodyDescriptor;
} }
if (!(flags & ClassFlag::kExtern) && if (!(flags & ClassFlag::kExtern) &&
(flags & ClassFlag::kHasSameInstanceTypeAsParent)) { (flags & ClassFlag::kHasSameInstanceTypeAsParent)) {
...@@ -428,7 +428,8 @@ void TypeVisitor::VisitClassFieldsAndMethods( ...@@ -428,7 +428,8 @@ void TypeVisitor::VisitClassFieldsAndMethods(
class_offset.SingleValue(), class_offset.SingleValue(),
field_expression.weak, field_expression.weak,
field_expression.const_qualified, field_expression.const_qualified,
field_expression.generate_verify}); field_expression.generate_verify,
field_expression.relaxed_write});
ResidueClass field_size = std::get<0>(field.GetFieldSizeInformation()); ResidueClass field_size = std::get<0>(field.GetFieldSizeInformation());
if (field.index) { if (field.index) {
// Validate that a value at any index in a packed array is aligned // Validate that a value at any index in a packed array is aligned
......
...@@ -903,9 +903,6 @@ void ClassType::GenerateSliceAccessor(size_t field_index) { ...@@ -903,9 +903,6 @@ void ClassType::GenerateSliceAccessor(size_t field_index) {
} }
bool ClassType::HasStaticSize() const { bool ClassType::HasStaticSize() const {
// Abstract classes don't have instances directly, so asking this question
// doesn't make sense.
DCHECK(!IsAbstract());
if (IsSubtypeOf(TypeOracle::GetJSObjectType()) && !IsShape()) return false; if (IsSubtypeOf(TypeOracle::GetJSObjectType()) && !IsShape()) return false;
return size().SingleValue().has_value(); return size().SingleValue().has_value();
} }
......
...@@ -227,6 +227,7 @@ struct Field { ...@@ -227,6 +227,7 @@ struct Field {
bool is_weak; bool is_weak;
bool const_qualified; bool const_qualified;
bool generate_verify; bool generate_verify;
bool relaxed_write;
}; };
std::ostream& operator<<(std::ostream& os, const Field& name_and_type); std::ostream& operator<<(std::ostream& os, const Field& name_and_type);
...@@ -668,8 +669,8 @@ class ClassType final : public AggregateType { ...@@ -668,8 +669,8 @@ class ClassType final : public AggregateType {
(!HasUndefinedLayout() && !IsShape())); (!HasUndefinedLayout() && !IsShape()));
} }
bool ShouldGenerateBodyDescriptor() const { bool ShouldGenerateBodyDescriptor() const {
if (IsAbstract()) return false; return flags_ & ClassFlag::kGenerateBodyDescriptor ||
return flags_ & ClassFlag::kGenerateBodyDescriptor || !IsExtern(); (!IsAbstract() && !IsExtern());
} }
bool DoNotGenerateCast() const { bool DoNotGenerateCast() const {
return flags_ & ClassFlag::kDoNotGenerateCast; return flags_ & ClassFlag::kDoNotGenerateCast;
......
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