[gjs/wip/ptomato/mozjs31prep: 9/15] doc: Update JS::Value memory notes
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/wip/ptomato/mozjs31prep: 9/15] doc: Update JS::Value memory notes
- Date: Mon, 19 Sep 2016 04:15:48 +0000 (UTC)
commit b673378d05d3db942c48a99459d63e307ffabe1d
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.
https://bugzilla.gnome.org/show_bug.cgi?id=742249
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]