}
+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());
}
+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 =
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
+ V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
};
+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) {
}
+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());
}
+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());
}
// 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);
// 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.
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
mark_compact_collector()->is_compacting();
ProcessArrayBuffers(retainer, record_slots);
ProcessNativeContexts(retainer, record_slots);
+ ProcessAllocationSites(retainer, record_slots);
}
void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer,
}
+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;
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;
}
native_contexts_list_ = undefined_value();
array_buffers_list_ = undefined_value();
+ allocation_sites_list_ = undefined_value();
return true;
}
}
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_; }
// 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_;
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();
}
+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());
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
V(LeaveInlined) \
+ V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset);
}
+ static HObjectAccess ForAllocationSiteWeakNext() {
+ return HObjectAccess(kInobject, AllocationSite::kWeakNextOffset);
+ }
+
static HObjectAccess ForFixedArrayLength() {
return HObjectAccess(kArrayLengths, FixedArray::kLengthOffset);
}
};
+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,
}
+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());
}
+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());
}
+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 =
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
+ V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
};
+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) {
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)
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());
table_.Register(kVisitNativeContext, &VisitNativeContext);
+ table_.Register(kVisitAllocationSite,
+ &FixedBodyVisitor<StaticVisitor,
+ AllocationSite::BodyDescriptor,
+ void>::Visit);
+
table_.Register(kVisitByteArray, &DataObjectVisitor::Visit);
table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit);
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);
V(FixedArray) \
V(FixedDoubleArray) \
V(NativeContext) \
+ V(AllocationSite) \
V(DataObject2) \
V(DataObject3) \
V(DataObject4) \
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);
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());
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);
};
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.
entry,
Deoptimizer::LAZY,
Deoptimizer::CALCULATE_ENTRY_ADDRESS);
- Add(address, LAZY_DEOPTIMIZATION, 63 + entry, "lazy_deopt");
+ Add(address, LAZY_DEOPTIMIZATION, 64 + entry, "lazy_deopt");
}
}
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);
}
+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
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
}
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
}
+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());
}
+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());
}
+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 =
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
+ V(LinkObjectInList) \
V(LoadContextSlot) \
V(LoadExternalArrayPointer) \
V(LoadFunctionPrototype) \
};
+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) {