Commit e79b841b authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[literals] Add a dedicated regexp boilerplate type

... and mark it as never-serialized wrt turbofan serialization.

Until this CL, the JSRegExp type was used as both for plain
user-visible regexp objects, and for internal regexp boilerplate
descriptions. Boilerplates are special: they are never exposed to the
user, they are only referenced from the feedback vector, they are
immutable.

To clarify this distinction, this CL introduces a dedicated struct
type RegExpBoilerplateDescription to hold the regexp boilerplate
description.

This makes Turbofan serialization simpler: boilerplates can be
accessed through direct reads since they are immutable. TF has no
special requirements on JSRegExp objects (it never reads into these
objects) and thus serializing only the references as a JSObjectRef is
fine.

Bug: v8:7790
Change-Id: I33b337fcfcf861a02bc6be6d0c6311d07cf05718
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2656257Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72522}
parent 996a2dd9
......@@ -358,15 +358,49 @@ TNode<JSRegExp> ConstructorBuiltinsAssembler::CreateRegExpLiteral(
CAST(LoadFeedbackVectorSlot(feedback_vector, slot));
GotoIfNot(HasBoilerplate(literal_site), &call_runtime);
{
TNode<JSRegExp> boilerplate = CAST(literal_site);
int size =
JSRegExp::kHeaderSize + JSRegExp::kInObjectFieldCount * kTaggedSize;
TNode<HeapObject> copy = Allocate(size);
for (int offset = 0; offset < size; offset += kTaggedSize) {
TNode<Object> value = LoadObjectField(boilerplate, offset);
StoreObjectFieldNoWriteBarrier(copy, offset, value);
}
result = CAST(copy);
STATIC_ASSERT(JSRegExp::kDataOffset == JSObject::kHeaderSize);
STATIC_ASSERT(JSRegExp::kSourceOffset ==
JSRegExp::kDataOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kFlagsOffset ==
JSRegExp::kSourceOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kHeaderSize ==
JSRegExp::kFlagsOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kLastIndexOffset == JSRegExp::kHeaderSize);
DCHECK_EQ(JSRegExp::Size(), JSRegExp::kLastIndexOffset + kTaggedSize);
TNode<RegExpBoilerplateDescription> boilerplate = CAST(literal_site);
TNode<HeapObject> new_object = Allocate(JSRegExp::Size());
// Initialize Object fields.
TNode<JSFunction> regexp_function = CAST(LoadContextElement(
LoadNativeContext(context), Context::REGEXP_FUNCTION_INDEX));
TNode<Map> initial_map = CAST(LoadObjectField(
regexp_function, JSFunction::kPrototypeOrInitialMapOffset));
StoreMapNoWriteBarrier(new_object, initial_map);
// Initialize JSReceiver fields.
StoreObjectFieldRoot(new_object, JSReceiver::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
// Initialize JSObject fields.
StoreObjectFieldRoot(new_object, JSObject::kElementsOffset,
RootIndex::kEmptyFixedArray);
// Initialize JSRegExp fields.
StoreObjectFieldNoWriteBarrier(
new_object, JSRegExp::kDataOffset,
LoadObjectField(boilerplate,
RegExpBoilerplateDescription::kDataOffset));
StoreObjectFieldNoWriteBarrier(
new_object, JSRegExp::kSourceOffset,
LoadObjectField(boilerplate,
RegExpBoilerplateDescription::kSourceOffset));
StoreObjectFieldNoWriteBarrier(
new_object, JSRegExp::kFlagsOffset,
LoadObjectField(boilerplate,
RegExpBoilerplateDescription::kFlagsOffset));
StoreObjectFieldNoWriteBarrier(
new_object, JSRegExp::kLastIndexOffset,
SmiConstant(JSRegExp::kInitialLastIndexValue));
result = CAST(new_object);
Goto(&end);
}
......
......@@ -27,7 +27,6 @@ class InternalizedString;
class JSBoundFunction;
class JSDataView;
class JSGlobalProxy;
class JSRegExp;
class JSTypedArray;
class NativeContext;
class ScriptContextTable;
......@@ -74,6 +73,7 @@ enum class OddballType : uint8_t {
V(Cell) \
V(FeedbackCell) \
V(FeedbackVector) \
V(RegExpBoilerplateDescription) \
V(SharedFunctionInfo) \
V(TemplateObjectDescription)
......@@ -100,7 +100,6 @@ enum class OddballType : uint8_t {
V(JSFunction) \
V(JSGlobalObject) \
V(JSGlobalProxy) \
V(JSRegExp) \
V(JSTypedArray) \
/* Subtypes of Context */ \
V(NativeContext) \
......@@ -392,19 +391,17 @@ class V8_EXPORT_PRIVATE JSFunctionRef : public JSObjectRef {
CodeRef code() const;
};
class JSRegExpRef : public JSObjectRef {
class RegExpBoilerplateDescriptionRef : public HeapObjectRef {
public:
DEFINE_REF_CONSTRUCTOR(JSRegExp, JSObjectRef)
DEFINE_REF_CONSTRUCTOR(RegExpBoilerplateDescription, HeapObjectRef)
Handle<JSRegExp> object() const;
Handle<RegExpBoilerplateDescription> object() const;
ObjectRef raw_properties_or_hash() const;
ObjectRef data() const;
ObjectRef source() const;
ObjectRef flags() const;
ObjectRef last_index() const;
void Serialize();
void SerializeAsRegExpBoilerplate();
FixedArrayRef data() const;
StringRef source() const;
int flags() const;
};
class HeapNumberRef : public HeapObjectRef {
......
......@@ -1172,7 +1172,8 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
ProcessedFeedback const& feedback =
broker()->GetFeedbackForRegExpLiteral(p.feedback());
if (!feedback.IsInsufficient()) {
JSRegExpRef literal = feedback.AsRegExpLiteral().value();
RegExpBoilerplateDescriptionRef literal =
feedback.AsRegExpLiteral().value();
Node* value = effect = AllocateLiteralRegExp(effect, control, literal);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
......@@ -1785,36 +1786,34 @@ Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control,
return builder.Finish();
}
Node* JSCreateLowering::AllocateLiteralRegExp(Node* effect, Node* control,
JSRegExpRef boilerplate) {
MapRef boilerplate_map = boilerplate.map();
Node* JSCreateLowering::AllocateLiteralRegExp(
Node* effect, Node* control, RegExpBoilerplateDescriptionRef boilerplate) {
MapRef initial_map = native_context().regexp_function().initial_map();
// Sanity check that JSRegExp object layout hasn't changed.
STATIC_ASSERT(static_cast<int>(JSRegExp::kDataOffset) ==
static_cast<int>(JSObject::kHeaderSize));
STATIC_ASSERT(JSRegExp::kDataOffset == JSObject::kHeaderSize);
STATIC_ASSERT(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kFlagsOffset ==
JSRegExp::kSourceOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kLastIndexOffset == JSRegExp::kHeaderSize);
STATIC_ASSERT(JSRegExp::kInObjectFieldCount == 1); // LastIndex.
const AllocationType allocation = AllocationType::kYoung;
const int size =
JSRegExp::kHeaderSize + JSRegExp::kInObjectFieldCount * kTaggedSize;
DCHECK_EQ(JSRegExp::Size(), JSRegExp::kLastIndexOffset + kTaggedSize);
AllocationBuilder builder(jsgraph(), effect, control);
builder.Allocate(size, allocation, Type::For(boilerplate_map));
builder.Store(AccessBuilder::ForMap(), boilerplate_map);
builder.Allocate(JSRegExp::Size(), AllocationType::kYoung,
Type::For(initial_map));
builder.Store(AccessBuilder::ForMap(), initial_map);
builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
boilerplate.raw_properties_or_hash());
builder.Store(AccessBuilder::ForJSObjectElements(), boilerplate.elements());
jsgraph()->EmptyFixedArrayConstant());
builder.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
builder.Store(AccessBuilder::ForJSRegExpData(), boilerplate.data());
builder.Store(AccessBuilder::ForJSRegExpSource(), boilerplate.source());
builder.Store(AccessBuilder::ForJSRegExpFlags(), boilerplate.flags());
builder.Store(AccessBuilder::ForJSRegExpFlags(),
jsgraph()->SmiConstant(boilerplate.flags()));
builder.Store(AccessBuilder::ForJSRegExpLastIndex(),
boilerplate.last_index());
jsgraph()->SmiConstant(JSRegExp::kInitialLastIndexValue));
return builder.Finish();
}
......
......@@ -109,7 +109,7 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
JSObjectRef boilerplate,
AllocationType allocation);
Node* AllocateLiteralRegExp(Node* effect, Node* control,
JSRegExpRef boilerplate);
RegExpBoilerplateDescriptionRef boilerplate);
Factory* factory() const;
Graph* graph() const;
......
......@@ -96,6 +96,20 @@ bool IsReadOnlyHeapObject(Object object) {
(object.IsHeapObject() &&
ReadOnlyHeap::Contains(HeapObject::cast(object)));
}
template <class T>
constexpr bool IsSerializedHeapObject() {
return false;
}
#define DEFINE_MARKER(Name) \
template <> \
constexpr bool IsSerializedHeapObject<Name>() { \
return true; \
} \
STATIC_ASSERT(IsSerializedHeapObject<Name>());
HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_MARKER)
#undef DEFINE_MARKER
} // namespace
class ObjectData : public ZoneObject {
......@@ -666,28 +680,31 @@ class JSFunctionData : public JSObjectData {
int initial_map_instance_size_with_min_slack_;
};
class JSRegExpData : public JSObjectData {
class RegExpBoilerplateDescriptionData : public HeapObjectData {
public:
JSRegExpData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSRegExp> object)
: JSObjectData(broker, storage, object) {}
void SerializeAsRegExpBoilerplate(JSHeapBroker* broker);
RegExpBoilerplateDescriptionData(JSHeapBroker* broker, ObjectData** storage,
Handle<RegExpBoilerplateDescription> object)
: HeapObjectData(broker, storage, object) {}
ObjectData* raw_properties_or_hash() const { return raw_properties_or_hash_; }
ObjectData* data() const { return data_; }
ObjectData* source() const { return source_; }
ObjectData* flags() const { return flags_; }
ObjectData* last_index() const { return last_index_; }
void Serialize(JSHeapBroker* broker);
ObjectData* data() const {
CHECK(serialized_);
return data_;
}
ObjectData* source() const {
CHECK(serialized_);
return source_;
}
int flags() const {
CHECK(serialized_);
return flags_;
}
private:
bool serialized_as_reg_exp_boilerplate_ = false;
ObjectData* raw_properties_or_hash_ = nullptr;
bool serialized_ = false;
ObjectData* data_ = nullptr;
ObjectData* source_ = nullptr;
ObjectData* flags_ = nullptr;
ObjectData* last_index_ = nullptr;
int flags_;
};
class HeapNumberData : public HeapObjectData {
......@@ -2368,21 +2385,17 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
if (IsJSArray()) AsJSArray()->Serialize(broker);
}
void JSRegExpData::SerializeAsRegExpBoilerplate(JSHeapBroker* broker) {
if (serialized_as_reg_exp_boilerplate_) return;
serialized_as_reg_exp_boilerplate_ = true;
TraceScope tracer(broker, this, "JSRegExpData::SerializeAsRegExpBoilerplate");
Handle<JSRegExp> boilerplate = Handle<JSRegExp>::cast(object());
void RegExpBoilerplateDescriptionData::Serialize(JSHeapBroker* broker) {
if (serialized_) return; // Only serialize once.
serialized_ = true;
SerializeElements(broker);
TraceScope tracer(broker, this,
"RegExpBoilerplateDescriptionData::Serialize");
auto boilerplate = Handle<RegExpBoilerplateDescription>::cast(object());
raw_properties_or_hash_ =
broker->GetOrCreateData(boilerplate->raw_properties_or_hash());
data_ = broker->GetOrCreateData(boilerplate->data());
source_ = broker->GetOrCreateData(boilerplate->source());
flags_ = broker->GetOrCreateData(boilerplate->flags());
last_index_ = broker->GetOrCreateData(boilerplate->last_index());
flags_ = boilerplate->flags();
}
#ifdef DEBUG
......@@ -3489,6 +3502,10 @@ BIMODAL_ACCESSOR_C(ObjectBoilerplateDescription, int, size)
BIMODAL_ACCESSOR(PropertyCell, Object, value)
BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details)
BIMODAL_ACCESSOR(RegExpBoilerplateDescription, FixedArray, data)
BIMODAL_ACCESSOR(RegExpBoilerplateDescription, String, source)
BIMODAL_ACCESSOR_C(RegExpBoilerplateDescription, int, flags)
base::Optional<CallHandlerInfoRef> FunctionTemplateInfoRef::call_code() const {
if (data_->should_access_heap()) {
return CallHandlerInfoRef(broker(), broker()->CanonicalPersistentHandle(
......@@ -4103,36 +4120,23 @@ bool NameRef::IsUniqueName() const {
return IsInternalizedString() || IsSymbol();
}
ObjectRef JSRegExpRef::data() const {
IF_ACCESS_FROM_HEAP(Object, data);
return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->data());
}
ObjectRef JSRegExpRef::flags() const {
IF_ACCESS_FROM_HEAP(Object, flags);
return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->flags());
}
ObjectRef JSRegExpRef::last_index() const {
IF_ACCESS_FROM_HEAP(Object, last_index);
return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->last_index());
}
ObjectRef JSRegExpRef::raw_properties_or_hash() const {
IF_ACCESS_FROM_HEAP(Object, raw_properties_or_hash);
return ObjectRef(broker(),
ObjectRef::data()->AsJSRegExp()->raw_properties_or_hash());
}
ObjectRef JSRegExpRef::source() const {
IF_ACCESS_FROM_HEAP(Object, source);
return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->source());
}
void JSRegExpRef::SerializeAsRegExpBoilerplate() {
if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
JSObjectRef::data()->AsJSRegExp()->SerializeAsRegExpBoilerplate(broker());
void RegExpBoilerplateDescriptionRef::Serialize() {
if (data_->should_access_heap()) {
// Even if the regexp boilerplate object itself is no longer serialized,
// both `data` and `source` fields still are and thus we need to make sure
// to visit them.
// TODO(jgruber,v8:7790): Remove once these are no longer serialized types.
STATIC_ASSERT(IsSerializedHeapObject<FixedArray>());
FixedArrayRef data_ref{
broker(), broker()->CanonicalPersistentHandle(object()->data())};
STATIC_ASSERT(IsSerializedHeapObject<String>());
StringRef source_ref{
broker(), broker()->CanonicalPersistentHandle(object()->source())};
} else {
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
HeapObjectRef::data()->AsRegExpBoilerplateDescription()->Serialize(
broker());
}
}
Handle<Object> ObjectRef::object() const {
......@@ -4955,9 +4959,9 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForRegExpLiteral(
return NewInsufficientFeedback(nexus.kind());
}
JSRegExpRef regexp(this, handle(object, isolate()));
regexp.SerializeAsRegExpBoilerplate();
return *zone()->New<RegExpLiteralFeedback>(regexp, nexus.kind());
RegExpBoilerplateDescriptionRef boilerplate(this, handle(object, isolate()));
boilerplate.Serialize();
return *zone()->New<RegExpLiteralFeedback>(boilerplate, nexus.kind());
}
ProcessedFeedback const& JSHeapBroker::ReadFeedbackForTemplateObject(
......
......@@ -246,7 +246,7 @@ class LiteralFeedback
};
class RegExpLiteralFeedback
: public SingleValueFeedback<JSRegExpRef,
: public SingleValueFeedback<RegExpBoilerplateDescriptionRef,
ProcessedFeedback::kRegExpLiteral> {
using SingleValueFeedback::SingleValueFeedback;
};
......
......@@ -311,6 +311,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case BYTECODE_ARRAY_TYPE:
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
case ARRAY_BOILERPLATE_DESCRIPTION_TYPE:
case REG_EXP_BOILERPLATE_DESCRIPTION_TYPE:
case TRANSITION_ARRAY_TYPE:
case FEEDBACK_CELL_TYPE:
case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
......
......@@ -1706,6 +1706,15 @@ void ArrayBoilerplateDescription::ArrayBoilerplateDescriptionPrint(
os << "\n";
}
void RegExpBoilerplateDescription::RegExpBoilerplateDescriptionPrint(
std::ostream& os) { // NOLINT
PrintHeader(os, "RegExpBoilerplateDescription");
os << "\n - data: " << Brief(data());
os << "\n - source: " << Brief(source());
os << "\n - flags: " << flags();
os << "\n";
}
void AsmWasmData::AsmWasmDataPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "AsmWasmData");
os << "\n - native module: " << Brief(managed_native_module());
......
......@@ -384,6 +384,20 @@ FactoryBase<Impl>::NewArrayBoilerplateDescription(
return result;
}
template <typename Impl>
Handle<RegExpBoilerplateDescription>
FactoryBase<Impl>::NewRegExpBoilerplateDescription(Handle<FixedArray> data,
Handle<String> source,
Smi flags) {
Handle<RegExpBoilerplateDescription> result =
Handle<RegExpBoilerplateDescription>::cast(NewStruct(
REG_EXP_BOILERPLATE_DESCRIPTION_TYPE, AllocationType::kOld));
result->set_data(*data);
result->set_source(*source);
result->set_flags(flags.value());
return result;
}
template <typename Impl>
Handle<TemplateObjectDescription>
FactoryBase<Impl>::NewTemplateObjectDescription(
......
......@@ -23,6 +23,7 @@ class SeqTwoByteString;
class FreshlyAllocatedBigInt;
class ObjectBoilerplateDescription;
class ArrayBoilerplateDescription;
class RegExpBoilerplateDescription;
class TemplateObjectDescription;
class SourceTextModuleInfo;
class PreparseData;
......@@ -137,6 +138,9 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
Handle<ArrayBoilerplateDescription> NewArrayBoilerplateDescription(
ElementsKind elements_kind, Handle<FixedArrayBase> constant_values);
Handle<RegExpBoilerplateDescription> NewRegExpBoilerplateDescription(
Handle<FixedArray> data, Handle<String> source, Smi flags);
// Create a new TemplateObjectDescription struct.
Handle<TemplateObjectDescription> NewTemplateObjectDescription(
Handle<FixedArray> raw_strings, Handle<FixedArray> cooked_strings);
......
......@@ -2233,7 +2233,7 @@ IGNITION_HANDLER(SwitchOnSmiNoFeedback, InterpreterAssembler) {
// Creates a regular expression literal for literal index <literal_idx> with
// <flags> and the pattern in <pattern_idx>.
IGNITION_HANDLER(CreateRegExpLiteral, InterpreterAssembler) {
TNode<Object> pattern = LoadConstantPoolEntryAtOperandIndex(0);
TNode<String> pattern = CAST(LoadConstantPoolEntryAtOperandIndex(0));
TNode<HeapObject> feedback_vector = LoadFeedbackVector();
TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
TNode<Smi> flags =
......
......@@ -162,12 +162,6 @@ MaybeHandle<JSRegExp> JSRegExp::New(Isolate* isolate, Handle<String> pattern,
return JSRegExp::Initialize(regexp, pattern, flags, backtrack_limit);
}
// static
Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
Isolate* const isolate = regexp->GetIsolate();
return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
}
Object JSRegExp::Code(bool is_latin1) const {
DCHECK_EQ(TypeTag(), JSRegExp::IRREGEXP);
return DataAt(code_index(is_latin1));
......@@ -416,14 +410,16 @@ MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
if (constructor.IsJSFunction() &&
JSFunction::cast(constructor).initial_map() == map) {
// If we still have the original map, set in-object properties directly.
regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, Smi::zero(),
regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
Smi::FromInt(kInitialLastIndexValue),
SKIP_WRITE_BARRIER);
} else {
// Map has changed, so use generic, but slower, method.
RETURN_ON_EXCEPTION(
isolate,
Object::SetProperty(isolate, regexp, factory->lastIndex_string(),
Handle<Smi>(Smi::zero(), isolate)),
Object::SetProperty(
isolate, regexp, factory->lastIndex_string(),
Handle<Smi>(Smi::FromInt(kInitialLastIndexValue), isolate)),
JSRegExp);
}
......
......@@ -79,7 +79,6 @@ class JSRegExp : public TorqueGeneratedJSRegExp<JSRegExp, JSObject> {
V8_EXPORT_PRIVATE static MaybeHandle<JSRegExp> New(
Isolate* isolate, Handle<String> source, Flags flags,
uint32_t backtrack_limit = kNoBacktrackLimit);
static Handle<JSRegExp> Copy(Handle<JSRegExp> regexp);
static MaybeHandle<JSRegExp> Initialize(
Handle<JSRegExp> regexp, Handle<String> source, Flags flags,
......@@ -147,6 +146,9 @@ class JSRegExp : public TorqueGeneratedJSRegExp<JSRegExp, JSObject> {
// TODO(v8:8944): improve handling of in-object fields
static constexpr int kLastIndexOffset = kHeaderSize;
// The initial value of the last_index field on a new JSRegExp instance.
static constexpr int kInitialLastIndexValue = 0;
// Indices in the data array.
static const int kTagIndex = 0;
static const int kSourceIndex = kTagIndex + 1;
......@@ -215,6 +217,9 @@ class JSRegExp : public TorqueGeneratedJSRegExp<JSRegExp, JSObject> {
static const int kLastIndexFieldIndex = 0;
static const int kInObjectFieldCount = 1;
// The actual object size including in-object fields.
static int Size() { return kHeaderSize + kInObjectFieldCount * kTaggedSize; }
// Descriptor array index to important methods in the prototype.
static const int kExecFunctionDescriptorIndex = 1;
static const int kSymbolMatchFunctionDescriptorIndex = 13;
......
......@@ -136,6 +136,12 @@ bool ArrayBoilerplateDescription::is_empty() const {
return constant_elements().length() == 0;
}
//
// RegExpBoilerplateDescription
//
TQ_OBJECT_CONSTRUCTORS_IMPL(RegExpBoilerplateDescription)
} // namespace internal
} // namespace v8
......
......@@ -13,6 +13,7 @@
#include "src/heap/local-factory-inl.h"
#include "src/objects/dictionary.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-regexp.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/smi.h"
......@@ -734,5 +735,20 @@ template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
LocalIsolate* isolate, ClassLiteral* expr);
void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
os << " " << ElementsKindToString(elements_kind()) << ", "
<< Brief(constant_elements());
}
void RegExpBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
// Note: keep boilerplate layout synced with JSRegExp layout.
STATIC_ASSERT(JSRegExp::kDataOffset == JSObject::kHeaderSize);
STATIC_ASSERT(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kFlagsOffset ==
JSRegExp::kSourceOffset + kTaggedSize);
STATIC_ASSERT(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize);
os << " " << Brief(data()) << ", " << Brief(source()) << ", " << flags();
}
} // namespace internal
} // namespace v8
......@@ -75,6 +75,18 @@ class ArrayBoilerplateDescription
TQ_OBJECT_CONSTRUCTORS(ArrayBoilerplateDescription)
};
class RegExpBoilerplateDescription
: public TorqueGeneratedRegExpBoilerplateDescription<
RegExpBoilerplateDescription, Struct> {
public:
// Dispatched behavior.
DECL_PRINTER(RegExpBoilerplateDescription)
void BriefPrintDetails(std::ostream& os);
private:
TQ_OBJECT_CONSTRUCTORS(RegExpBoilerplateDescription)
};
class ClassBoilerplate : public FixedArray {
public:
enum ValueKind { kData, kGetter, kSetter };
......
......@@ -7,3 +7,10 @@ extern class ArrayBoilerplateDescription extends Struct {
flags: Smi;
constant_elements: FixedArrayBase;
}
@generateCppClass
extern class RegExpBoilerplateDescription extends Struct {
data: FixedArray;
source: String;
flags: SmiTagged<JSRegExpFlags>;
}
......@@ -141,6 +141,8 @@ namespace internal {
V(_, PROPERTY_DESCRIPTOR_OBJECT_TYPE, PropertyDescriptorObject, \
property_descriptor_object) \
V(_, PROTOTYPE_INFO_TYPE, PrototypeInfo, prototype_info) \
V(_, REG_EXP_BOILERPLATE_DESCRIPTION_TYPE, RegExpBoilerplateDescription, \
regexp_boilerplate_description) \
V(_, SCRIPT_TYPE, Script, script) \
V(_, SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, SourceTextModuleInfoEntry, \
module_info_entry) \
......
......@@ -2184,11 +2184,6 @@ void ClassPositions::BriefPrintDetails(std::ostream& os) {
os << " " << start() << ", " << end();
}
void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
os << " " << ElementsKindToString(elements_kind()) << ", "
<< Brief(constant_elements());
}
void CallableTask::BriefPrintDetails(std::ostream& os) {
os << " callable=" << Brief(callable());
}
......
......@@ -666,36 +666,46 @@ RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
CONVERT_SMI_ARG_CHECKED(flags, 3);
Handle<FeedbackVector> vector;
if (maybe_vector->IsFeedbackVector()) {
vector = Handle<FeedbackVector>::cast(maybe_vector);
} else {
DCHECK(maybe_vector->IsUndefined());
}
if (vector.is_null()) {
Handle<JSRegExp> new_regexp;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, new_regexp,
JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
return *new_regexp;
if (maybe_vector->IsUndefined()) {
// We don't have a vector; don't create a boilerplate, simply construct a
// plain JSRegExp instance and return it.
RETURN_RESULT_OR_FAILURE(
isolate, JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
}
// This function assumes that the boilerplate does not yet exist.
Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(maybe_vector);
FeedbackSlot literal_slot(FeedbackVector::ToSlot(index));
Handle<Object> literal_site(vector->Get(literal_slot)->cast<Object>(),
isolate);
// This function must not be called when a boilerplate already exists (if it
// exists, callers should instead copy the boilerplate into a new JSRegExp
// instance).
CHECK(!HasBoilerplate(literal_site));
Handle<JSRegExp> boilerplate;
Handle<JSRegExp> regexp_instance;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, boilerplate,
isolate, regexp_instance,
JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
// JSRegExp literal sites are initialized in a two-step process:
// Uninitialized-Preinitialized, and Preinitialized-Initialized.
if (IsUninitializedLiteralSite(*literal_site)) {
PreInitializeLiteralSite(vector, literal_slot);
return *boilerplate;
return *regexp_instance;
}
Handle<FixedArray> data(FixedArray::cast(regexp_instance->data()), isolate);
Handle<String> source(String::cast(regexp_instance->source()), isolate);
Handle<RegExpBoilerplateDescription> boilerplate =
isolate->factory()->NewRegExpBoilerplateDescription(
data, source, Smi::cast(regexp_instance->flags()));
vector->SynchronizedSet(literal_slot, *boilerplate);
return *JSRegExp::Copy(boilerplate);
DCHECK(HasBoilerplate(
handle(vector->Get(literal_slot)->cast<Object>(), isolate)));
return *regexp_instance;
}
} // namespace internal
......
This diff is collapsed.
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