Browse Source

test: bundle node-weak in test/gc so that it doesn't need to be downloaded

v0.9.1-release
Nathan Rajlich 13 years ago
committed by Bert Belder
parent
commit
6a8b5b36b4
  1. 13
      Makefile
  2. 13
      test/gc/node_modules/weak/LICENSE
  3. 114
      test/gc/node_modules/weak/README.md
  4. 8
      test/gc/node_modules/weak/binding.gyp
  5. 9
      test/gc/node_modules/weak/lib/weak.js
  6. 55
      test/gc/node_modules/weak/package.json
  7. 315
      test/gc/node_modules/weak/src/weakref.cc
  8. 20
      vcbuild.bat

13
Makefile

@ -61,17 +61,16 @@ test-http1: all
test-valgrind: all
$(PYTHON) tools/test.py --mode=release --valgrind simple message
node_modules/weak:
test/gc/node_modules/weak/build:
@if [ ! -f node ]; then make all; fi
@if [ ! -d node_modules ]; then mkdir -p node_modules; fi
./node deps/npm/bin/npm-cli.js install weak \
--nodedir="$(shell pwd)" \
--prefix="$(shell pwd)" --unsafe-perm # go ahead and run as root.
./node deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \
--directory="$(shell pwd)/test/gc/node_modules/weak" \
--nodedir="$(shell pwd)"
test-gc: all node_modules/weak
test-gc: all test/gc/node_modules/weak/build
$(PYTHON) tools/test.py --mode=release gc
test-all: all node_modules/weak
test-all: all test/gc/node_modules/weak/build
$(PYTHON) tools/test.py --mode=debug,release
make test-npm

13
test/gc/node_modules/weak/LICENSE

@ -0,0 +1,13 @@
Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

114
test/gc/node_modules/weak/README.md

@ -0,0 +1,114 @@
node-weak
=========
### Make weak references to JavaScript Objects.
[![Build Status](https://secure.travis-ci.org/TooTallNate/node-weak.png)](http://travis-ci.org/TooTallNate/node-weak)
On certain rarer occasions, you run into the need to be notified when a JavaScript
object is going to be garbage collected. This feature is exposed to V8's C++ API,
but not to JavaScript.
That's where `node-weak` comes in! This module exports V8's `Persistent<Object>`
functionality to JavaScript. This allows you to create weak references, and
optionally attach a callback function to any arbitrary JS object. The callback
function will be invoked right before the Object is garbage collected (i.e. after
there are no more remaining references to the Object in JS-land).
This module can, for example, be used for debugging; to determine whether or not
an Object is being garbage collected as it should.
Take a look at the example below for commented walkthrough scenario.
Installation
------------
Install with `npm`:
``` bash
$ npm install weak
```
Example
-------
Here's an example of calling a `cleanup()` function on a Object before it gets
garbage collected:
``` js
var weak = require('weak')
// we are going to "monitor" this Object and invoke "cleanup"
// before the object is garbage collected
var obj = {
a: true
, foo: 'bar'
}
// The function to call before Garbage Collection.
// Note that by the time this is called, 'obj' has been set to `null`.
function cleanup (o) {
delete o.a
delete o.foo
}
// Here's where we set up the weak reference
var ref = weak(obj, function () {
// `this` inside the callback is the 'obj'. DO NOT store any new references
// to the object, and DO NOT use the object in any async functions.
cleanup(this)
})
// While `obj` is alive, `ref` proxies everything to it, so:
ref.a === obj.a
ref.foo === obj.foo
// Clear out any references to the object, so that it will be GC'd at some point...
obj = null
//
//// Time passes, and the garbage collector is run
//
// `callback()` above is called, and `ref` now acts like an empty object.
typeof ref.foo === 'undefined'
```
API
---
### weakref weak(Object obj [, Function callback])
The main exports is the function that creates the weak reference.
The first argument is the Object that should be monitored.
The Object can be a regular Object, an Array, a Function, a RegExp, or any of
the primitive types or constructor function created with `new`.
Optionally, you can set a callback function to be invoked
before the object is garbage collected.
### Object weak.get(weakref ref)
`get()` returns the actual reference to the Object that this weak reference was
created with. If this is called with a dead reference, `undefined` is returned.
### Boolean weak.isDead(weakref ref)
Checks to see if `ref` is a dead reference. Returns `true` if the original Object
has already been GC'd, `false` otherwise.
### null weak.addCallback(weakref ref, Function callback)
Adds `callback` to the Array of callback functions that will be invoked before the
Objects gets garbage collected. The callbacks get executed in the order that they
are added.
### Array weak.callbacks(weakref ref)
Returns the internal `Array` that `ref` iterates through to invoke the GC
callbacks. The array can be `push()`ed or `unshift()`ed onto, to have more control
over the execution order of the callbacks. This is similar in concept to node's
`EventEmitter#listeners()` function.

8
test/gc/node_modules/weak/binding.gyp

@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'weakref',
'sources': [ 'src/weakref.cc' ]
}
]
}

