The gc should be able to traverse all AllocationSites for decision making. The sites are threaded into a weak list. Special problems include:
* Allocations of AllocationSites occur in generated code, so generated code needs to be able to add to the list. For now I have a special hydrogen instruction, though it would be nice to use general purpose instructions. * The snapshot contains AllocationSites, and these need to be re-threaded into the list on deserialization. Something nice is that the AllocationSites are only created in old space, so a special new space visitor isn't required. BUG= R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/18173013 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15715 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
7632a311aa
commit
b9f0c06ab2
@ -272,6 +272,24 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
|
||||
switch (hydrogen()->known_list()) {
|
||||
case HLinkObjectInList::ALLOCATION_SITE_LIST:
|
||||
return ExternalReference::allocation_sites_list_address(isolate);
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
// Return a dummy value
|
||||
return ExternalReference::isolate_address(isolate);
|
||||
}
|
||||
|
||||
|
||||
void LLinkObjectInList::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add(" offset %d", hydrogen()->store_field().offset());
|
||||
}
|
||||
|
||||
|
||||
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
|
||||
context()->PrintTo(stream);
|
||||
stream->Add("[%d]", slot_index());
|
||||
@ -2113,6 +2131,13 @@ LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
|
||||
LOperand* object = UseRegister(instr->value());
|
||||
LLinkObjectInList* result = new(zone()) LLinkObjectInList(object);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
LInstruction* result =
|
||||
|
@ -120,6 +120,7 @@ class LCodeGen;
|
||||
V(IsUndetectableAndBranch) \
|
||||
V(Label) \
|
||||
V(LazyBailout) \
|
||||
V(LinkObjectInList) \
|
||||
V(LoadContextSlot) \
|
||||
V(LoadExternalArrayPointer) \
|
||||
V(LoadFunctionPrototype) \
|
||||
@ -1683,6 +1684,23 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LLinkObjectInList: public LTemplateInstruction<0, 1, 0> {
|
||||
public:
|
||||
explicit LLinkObjectInList(LOperand* object) {
|
||||
inputs_[0] = object;
|
||||
}
|
||||
|
||||
LOperand* object() { return inputs_[0]; }
|
||||
|
||||
ExternalReference GetReference(Isolate* isolate);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
};
|
||||
|
||||
|
||||
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LLoadContextSlot(LOperand* context) {
|
||||
|
@ -2928,6 +2928,19 @@ void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
|
||||
Register object = ToRegister(instr->object());
|
||||
ExternalReference sites_list_address = instr->GetReference(isolate());
|
||||
|
||||
__ mov(ip, Operand(sites_list_address));
|
||||
__ ldr(ip, MemOperand(ip));
|
||||
__ str(ip, FieldMemOperand(object,
|
||||
instr->hydrogen()->store_field().offset()));
|
||||
__ mov(ip, Operand(sites_list_address));
|
||||
__ str(object, MemOperand(ip));
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register result = ToRegister(instr->result());
|
||||
|
@ -1125,6 +1125,12 @@ ExternalReference ExternalReference::roots_array_start(Isolate* isolate) {
|
||||
}
|
||||
|
||||
|
||||
ExternalReference ExternalReference::allocation_sites_list_address(
|
||||
Isolate* isolate) {
|
||||
return ExternalReference(isolate->heap()->allocation_sites_list_address());
|
||||
}
|
||||
|
||||
|
||||
ExternalReference ExternalReference::address_of_stack_limit(Isolate* isolate) {
|
||||
return ExternalReference(isolate->stack_guard()->address_of_jslimit());
|
||||
}
|
||||
|
@ -747,6 +747,9 @@ class ExternalReference BASE_EMBEDDED {
|
||||
// Static variable Heap::roots_array_start()
|
||||
static ExternalReference roots_array_start(Isolate* isolate);
|
||||
|
||||
// Static variable Heap::allocation_sites_list_address()
|
||||
static ExternalReference allocation_sites_list_address(Isolate* isolate);
|
||||
|
||||
// Static variable StackGuard::address_of_jslimit()
|
||||
static ExternalReference address_of_stack_limit(Isolate* isolate);
|
||||
|
||||
|
@ -445,8 +445,12 @@ HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
|
||||
// Store the payload (smi elements kind)
|
||||
HValue* initial_elements_kind = AddInstruction(new(zone) HConstant(
|
||||
GetInitialFastElementsKind()));
|
||||
AddInstruction(new(zone) HStoreNamedField(object,
|
||||
HObjectAccess::ForAllocationSiteTransitionInfo(), initial_elements_kind));
|
||||
Add<HStoreNamedField>(object,
|
||||
HObjectAccess::ForAllocationSiteTransitionInfo(),
|
||||
initial_elements_kind);
|
||||
|
||||
Add<HLinkObjectInList>(object, HObjectAccess::ForAllocationSiteWeakNext(),
|
||||
HLinkObjectInList::ALLOCATION_SITE_LIST);
|
||||
|
||||
// We use a hammer (SkipWriteBarrier()) to indicate that we know the input
|
||||
// cell is really a Cell, and so no write barrier is needed.
|
||||
|
43
src/heap.cc
43
src/heap.cc
@ -182,6 +182,7 @@ Heap::Heap()
|
||||
memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
|
||||
native_contexts_list_ = NULL;
|
||||
array_buffers_list_ = Smi::FromInt(0);
|
||||
allocation_sites_list_ = Smi::FromInt(0);
|
||||
mark_compact_collector_.heap_ = this;
|
||||
external_string_table_.heap_ = this;
|
||||
// Put a dummy entry in the remembered pages so we can find the list the
|
||||
@ -1664,6 +1665,7 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
|
||||
mark_compact_collector()->is_compacting();
|
||||
ProcessArrayBuffers(retainer, record_slots);
|
||||
ProcessNativeContexts(retainer, record_slots);
|
||||
ProcessAllocationSites(retainer, record_slots);
|
||||
}
|
||||
|
||||
void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer,
|
||||
@ -1757,6 +1759,39 @@ void Heap::TearDownArrayBuffers() {
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
struct WeakListVisitor<AllocationSite> {
|
||||
static void SetWeakNext(AllocationSite* obj, Object* next) {
|
||||
obj->set_weak_next(next);
|
||||
}
|
||||
|
||||
static Object* WeakNext(AllocationSite* obj) {
|
||||
return obj->weak_next();
|
||||
}
|
||||
|
||||
static void VisitLiveObject(Heap* heap,
|
||||
AllocationSite* array_buffer,
|
||||
WeakObjectRetainer* retainer,
|
||||
bool record_slots) {}
|
||||
|
||||
static void VisitPhantomObject(Heap* heap, AllocationSite* phantom) {}
|
||||
|
||||
static int WeakNextOffset() {
|
||||
return AllocationSite::kWeakNextOffset;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer,
|
||||
bool record_slots) {
|
||||
Object* allocation_site_obj =
|
||||
VisitWeakList<AllocationSite>(this,
|
||||
allocation_sites_list(),
|
||||
retainer, record_slots);
|
||||
set_allocation_sites_list(allocation_site_obj);
|
||||
}
|
||||
|
||||
|
||||
void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
|
||||
@ -2887,7 +2922,12 @@ MaybeObject* Heap::AllocateAllocationSite() {
|
||||
MaybeObject* maybe_result = Allocate(allocation_site_map(),
|
||||
OLD_POINTER_SPACE);
|
||||
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||
AllocationSite::cast(result)->Initialize();
|
||||
AllocationSite* site = AllocationSite::cast(result);
|
||||
site->Initialize();
|
||||
|
||||
// Link the site
|
||||
site->set_weak_next(allocation_sites_list());
|
||||
set_allocation_sites_list(site);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -6889,6 +6929,7 @@ bool Heap::CreateHeapObjects() {
|
||||
|
||||
native_contexts_list_ = undefined_value();
|
||||
array_buffers_list_ = undefined_value();
|
||||
allocation_sites_list_ = undefined_value();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1376,6 +1376,11 @@ class Heap {
|
||||
}
|
||||
Object* array_buffers_list() { return array_buffers_list_; }
|
||||
|
||||
void set_allocation_sites_list(Object* object) {
|
||||
allocation_sites_list_ = object;
|
||||
}
|
||||
Object* allocation_sites_list() { return allocation_sites_list_; }
|
||||
Object** allocation_sites_list_address() { return &allocation_sites_list_; }
|
||||
|
||||
// Number of mark-sweeps.
|
||||
unsigned int ms_count() { return ms_count_; }
|
||||
@ -2045,9 +2050,10 @@ class Heap {
|
||||
// last GC.
|
||||
bool old_gen_exhausted_;
|
||||
|
||||
// Weak list heads, threaded through the objects.
|
||||
Object* native_contexts_list_;
|
||||
|
||||
Object* array_buffers_list_;
|
||||
Object* allocation_sites_list_;
|
||||
|
||||
StoreBufferRebuilder store_buffer_rebuilder_;
|
||||
|
||||
@ -2197,6 +2203,7 @@ class Heap {
|
||||
|
||||
void ProcessNativeContexts(WeakObjectRetainer* retainer, bool record_slots);
|
||||
void ProcessArrayBuffers(WeakObjectRetainer* retainer, bool record_slots);
|
||||
void ProcessAllocationSites(WeakObjectRetainer* retainer, bool record_slots);
|
||||
|
||||
// Called on heap tear-down.
|
||||
void TearDownArrayBuffers();
|
||||
|
@ -3059,6 +3059,12 @@ void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void HLinkObjectInList::PrintDataTo(StringStream* stream) {
|
||||
value()->PrintNameTo(stream);
|
||||
stream->Add(" offset %d", store_field_.offset());
|
||||
}
|
||||
|
||||
|
||||
void HLoadContextSlot::PrintDataTo(StringStream* stream) {
|
||||
value()->PrintNameTo(stream);
|
||||
stream->Add("[%d]", slot_index());
|
||||
|
@ -131,6 +131,7 @@ class LChunkBuilder;
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
V(LeaveInlined) \
|
||||
V(LinkObjectInList) \
|
||||
V(LoadContextSlot) \
|
||||
V(LoadExternalArrayPointer) \
|
||||
V(LoadFunctionPrototype) \
|
||||
@ -5332,6 +5333,10 @@ class HObjectAccess {
|
||||
return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForAllocationSiteWeakNext() {
|
||||
return HObjectAccess(kInobject, AllocationSite::kWeakNextOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForFixedArrayLength() {
|
||||
return HObjectAccess(kArrayLengths, FixedArray::kLengthOffset);
|
||||
}
|
||||
@ -5422,6 +5427,38 @@ class HObjectAccess {
|
||||
};
|
||||
|
||||
|
||||
class HLinkObjectInList: public HUnaryOperation {
|
||||
public:
|
||||
// There needs to be a mapping from every KnownList to an external reference
|
||||
enum KnownList {
|
||||
ALLOCATION_SITE_LIST
|
||||
};
|
||||
|
||||
HLinkObjectInList(HValue* object, HObjectAccess store_field,
|
||||
KnownList known_list)
|
||||
: HUnaryOperation(object),
|
||||
store_field_(store_field),
|
||||
known_list_(known_list) {
|
||||
set_representation(Representation::Tagged());
|
||||
}
|
||||
|
||||
HObjectAccess store_field() const { return store_field_; }
|
||||
KnownList known_list() const { return known_list_; }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList)
|
||||
|
||||
private:
|
||||
HObjectAccess store_field_;
|
||||
KnownList known_list_;
|
||||
};
|
||||
|
||||
|
||||
class HLoadNamedField: public HTemplateInstruction<2> {
|
||||
public:
|
||||
HLoadNamedField(HValue* object,
|
||||
|
@ -2992,6 +2992,20 @@ void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
|
||||
Register object = ToRegister(instr->object());
|
||||
Register temp = ToRegister(instr->temp());
|
||||
ExternalReference sites_list_address = instr->GetReference(isolate());
|
||||
|
||||
__ mov(temp, Immediate(sites_list_address));
|
||||
__ mov(temp, Operand(temp, 0));
|
||||
__ mov(FieldOperand(object, instr->hydrogen()->store_field().offset()),
|
||||
temp);
|
||||
__ mov(temp, Immediate(sites_list_address));
|
||||
__ mov(Operand(temp, 0), object);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register result = ToRegister(instr->result());
|
||||
|
@ -302,6 +302,24 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
|
||||
switch (hydrogen()->known_list()) {
|
||||
case HLinkObjectInList::ALLOCATION_SITE_LIST:
|
||||
return ExternalReference::allocation_sites_list_address(isolate);
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
// Return a dummy value
|
||||
return ExternalReference::isolate_address(isolate);
|
||||
}
|
||||
|
||||
|
||||
void LLinkObjectInList::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add(" offset %d", hydrogen()->store_field().offset());
|
||||
}
|
||||
|
||||
|
||||
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
|
||||
context()->PrintTo(stream);
|
||||
stream->Add("[%d]", slot_index());
|
||||
@ -2162,6 +2180,14 @@ LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
|
||||
LOperand* object = UseRegister(instr->value());
|
||||
LOperand* temp = TempRegister();
|
||||
LLinkObjectInList* result = new(zone()) LLinkObjectInList(object, temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
LInstruction* result =
|
||||
|
@ -115,6 +115,7 @@ class LCodeGen;
|
||||
V(IsUndetectableAndBranch) \
|
||||
V(Label) \
|
||||
V(LazyBailout) \
|
||||
V(LinkObjectInList) \
|
||||
V(LoadContextSlot) \
|
||||
V(LoadExternalArrayPointer) \
|
||||
V(LoadFunctionPrototype) \
|
||||
@ -1706,6 +1707,25 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 3, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LLinkObjectInList: public LTemplateInstruction<0, 1, 1> {
|
||||
public:
|
||||
explicit LLinkObjectInList(LOperand* object, LOperand* temp) {
|
||||
inputs_[0] = object;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
LOperand* object() { return inputs_[0]; }
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
ExternalReference GetReference(Isolate* isolate);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
};
|
||||
|
||||
|
||||
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LLoadContextSlot(LOperand* context) {
|
||||
|
@ -4450,6 +4450,7 @@ ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
|
||||
ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset)
|
||||
|
||||
ACCESSORS(AllocationSite, transition_info, Object, kTransitionInfoOffset)
|
||||
ACCESSORS(AllocationSite, weak_next, Object, kWeakNextOffset)
|
||||
ACCESSORS(AllocationSiteInfo, allocation_site, Object, kAllocationSiteOffset)
|
||||
|
||||
ACCESSORS(Script, source, Object, kSourceOffset)
|
||||
|
@ -1119,6 +1119,10 @@ void TypeSwitchInfo::TypeSwitchInfoPrint(FILE* out) {
|
||||
|
||||
void AllocationSite::AllocationSitePrint(FILE* out) {
|
||||
HeapObject::PrintHeader(out, "AllocationSite");
|
||||
PrintF(out, " - weak_next: ");
|
||||
weak_next()->ShortPrint(out);
|
||||
PrintF(out, "\n");
|
||||
|
||||
PrintF(out, " - transition_info: ");
|
||||
if (transition_info()->IsCell()) {
|
||||
Cell* cell = Cell::cast(transition_info());
|
||||
|
@ -185,6 +185,11 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() {
|
||||
|
||||
table_.Register(kVisitNativeContext, &VisitNativeContext);
|
||||
|
||||
table_.Register(kVisitAllocationSite,
|
||||
&FixedBodyVisitor<StaticVisitor,
|
||||
AllocationSite::BodyDescriptor,
|
||||
void>::Visit);
|
||||
|
||||
table_.Register(kVisitByteArray, &DataObjectVisitor::Visit);
|
||||
|
||||
table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit);
|
||||
|
@ -182,6 +182,10 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
case NAME##_TYPE:
|
||||
STRUCT_LIST(MAKE_STRUCT_CASE)
|
||||
#undef MAKE_STRUCT_CASE
|
||||
if (instance_type == ALLOCATION_SITE_TYPE) {
|
||||
return kVisitAllocationSite;
|
||||
}
|
||||
|
||||
return GetVisitorIdForSize(kVisitStruct,
|
||||
kVisitStructGeneric,
|
||||
instance_size);
|
||||
|
@ -55,6 +55,7 @@ class StaticVisitorBase : public AllStatic {
|
||||
V(FixedArray) \
|
||||
V(FixedDoubleArray) \
|
||||
V(NativeContext) \
|
||||
V(AllocationSite) \
|
||||
V(DataObject2) \
|
||||
V(DataObject3) \
|
||||
V(DataObject4) \
|
||||
|
@ -1706,7 +1706,11 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
|
||||
case NAME##_TYPE:
|
||||
STRUCT_LIST(MAKE_STRUCT_CASE)
|
||||
#undef MAKE_STRUCT_CASE
|
||||
StructBodyDescriptor::IterateBody(this, object_size, v);
|
||||
if (type == ALLOCATION_SITE_TYPE) {
|
||||
AllocationSite::BodyDescriptor::IterateBody(this, v);
|
||||
} else {
|
||||
StructBodyDescriptor::IterateBody(this, object_size, v);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PrintF("Unknown type: %d\n", type);
|
||||
|
@ -7474,11 +7474,10 @@ enum AllocationSiteMode {
|
||||
|
||||
class AllocationSite: public Struct {
|
||||
public:
|
||||
static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
|
||||
static const int kSize = kTransitionInfoOffset + kPointerSize;
|
||||
static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
|
||||
|
||||
DECL_ACCESSORS(transition_info, Object)
|
||||
DECL_ACCESSORS(weak_next, Object)
|
||||
|
||||
void Initialize() {
|
||||
SetElementsKind(GetInitialFastElementsKind());
|
||||
@ -7508,6 +7507,14 @@ class AllocationSite: public Struct {
|
||||
ElementsKind boilerplate_elements_kind);
|
||||
static inline AllocationSiteMode GetMode(ElementsKind from, ElementsKind to);
|
||||
|
||||
static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
|
||||
static const int kWeakNextOffset = kTransitionInfoOffset + kPointerSize;
|
||||
static const int kSize = kWeakNextOffset + kPointerSize;
|
||||
|
||||
typedef FixedBodyDescriptor<HeapObject::kHeaderSize,
|
||||
kTransitionInfoOffset + kPointerSize,
|
||||
kSize> BodyDescriptor;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSite);
|
||||
};
|
||||
|
@ -577,6 +577,10 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
|
||||
UNCLASSIFIED,
|
||||
62,
|
||||
"Heap::NewSpaceAllocationLimitAddress");
|
||||
Add(ExternalReference::allocation_sites_list_address(isolate).address(),
|
||||
UNCLASSIFIED,
|
||||
63,
|
||||
"Heap::allocation_sites_list_address()");
|
||||
|
||||
// Add a small set of deopt entry addresses to encoder without generating the
|
||||
// deopt table code, which isn't possible at deserialization time.
|
||||
@ -587,7 +591,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
|
||||
entry,
|
||||
Deoptimizer::LAZY,
|
||||
Deoptimizer::CALCULATE_ENTRY_ADDRESS);
|
||||
Add(address, LAZY_DEOPTIMIZATION, 63 + entry, "lazy_deopt");
|
||||
Add(address, LAZY_DEOPTIMIZATION, 64 + entry, "lazy_deopt");
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,6 +694,13 @@ void Deserializer::Deserialize() {
|
||||
isolate_->heap()->set_array_buffers_list(
|
||||
isolate_->heap()->undefined_value());
|
||||
|
||||
// The allocation site list is build during root iteration, but if no sites
|
||||
// were encountered then it needs to be initialized to undefined.
|
||||
if (isolate_->heap()->allocation_sites_list() == Smi::FromInt(0)) {
|
||||
isolate_->heap()->set_allocation_sites_list(
|
||||
isolate_->heap()->undefined_value());
|
||||
}
|
||||
|
||||
// Update data pointers to the external strings containing natives sources.
|
||||
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
|
||||
Object* source = isolate_->heap()->natives_source_cache()->get(i);
|
||||
@ -745,6 +756,16 @@ void Deserializer::VisitPointers(Object** start, Object** end) {
|
||||
}
|
||||
|
||||
|
||||
void Deserializer::RelinkAllocationSite(AllocationSite* site) {
|
||||
if (isolate_->heap()->allocation_sites_list() == Smi::FromInt(0)) {
|
||||
site->set_weak_next(isolate_->heap()->undefined_value());
|
||||
} else {
|
||||
site->set_weak_next(isolate_->heap()->allocation_sites_list());
|
||||
}
|
||||
isolate_->heap()->set_allocation_sites_list(site);
|
||||
}
|
||||
|
||||
|
||||
// This routine writes the new object into the pointer provided and then
|
||||
// returns true if the new object was in young space and false otherwise.
|
||||
// The reason for this strange interface is that otherwise the object is
|
||||
@ -754,16 +775,25 @@ void Deserializer::ReadObject(int space_number,
|
||||
Object** write_back) {
|
||||
int size = source_->GetInt() << kObjectAlignmentBits;
|
||||
Address address = Allocate(space_number, size);
|
||||
*write_back = HeapObject::FromAddress(address);
|
||||
HeapObject* obj = HeapObject::FromAddress(address);
|
||||
*write_back = obj;
|
||||
Object** current = reinterpret_cast<Object**>(address);
|
||||
Object** limit = current + (size >> kPointerSizeLog2);
|
||||
if (FLAG_log_snapshot_positions) {
|
||||
LOG(isolate_, SnapshotPositionEvent(address, source_->position()));
|
||||
}
|
||||
ReadChunk(current, limit, space_number, address);
|
||||
|
||||
// TODO(mvstanton): consider treating the heap()->allocation_sites_list()
|
||||
// as a (weak) root. If this root is relocated correctly,
|
||||
// RelinkAllocationSite() isn't necessary.
|
||||
if (obj->IsAllocationSite()) {
|
||||
RelinkAllocationSite(AllocationSite::cast(obj));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool is_codespace = (space_number == CODE_SPACE);
|
||||
ASSERT(HeapObject::FromAddress(address)->IsCode() == is_codespace);
|
||||
ASSERT(obj->IsCode() == is_codespace);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -347,6 +347,10 @@ class Deserializer: public SerializerDeserializer {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// Allocation sites are present in the snapshot, and must be linked into
|
||||
// a list at deserialization time.
|
||||
void RelinkAllocationSite(AllocationSite* site);
|
||||
|
||||
// Fills in some heap data in an area from start to end (non-inclusive). The
|
||||
// space id is used for the write barrier. The object_address is the address
|
||||
// of the object we are writing into, or NULL if we are not writing into an
|
||||
|
@ -2603,6 +2603,16 @@ void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
|
||||
Register object = ToRegister(instr->object());
|
||||
ExternalReference sites_list_address = instr->GetReference(isolate());
|
||||
__ Load(kScratchRegister, sites_list_address);
|
||||
__ movq(FieldOperand(object, instr->hydrogen()->store_field().offset()),
|
||||
kScratchRegister);
|
||||
__ Store(sites_list_address, object);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register result = ToRegister(instr->result());
|
||||
|
@ -275,6 +275,24 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
|
||||
switch (hydrogen()->known_list()) {
|
||||
case HLinkObjectInList::ALLOCATION_SITE_LIST:
|
||||
return ExternalReference::allocation_sites_list_address(isolate);
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
// Return a dummy value
|
||||
return ExternalReference::isolate_address(isolate);
|
||||
}
|
||||
|
||||
|
||||
void LLinkObjectInList::PrintDataTo(StringStream* stream) {
|
||||
object()->PrintTo(stream);
|
||||
stream->Add(" offset %d", hydrogen()->store_field().offset());
|
||||
}
|
||||
|
||||
|
||||
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
|
||||
context()->PrintTo(stream);
|
||||
stream->Add("[%d]", slot_index());
|
||||
@ -2028,6 +2046,13 @@ LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
|
||||
LOperand* object = UseRegister(instr->value());
|
||||
LLinkObjectInList* result = new(zone()) LLinkObjectInList(object);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
LInstruction* result =
|
||||
|
@ -121,6 +121,7 @@ class LCodeGen;
|
||||
V(IsUndetectableAndBranch) \
|
||||
V(Label) \
|
||||
V(LazyBailout) \
|
||||
V(LinkObjectInList) \
|
||||
V(LoadContextSlot) \
|
||||
V(LoadExternalArrayPointer) \
|
||||
V(LoadFunctionPrototype) \
|
||||
@ -1620,6 +1621,23 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LLinkObjectInList: public LTemplateInstruction<0, 1, 0> {
|
||||
public:
|
||||
explicit LLinkObjectInList(LOperand* object) {
|
||||
inputs_[0] = object;
|
||||
}
|
||||
|
||||
LOperand* object() { return inputs_[0]; }
|
||||
|
||||
ExternalReference GetReference(Isolate* isolate);
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
|
||||
DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
};
|
||||
|
||||
|
||||
class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LLoadContextSlot(LOperand* context) {
|
||||
|
Loading…
Reference in New Issue
Block a user