Add OptimizedCodeEntry as a new heap object type. An optimized code entry represents...
authortitzer@chromium.org <titzer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 16:48:40 +0000 (16:48 +0000)
committertitzer@chromium.org <titzer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 16:48:40 +0000 (16:48 +0000)
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

12 files changed:
include/v8.h
src/factory.cc
src/factory.h
src/heap.cc
src/heap.h
src/objects-debug.cc
src/objects-inl.h
src/objects-printer.cc
src/objects-visiting.cc
src/objects-visiting.h
src/objects.cc
src/objects.h

index c29bba6..51bd362 100644 (file)
@@ -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;
index 9323c2f..6faa84e 100644 (file)
@@ -1249,6 +1249,21 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
 }
 
 
+Handle<OptimizedCodeEntry> Factory::NewOptimizedCodeEntry(
+      Handle<Context> native_context,
+      Handle<JSFunction> function,
+      Handle<Code> code,
+      Handle<FixedArray> literals) {
+  CALL_HEAP_FUNCTION(isolate(),
+                     isolate()->heap()->AllocateOptimizedCodeEntry(
+                         *native_context,
+                         *function,
+                         *code,
+                         *literals),
+                     OptimizedCodeEntry);
+}
+
+
 Handle<String> Factory::NumberToString(Handle<Object> number) {
   CALL_HEAP_FUNCTION(isolate(),
                      isolate()->heap()->NumberToString(*number), String);
index 02c9a4d..390329c 100644 (file)
@@ -487,6 +487,12 @@ class Factory {
       Handle<ScopeInfo> scope_info);
   Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
 
+  Handle<OptimizedCodeEntry> NewOptimizedCodeEntry(
+      Handle<Context> native_context,
+      Handle<JSFunction> function,
+      Handle<Code> code,
+      Handle<FixedArray> literals);
+
   Handle<JSMessageObject> NewJSMessageObject(
       Handle<String> type,
       Handle<JSArray> arguments,
index f48d9cc..4fd478f 100644 (file)
@@ -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<OptimizedCodeEntry>(&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,
index 5be7861..f0920b3 100644 (file)
@@ -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.
index a61eacf..4ba70c3 100644 (file)
@@ -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();
index f629d9f..77b4e38 100644 (file)
@@ -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<bool>(READ_BYTE_FIELD(this, kCacheableOffset));
+}
+
+
+void OptimizedCodeEntry::set_cacheable(bool val) {
+  WRITE_BYTE_FIELD(this, kCacheableOffset, static_cast<byte>(val));
+}
+
+
 bool JSFunction::IsBuiltin() {
   return context()->global_object()->IsJSBuiltinsObject();
 }
index 9ea060f..dd6cd2c 100644 (file)
@@ -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);
index cd46013..ece8b35 100644 (file)
@@ -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,
index 2175737..44ad8e9 100644 (file)
@@ -92,6 +92,7 @@ class StaticVisitorBase : public AllStatic {
   V(Cell)                     \
   V(PropertyCell)             \
   V(SharedFunctionInfo)       \
+  V(OptimizedCodeEntry)       \
   V(JSFunction)               \
   V(JSWeakMap)                \
   V(JSWeakSet)                \
index 0171bf8..452c1d6 100644 (file)
@@ -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<JSFunction> function,
                              ClearExceptionFlag flag) {
   bool result = true;
index 00c534d..040664d 100644 (file)
 //       - 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<kLiteralsOffset,
+                              kNextByNativeContextOffset + kPointerSize,
+                              kSize> 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.