9
test/gc/node_modules/weak/lib/weak.js

@ -0,0 +1,9 @@
var bindings = require('../build/Release/weakref.node')
module.exports = bindings.create
// backwards-compat with node-weakref
bindings.weaken = bindings.create
Object.keys(bindings).forEach(function (name) {
module.exports[name] = bindings[name]
})

55
test/gc/node_modules/weak/package.json

@ -0,0 +1,55 @@
{
"author": {
"name": "Ben Noordhuis",
"email": "info@bnoordhuis.nl"
},
"contributors": [
{
"name": "Nathan Rajlich",
"email": "nathan@tootallnate.net",
"url": "http://tootallnate.net"
}
],
"name": "weak",
"description": "Make weak references to JavaScript Objects.",
"keywords": [
"weak",
"reference",
"js",
"javascript",
"object",
"function",
"callback"
],
"version": "0.2.1",
"repository": {
"type": "git",
"url": "git://github.com/TooTallNate/node-weak.git"
},
"main": "./lib/weak.js",
"scripts": {
"test": "mocha -gc --reporter spec",
"install": "node-gyp rebuild"
},
"engines": {
"node": "*"
},
"dependencies": {
"bindings": "*"
},
"devDependencies": {
"mocha": "> 0.7.0",
"should": "*"
},
"_npmUser": {
"name": "tootallnate",
"email": "nathan@tootallnate.net"
},
"_id": "weak@0.2.1",
"optionalDependencies": {},
"_engineSupported": true,
"_npmVersion": "1.1.25",
"_nodeVersion": "v0.7.10",
"_defaultsLoaded": true,
"_from": "weak"
}

315
test/gc/node_modules/weak/src/weakref.cc

