Skip to content

Commit

Permalink
TritonDataCenter#36: Update mdb_v8 for V8 4.6.x
Browse files Browse the repository at this point in the history
This change makes mdb_v8's test suite pass with
https://github.com/nodejs/node/tree/vee-eight-4.6, which is the branch
where V8 4.6.x is integrated into node's master.

There are two main changes. The first one is that Map's
"inobject_properties" property has been renamed to
"inobject_properties_or_constructor_function_index". Since mdb_v8's
doesn't support new V8 primitives yet, we only care about using the
proper name for this property, not about the fact that it has a
different semantic for these new V8 primitives.

The second one is that typed arrays, which are used to represent Buffer
instances since node v4.0.0, store their underlying storage slightly
differently. For V8 versions 4.6 and later, we now use the
JSArrayBufferView and the JSArrayBuffer properties to get access to that
underlying storage, as it seems more reliable and less likely to change
than accessing the first elements' slot, whose representation has
changed between V8 4.5 and 4.6. It used to be a ExternalUint8Array, and
it is now a FixedTypedArray casted as a FixedTypedArrayBase.
  • Loading branch information
Julien Gilli committed Sep 25, 2015
1 parent 60c8b6c commit 853e337
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 25 deletions.
112 changes: 97 additions & 15 deletions src/mdb_v8.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ ssize_t V8_OFF_JSOBJECT_PROPERTIES;
ssize_t V8_OFF_MAP_CONSTRUCTOR;
ssize_t V8_OFF_MAP_CONSTRUCTOR_OR_BACKPOINTER;
ssize_t V8_OFF_MAP_INOBJECT_PROPERTIES;
ssize_t V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX;
ssize_t V8_OFF_MAP_INSTANCE_ATTRIBUTES;
ssize_t V8_OFF_MAP_INSTANCE_DESCRIPTORS;
ssize_t V8_OFF_MAP_INSTANCE_SIZE;
Expand All @@ -224,6 +225,9 @@ ssize_t V8_OFF_SLICEDSTRING_PARENT;
ssize_t V8_OFF_SLICEDSTRING_OFFSET;
ssize_t V8_OFF_STRING_LENGTH;
ssize_t V8_OFF_JSTYPEDARRAY_LENGTH;
ssize_t V8_OFF_JSARRAYBUFFER_BACKINGSTORE;
ssize_t V8_OFF_JSARRAYBUFFERVIEW_BUFFER;
ssize_t V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET;

/* see node_string.h */
#define NODE_OFF_EXTSTR_DATA sizeof (uintptr_t)
Expand Down Expand Up @@ -424,7 +428,17 @@ static v8_offset_t v8_offsets[] = {
"Map", "constructor_or_backpointer",
B_FALSE, V8_CONSTANT_ADDED_SINCE(4, 3)},
{ &V8_OFF_MAP_INOBJECT_PROPERTIES,
"Map", "inobject_properties" },
"Map", "inobject_properties",
B_FALSE, V8_CONSTANT_REMOVED_SINCE(4, 6) },
#ifdef _LP64
{ &V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX,
"Map", "inobject_properties_or_constructor_function_index",
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 8 },
#else
{ &V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX,
"Map", "inobject_properties_or_constructor_function_index",
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 4 },
#endif
{ &V8_OFF_MAP_INSTANCE_ATTRIBUTES,
"Map", "instance_attributes" },
{ &V8_OFF_MAP_INSTANCE_DESCRIPTORS,
Expand Down Expand Up @@ -482,6 +496,26 @@ static v8_offset_t v8_offsets[] = {
"JSTypedArray", "length",
B_FALSE, V8_CONSTANT_FALLBACK(4, 5), 27 },
#endif
#ifdef _LP64
{ &V8_OFF_JSARRAYBUFFER_BACKINGSTORE,
"JSArrayBuffer", "backing_store",
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 23 },
#else
{ &V8_OFF_JSARRAYBUFFER_BACKINGSTORE,
"JSArrayBuffer", "backing_store",
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 11 },
#endif
{ &V8_OFF_JSARRAYBUFFERVIEW_BUFFER,
"JSArrayBufferView", "buffer" },
#ifdef _LP64
{ &V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET,
"JSArrayBufferView", "byte_offset",
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 31 },
#else
{ &V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET,
"JSArrayBufferView", "byte_offset",
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 15 },
#endif
};

