Index: src/objects.h |
=================================================================== |
--- src/objects.h (revision 5500) |
+++ src/objects.h (working copy) |
@@ -1576,7 +1576,7 @@ |
// initialized by set_properties |
// Note: this call does not update write barrier, it is caller's |
// reponsibility to ensure that *v* can be collected without WB here. |
- inline void InitializeBody(int object_size); |
+ inline void InitializeBody(int object_size, Object* value); |
// Check whether this object references another object |
bool ReferencesObject(Object* obj); |
@@ -3151,6 +3151,12 @@ |
return ((1 << kHasFastElements) & bit_field2()) != 0; |
} |
+ // Tells whether the map is attached to SharedFunctionInfo |
+ // (for inobject slack tracking). |
+ inline void set_attached_to_shared_function_info(bool value); |
+ |
+ inline bool attached_to_shared_function_info(); |
+ |
// Tells whether the instance needs security checks when accessing its |
// properties. |
inline void set_is_access_check_needed(bool access_check_needed); |
@@ -3162,6 +3168,8 @@ |
// [constructor]: points back to the function responsible for this map. |
DECL_ACCESSORS(constructor, Object) |
+ inline JSFunction* unchecked_constructor(); |
+ |
// [instance descriptors]: describes the object. |
DECL_ACCESSORS(instance_descriptors, DescriptorArray) |
@@ -3240,6 +3248,10 @@ |
inline int visitor_id(); |
inline void set_visitor_id(int visitor_id); |
+ typedef void (*TraverseCallback)(Map* map, void* data); |
+ |
+ void TraverseTransitionTree(TraverseCallback callback, void* data); |
+ |
static const int kMaxPreAllocatedPropertyFields = 255; |
// Layout description. |
@@ -3293,6 +3305,7 @@ |
static const int kFunctionWithPrototype = 1; |
static const int kHasFastElements = 2; |
static const int kStringWrapperSafeForDefaultValueOf = 3; |
+ static const int kAttachedToSharedFunctionInfo = 4; |
// Layout of the default cache. It holds alternating name and code objects. |
static const int kCodeCacheEntrySize = 2; |
@@ -3447,6 +3460,95 @@ |
inline int expected_nof_properties(); |
inline void set_expected_nof_properties(int value); |
+ // Inobject slack tracking is the way to reclaim unused inobject space. |
+ // |
+ // The instance size is initially determined by adding some slack to |
+ // expected_nof_properties (to allow for a few extra properties added |
+ // after the constructor). There is no guarantee that the extra space |
+ // will not be wasted. |
+ // |
+ // Here is the algorithm to reclaim the unused inobject space: |
+ // - Detect the first constructor call for this SharedFunctionInfo. |
+ // When it happens enter the "in progress" state: remember the |
+ // constructor's initial_map and install a special construct stub that |
+ // counts constructor calls. |
+ // - While the tracking is in progress create objects filled with |
+ // one_pointer_filler_map instead of undefined_value. This way they can be |
+ // resized quickly and safely. |
+ // - Once enough (kGenerousAllocationCount) objects have been created |
+ // compute the 'slack' (traverse the map transition tree starting from the |
+ // initial_map and find the lowest value of unused_property_fields). |
+ // - Traverse the transition tree again and decrease the instance size |
+ // of every map. Existing objects will resize automatically (they are |
+ // filled with one_pointer_filler_map). All further allocations will |
+ // use the adjusted instance size. |
+ // - Decrease expected_nof_properties so that an allocations made from |
+ // another context will use the adjusted instance size too. |
+ // - Exit "in progress" state by clearing the reference to the initial_map |
+ // and setting the regular construct stub (generic or inline). |
+ // |
+ // The above is the main event sequence. Two special cases are possible |
+ // while the tracking is in progress: |
+ // |
+ // - GC occurs. |
+ // Check if the initial_map is referenced by any live objects (except this |
+ // SharedFunctionInfo). If it is, continue tracking as usual. |
+ // If it is not, clear the reference and reset the tracking state. The |
+ // tracking will be initiated again on the next constructor call. |
+ // |
+ // - The constructor is called from another context. |
Vitaly Repeshko
2010/09/22 14:40:25
As we discussed this probably applies also to the
Vladislav Kaznacheev
2010/09/23 08:38:16
Done.
|
+ // Immediately complete the tracking, perform all the necessary changes |
+ // to maps. This is necessary because there is no efficient way to track |
+ // object creation in multiple contexts. |
+ // Proceed to create an object in the current context (with the adjusted |
+ // size). |
+ // |
+ // Important: inobject slack tracking is not attempted during the snapshot |
+ // creation. |
+ |
+ static const int kGenerousAllocationCount = 16; |
+ |
+ // [construction_count]: Counter for constructor calls made during |
+ // the tracking phase. |
+ inline int construction_count(); |
+ inline void set_construction_count(int value); |
+ |
+ // [initial_map]: initial map of the first function called as a constructor. |
+ // Saved for the duration of the tracking phase. |
+ // This is a weak link (GC resets it to undefined_value if no other live |
+ // object reference this map). |
+ DECL_ACCESSORS(initial_map, Object) |
+ |
+ // True if the initial_map is not undefined and the countdown stub is |
+ // installed. |
+ inline bool IsInobjectSlackTrackingInProgress(); |
+ |
+ // Starts the tracking. |
+ // Stores the initial map and installs the countdown stub. |
+ // IsInobjectSlackTrackingInProgress is normally true after this call, |
+ // except when tracking have not been started (e.g. the map has no unused |
+ // properties or the snapshot is being built). |
+ void StartInobjectSlackTracking(Map* map); |
+ |
+ // Completes the tracking. |
+ // IsInobjectSlackTrackingInProgress is false after this call. |
+ void CompleteInobjectSlackTracking(); |
+ |
+ // Clears the initial_map before the GC marking phase to ensure the reference |
+ // is weak. IsInobjectSlackTrackingInProgress is false after this call. |
+ void DetachInitialMap(); |
+ |
+ // Restores the link to the initial map after the GC marking phase. |
+ // IsInobjectSlackTrackingInProgress is true after this call. |
+ void AttachInitialMap(Map* map); |
+ |
+ // False if there are definitely no live objects created from this function. |
+ // True if live objects _may_ exist (existence not guaranteed). |
+ // May go back from true to false after GC. |
+ inline bool live_objects_may_exist(); |
+ |
+ inline void set_live_objects_may_exist(bool value); |
+ |
// [instance class name]: class name for instances. |
DECL_ACCESSORS(instance_class_name, Object) |
@@ -3598,8 +3700,10 @@ |
static const int kScriptOffset = kFunctionDataOffset + kPointerSize; |
static const int kDebugInfoOffset = kScriptOffset + kPointerSize; |
static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize; |
+ static const int kInitialMapOffset = |
+ kInferredNameOffset + kPointerSize; |
static const int kThisPropertyAssignmentsOffset = |
- kInferredNameOffset + kPointerSize; |
+ kInitialMapOffset + kPointerSize; |
#if V8_HOST_ARCH_32_BIT |
// Smi fields. |
static const int kLengthOffset = |
@@ -3623,7 +3727,7 @@ |
static const int kSize = kThisPropertyAssignmentsCountOffset + kPointerSize; |
#else |
// The only reason to use smi fields instead of int fields |
- // is to allow interation without maps decoding during |
+ // is to allow iteration without maps decoding during |
// garbage collections. |
// To avoid wasting space on 64-bit architectures we use |
// the following trick: we group integer fields into pairs |
@@ -3658,6 +3762,18 @@ |
static const int kSize = kThisPropertyAssignmentsCountOffset + kIntSize; |
#endif |
+ |
+ // The construction counter for inobject slack tracking is stored in the |
+ // most significant byte of compiler_hints which is otherwise unused. |
+ // Its offset depends on the endian-ness of the architecture. |
+#if __BYTE_ORDER == __LITTLE_ENDIAN |
+ static const int kConstructionCountOffset = kCompilerHintsOffset + 3; |
+#elif __BYTE_ORDER == __BIG_ENDIAN |
+ static const int kConstructionCountOffset = kCompilerHintsOffset + 0; |
+#else |
+#error Unknown byte ordering |
+#endif |
+ |
static const int kAlignedSize = POINTER_SIZE_ALIGN(kSize); |
typedef FixedBodyDescriptor<kNameOffset, |
@@ -3677,7 +3793,8 @@ |
static const int kHasOnlySimpleThisPropertyAssignments = 0; |
static const int kTryFullCodegen = 1; |
static const int kAllowLazyCompilation = 2; |
- static const int kCodeAgeShift = 3; |
+ static const int kLiveObjectsMayExist = 3; |
+ static const int kCodeAgeShift = 4; |
static const int kCodeAgeMask = 7; |
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo); |