Skip to content

Commit 88a98ea

Browse files
author
Julien Gilli
committed
#36: Update mdb_v8 for V8 4.6.x
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 know 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.
1 parent 60c8b6c commit 88a98ea

File tree

2 files changed

+130
-25
lines changed

2 files changed

+130
-25
lines changed

src/mdb_v8.c

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ ssize_t V8_OFF_JSOBJECT_PROPERTIES;
198198
ssize_t V8_OFF_MAP_CONSTRUCTOR;
199199
ssize_t V8_OFF_MAP_CONSTRUCTOR_OR_BACKPOINTER;
200200
ssize_t V8_OFF_MAP_INOBJECT_PROPERTIES;
201+
ssize_t V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX;
201202
ssize_t V8_OFF_MAP_INSTANCE_ATTRIBUTES;
202203
ssize_t V8_OFF_MAP_INSTANCE_DESCRIPTORS;
203204
ssize_t V8_OFF_MAP_INSTANCE_SIZE;
@@ -224,6 +225,9 @@ ssize_t V8_OFF_SLICEDSTRING_PARENT;
224225
ssize_t V8_OFF_SLICEDSTRING_OFFSET;
225226
ssize_t V8_OFF_STRING_LENGTH;
226227
ssize_t V8_OFF_JSTYPEDARRAY_LENGTH;
228+
ssize_t V8_OFF_JSARRAYBUFFER_BACKINGSTORE;
229+
ssize_t V8_OFF_JSARRAYBUFFERVIEW_BUFFER;
230+
ssize_t V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET;
227231

228232
/* see node_string.h */
229233
#define NODE_OFF_EXTSTR_DATA sizeof (uintptr_t)
@@ -424,7 +428,17 @@ static v8_offset_t v8_offsets[] = {
424428
"Map", "constructor_or_backpointer",
425429
B_FALSE, V8_CONSTANT_ADDED_SINCE(4, 3)},
426430
{ &V8_OFF_MAP_INOBJECT_PROPERTIES,
427-
"Map", "inobject_properties" },
431+
"Map", "inobject_properties",
432+
B_FALSE, V8_CONSTANT_REMOVED_SINCE(4, 6) },
433+
#ifdef _LP64
434+
{ &V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX,
435+
"Map", "inobject_properties_or_constructor_function_index",
436+
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 8 },
437+
#else
438+
{ &V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX,
439+
"Map", "inobject_properties_or_constructor_function_index",
440+
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 4 },
441+
#endif
428442
{ &V8_OFF_MAP_INSTANCE_ATTRIBUTES,
429443
"Map", "instance_attributes" },
430444
{ &V8_OFF_MAP_INSTANCE_DESCRIPTORS,
@@ -482,6 +496,26 @@ static v8_offset_t v8_offsets[] = {
482496
"JSTypedArray", "length",
483497
B_FALSE, V8_CONSTANT_FALLBACK(4, 5), 27 },
484498
#endif
499+
#ifdef _LP64
500+
{ &V8_OFF_JSARRAYBUFFER_BACKINGSTORE,
501+
"JSArrayBuffer", "backing_store",
502+
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 23 },
503+
#else
504+
{ &V8_OFF_JSARRAYBUFFER_BACKINGSTORE,
505+
"JSArrayBuffer", "backing_store",
506+
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 11 },
507+
#endif
508+
{ &V8_OFF_JSARRAYBUFFERVIEW_BUFFER,
509+
"JSArrayBufferView", "buffer" },
510+
#ifdef _LP64
511+
{ &V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET,
512+
"JSArrayBufferView", "byte_offset",
513+
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 31 },
514+
#else
515+
{ &V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET,
516+
"JSArrayBufferView", "byte_offset",
517+
B_FALSE, V8_CONSTANT_FALLBACK(4, 6), 15 },
518+
#endif
485519
};
486520

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

914+
if (V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX != -1)
915+
V8_OFF_MAP_INOBJECT_PROPERTIES =
916+
V8_OFF_MAP_INOBJECT_PROPERTIES_OR_CTOR_FUN_INDEX;
917+
880918
return (failed ? -1 : 0);
881919
}
882920