static int v8_noffsets = sizeof (v8_offsets) / sizeof (v8_offsets[0]);
Expand Down Expand Up @@ -877,6 +911,10 @@ autoconfigure(v8_cfg_t *cfgp)
if (V8_OFF_MAP_CONSTRUCTOR_OR_BACKPOINTER != -1)
V8_OFF_MAP_CONSTRUCTOR = V8_OFF_MAP_CONSTRUCTOR_OR_BACKPOINTER;

if (V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX != -1)
V8_OFF_MAP_INOBJECT_PROPERTIES =
V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX;

return (failed ? -1 : 0);
}

Expand Down Expand Up @@ -5420,6 +5458,8 @@ dcmd_nodebuffer(uintptr_t addr, uint_t flags, int argc,
char *bufp = buf;
size_t len = sizeof (buf);
uintptr_t elts, rawbuf;
uintptr_t arraybuffer_view_buffer;
uintptr_t arraybufferview_content_offset;

/*
* The undocumented "-f" option allows users to override constructor
Expand All @@ -5440,21 +5480,63 @@ dcmd_nodebuffer(uintptr_t addr, uint_t flags, int argc,
}
}

/*
* This works for Buffer instance in node < 4.0 because they use
* elements slots to reference the backing storage. It also works
* with Buffer in node >= 4.0 because they actually are typed arrays
* and typed arrays use elements slots to store the external data.
* We could use the "backing_store" member of the JSArrayBuffer
* associated to a typed array instead, but using elements for
* both "old" Buffer instances and new ones has the benefit of
* being able to reuse more code.
*/
if (read_heap_ptr(&elts, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0)
return (DCMD_ERR);
if (strcmp(buf, "Buffer") == 0 ||
V8_OFF_JSARRAYBUFFER_BACKINGSTORE == -1) {
/*
* This works for Buffer instances in node < 4.0 because they
* use elements slots to reference the backing storage. If
* the constructor name is not "Buffer" but "Uint8Array" and
* V8_OFF_JSARRAYBUFFER_BACKINGSTORE == -1, it means we are in
* the range of node versions >= 4.0 and <= 4.1 that ship with
* V8 4.5.x. For these versions, it also works because Buffer
* instances are actually typed arrays but their backing storage
* an ExternalUint8Arrayelements whose address is stored in the
* first element's slot.
*/
if (read_heap_ptr(&elts, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0)
return (DCMD_ERR);

if (obj_v8internal(elts, 0, &rawbuf) != 0)
return (DCMD_ERR);
if (obj_v8internal(elts, 0, &rawbuf) != 0)
return (DCMD_ERR);
} else {
/*
* The buffer instance's constructor name is Uint8Array, and
* V8_OFF_JSARRAYBUFFER_BACKINGSTORE != -1, which means that
* we're dealing with a node version that ships with V8 4.6 or
* later. For these versions, buffer instances store their data
* as a typed array, but this time instead of having the backing
* store as an ExternalUint8Array referenced from an element
* slot, it can be found at two different locations:
*
* 1. As a FixedTypedArray casted as a FixedTypedArrayBase in an
* element slot.
*
* 2. As the "backing_store" property of the corresponding
* JSArrayBuffer.
*
* The second way to retrieve the backing store seems like
* it will be less likely to change, and is thus the one we're
* using.
*/
if (V8_OFF_JSARRAYBUFFER_BACKINGSTORE == -1 ||
V8_OFF_JSARRAYBUFFERVIEW_BUFFER == -1 ||
V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET == -1)
return (DCMD_ERR);

if (read_heap_ptr(&arraybuffer_view_buffer, addr,
V8_OFF_JSARRAYBUFFERVIEW_BUFFER) != 0)
return (DCMD_ERR);

if (read_heap_ptr(&rawbuf, arraybuffer_view_buffer,
V8_OFF_JSARRAYBUFFER_BACKINGSTORE) != 0)
return (DCMD_ERR);

if (read_heap_smi(&arraybufferview_content_offset, addr,
V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET) != 0)
return (DCMD_ERR);

rawbuf += arraybufferview_content_offset;
}

mdb_printf("%p\n", rawbuf);
return (DCMD_OK);
Expand Down
43 changes: 33 additions & 10 deletions test/standalone/tst.postmortem_details.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ var os = require('os');
var path = require('path');
var util = require('util');

var NODE_MAJOR = Number(process.versions.node.split('.')[0]);
var NODE_VERSIONS = process.versions.node.split('.');
var NODE_MAJOR = Number(NODE_VERSIONS[0]);
assert.equal(isNaN(NODE_MAJOR), false);

var V8_VERSIONS = process.versions.v8.split('.');
var V8_MAJOR = Number(V8_VERSIONS[0]);
assert.equal(isNaN(V8_MAJOR), false);

var V8_MINOR = Number(V8_VERSIONS[1]);
assert.equal(isNaN(V8_MINOR), false);

/*
* We're going to look specifically for this function and buffer in the core
* file.
Expand Down Expand Up @@ -135,9 +143,17 @@ gcore.on('exit', function (code) {
assert.equal(testlines.length, 1);
assert.equal(testlines[0], '0x' + buffer + ': Hello');
});
verifiers.push(function verifyV8internal(testlines) {
assert.deepEqual(testlines, [ buffer ]);
});
// Buffer instances are implemented as typed arrays in Node
// versions that ship with V8 >= 4.6. Typed arrays in these versions
// of V8 do not *directly* store their underlying buffer as an
// "internal" element, so ::v8internal would not output its address.
// It would instead output the address of a FixedTypedArrayBase
// instance. Thus, skip the test.
if (V8_MAJOR < 4 || V8_MAJOR === 4 && V8_MINOR < 6) {
verifiers.push(function verifyV8internal(testlines) {
assert.deepEqual(testlines, [ buffer ]);
});
}
verifiers.push(function verifyJsfunctionN(testlines) {
assert.equal(testlines.length, 2);
var parts = testlines[1].trim().split(/\s+/);
Expand Down Expand Up @@ -212,12 +228,19 @@ gcore.on('exit', function (code) {
mdb.stdin.write('::cat ' + tmpfile +
' | ::nodebuffer | ::eval "./ccccc"\n');

mdb.stdin.write('!echo test: v8internal\n');
mdb.stdin.write('::cat ' + tmpfile +
' | ::v8print ! awk \'$2 == "elements"{' +
'print $4 }\' > ' + tmpfile + '\n');
mdb.stdin.write('::cat ' + tmpfile + ' | ::v8internal 0\n');

// Buffer instances are implemented as typed arrays in Node
// versions that ship with V8 >= 4.6. Typed arrays in these versions
// of V8 do not *directly* store their underlying buffer as an
// "internal" element, so ::v8internal would not output its address.
// It would instead output the address of a FixedTypedArrayBase
// instance. Thus, skip the test.
if (V8_MAJOR < 4 || V8_MAJOR === 4 && V8_MINOR < 6) {
mdb.stdin.write('!echo test: v8internal\n');
mdb.stdin.write('::cat ' + tmpfile +
' | ::v8print ! awk \'$2 == "elements"{' +
'print $4 }\' > ' + tmpfile + '\n');
mdb.stdin.write('::cat ' + tmpfile + ' | ::v8internal 0\n');
}
mdb.stdin.write('!echo test: jsfunctions -n\n');
mdb.stdin.write('::jsfunctions -n myTestFunction ! cat\n');
mdb.stdin.write('!echo test: jsfunctions -s\n');
Expand Down

0 comments on commit 853e337

Please sign in to comment.