@ohos-ports/weak-napi 2.0.2-beta.0 → 2.0.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "callback",
18
18
  "napi"
19
19
  ],
20
- "version": "2.0.2-beta.0",
20
+ "version": "2.0.2-beta.1",
21
21
  "repository": {
22
22
  "type": "git",
23
23
  "url": "https://github.com/ohos-ports/ohos-ports.git",
@@ -27,7 +27,8 @@
27
27
  "scripts": {
28
28
  "test": "nyc mocha --expose-gc",
29
29
  "install": "node-gyp-build",
30
- "prebuild": "prebuildify --napi --tag-armv --tag-uv"
30
+ "prebuild": "prebuildify --napi --tag-armv --tag-uv",
31
+ "prepack": "prebuildify-ci download && ([ $(ls prebuilds | wc -l) = '5' ] || (echo 'Some prebuilds are missing'; exit 1))"
31
32
  },
32
33
  "dependencies": {
33
34
  "node-addon-api": "^3.0.0",
@@ -44,12 +45,11 @@
44
45
  "url": "https://github.com/ohos-ports/ohos-ports/issues"
45
46
  },
46
47
  "files": [
47
- "lib/",
48
- "src/",
49
- "test/",
50
- "prebuilds/",
51
- "build/Release/weakref.node",
48
+ "lib",
49
+ "src",
52
50
  "binding.gyp",
51
+ "build/Release/weakref.node",
52
+ "prebuilds/",
53
53
  "LICENSE",
54
54
  "README.md",
55
55
  "History.md"
package/src/weakref.cc CHANGED
@@ -5,21 +5,6 @@ using namespace Napi;
5
5
 
6
6
  namespace {
7
7
 
8
- // Node.js v12+ (and the ohos node v26.8.1 runtime) uses V8 incremental
9
- // finalization: weak-reference finalizers can run while the environment is
10
- // being torn down at process exit, after the libuv loop has stopped. At that
11
- // point calling SetImmediate() below would install fresh uv_check_t/uv_idle_t
12
- // handles onto a dead event loop and invoke into a finalizing napi_env,
13
- // crashing the process (use-after-free, SIGSEGV). napi_add_env_cleanup_hook
14
- // gives us a reliable signal that the environment is shutting down; once it
15
- // is set we drop the pending weak callback instead of scheduling it. This is
16
- // safe: the process is exiting and the callback would never run anyway.
17
- bool g_env_tearing_down = false;
18
-
19
- void OnEnvTeardown(void* /*arg*/) {
20
- g_env_tearing_down = true;
21
- }
22
-
23
8
  class ObjectInfo : public ObjectWrap<ObjectInfo> {
24
9
  public:
25
10
  ObjectInfo(const CallbackInfo& args) : ObjectWrap(args) {
@@ -33,21 +18,10 @@ class ObjectInfo : public ObjectWrap<ObjectInfo> {
33
18
  }
34
19
 
35
20
  void OnFree() {
36
- if (g_env_tearing_down)
37
- return;
38
21
  SetImmediate(Env(), [this]() {
39
22
  callback_.MakeCallback(Value(), {});
40
23
  callback_.Reset();
41
- // Release the strong persistent reference so the JS ObjectInfo wrapper
42
- // becomes collectible (the JS Proxy created by lib/weak.js keeps it
43
- // alive as long as the user holds it). We must NOT use Reset() here:
44
- // napi_delete_reference() frees the internal Reference record while the
45
- // object's private "wrapper" property still points at it, so any later
46
- // napi_unwrap() on the live object would dereference freed memory and
47
- // crash (observed as SIGSEGV on Node v26.8.1). Unref() drops the
48
- // reference count to zero; the ObjectWrap finalizer then deletes the
49
- // native instance only after the JS object is actually collected.
50
- Unref();
24
+ Reset();
51
25
  });
52
26
  }
53
27
 
@@ -87,7 +61,6 @@ class WeakTag : public ObjectWrap<WeakTag> {
87
61
  };
88
62
 
89
63
  Object Init(Env env, Object exports) {
90
- napi_add_env_cleanup_hook(env, OnEnvTeardown, nullptr);
91
64
  exports["WeakTag"] = WeakTag::GetClass(env);
92
65
  exports["ObjectInfo"] = ObjectInfo::GetClass(env);
93
66
  return exports;
package/test/buffer.js DELETED
@@ -1,44 +0,0 @@
1
- 'use strict';
2
- const assert = require('assert');
3
- const weak = require('../');
4
-
5
- // On modern V8 (Node.js >= 12, including the ohos node v26.8.1 runtime),
6
- // garbage collection finalization is incremental: gc() may return before the
7
- // weak-reference finalizers execute, and finalization work is spread over
8
- // several subsequent GC cycles / event-loop turns. The weak-napi GC callback
9
- // is therefore guaranteed to fire once the Buffer is truly collected, but
10
- // NOT necessarily within a single setImmediate tick after gc(). This matches
11
- // documented V8 behavior on every platform and is not a HarmonyOS platform
12
- // defect; the callback is still invoked before the Buffer's memory is
13
- // reclaimed from the JS object's perspective. See test/callback.js for the
14
- // full explanation shared by both test files.
15
- function waitForGcCallback(isDone, done, maxAttempts) {
16
- let attempts = 0;
17
- maxAttempts = maxAttempts || 200;
18
- (function poll() {
19
- gc();
20
- attempts++;
21
- if (isDone()) return done();
22
- if (attempts >= maxAttempts) {
23
- return done(new Error(
24
- 'weak GC callback did not fire after ' + attempts + ' gc attempts'));
25
- }
26
- setTimeout(poll, 0);
27
- })();
28
- }
29
-
30
- describe('weak()', function () {
31
- afterEach(gc);
32
-
33
- describe('Buffer', function () {
34
- it('should invoke callback when Buffer is garbage collected', function(done) {
35
- let called = false;
36
- weak(Buffer('test'), function (buf) {
37
- called = true;
38
- });
39
-
40
- assert(!called);
41
- waitForGcCallback(() => called, done);
42
- });
43
- });
44
- });
package/test/callback.js DELETED
@@ -1,148 +0,0 @@
1
- 'use strict';
2
- const assert = require('assert');
3
- const weak = require('../');
4
-
5
- // On modern V8 (Node.js >= 12, including the ohos node v26.8.1 runtime),
6
- // garbage collection finalization is incremental: gc() may return before the
7
- // weak-reference finalizers execute, and finalization work is spread over
8
- // several subsequent GC cycles / event-loop turns. The weak-napi GC callback
9
- // is therefore guaranteed to fire once the target object is truly collected,
10
- // but NOT necessarily within a single setImmediate tick after gc().
11
- //
12
- // This matches documented V8 behavior on every platform (upstream weak-napi
13
- // is unmaintained since 2019 and its tests encode the synchronous
14
- // finalization behavior of contemporary V8); it is a runtime-version
15
- // behavior, not a HarmonyOS platform defect. The essential semantics are
16
- // preserved and asserted below:
17
- // * the GC callback DOES fire once the target is collected,
18
- // * weak.get()/isDead() report the target as dead once the callback ran,
19
- // * GC callbacks never preempt nextTick callbacks.
20
- // These helpers wait for the callback across event loop turns while applying
21
- // GC pressure, which works both on old V8 (callback fires immediately) and
22
- // on modern V8 (callback fires a few cycles later).
23
- function waitForGcCallback(isDone, done, maxAttempts) {
24
- let attempts = 0;
25
- maxAttempts = maxAttempts || 200;
26
- (function poll() {
27
- gc();
28
- attempts++;
29
- if (isDone()) return done();
30
- if (attempts >= maxAttempts) {
31
- return done(new Error(
32
- 'weak GC callback did not fire after ' + attempts + ' gc attempts'));
33
- }
34
- setTimeout(poll, 0);
35
- })();
36
- }
37
-
38
- describe('weak()', function() {
39
- afterEach(gc);
40
-
41
- describe('garbage collection callback', function() {
42
- it('should accept a function as second argument', function() {
43
- const r = weak({}, function () {});
44
- assert.strictEqual(1, weak.callbacks(r).length);
45
- });
46
-
47
- it('should invoke the callback once the target is gc\'d', function(done) {
48
- let called = false;
49
- weak({}, function() {
50
- called = true
51
- });
52
- assert(!called);
53
- waitForGcCallback(() => called, done);
54
- });
55
-
56
- it('should invoke *all* callbacks in the internal "callback" Array',
57
- function(done) {
58
- const r = weak({});
59
- let called1 = false;
60
- let called2 = false;
61
- weak.addCallback(r, function() {
62
- called1 = true
63
- });
64
- weak.addCallback(r, function() {
65
- called2 = true
66
- });
67
- waitForGcCallback(() => called1 && called2, done);
68
- });
69
-
70
- it('should invoke *all* callbacks from different weak references',
71
- function(done) {
72
- let obj = {};
73
- const r1 = weak(obj);
74
- const r2 = weak(obj);
75
- assert.strictEqual(weak.get(r1), obj);
76
- assert.strictEqual(weak.isDead(r1), false);
77
- obj = null;
78
- let called1 = false;
79
- let called2 = false;
80
- weak.addCallback(r1, function() {
81
- called1 = true
82
- });
83
- weak.addCallback(r2, function() {
84
- called2 = true
85
- });
86
- waitForGcCallback(() => called1 && called2, function() {
87
- assert.strictEqual(weak.get(r1), undefined);
88
- assert.strictEqual(weak.isDead(r1), true);
89
- done();
90
- });
91
- });
92
-
93
- it('should not preempt nextTick callbacks with the GC callback',
94
- function(done) {
95
- const events = [];
96
- weak({}, function() {
97
- events.push('gcb');
98
- });
99
-
100
- process.nextTick(function() {
101
- events.push('tick');
102
- });
103
-
104
- waitForGcCallback(() => events.indexOf('gcb') !== -1, function() {
105
- assert(events.indexOf('tick') !== -1);
106
- assert(events.indexOf('tick') < events.indexOf('gcb'));
107
- done();
108
- });
109
- });
110
- });
111
- });
112
-
113
- describe('callbacks()', function() {
114
- it('should return the Weakref\'s "callback" Array', function () {
115
- const r = weak({}, function() {});
116
- const callbacks = weak.callbacks(r);
117
- assert(Array.isArray(callbacks));
118
- assert.strictEqual(1, callbacks.length);
119
- });
120
- });
121
-
122
- describe('removeCallback()', function() {
123
- it('removed callbacks should not be called', function() {
124
- let called = false;
125
- const fn = function() { called = true };
126
- const r = weak({}, fn);
127
- weak.removeCallback(r, fn);
128
- gc();
129
- assert(!called);
130
- });
131
- });
132
-
133
- describe('removeCallbacks()', function() {
134
- it('removed callbacks should not be called', function() {
135
- let called = false;
136
- const fn = function() { called = true };
137
- const r = weak({}, fn);
138
- weak.removeCallbacks(r);
139
- gc();
140
- assert(!called);
141
- });
142
- });
143
-
144
- describe('isNearDeath()', function() {
145
- it('returns false', function() {
146
- assert(!weak.isNearDeath('whatever'));
147
- });
148
- });
package/test/create.js DELETED
@@ -1,42 +0,0 @@
1
- 'use strict';
2
- const assert = require('assert');
3
- const weak = require('../');
4
-
5
- describe('create()', function() {
6
- afterEach(gc)
7
-
8
- it('should throw on non-"object" values', function() {
9
- [
10
- 0,
11
- 0.0,
12
- true,
13
- false,
14
- null,
15
- undefined,
16
- 'foo',
17
- Symbol(),
18
- ].forEach((val) => {
19
- assert.throws(function() {
20
- weak.create(val);
21
- });
22
- });
23
- });
24
-
25
- it('should accept "object" values', function() {
26
- [
27
- {},
28
- function() {},
29
- () => {},
30
- [],
31
- Buffer(''),
32
- new ArrayBuffer(10),
33
- new Int32Array(new ArrayBuffer(12)),
34
- Promise.resolve(),
35
- new WeakMap(),
36
- ].forEach((val) => {
37
- assert.doesNotThrow(() => {
38
- assert.ok(weak.create(val));
39
- }, Error, String(val));
40
- });
41
- });
42
- });
package/test/exports.js DELETED
@@ -1,31 +0,0 @@
1
- 'use strict';
2
- const assert = require('assert');
3
- const weak = require('../');
4
-
5
- function checkFunction(prop) {
6
- it(`should have a function "${prop}"`, function () {
7
- assert.strictEqual(typeof weak[prop], 'function');
8
- })
9
- }
10
-
11
- describe('exports', function () {
12
- afterEach(gc);
13
-
14
- it('should be a function', function() {
15
- assert.strictEqual(typeof weak, 'function');
16
- });
17
-
18
- checkFunction('get');
19
- checkFunction('create');
20
- checkFunction('isWeakRef');
21
- checkFunction('isNearDeath');
22
- checkFunction('isDead');
23
- checkFunction('callbacks');
24
- checkFunction('addCallback');
25
- checkFunction('removeCallback');
26
- checkFunction('removeCallbacks');
27
-
28
- it('should be a circular reference to "create"', function () {
29
- assert.strictEqual(weak, weak.create);
30
- });
31
- });
package/test/weakref.js DELETED
@@ -1,151 +0,0 @@
1
- 'use strict';
2
- const assert = require('assert');
3
- const weak = require('../');
4
-
5
- describe('Weakref', function() {
6
- afterEach(gc);
7
-
8
- it('weak() should return a `Weakref` instance', function() {
9
- var ref = weak({});
10
- assert(weak.isWeakRef(ref));
11
- });
12
-
13
- it('should proxy named gets to the target', function() {
14
- const o = { foo: 'bar' };
15
- const r = weak(o);
16
- assert.strictEqual(r.foo, 'bar');
17
- });
18
-
19
- it('should proxy named sets to the target', function() {
20
- const o = {};
21
- const r = weak(o);
22
- r.foo = 'bar';
23
- assert.strictEqual(r.foo, 'bar');
24
- });
25
-
26
- it('should proxy named deletes to the target', function() {
27
- const o = { foo: 'bar' };
28
- const r = weak(o);
29
- delete r.foo;
30
- assert(!r.foo);
31
- });
32
-
33
- it('should proxy indexed gets to the target', function() {
34
- const a = [ 'foo' ];
35
- const r = weak(a)
36
- assert.strictEqual(1, a.length);
37
- assert.strictEqual(1, r.length);
38
- assert.strictEqual('foo', r[0]);
39
- });
40
-
41
- it('should proxy indexed sets to the target', function() {
42
- const a = [];
43
- const r = weak(a);
44
- assert.strictEqual(0, a.length);
45
- assert.strictEqual(0, r.length);
46
- r[0] = 'foo';
47
- assert.strictEqual(1, a.length);
48
- assert.strictEqual('foo', a[0]);
49
- r.push('bar');
50
- assert.strictEqual(2, a.length);
51
- assert.strictEqual('bar', a[1]);
52
- });
53
-
54
- it('should proxy indexed deletes to the target', function() {
55
- const a = [ 'foo' ];
56
- const r = weak(a);
57
- delete r[0];
58
- assert.strictEqual('undefined', typeof a[0]);
59
- });
60
-
61
- it('should proxy enumeration', function() {
62
- const o = { a: 'a', b: 'b', c: 'c', d: 'd' };
63
- const r = weak(o);
64
- assert.deepEqual(Object.keys(o), Object.keys(r))
65
- });
66
-
67
- it('should act like an empty object after target is gc\'d', function() {
68
- let o = { foo: 'bar' };
69
- const r = weak(o);
70
- o = null;
71
- assert.strictEqual('bar', r.foo);
72
- gc();
73
- assert(!r.foo);
74
- assert.strictEqual(0, Object.keys(r).length);
75
- });
76
-
77
- it('relays prototype set/gets', function() {
78
- const p = {};
79
- let o = { foo: 'bar' };
80
- const r = weak(o);
81
- Object.setPrototypeOf(r, p);
82
- assert.strictEqual(Object.getPrototypeOf(r), p);
83
- });
84
-
85
- it('voids prototype set/gets for gc\'ed objects', function() {
86
- const p = {};
87
- let o = { foo: 'bar' };
88
- const r = weak(o);
89
- Object.setPrototypeOf(r, p);
90
- assert.strictEqual(Object.getPrototypeOf(r), p);
91
- o = null;
92
- gc();
93
- assert.throws(() => {
94
- Object.setPrototypeOf(r, p);
95
- });
96
- assert.strictEqual(Object.getPrototypeOf(r), null);
97
- });
98
-
99
- it('relays extensibility restrictions', function() {
100
- const p = {};
101
- const o = { foo: 'bar' };
102
- const r = weak(o);
103
- assert(Object.isExtensible(r));
104
- assert(Object.isExtensible(o));
105
- Object.preventExtensions(r);
106
- assert(!Object.isExtensible(r));
107
- assert(!Object.isExtensible(o));
108
- });
109
-
110
- it('voids extensibility restrictions for gc\'ed objects', function() {
111
- const p = {};
112
- let o = { foo: 'bar' };
113
- const r = weak(o);
114
- assert(Object.isExtensible(r));
115
- assert(Object.isExtensible(o));
116
- o = null;
117
- gc();
118
- Object.preventExtensions(r);
119
- assert(!Object.isExtensible(r));
120
- });
121
-
122
- it('forwards object descriptor definitions', function() {
123
- const p = {};
124
- let o = { foo: 'bar' };
125
- const r = weak(o);
126
- assert(Object.defineProperty(r, 'foo', { value: 42 }));
127
- assert.strictEqual(r.foo, 42);
128
- assert('foo' in r);
129
- o = null;
130
- gc();
131
- assert.strictEqual(r.foo, undefined);
132
- r.foo = 9;
133
- assert.strictEqual(r.foo, undefined);
134
- assert.throws(() => {
135
- assert(Object.defineProperty(r, 'foo', { value: 42 }));
136
- });
137
- assert(!('foo' in r));
138
- assert.strictEqual(r.foo, undefined);
139
- assert.strictEqual(Object.getOwnPropertyDescriptor(r, 'foo'), undefined);
140
- });
141
-
142
- it('forwards property deletions', function() {
143
- const p = {};
144
- let o = { foo: 'bar' };
145
- const r = weak(o);
146
- assert.strictEqual(r.foo, 'bar');
147
- o = null;
148
- gc();
149
- assert.strictEqual(delete r.foo, true);
150
- });
151
- });