From b5b3226e10feff70dd6d4a84dae8db42d92b5ea9 Mon Sep 17 00:00:00 2001 From: irbull Date: Fri, 15 May 2015 06:59:24 -0700 Subject: [PATCH] Adds a twin() method to V8Value The twin() method will return a new Java object pointing at the same V8Value. Care is taken to ensure the same type is returned (V8Object, V8Function, V8Array). The twin will mimic any changes made to the original (since they are the same V8Objects), but can be released independently. --- jni/com_eclipsesource_v8_V8Impl.cpp | 8 ++ jni/com_eclipsesource_v8_V8Impl.h | 8 ++ src/main/java/com/eclipsesource/v8/V8.java | 11 ++ .../java/com/eclipsesource/v8/V8Array.java | 9 ++ .../java/com/eclipsesource/v8/V8Function.java | 9 ++ .../java/com/eclipsesource/v8/V8Object.java | 14 +- .../java/com/eclipsesource/v8/V8Value.java | 31 ++++- .../com/eclipsesource/v8/V8ObjectTest.java | 129 ++++++++++++++++++ 8 files changed, 211 insertions(+), 8 deletions(-) diff --git a/jni/com_eclipsesource_v8_V8Impl.cpp b/jni/com_eclipsesource_v8_V8Impl.cpp index bdab49d34..fffb83112 100644 --- a/jni/com_eclipsesource_v8_V8Impl.cpp +++ b/jni/com_eclipsesource_v8_V8Impl.cpp @@ -262,6 +262,14 @@ JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1initNewV8Object reinterpret_cast(v8RuntimePtr)->objects[objectHandle]->Reset(reinterpret_cast(v8RuntimePtr)->isolate, obj); } +JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1createTwin + (JNIEnv *env, jobject, jlong v8RuntimePtr, jint objectHandle, jint twinObjectHandle) { + Isolate* isolate = SETUP(env, v8RuntimePtr, ); + Handle obj = Local::New(isolate, *reinterpret_cast(v8RuntimePtr)->objects[objectHandle]); + createPersistentContainer(reinterpret_cast(v8RuntimePtr), twinObjectHandle); + reinterpret_cast(v8RuntimePtr)->objects[twinObjectHandle]->Reset(reinterpret_cast(v8RuntimePtr)->isolate, obj); +} + JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1initNewV8Array (JNIEnv *env, jobject, jlong v8RuntimePtr, jint arrayHandle) { Isolate* isolate = SETUP(env, v8RuntimePtr, ); diff --git a/jni/com_eclipsesource_v8_V8Impl.h b/jni/com_eclipsesource_v8_V8Impl.h index f687a8b96..4ca78ed05 100644 --- a/jni/com_eclipsesource_v8_V8Impl.h +++ b/jni/com_eclipsesource_v8_V8Impl.h @@ -35,6 +35,14 @@ extern "C" { JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1initNewV8Object (JNIEnv *, jobject, jlong, jint); +/* + * Class: com_eclipsesource_v8_V8 + * Method: _createTwin + * Signature: (JII)V + */ +JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1createTwin + (JNIEnv *, jobject, jlong, jint, jint); + /* * Class: com_eclipsesource_v8_V8 * Method: _releaseRuntime diff --git a/src/main/java/com/eclipsesource/v8/V8.java b/src/main/java/com/eclipsesource/v8/V8.java index 4a0e5cadb..838148790 100644 --- a/src/main/java/com/eclipsesource/v8/V8.java +++ b/src/main/java/com/eclipsesource/v8/V8.java @@ -183,6 +183,11 @@ public int executeIntegerScript(final String script, final String scriptName, fi return executeIntegerScript(v8RuntimePtr, script, scriptName, lineNumber); } + void createTwin(final V8Value value, final int twinObjectHandle) { + checkThread(); + createTwin(v8RuntimePtr, value.getHandle(), twinObjectHandle); + } + public double executeDoubleScript(final String script) { return executeDoubleScript(script, null, 0); } @@ -483,6 +488,10 @@ protected void initNewV8Object(final long v8RuntimePtr, final int objectHandle) _initNewV8Object(v8RuntimePtr, objectHandle); } + protected void createTwin(final long v8RuntimePtr, final int objectHandle, final int twinObjectHandle) { + _createTwin(v8RuntimePtr, objectHandle, twinObjectHandle); + } + protected int executeIntegerScript(final long v8RuntimePtr, final String script, final String scriptName, final int lineNumber) { return _executeIntegerScript(v8RuntimePtr, script, scriptName, lineNumber); } @@ -741,6 +750,8 @@ protected void terminateExecution(final long v8RuntimePtr) { private native void _initNewV8Object(long v8RuntimePtr, int objectHandle); + private native void _createTwin(long v8RuntimePtr, int objectHandle, int twinObjectHandle); + private native void _releaseRuntime(long v8RuntimePtr); private native long _createIsolate(String globalAlias); diff --git a/src/main/java/com/eclipsesource/v8/V8Array.java b/src/main/java/com/eclipsesource/v8/V8Array.java index 76521b71a..648ec1e49 100644 --- a/src/main/java/com/eclipsesource/v8/V8Array.java +++ b/src/main/java/com/eclipsesource/v8/V8Array.java @@ -21,6 +21,15 @@ public V8Array(final V8 v8) { v8.checkThread(); } + @Override + protected V8Value createTwin(final int newHandle) { + return new V8Array(v8, newHandle); + } + + protected V8Array(final V8 v8, final int objectHandle) { + super(v8, objectHandle); + } + @Override protected void initialize(final long runtimePtr, final int objectHandle) { v8.initNewV8Array(runtimePtr, objectHandle); diff --git a/src/main/java/com/eclipsesource/v8/V8Function.java b/src/main/java/com/eclipsesource/v8/V8Function.java index 74a999aa4..4c326c3af 100644 --- a/src/main/java/com/eclipsesource/v8/V8Function.java +++ b/src/main/java/com/eclipsesource/v8/V8Function.java @@ -16,6 +16,15 @@ protected V8Function(final V8 v8) { super(v8); } + protected V8Function(final V8 v8, final int objectHandle) { + super(v8, objectHandle); + } + + @Override + protected V8Value createTwin(final int newHandle) { + return new V8Function(v8, newHandle); + } + public Object call(final V8Object receiver, final V8Array parameters) { v8.checkThread(); checkReleaesd(); diff --git a/src/main/java/com/eclipsesource/v8/V8Object.java b/src/main/java/com/eclipsesource/v8/V8Object.java index a34709fa1..0c14a0620 100644 --- a/src/main/java/com/eclipsesource/v8/V8Object.java +++ b/src/main/java/com/eclipsesource/v8/V8Object.java @@ -18,18 +18,18 @@ protected V8Object() { } + @Override + protected V8Value createTwin(final int newHandle) { + return new V8Object(v8, newHandle); + } + protected V8Object(final V8 v8, final int objectHandle) { - if (v8 == null) { - this.v8 = (V8) this; - } - this.objectHandle = objectHandle; - released = false; + super(v8, objectHandle); } public V8Object(final V8 v8) { - this.v8 = v8; + super(v8); v8.checkThread(); - objectHandle = v8ObjectInstanceCounter++; initialize(v8.getV8RuntimePtr(), objectHandle); } diff --git a/src/main/java/com/eclipsesource/v8/V8Value.java b/src/main/java/com/eclipsesource/v8/V8Value.java index 494ca3c86..e2ff0dcb2 100644 --- a/src/main/java/com/eclipsesource/v8/V8Value.java +++ b/src/main/java/com/eclipsesource/v8/V8Value.java @@ -28,10 +28,26 @@ abstract public class V8Value { protected int objectHandle; protected boolean released = true; - public V8Value() { + protected V8Value() { super(); } + public V8Value(final V8 v8) { + this.v8 = v8; + objectHandle = v8ObjectInstanceCounter++; + } + + protected V8Value(final V8 v8, final int objectHandle) { + if (v8 == null) { + this.v8 = (V8) this; + } else { + this.v8 = v8; + v8.addObjRef(); + } + this.objectHandle = objectHandle; + released = false; + } + protected void initialize(final long runtimePtr, final int objectHandle) { v8.initNewV8Object(runtimePtr, objectHandle); v8.addObjRef(); @@ -51,6 +67,19 @@ public V8 getRutime() { return v8; } + public V8Value twin() { + if (isUndefined()) { + return this; + } + v8.checkThread(); + v8.checkReleaesd(); + int twinHandle = v8ObjectInstanceCounter++; + v8.createTwin(this, twinHandle); + return createTwin(twinHandle); + } + + protected abstract V8Value createTwin(int twinObjectHandle); + public void release() { v8.checkThread(); if ( !released ) { diff --git a/src/test/java/com/eclipsesource/v8/V8ObjectTest.java b/src/test/java/com/eclipsesource/v8/V8ObjectTest.java index 42cca985e..9d78e6243 100644 --- a/src/test/java/com/eclipsesource/v8/V8ObjectTest.java +++ b/src/test/java/com/eclipsesource/v8/V8ObjectTest.java @@ -1041,4 +1041,133 @@ public void testToStringInCallback() { a.release(); } + @Test + public void testV8ObjectTwinEqual() { + V8Object v8Object = new V8Object(v8); + + V8Value twin = v8Object.twin(); + + assertNotSame(v8Object, twin); + assertTrue(v8Object.equals(twin)); + assertTrue(twin.equals(v8Object)); + v8Object.release(); + twin.release(); + } + + @Test + public void testV8ObjectTwinSameValue() { + V8Object v8Object = new V8Object(v8); + + V8Value twin = v8Object.twin(); + + assertNotSame(v8Object, twin); + assertTrue(v8Object.sameValue(twin)); + assertTrue(twin.sameValue(v8Object)); + v8Object.release(); + twin.release(); + } + + @Test + public void testV8ObjectTwinStrictEquals() { + V8Object v8Object = new V8Object(v8); + + V8Value twin = v8Object.twin(); + + assertNotSame(v8Object, twin); + assertTrue(v8Object.strictEquals(twin)); + assertTrue(twin.strictEquals(v8Object)); + v8Object.release(); + twin.release(); + } + + @Test + public void testV8ObjectTwinSameHashCode() { + V8Object v8Object = new V8Object(v8); + + V8Value twin = v8Object.twin(); + + assertEquals(v8Object.hashCode(), twin.hashCode()); + v8Object.release(); + twin.release(); + } + + @Test + public void testTwinIsObject() { + V8Object v8Object = new V8Object(v8); + + V8Value twin = v8Object.twin(); + + assertTrue(twin instanceof V8Object); + v8Object.release(); + twin.release(); + } + + @Test + public void testTwinIsArray() { + V8Object v8Object = new V8Array(v8); + + V8Value twin = v8Object.twin(); + + assertTrue(twin instanceof V8Array); + v8Object.release(); + twin.release(); + } + + @Test + public void testTwinIsFunction() { + v8.executeVoidScript("function add(x, y) {return x+y;}"); + V8Object v8Object = v8.getObject("add"); + + V8Value twin = v8Object.twin(); + + assertTrue(twin instanceof V8Function); + v8Object.release(); + twin.release(); + } + + @Test + public void testTwinIsUndefined() { + V8Object v8Object = (V8Object) V8.getUndefined(); + + V8Value twin = v8Object.twin(); + + assertTrue(twin.isUndefined()); + v8Object.release(); + twin.release(); + } + + @Test + public void testReleaseTwinDoesNotReleaseOriginal() { + V8Object v8Object = new V8Object(v8); + V8Value twin = v8Object.twin(); + + twin.release(); + + assertFalse(v8Object.isReleased()); + v8Object.release(); + } + + @Test + public void testReleaseObjectDoesNotReleaseTwin() { + V8Object v8Object = new V8Object(v8); + V8Value twin = v8Object.twin(); + + v8Object.release(); + + assertFalse(twin.isReleased()); + twin.release(); + } + + @Test + public void testTwinMimicsObject() { + V8Object v8Object = new V8Object(v8); + V8Value twin = v8Object.twin(); + + v8Object.add("foo", "bar"); + + assertEquals("bar", ((V8Object) twin).getString("foo")); + v8Object.release(); + twin.release(); + } + }