From b8844ab97cf0e6ad55a0668a1a228de3cfc7dc52 Mon Sep 17 00:00:00 2001 From: Martin Grossi <25255126+enlightenedmouse@users.noreply.github.com> Date: Mon, 21 Jan 2019 23:50:51 -0500 Subject: [PATCH 1/2] Implement 'pack(n)' option --- lib/struct.js | 37 ++++++++++++++++++++++++++++--------- test/struct.js | 17 +++++++++++++++++ test/struct_tests.cc | 15 +++++++++++++++ 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/lib/struct.js b/lib/struct.js index 25fc033..a6903ca 100644 --- a/lib/struct.js +++ b/lib/struct.js @@ -122,10 +122,14 @@ function Struct () { StructType.size = 0 StructType.alignment = 0 StructType.indirection = 1 - StructType.isPacked = opt.packed ? Boolean(opt.packed) : false + StructType.pack = typeof(opt.pack) === "number" ? opt.pack : opt.packed ? 1 : 0; StructType.get = get StructType.set = set + if( StructType.pack ) { + assert([1,2,4,8,16].includes(StructType.pack),'pack value must be 1, 2, 4, 8, or 16') + } + // Read the fields list and apply all the fields to the struct // TODO: Better arg handling... (maybe look at ES6 binary data API?) var arg = arguments[0] @@ -247,13 +251,17 @@ function recalc (struct) { if (type.indirection > 1) { alignment = ref.alignof.pointer } - if (struct.isPacked) { - struct.alignment = Math.min(struct.alignment || alignment, alignment) - } else { - struct.alignment = Math.max(struct.alignment, alignment) - } + // the alignment of the structure will be as that of its largest member + struct.alignment = Math.max(struct.alignment, alignment) }) + if( struct.pack ) { + // if packed, the alignment of the structure will be that of the n-byte + // boundary or the alignment of the largest member of the structure; whichever + // is smaller + struct.alignment = Math.min(struct.alignment, struct.pack); + } + // second loop through sets the `offset` property on each "field" // object, and sets the `struct.size` as we go along fieldNames.forEach(function (name) { @@ -276,12 +284,19 @@ function recalc (struct) { function addType (type) { var offset = struct.size var align = type.indirection === 1 ? type.alignment : ref.alignof.pointer - var padding = struct.isPacked ? 0 : (align - (offset % align)) % align + if( struct.pack ) { + // #pragma pack(n) + // https://docs.microsoft.com/en-us/cpp/preprocessor/pack?view=vs-2017 + // The alignment of a member will be on a boundary that is either a multiple + // of n or a multiple of the size of the member, whichever is smaller + align = Math.min(struct.pack, align); + } + var padding = (align - (offset % align)) % align var size = type.indirection === 1 ? type.size : ref.sizeof.pointer offset += padding - if (!struct.isPacked) { + if (!struct.pack) { assert.equal(offset % align, 0, "offset should align") } @@ -292,7 +307,11 @@ function recalc (struct) { return offset } - // any final padding? + // http://www.catb.org/esr/structure-packing/#_structure_alignment_and_padding + // The stride address of a structure is the first address following the structure + // data that has the same alignment as the structure. The general rule of + // trailing structure padding is that the structure has trailing padding out to + // its stride address var left = struct.size % struct.alignment if (left > 0) { debug('additional padding to the end of struct:', struct.alignment - left) diff --git a/test/struct.js b/test/struct.js index 8f29eee..fb69146 100644 --- a/test/struct.js +++ b/test/struct.js @@ -377,6 +377,23 @@ describe('Struct', function () { test19.defineProperty('next', ref.refType(test19)); test(test19, 19); + var test20 = Struct({ + a: 'char', + p: ref.refType('void') + }, {packed: true}) + test(test20, 20) + + var test21 = Struct({ + a: 'char', + p: ref.refType('void') + }) + test(test21, 21) + + var test22 = Struct({ + a: 'char', + p: ref.refType('void') + },{pack: 2}) + test(test22, 22) }) describe('packed struct', function () { diff --git a/test/struct_tests.cc b/test/struct_tests.cc index b2192db..5ebc09c 100644 --- a/test/struct_tests.cc +++ b/test/struct_tests.cc @@ -157,6 +157,12 @@ typedef struct _test21 { void *p; } test21; +#pragma pack(2) +typedef struct _test22 { + char a; + void *p; +} test22; + void Initialize(v8::Handle target) { Nan::HandleScope scope; @@ -289,9 +295,18 @@ void Initialize(v8::Handle target) { target->Set(Nan::New("test20 sizeof").ToLocalChecked(), Nan::New(sizeof(test20))); target->Set(Nan::New("test20 alignof").ToLocalChecked(), Nan::New(__alignof__(test20))); + target->Set(Nan::New("test20 offsetof a").ToLocalChecked(), Nan::New(offsetof(test20, a))); + target->Set(Nan::New("test20 offsetof p").ToLocalChecked(), Nan::New(offsetof(test20, p))); target->Set(Nan::New("test21 sizeof").ToLocalChecked(), Nan::New(sizeof(test21))); target->Set(Nan::New("test21 alignof").ToLocalChecked(), Nan::New(__alignof__(test21))); + target->Set(Nan::New("test21 offsetof a").ToLocalChecked(), Nan::New(offsetof(test21, a))); + target->Set(Nan::New("test21 offsetof p").ToLocalChecked(), Nan::New(offsetof(test21, p))); + + target->Set(Nan::New("test22 sizeof").ToLocalChecked(), Nan::New(sizeof(test22))); + target->Set(Nan::New("test22 alignof").ToLocalChecked(), Nan::New(__alignof__(test22))); + target->Set(Nan::New("test22 offsetof a").ToLocalChecked(), Nan::New(offsetof(test22, a))); + target->Set(Nan::New("test22 offsetof p").ToLocalChecked(), Nan::New(offsetof(test22, p))); } } // anonymous namespace From d9394a4cee6d1562ac6262c72744487b0c8bd1a6 Mon Sep 17 00:00:00 2001 From: Martin Grossi <25255126+enlightenedmouse@users.noreply.github.com> Date: Tue, 22 Jan 2019 00:36:24 -0500 Subject: [PATCH 2/2] Removes ES2016 specific Array method. --- lib/struct.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/struct.js b/lib/struct.js index a6903ca..b0b9549 100644 --- a/lib/struct.js +++ b/lib/struct.js @@ -127,7 +127,7 @@ function Struct () { StructType.set = set if( StructType.pack ) { - assert([1,2,4,8,16].includes(StructType.pack),'pack value must be 1, 2, 4, 8, or 16') + assert([1,2,4,8,16].indexOf(StructType.pack)>=0,'pack value must be 1, 2, 4, 8, or 16') } // Read the fields list and apply all the fields to the struct