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:
mvstanton@chromium.org 2013-07-17 11:50:24 +00:00
parent 7632a311aa
commit b9f0c06ab2
25 changed files with 343 additions and 10 deletions

View File

@ -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 =

View File

@ -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) {

View File

@ -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());

View File

@ -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());
}

View File

@ -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);

View File

@ -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.

View File

@ -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;
}

View File

@ -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();

View File

@ -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());

View File

@ -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,

View File

@ -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());

View File

@ -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 =

View File

@ -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) {

View File

@ -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)

View File

@ -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());

View File

@ -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);

View File

@ -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);

View File

@ -55,6 +55,7 @@ class StaticVisitorBase : public AllStatic {
V(FixedArray) \
V(FixedDoubleArray) \
V(NativeContext) \
V(AllocationSite) \
V(DataObject2) \
V(DataObject3) \
V(DataObject4) \

View File

@ -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);

View File

@ -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);
};

View File

@ -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
}

View File

@ -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

View File

@ -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());

View File

@ -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 =

View File

@ -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) {