[gjs/wip/ptomato/mozjs31prep: 6/8] doc: Update JS::Value memory notes



commit 999146703aaddd2617bcdee813c12670db96a739
Author: Philip Chimento <philip chimento gmail com>
Date:   Tue Sep 6 22:54:20 2016 -0700

    doc: Update JS::Value memory notes
    
    This information was out of date, not corresponding to how JS::Value
    worked in mozjs24. This updates the information and also abridges it,
    since it is explained fairly well on the MDN wiki now; we don't need to
    maintain a separate document about it that will just get out of date.

 doc/SpiderMonkey_Memory.txt |   42 ++++++++++++++----------------------------
 1 files changed, 14 insertions(+), 28 deletions(-)
---
diff --git a/doc/SpiderMonkey_Memory.txt b/doc/SpiderMonkey_Memory.txt
index 6ef57c6..587eec4 100644
--- a/doc/SpiderMonkey_Memory.txt
+++ b/doc/SpiderMonkey_Memory.txt
@@ -12,49 +12,35 @@ This is a good approach for "embeddable" interpreters, because unlike say the Bo
 
 == Representation of objects ==
 
-An object has two forms. 
-* "jsval" is a type-tagged version, think of GValue (though it is much more efficient)
-* inside a jsval can be one of: a 31-bit signed integer, a boolean, a double*, a JSString*, a JSObject*, 
JSVAL_NULL, or JSVAL_VOID.
+An object has two forms.
+* "JS::Value" is a type-tagged version, think of GValue (though it is much more efficient)
+* inside a JS::Value can be one of: a 32-bit integer, a boolean, a double, a JSString*, or a JSObject*.
 
-jsval is 32 bits. The three least significant bits are a type tag. When JavaScript allocates a double*, 
JSString*, or JSObject* it aligns the allocations so the least significant 3 bits are always zero in the 
pointer. This leaves those three bits for the type tag.
+JS::Value is a 64 bits-wide union. Some of the bits are a type tag. However, don't rely on the layout of 
JS::Value, as it may change between API versions.
 
-The least significant bit in the type tag indicates "integer or not." If the value is an integer, then the 
remaining 31 bits are all used for the integer value.
+You check the type tag with the methods val.isObject(), val.isInt32(), val.isDouble(), val.isString(), 
val.isBoolean(). Use val.isNull() and val.isUndefined() rather than comparing "val == JSVAL_NULL" and "val == 
JSVAL_VOID" to avoid an extra memory access.
 
-What would have been MAXINT is used for JSVAL_VOID. So JSVAL_VOID has the integer flag set, but is not an 
integer.
+null does not count as an object, so val.isObject() does not return true for null. This contrasts with the 
behavior of JSVAL_IS_OBJECT(val), which was the previous API, but this was changed because the object-or-null 
behavior was a source of bugs. If you still want this behaviour use val.isObjectOrNull().
 
-If the type tag is not an integer, the remaining two bits distinguish objects, doubles, and strings.
+The methods val.toObject(), val.toInt32(), etc. are just accessing the appropriate members of the union.
 
-You check the type tag with macros JSVAL_IS_OBJECT(), JSVAL_IS_INT(), JSVAL_IS_DOUBLE(), JSVAL_IS_STRING(), 
JSVAL_IS_BOOLEAN(). You can just compare "val == JSVAL_NULL" and "val == JSVAL_VOID" or you can use 
JSVAL_IS_NULL(), JSVAL_IS_VOID().
-
-NULL counts as an object, so JSVAL_IS_OBJECT() returns true for null.
-
-VOID does not count as an integer. JSVAL_IS_INT() looks like:
-<pre>
-#define JSVAL_IS_INT(v)         (((v) & JSVAL_INT) && (v) != JSVAL_VOID)
-</pre>
-where JSVAL_INT is 0x1, the flag for integer.
-
-JSVAL_VOID shows up in the language as "undefined".
-
-The macros JSVAL_TO_OBJECT(), JSVAL_TO_INT(), etc. are just stripping out the type tag and returning the 
underlying JSObject* or integer or whatever.
-
-The jsapi.h header is pretty readable, if you want to learn more. Types you see in there not mentioned 
above, such as JSFunction*, would show up as an object - JSVAL_IS_OBJECT() would return true. From a jsval 
perspective, everything is one of object, string, double, int, boolean, null, or void. null is a special 
object, and again JSVAL_IS_OBJECT() returns true for it. void is stored like an integer but not considered an 
integer, so JSVAL_IS_INT() returns false.
+The jsapi.h header is pretty readable, if you want to learn more. Types you see in there not mentioned 
above, such as JSFunction*, would show up as an object - val.isObject() would return true. From a JS::Value 
perspective, everything is one of object, string, double, int, boolean, null, or undefined.
 
 == Value types vs. allocated types; "gcthing" ==
 