@ -0,0 +1,315 @@
/*
* Copyright (c) 2011, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "v8.h"
#include "node.h"
using namespace v8;
using namespace node;
namespace {
typedef struct proxy_container {
Persistent<Object> proxy;
Persistent<Object> target;
Persistent<Array> callbacks;
} proxy_container;
Persistent<ObjectTemplate> proxyClass;
bool IsDead(Handle<Object> proxy) {
assert(proxy->InternalFieldCount() == 1);
proxy_container *cont = reinterpret_cast<proxy_container*>(
proxy->GetPointerFromInternalField(0));
return cont == NULL || cont->target.IsEmpty();
}
Handle<Object> Unwrap(Handle<Object> proxy) {
assert(!IsDead(proxy));
proxy_container *cont = reinterpret_cast<proxy_container*>(
proxy->GetPointerFromInternalField(0));
return cont->target;
}
Handle<Array> GetCallbacks(Handle<Object> proxy) {
proxy_container *cont = reinterpret_cast<proxy_container*>(
proxy->GetPointerFromInternalField(0));
assert(cont != NULL);
return cont->callbacks;
}
#define UNWRAP \
HandleScope scope; \
Handle<Object> obj; \
const bool dead = IsDead(info.This()); \
if (!dead) obj = Unwrap(info.This()); \
Handle<Value> WeakNamedPropertyGetter(Local<String> property,
const AccessorInfo& info) {
UNWRAP
return dead ? Local<Value>() : obj->Get(property);
}
Handle<Value> WeakNamedPropertySetter(Local<String> property,
Local<Value> value,
const AccessorInfo& info) {
UNWRAP
if (!dead) obj->Set(property, value);
return value;
}
Handle<Integer> WeakNamedPropertyQuery(Local<String> property,
const AccessorInfo& info) {
return HandleScope().Close(Integer::New(None));
}
Handle<Boolean> WeakNamedPropertyDeleter(Local<String> property,
const AccessorInfo& info) {
UNWRAP
return Boolean::New(!dead && obj->Delete(property));
}
Handle<Value> WeakIndexedPropertyGetter(uint32_t index,
const AccessorInfo& info) {
UNWRAP
return dead ? Local<Value>() : obj->Get(index);
}
Handle<Value> WeakIndexedPropertySetter(uint32_t index,
Local<Value> value,
const AccessorInfo& info) {
UNWRAP
if (!dead) obj->Set(index, value);
return value;
}
Handle<Integer> WeakIndexedPropertyQuery(uint32_t index,
const AccessorInfo& info) {
return HandleScope().Close(Integer::New(None));
}
Handle<Boolean> WeakIndexedPropertyDeleter(uint32_t index,
const AccessorInfo& info) {
UNWRAP
return Boolean::New(!dead && obj->Delete(index));
}
Handle<Array> WeakPropertyEnumerator(const AccessorInfo& info) {
UNWRAP
return HandleScope().Close(dead ? Array::New(0) : obj->GetPropertyNames());
}
void AddCallback(Handle<Object> proxy, Handle<Function> callback) {
Handle<Array> callbacks = GetCallbacks(proxy);
callbacks->Set(Integer::New(callbacks->Length()), callback);
}
void TargetCallback(Persistent<Value> target, void* arg) {
HandleScope scope;
assert(target.IsNearDeath());
proxy_container *cont = reinterpret_cast<proxy_container*>(arg);
// invoke any listening callbacks
uint32_t len = cont->callbacks->Length();
Handle<Value> argv[1];
argv[0] = target;
for (uint32_t i=0; i<len; i++) {
Handle<Function> cb = Handle<Function>::Cast(
cont->callbacks->Get(Integer::New(i)));
TryCatch try_catch;
cb->Call(target->ToObject(), 1, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}
}
cont->proxy->SetPointerInInternalField(0, NULL);
cont->proxy.Dispose();
cont->proxy.Clear();
cont->target.Dispose();
cont->target.Clear();
cont->callbacks.Dispose();
cont->callbacks.Clear();
free(cont);
}
Handle<Value> Create(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsObject()) {
Local<String> message = String::New("Object expected");
return ThrowException(Exception::TypeError(message));
}
proxy_container *cont = (proxy_container *)
malloc(sizeof(proxy_container));
cont->target = Persistent<Object>::New(args[0]->ToObject());
cont->callbacks = Persistent<Array>::New(Array::New());
cont->proxy = Persistent<Object>::New(proxyClass->NewInstance());
cont->proxy->SetPointerInInternalField(0, cont);
cont->target.MakeWeak(cont, TargetCallback);
if (args.Length() >= 2) {
AddCallback(cont->proxy, Handle<Function>::Cast(args[1]));
}
return cont->proxy;
}
/**
* TODO: Make this better.
*/
bool isWeakRef (Handle<Value> val) {
return val->IsObject() && val->ToObject()->InternalFieldCount() == 1;
}
Handle<Value> IsWeakRef (const Arguments& args) {
HandleScope scope;
return Boolean::New(isWeakRef(args[0]));
}
Handle<Value> Get(const Arguments& args) {
HandleScope scope;
if (!isWeakRef(args[0])) {
Local<String> message = String::New("Weakref instance expected");
return ThrowException(Exception::TypeError(message));
}
Local<Object> proxy = args[0]->ToObject();
const bool dead = IsDead(proxy);
if (dead) return Undefined();
Handle<Object> obj = Unwrap(proxy);
return scope.Close(obj);
}
Handle<Value> IsNearDeath(const Arguments& args) {
HandleScope scope;
if (!isWeakRef(args[0])) {
Local<String> message = String::New("Weakref instance expected");
return ThrowException(Exception::TypeError(message));
}
Local<Object> proxy = args[0]->ToObject();
proxy_container *cont = reinterpret_cast<proxy_container*>(
proxy->GetPointerFromInternalField(0));
assert(cont != NULL);
Handle<Boolean> rtn = Boolean::New(cont->target.IsNearDeath());
return scope.Close(rtn);
}
Handle<Value> IsDead(const Arguments& args) {
HandleScope scope;
if (!isWeakRef(args[0])) {
Local<String> message = String::New("Weakref instance expected");
return ThrowException(Exception::TypeError(message));
}
Local<Object> proxy = args[0]->ToObject();
const bool dead = IsDead(proxy);
return Boolean::New(dead);
}
Handle<Value> AddCallback(const Arguments& args) {
HandleScope scope;
if (!isWeakRef(args[0])) {
Local<String> message = String::New("Weakref instance expected");
return ThrowException(Exception::TypeError(message));
}
Local<Object> proxy = args[0]->ToObject();
AddCallback(proxy, Handle<Function>::Cast(args[1]));
return Undefined();
}
Handle<Value> Callbacks(const Arguments& args) {
HandleScope scope;
if (!isWeakRef(args[0])) {
Local<String> message = String::New("Weakref instance expected");
return ThrowException(Exception::TypeError(message));
}
Local<Object> proxy = args[0]->ToObject();
return scope.Close(GetCallbacks(proxy));
}
void Initialize(Handle<Object> target) {
HandleScope scope;
proxyClass = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
proxyClass->SetNamedPropertyHandler(WeakNamedPropertyGetter,
WeakNamedPropertySetter,
WeakNamedPropertyQuery,
WeakNamedPropertyDeleter,
WeakPropertyEnumerator);
proxyClass->SetIndexedPropertyHandler(WeakIndexedPropertyGetter,
WeakIndexedPropertySetter,
WeakIndexedPropertyQuery,
WeakIndexedPropertyDeleter,
WeakPropertyEnumerator);
proxyClass->SetInternalFieldCount(1);
NODE_SET_METHOD(target, "get", Get);
NODE_SET_METHOD(target, "create", Create);
NODE_SET_METHOD(target, "isWeakRef", IsWeakRef);
NODE_SET_METHOD(target, "isNearDeath", IsNearDeath);
NODE_SET_METHOD(target, "isDead", IsDead);
NODE_SET_METHOD(target, "callbacks", Callbacks);
NODE_SET_METHOD(target, "addCallback", AddCallback);
}
} // anonymous namespace
NODE_MODULE(weakref, Initialize);

