Index: src/objects.h |
diff --git a/src/objects.h b/src/objects.h |
index f26dc07c1e170f176855e28259b97b75af596a56..47fea39e4d9e7566646541c0cd8869ef743b3251 100644 |
--- a/src/objects.h |
+++ b/src/objects.h |
@@ -6001,10 +6001,6 @@ class Map: public HeapObject { |
class IsFrozen: public BitField<bool, 25, 1> {}; |
class IsUnstable: public BitField<bool, 26, 1> {}; |
class IsMigrationTarget: public BitField<bool, 27, 1> {}; |
- class DoneInobjectSlackTracking: public BitField<bool, 28, 1> {}; |
- // Keep this bit field at the very end for better code in |
- // Builtins::kJSConstructStubGeneric stub. |
- class ConstructionCount: public BitField<int, 29, 3> {}; |
// Tells whether the object in the prototype property will be used |
// for instances created from this function. If the prototype |
@@ -6186,6 +6182,12 @@ class Map: public HeapObject { |
// function that was used to instantiate the object). |
String* constructor_name(); |
+ // 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 map is shared between objects that may have different |
// behavior. If true, the map should never be modified, instead a clone |
// should be created and modified. |
@@ -6320,10 +6322,6 @@ class Map: public HeapObject { |
inline bool is_stable(); |
inline void set_migration_target(bool value); |
inline bool is_migration_target(); |
- inline void set_done_inobject_slack_tracking(bool value); |
- inline bool done_inobject_slack_tracking(); |
- inline void set_construction_count(int value); |
- inline int construction_count(); |
inline void deprecate(); |
inline bool is_deprecated(); |
inline bool CanBeDeprecated(); |
@@ -6564,7 +6562,7 @@ class Map: public HeapObject { |
// Bit positions for bit field 2 |
static const int kIsExtensible = 0; |
static const int kStringWrapperSafeForDefaultValueOf = 1; |
- // Currently bit 2 is not used. |
+ static const int kAttachedToSharedFunctionInfo = 2; |
// No bits can be used after kElementsKindFirstBit, they are all reserved for |
// storing ElementKind. |
static const int kElementsKindShift = 3; |
@@ -6957,16 +6955,108 @@ class SharedFunctionInfo: public HeapObject { |
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. Some 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. |
+ // Immediately complete the tracking, perform all the necessary changes |
+ // to maps. This is necessary because there is no efficient way to track |
+ // multiple initial_maps. |
+ // Proceed to create an object in the current context (with the adjusted |
+ // size). |
+ // |
+ // - A different constructor function sharing the same SharedFunctionInfo is |
+ // called in the same context. This could be another closure in the same |
+ // context, or the first function could have been disposed. |
+ // This is handled the same way as the previous case. |
+ // |
+ // Important: inobject slack tracking is not attempted during the snapshot |
+ // creation. |
+ |
+ static const int kGenerousAllocationCount = 8; |
+ |
+ // [construction_count]: Counter for constructor calls made during |
+ // the tracking phase. |
+ inline int construction_count(); |
+ inline void set_construction_count(int value); |
+ |
// [feedback_vector] - accumulates ast node feedback from full-codegen and |
// (increasingly) from crankshafted code where sufficient feedback isn't |
// available. Currently the field is duplicated in |
// TypeFeedbackInfo::feedback_vector, but the allocation is done here. |
DECL_ACCESSORS(feedback_vector, FixedArray) |
+ // [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(); |
+ |
// Invoked before pointers in SharedFunctionInfo are being marked. |
// Also clears the optimized code map. |
inline void BeforeVisitingPointers(); |
+ // 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. |
+ DECL_BOOLEAN_ACCESSORS(live_objects_may_exist) |
+ |
// [instance class name]: class name for instances. |
DECL_ACCESSORS(instance_class_name, Object) |
@@ -7212,10 +7302,12 @@ class SharedFunctionInfo: public HeapObject { |
static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize; |
static const int kFeedbackVectorOffset = |
kInferredNameOffset + kPointerSize; |
+ static const int kInitialMapOffset = |
+ kFeedbackVectorOffset + kPointerSize; |
#if V8_HOST_ARCH_32_BIT |
// Smi fields. |
static const int kLengthOffset = |
- kFeedbackVectorOffset + kPointerSize; |
+ kInitialMapOffset + kPointerSize; |
static const int kFormalParameterCountOffset = kLengthOffset + kPointerSize; |
static const int kExpectedNofPropertiesOffset = |
kFormalParameterCountOffset + kPointerSize; |
@@ -7251,7 +7343,7 @@ class SharedFunctionInfo: public HeapObject { |
// word is not set and thus this word cannot be treated as pointer |
// to HeapObject during old space traversal. |
static const int kLengthOffset = |
- kFeedbackVectorOffset + kPointerSize; |
+ kInitialMapOffset + kPointerSize; |
static const int kFormalParameterCountOffset = |
kLengthOffset + kIntSize; |
@@ -7285,10 +7377,21 @@ class SharedFunctionInfo: public HeapObject { |
#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 defined(V8_TARGET_LITTLE_ENDIAN) |
+ static const int kConstructionCountOffset = kCompilerHintsOffset + 3; |
+#elif defined(V8_TARGET_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, |
- kFeedbackVectorOffset + kPointerSize, |
+ kInitialMapOffset + kPointerSize, |
kSize> BodyDescriptor; |
// Bit positions in start_position_and_type. |
@@ -7303,6 +7406,7 @@ class SharedFunctionInfo: public HeapObject { |
enum CompilerHints { |
kAllowLazyCompilation, |
kAllowLazyCompilationWithoutContext, |
+ kLiveObjectsMayExist, |
kOptimizationDisabled, |
kStrictModeFunction, |
kUsesArguments, |
@@ -7518,54 +7622,6 @@ class JSFunction: public JSObject { |
// Tells whether or not the function is on the concurrent recompilation queue. |
inline bool IsInOptimizationQueue(); |
- // 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 JSFunction. |
- // When it happens enter the "in progress" state: initialize construction |
- // counter in the initial_map and set the |done_inobject_slack_tracking| |
- // flag. |
- // - 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. |
- // - SharedFunctionInfo's expected_nof_properties left unmodified since |
- // allocations made using different closures could actually create different |
- // kind of objects (see prototype inheritance pattern). |
- // |
- // Important: inobject slack tracking is not attempted during the snapshot |
- // creation. |
- |
- static const int kGenerousAllocationCount = Map::ConstructionCount::kMax; |
- static const int kFinishSlackTracking = 1; |
- static const int kNoSlackTracking = 0; |
- |
- // True if the initial_map is set and the object constructions countdown |
- // counter is not zero. |
- inline bool IsInobjectSlackTrackingInProgress(); |
- |
- // Starts the tracking. |
- // Initializes object constructions countdown counter in the initial map. |
- // 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(); |
- |
- // Completes the tracking. |
- // IsInobjectSlackTrackingInProgress is false after this call. |
- void CompleteInobjectSlackTracking(); |
- |
// [literals_or_bindings]: Fixed array holding either |
// the materialized literals or the bindings of a bound function. |
// |