-For integers, booleans, JSVAL_NULL, and JSVAL_VOID there is no pointer. The value is just stuffed into the 
jsval. So there is no way to "free" these, and no way for them to be finalized or become dangling.
+For integers, booleans, doubles, null, and undefined there is no pointer. The value is just part of the 
JS::Value union. So there is no way to "free" these, and no way for them to be finalized or become dangling.
 
 The importance is: these types just get ignored by the garbage collector.
 
-However, doubles, strings, and objects are all allocated pointers that get finalized eventually. These are 
what garbage collection applies to.
+However, strings and objects are all allocated pointers that get finalized eventually. These are what 
garbage collection applies to.
 
-The API refers to these allocated types as "GC things." The macro JSVAL_TO_GCTHING() masks out the type tag 
to return a pointer (remember the pointer has the low three bits all zero, since it was allocated aligned). 
JSVAL_IS_GCTHING() returns true for string, double, object, null; and false for void, boolean, integer.
+The API refers to these allocated types as "GC things." The macro val.toGCThing() returns the value part of 
the union as a pointer. val.isGCThing() returns true for string, object, null; and false for void, boolean, 
double, integer.
 
 == Tracing ==
 
 The general rule is that SpiderMonkey has a set of GC roots. To do the garbage collection, it finds all 
objects accessible from those roots, and finalizes all objects that are not.
 
-So if you store a jsval or JSObject*/JSString*/JSFunction* somewhere that SpiderMonkey does not know about - 
say, in the private data of an object - that will not be found. SpiderMonkey may try to finalize this object 
even though you have a reference to it.
+So if you store a JS::Value or JSObject*/JSString*/JSFunction* somewhere that SpiderMonkey does not know 
about - say, in the private data of an object - that will not be found. SpiderMonkey may try to finalize this 
object even though you have a reference to it.
 
 If you reference JavaScript objects from your custom object, you have to set the JSCLASS_MARK_IS_TRACE flag 
in your JSClass, and define a trace function in the class struct. A trace function just invokes 
JS_CallTracer() to tell SpiderMonkey about any objects you reference. See 
[http://developer.mozilla.org/en/docs/JSTraceOp JSTraceOp docs].
 
@@ -65,7 +51,7 @@ You can also manually add roots with [http://developer.mozilla.org/en/docs/JS_Ad
 
 JS_AddRoot() pins an object in memory forever until you call JS_RemoveRoot(), so be careful of leaks. 
Basically JS_AddRoot() changes memory management of an object to manual mode.
 
-Note that the argument to JS_AddRoot() is the location of your value, not the value itself. That is, a 
"JSObject**" or "jsval*". Some implications are:
+Note that the argument to JS_AddRoot() is the location of your value, not the value itself. That is, a 
"JSObject**" or "JS::Value*". Some implications are:
 * the location can't go away (don't use a stack address that will vanish before you JS_RemoveRoot(), for 
example)
 * the root is keeping "whatever is at the location" from being collected, not "whatever was originally at 
the location"
 
@@ -86,7 +72,7 @@ If you do not immediately add the object to some other object so it's referenced
 
 === JSFunctionSpec and extra local roots ===
 
-When SpiderMonkey is calling a native function, it will pass in an argv of jsval. It already has to add all 
the argv values as GC roots. The "extra local roots" feature tells SpiderMonkey to stick some extra slots on 
the end of argv that are also GC roots. You can then assign to argv[MAX(min_args, actual_argc)] and whatever 
you put in there won't get garbage collected.
+When SpiderMonkey is calling a native function, it will pass in an argv of JS::Value. It already has to add 
all the argv values as GC roots. The "extra local roots" feature tells SpiderMonkey to stick some extra slots 
on the end of argv that are also GC roots. You can then assign to argv[MAX(min_args, actual_argc)] and 
whatever you put in there won't get garbage collected.
 
 This is kind of a confusing and unreadable hack IMO, though it is probably efficient and thus justified in 
certain cases. I don't know really.
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]