20
vcbuild.bat

@ -28,6 +28,7 @@ set msi=
set licensertf=
set upload=
set jslint=
set buildnodeweak=
set noetw=
set noetw_arg=
set noetw_msi_arg=
@ -51,7 +52,8 @@ if /i "%1"=="test-internet" set test=test-internet&goto arg-ok
if /i "%1"=="test-pummel" set test=test-pummel&goto arg-ok
if /i "%1"=="test-simple" set test=test-simple&goto arg-ok
if /i "%1"=="test-message" set test=test-message&goto arg-ok
if /i "%1"=="test-all" set test=test-all&goto arg-ok
if /i "%1"=="test-gc" set test=test-gc&set buildnodeweak=1&goto arg-ok
if /i "%1"=="test-all" set test=test-all&set buildnodeweak=1&goto arg-ok
if /i "%1"=="test" set test=test&goto arg-ok
if /i "%1"=="msi" set msi=1&set licensertf=1&goto arg-ok
if /i "%1"=="upload" set upload=1&goto arg-ok
@ -62,6 +64,7 @@ echo Warning: ignoring invalid command line option `%1`.
:arg-ok
shift
goto next-arg
:args-done
if defined upload goto upload
if defined jslint goto jslint
@ -139,13 +142,24 @@ if "%test%"=="test-internet" set test_args=%test_args% internet
if "%test%"=="test-pummel" set test_args=%test_args% pummel
if "%test%"=="test-simple" set test_args=%test_args% simple
if "%test%"=="test-message" set test_args=%test_args% message
if "%test%"=="test-gc" set test_args=%test_args% gc
if "%test%"=="test-all" set test_args=%test_args%
:build-node-weak
@rem Build node-weak if required
if "%buildnodeweak%"=="" goto run-tests
"%config%\node" deps\npm\node_modules\node-gyp\bin\node-gyp rebuild --directory="%~dp0test\gc\node_modules\weak" --nodedir="%~dp0."
if errorlevel 1 goto build-node-weak-failed
goto run-tests
:build-node-weak-failed
echo Failed to build node-weak.
goto exit
:run-tests
echo running 'python tools/test.py %test_args%'
python tools/test.py %test_args%
if "%test%"=="test" goto jslint
goto exit
:create-msvs-files-failed

Loading…
Cancel
Save