From 22b70b050845dd1dc5fe312e6246070b46f5bc73 Mon Sep 17 00:00:00 2001 From: "titzer@chromium.org" Date: Wed, 28 Aug 2013 16:48:40 +0000 Subject: [PATCH] Add OptimizedCodeEntry as a new heap object type. An optimized code entry represents an association between the native context, a function, optimized code, and the literals. Such associations are needed by the deoptimizer and optimized code cache to efficiently find related optimized code and functions for a given context or shared function info. BUG= R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/23691002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16407 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 4 +-- src/factory.cc | 15 ++++++++++ src/factory.h | 6 ++++ src/heap.cc | 30 ++++++++++++++++++++ src/heap.h | 17 ++++++++++-- src/objects-debug.cc | 14 ++++++++++ src/objects-inl.h | 48 ++++++++++++++++++++++++++++++++ src/objects-printer.cc | 22 +++++++++++++++ src/objects-visiting.cc | 3 ++ src/objects-visiting.h | 1 + src/objects.cc | 13 +++++++++ src/objects.h | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 242 insertions(+), 5 deletions(-) diff --git a/include/v8.h b/include/v8.h index c29bba6..51bd362 100644 --- a/include/v8.h +++ b/include/v8.h @@ -5416,7 +5416,7 @@ class Internals { static const int kNullValueRootIndex = 7; static const int kTrueValueRootIndex = 8; static const int kFalseValueRootIndex = 9; - static const int kEmptyStringRootIndex = 133; + static const int kEmptyStringRootIndex = 134; static const int kNodeClassIdOffset = 1 * kApiPointerSize; static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3; @@ -5427,7 +5427,7 @@ class Internals { static const int kNodeIsIndependentShift = 4; static const int kNodeIsPartiallyDependentShift = 5; - static const int kJSObjectType = 0xb1; + static const int kJSObjectType = 0xb2; static const int kFirstNonstringType = 0x80; static const int kOddballType = 0x83; static const int kForeignType = 0x87; diff --git a/src/factory.cc b/src/factory.cc index 9323c2f..6faa84e 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1249,6 +1249,21 @@ Handle Factory::NewSharedFunctionInfo(Handle name) { } +Handle Factory::NewOptimizedCodeEntry( + Handle native_context, + Handle function, + Handle code, + Handle literals) { + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->AllocateOptimizedCodeEntry( + *native_context, + *function, + *code, + *literals), + OptimizedCodeEntry); +} + + Handle Factory::NumberToString(Handle number) { CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->NumberToString(*number), String); diff --git a/src/factory.h b/src/factory.h index 02c9a4d..390329c 100644 --- a/src/factory.h +++ b/src/factory.h @@ -487,6 +487,12 @@ class Factory { Handle scope_info); Handle NewSharedFunctionInfo(Handle name); + Handle NewOptimizedCodeEntry( + Handle native_context, + Handle function, + Handle code, + Handle literals); + Handle NewJSMessageObject( Handle type, Handle arguments, diff --git a/src/heap.cc b/src/heap.cc index f48d9cc..4fd478f 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2824,6 +2824,12 @@ bool Heap::CreateInitialMaps() { } set_shared_function_info_map(Map::cast(obj)); + { MaybeObject* maybe_obj = AllocateMap(OPTIMIZED_CODE_ENTRY_TYPE, + OptimizedCodeEntry::kAlignedSize); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_optimized_code_entry_map(Map::cast(obj)); + { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE, JSMessageObject::kSize); if (!maybe_obj->ToObject(&obj)) return false; @@ -3651,6 +3657,30 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { } +MaybeObject* Heap::AllocateOptimizedCodeEntry( + Context* native_context, + JSFunction* function, + Code* code, + FixedArray* literals) { + OptimizedCodeEntry* entry; + MaybeObject* maybe = Allocate(optimized_code_entry_map(), OLD_POINTER_SPACE); + if (!maybe->To(&entry)) return maybe; + + // Set pointer fields. + entry->set_native_context(native_context); + entry->set_function(function); + entry->set_code(code); + entry->set_literals(literals); + + // NULL-out link fields. + entry->set_next_by_shared_info(NULL, SKIP_WRITE_BARRIER); + entry->set_next_by_native_context(NULL, SKIP_WRITE_BARRIER); + entry->set_cacheable(false); + + return entry; +} + + MaybeObject* Heap::AllocateJSMessageObject(String* type, JSArray* arguments, int start_position, diff --git a/src/heap.h b/src/heap.h index 5be7861..f0920b3 100644 --- a/src/heap.h +++ b/src/heap.h @@ -63,6 +63,7 @@ namespace internal { V(Map, cell_map, CellMap) \ V(Map, global_property_cell_map, GlobalPropertyCellMap) \ V(Map, shared_function_info_map, SharedFunctionInfoMap) \ + V(Map, optimized_code_entry_map, OptimizedCodeEntryMap) \ V(Map, meta_map, MetaMap) \ V(Map, heap_number_map, HeapNumberMap) \ V(Map, native_context_map, NativeContextMap) \ @@ -78,9 +79,9 @@ namespace internal { V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \ V(Smi, stack_limit, StackLimit) \ V(Oddball, arguments_marker, ArgumentsMarker) \ - /* The first 32 roots above this line should be boring from a GC point of */ \ - /* view. This means they are never in new space and never on a page that */ \ - /* is being compacted. */ \ + /* The roots above this line should be boring from a GC point of view. */ \ + /* This means they are never in new space and never on a page that is */ \ + /* being compacted. */ \ V(FixedArray, number_string_cache, NumberStringCache) \ V(Object, instanceof_cache_function, InstanceofCacheFunction) \ V(Object, instanceof_cache_map, InstanceofCacheMap) \ @@ -1097,6 +1098,16 @@ class Heap { // Please note this does not perform a garbage collection. MUST_USE_RESULT MaybeObject* AllocateSharedFunctionInfo(Object* name); + // Allocates a new OptimizedCodeEntry object. + // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation + // failed. + // Please note this does not perform a garbage collection. + MUST_USE_RESULT MaybeObject* AllocateOptimizedCodeEntry( + Context* native_context, + JSFunction* function, + Code* code, + FixedArray* literals); + // Allocates a new JSMessageObject object. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. diff --git a/src/objects-debug.cc b/src/objects-debug.cc index a61eacf..4ba70c3 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -201,6 +201,9 @@ void HeapObject::HeapObjectVerify() { case SHARED_FUNCTION_INFO_TYPE: SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify(); break; + case OPTIMIZED_CODE_ENTRY_TYPE: + OptimizedCodeEntry::cast(this)->OptimizedCodeEntryVerify(); + break; case JS_MESSAGE_OBJECT_TYPE: JSMessageObject::cast(this)->JSMessageObjectVerify(); break; @@ -577,6 +580,17 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() { } +void OptimizedCodeEntry::OptimizedCodeEntryVerify() { + CHECK(IsOptimizedCodeEntry()); + VerifyObjectField(kNativeContextOffset); + VerifyObjectField(kFunctionOffset); + VerifyObjectField(kCodeOffset); + VerifyObjectField(kLiteralsOffset); + VerifyObjectField(kNextBySharedInfoOffset); + VerifyObjectField(kNextByNativeContextOffset); +} + + void JSGlobalProxy::JSGlobalProxyVerify() { CHECK(IsJSGlobalProxy()); JSObjectVerify(); diff --git a/src/objects-inl.h b/src/objects-inl.h index f629d9f..77b4e38 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -675,6 +675,7 @@ TYPE_CHECKER(Oddball, ODDBALL_TYPE) TYPE_CHECKER(Cell, CELL_TYPE) TYPE_CHECKER(PropertyCell, PROPERTY_CELL_TYPE) TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE) +TYPE_CHECKER(OptimizedCodeEntry, OPTIMIZED_CODE_ENTRY_TYPE) TYPE_CHECKER(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE) TYPE_CHECKER(JSModule, JS_MODULE_TYPE) TYPE_CHECKER(JSValue, JS_VALUE_TYPE) @@ -2572,6 +2573,7 @@ CAST_ACCESSOR(Oddball) CAST_ACCESSOR(Cell) CAST_ACCESSOR(PropertyCell) CAST_ACCESSOR(SharedFunctionInfo) +CAST_ACCESSOR(OptimizedCodeEntry) CAST_ACCESSOR(Map) CAST_ACCESSOR(JSFunction) CAST_ACCESSOR(GlobalObject) @@ -4924,6 +4926,52 @@ void SharedFunctionInfo::TryReenableOptimization() { } +ACCESSORS(OptimizedCodeEntry, native_context, Context, kNativeContextOffset) +ACCESSORS(OptimizedCodeEntry, function, JSFunction, kFunctionOffset) +ACCESSORS(OptimizedCodeEntry, code, Code, kCodeOffset) +ACCESSORS(OptimizedCodeEntry, literals, FixedArray, kLiteralsOffset) + + +OptimizedCodeEntry* OptimizedCodeEntry::next_by_shared_info() { + Object* object = READ_FIELD(this, kNextBySharedInfoOffset); + if (object == NULL) return NULL; + return OptimizedCodeEntry::cast(object); +} + + +OptimizedCodeEntry* OptimizedCodeEntry::next_by_native_context() { + Object* object = READ_FIELD(this, kNextByNativeContextOffset); + if (object == NULL) return NULL; + return OptimizedCodeEntry::cast(object); +} + + +void OptimizedCodeEntry::set_next_by_shared_info(OptimizedCodeEntry* value, + WriteBarrierMode mode) { + WRITE_FIELD(this, kNextBySharedInfoOffset, value); + CONDITIONAL_WRITE_BARRIER( + GetHeap(), this, kNextBySharedInfoOffset, value, mode); +} + + +void OptimizedCodeEntry::set_next_by_native_context(OptimizedCodeEntry* value, + WriteBarrierMode mode) { + WRITE_FIELD(this, kNextByNativeContextOffset, value); + CONDITIONAL_WRITE_BARRIER( + GetHeap(), this, kNextByNativeContextOffset, value, mode); +} + + +bool OptimizedCodeEntry::cacheable() { + return static_cast(READ_BYTE_FIELD(this, kCacheableOffset)); +} + + +void OptimizedCodeEntry::set_cacheable(bool val) { + WRITE_BYTE_FIELD(this, kCacheableOffset, static_cast(val)); +} + + bool JSFunction::IsBuiltin() { return context()->global_object()->IsJSBuiltinsObject(); } diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 9ea060f..dd6cd2c 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -195,6 +195,9 @@ void HeapObject::HeapObjectPrint(FILE* out) { case SHARED_FUNCTION_INFO_TYPE: SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out); break; + case OPTIMIZED_CODE_ENTRY_TYPE: + OptimizedCodeEntry::cast(this)->OptimizedCodeEntryPrint(out); + break; case JS_MESSAGE_OBJECT_TYPE: JSMessageObject::cast(this)->JSMessageObjectPrint(out); break; @@ -890,6 +893,25 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) { } +void OptimizedCodeEntry::OptimizedCodeEntryPrint(FILE* out) { + HeapObject::PrintHeader(out, "OptimizedCodeEntry"); + PrintF(out, "\n - native_context = "); + native_context()->ShortPrint(out); + PrintF(out, "\n - function = "); + function()->ShortPrint(out); + PrintF(out, "\n - code = "); + code()->ShortPrint(out); + PrintF(out, "\n - literals = "); + literals()->ShortPrint(out); + PrintF(out, "\n - next_by_shared_info = "); + next_by_shared_info()->ShortPrint(out); + PrintF(out, "\n - next_by_native_context = "); + next_by_native_context()->ShortPrint(out); + PrintF(out, "\n - cacheable = %s", cacheable() ? "true" : "false"); + PrintF(out, "\n"); +} + + void JSGlobalProxy::JSGlobalProxyPrint(FILE* out) { PrintF(out, "global_proxy "); JSObjectPrint(out); diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc index cd46013..ece8b35 100644 --- a/src/objects-visiting.cc +++ b/src/objects-visiting.cc @@ -119,6 +119,9 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case SHARED_FUNCTION_INFO_TYPE: return kVisitSharedFunctionInfo; + case OPTIMIZED_CODE_ENTRY_TYPE: + return kVisitOptimizedCodeEntry; + case JS_PROXY_TYPE: return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric, diff --git a/src/objects-visiting.h b/src/objects-visiting.h index 2175737..44ad8e9 100644 --- a/src/objects-visiting.h +++ b/src/objects-visiting.h @@ -92,6 +92,7 @@ class StaticVisitorBase : public AllStatic { V(Cell) \ V(PropertyCell) \ V(SharedFunctionInfo) \ + V(OptimizedCodeEntry) \ V(JSFunction) \ V(JSWeakMap) \ V(JSWeakSet) \ diff --git a/src/objects.cc b/src/objects.cc index 0171bf8..452c1d6 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1786,6 +1786,10 @@ void HeapObject::IterateBody(InstanceType type, int object_size, SharedFunctionInfo::BodyDescriptor::IterateBody(this, v); break; } + case OPTIMIZED_CODE_ENTRY_TYPE: { + OptimizedCodeEntry::BodyDescriptor::IterateBody(this, v); + break; + } #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: @@ -9430,6 +9434,15 @@ void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) { } +void OptimizedCodeEntry::Kill() { + set_function(NULL, SKIP_WRITE_BARRIER); + set_code(NULL, SKIP_WRITE_BARRIER); + set_native_context(NULL, SKIP_WRITE_BARRIER); + set_literals(NULL, SKIP_WRITE_BARRIER); + set_cacheable(false); +} + + bool JSFunction::CompileLazy(Handle function, ClearExceptionFlag flag) { bool result = true; diff --git a/src/objects.h b/src/objects.h index 00c534d..040664d 100644 --- a/src/objects.h +++ b/src/objects.h @@ -131,6 +131,7 @@ // - Oddball // - Foreign // - SharedFunctionInfo +// - OptimizedCodeEntry // - Struct // - Box // - DeclaredAccessorDescriptor @@ -406,6 +407,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(FIXED_ARRAY_TYPE) \ V(FIXED_DOUBLE_ARRAY_TYPE) \ V(SHARED_FUNCTION_INFO_TYPE) \ + V(OPTIMIZED_CODE_ENTRY_TYPE) \ \ V(JS_MESSAGE_OBJECT_TYPE) \ \ @@ -756,6 +758,7 @@ enum InstanceType { FIXED_ARRAY_TYPE, SHARED_FUNCTION_INFO_TYPE, + OPTIMIZED_CODE_ENTRY_TYPE, JS_MESSAGE_OBJECT_TYPE, @@ -1017,6 +1020,7 @@ class MaybeObject BASE_EMBEDDED { V(Code) \ V(Oddball) \ V(SharedFunctionInfo) \ + V(OptimizedCodeEntry) \ V(JSValue) \ V(JSDate) \ V(JSMessageObject) \ @@ -6837,6 +6841,76 @@ class SharedFunctionInfo: public HeapObject { }; +// An optimized code entry represents an association between the native +// context, a function, optimized code, and the literals. The entries +// are linked into two lists for efficient lookup: by native context +// (linked through next_by_native_context), or by shared function +// info (linked through next_by_shared_info). +// The references to the native context, function, and code are weak, +// in order not to leak native contexts or functions through +// SharedFunctionInfo. This means an entry can become "dead" through GC. +// Entries are removed lazily as each list is traversed. +class OptimizedCodeEntry: public HeapObject { + public: + // [native_context]: The native context of this entry. (WEAK) + DECL_ACCESSORS(native_context, Context) + + // [function]: The JSFunction of this entry. (WEAK) + DECL_ACCESSORS(function, JSFunction) + + // [code]: The optimized code of this entry. (WEAK) + DECL_ACCESSORS(code, Code) + + // [literals]: Array of literals for this entry. + DECL_ACCESSORS(literals, FixedArray) + + // [next_by_shared_info]: The next link in the list, when traversing + // starting with a SharedFunctionInfo. (NULL if none). + DECL_ACCESSORS(next_by_shared_info, OptimizedCodeEntry) + + // [next_by_native_context]: The next link in the list, when traversing + // starting with a native context. (NULL if none) + DECL_ACCESSORS(next_by_native_context, OptimizedCodeEntry) + + // Casting. + static inline OptimizedCodeEntry* cast(Object* obj); + + DECLARE_PRINTER(OptimizedCodeEntry) + DECLARE_VERIFIER(OptimizedCodeEntry) + + // Layout description. + static const int kNativeContextOffset = JSObject::kHeaderSize; + static const int kFunctionOffset = kNativeContextOffset + kPointerSize; + static const int kCodeOffset = kFunctionOffset + kPointerSize; + static const int kLiteralsOffset = kCodeOffset + kPointerSize; + static const int kNextBySharedInfoOffset = + kLiteralsOffset + kPointerSize; + static const int kNextByNativeContextOffset = + kNextBySharedInfoOffset + kPointerSize; + static const int kCacheableOffset = kNextByNativeContextOffset + kPointerSize; + static const int kSize = kCacheableOffset + kIntSize; + static const int kAlignedSize = OBJECT_POINTER_ALIGN(kSize); + + typedef FixedBodyDescriptor BodyDescriptor; + + // Kills an entry, nulling out its references to native context, function, + // code, and literals. + void Kill(); + inline bool cacheable(); + inline void set_cacheable(bool val); + + private: + // Used internally during traversal to skip dead entries. + inline bool IsDead() { + return function() == NULL || code() == NULL; + } + + DISALLOW_IMPLICIT_CONSTRUCTORS(OptimizedCodeEntry); +}; + + class JSGeneratorObject: public JSObject { public: // [function]: The function corresponding to this generator object. -- 2.7.4