@@ -5420,6 +5458,8 @@ dcmd_nodebuffer(uintptr_t addr, uint_t flags, int argc,
54205458
char *bufp = buf;
54215459
size_t len = sizeof (buf);
54225460
uintptr_t elts, rawbuf;
5461+
uintptr_t arraybuffer_view_buffer;
5462+
uintptr_t arraybufferview_content_offset;
54235463

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

5443-
/*
5444-
* This works for Buffer instance in node < 4.0 because they use
5445-
* elements slots to reference the backing storage. It also works
5446-
* with Buffer in node >= 4.0 because they actually are typed arrays
5447-
* and typed arrays use elements slots to store the external data.
5448-
* We could use the "backing_store" member of the JSArrayBuffer
5449-
* associated to a typed array instead, but using elements for
5450-
* both "old" Buffer instances and new ones has the benefit of
5451-
* being able to reuse more code.
5452-
*/
5453-
if (read_heap_ptr(&elts, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0)
5454-
return (DCMD_ERR);
5483+
if (strcmp(buf, "Buffer") == 0 ||
5484+
V8_OFF_JSARRAYBUFFER_BACKINGSTORE == -1) {
5485+
/*
5486+
* This works for Buffer instances in node < 4.0 because they
5487+
* use elements slots to reference the backing storage. If
5488+
* the constructor name is not "Buffer" but "Uint8Array" and
5489+
* V8_OFF_JSARRAYBUFFER_BACKINGSTORE == -1, it means we are in
5490+
* the range of node versions >= 4.0 and <= 4.1 that ship with
5491+
* V8 4.5.x. For these versions, it also works because Buffer
5492+
* instances are actually typed arrays but their backing storage
5493+
* an ExternalUint8Arrayelements whose address is stored in the
5494+
* first element's slot.
5495+
*/
5496+
if (read_heap_ptr(&elts, addr, V8_OFF_JSOBJECT_ELEMENTS) != 0)
5497+
return (DCMD_ERR);
54555498

5456-
if (obj_v8internal(elts, 0, &rawbuf) != 0)
5457-
return (DCMD_ERR);
5499+
if (obj_v8internal(elts, 0, &rawbuf) != 0)
5500+
return (DCMD_ERR);
5501+
} else {
5502+
/*
5503+
* The buffer instance's constructor name is Uint8Array, and
5504+
* V8_OFF_JSARRAYBUFFER_BACKINGSTORE != -1, which means that
5505+
* we're dealing with a node version that ships with V8 4.6 or
5506+
* later. For these versions, buffer instances store their data
5507+
* as a typed array, but this time instead of having the backing
5508+
* store as an ExternalUint8Array referenced from an element
5509+
* slot, it can be found at two different locations:
5510+
*
5511+
* 1. As a FixedTypedArray casted as a FixedTypedArrayBase in an
5512+
* element slot.
5513+
*
5514+
* 2. As the "backing_store" property of the corresponding
5515+
* JSArrayBuffer.
5516+
*
5517+
* The second way to retrieve the backing store seems like
5518+
* it will be less likely to change, and is thus the one we're
5519+
* using.
5520+
*/
5521+
if (V8_OFF_JSARRAYBUFFER_BACKINGSTORE == -1 ||
5522+
V8_OFF_JSARRAYBUFFERVIEW_BUFFER == -1 ||
5523+
V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET == -1)
5524+
return (DCMD_ERR);
5525+
5526+
if (read_heap_ptr(&arraybuffer_view_buffer, addr,
5527+
V8_OFF_JSARRAYBUFFERVIEW_BUFFER) != 0)
5528+
return (DCMD_ERR);
5529+
5530+
if (read_heap_ptr(&rawbuf, arraybuffer_view_buffer,
5531+
V8_OFF_JSARRAYBUFFER_BACKINGSTORE) != 0)
5532+
return (DCMD_ERR);
5533+
5534+
if (read_heap_smi(&arraybufferview_content_offset, addr,
5535+
V8_OFF_JSARRAYBUFFERVIEW_CONTENT_OFFSET) != 0)
5536+
return (DCMD_ERR);
5537+
5538+
rawbuf += arraybufferview_content_offset;
5539+
}
54585540

54595541
mdb_printf("%p\n", rawbuf);
54605542
return (DCMD_OK);

test/standalone/tst.postmortem_details.js

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@ var os = require('os');
1414
var path = require('path');
1515
var util = require('util');
1616

17-
var NODE_MAJOR = Number(process.versions.node.split('.')[0]);
17+
var NODE_VERSIONS = process.versions.node.split('.');
18+
var NODE_MAJOR = Number(NODE_VERSIONS[0]);
1819
assert.equal(isNaN(NODE_MAJOR), false);
1920

21+
var V8_VERSIONS = process.versions.v8.split('.');
22+
var V8_MAJOR = Number(V8_VERSIONS[0]);
23+
assert.equal(isNaN(V8_MAJOR), false);
24+
25+
var V8_MINOR = Number(V8_VERSIONS[1]);
26+
assert.equal(isNaN(V8_MINOR), false);
27+
2028
/*
2129
* We're going to look specifically for this function and buffer in the core
2230
* file.
@@ -135,9 +143,17 @@ gcore.on('exit', function (code) {
135143
assert.equal(testlines.length, 1);
136144
assert.equal(testlines[0], '0x' + buffer + ': Hello');
137145
});
138-
verifiers.push(function verifyV8internal(testlines) {
139-
assert.deepEqual(testlines, [ buffer ]);
140-
});
146+
// Buffer instances are implemented as typed arrays in Node
147+
// versions that ship with V8 >= 4.6. Typed arrays in these versions
148+
// of V8 do not *directly* store their underlying buffer as an
149+
// "internal" element, so ::v8internal would not output its address.
150+
// It would instead output the address of a FixedTypedArrayBase
151+
// instance. Thus, skip the test.
152+
if (V8_MAJOR < 4 || V8_MAJOR === 4 && V8_MINOR < 6) {
153+
verifiers.push(function verifyV8internal(testlines) {
154+
assert.deepEqual(testlines, [ buffer ]);
155+
});
156+
}
141157
verifiers.push(function verifyJsfunctionN(testlines) {
142158
assert.equal(testlines.length, 2);
143159
var parts = testlines[1].trim().split(/\s+/);
@@ -212,12 +228,19 @@ gcore.on('exit', function (code) {
212228
mdb.stdin.write('::cat ' + tmpfile +
213229
' | ::nodebuffer | ::eval "./ccccc"\n');
214230

215-
mdb.stdin.write('!echo test: v8internal\n');
216-
mdb.stdin.write('::cat ' + tmpfile +
217-
' | ::v8print ! awk \'$2 == "elements"{' +
218-
'print $4 }\' > ' + tmpfile + '\n');
219-
mdb.stdin.write('::cat ' + tmpfile + ' | ::v8internal 0\n');
220-
231+
// Buffer instances are implemented as typed arrays in Node
232+
// versions that ship with V8 >= 4.6. Typed arrays in these versions
233+
// of V8 do not *directly* store their underlying buffer as an
234+
// "internal" element, so ::v8internal would not output its address.
235+
// It would instead output the address of a FixedTypedArrayBase
236+
// instance. Thus, skip the test.
237+
if (V8_MAJOR < 4 || V8_MAJOR === 4 && V8_MINOR < 6) {
238+
mdb.stdin.write('!echo test: v8internal\n');
239+
mdb.stdin.write('::cat ' + tmpfile +
240+
' | ::v8print ! awk \'$2 == "elements"{' +
241+
'print $4 }\' > ' + tmpfile + '\n');
242+
mdb.stdin.write('::cat ' + tmpfile + ' | ::v8internal 0\n');
243+
}
221244
mdb.stdin.write('!echo test: jsfunctions -n\n');
222245
mdb.stdin.write('::jsfunctions -n myTestFunction ! cat\n');
223246
mdb.stdin.write('!echo test: jsfunctions -s\n');

0 commit comments

Comments
 (0)