diff --git a/build.third_step1.gradle b/build.third_step1.gradle index 71377e1f2..684a4a092 100644 --- a/build.third_step1.gradle +++ b/build.third_step1.gradle @@ -34,7 +34,8 @@ sourceSets{ "${srcDir}/fine-commons-fileupload/src", "${srcDir}/fine-commons-lang3/src", "${srcDir}/fine-commons-collections4/src", - "${srcDir}/fine-joda/src" + "${srcDir}/fine-joda/src", + "${srcDir}/fine-j2v8/src" ] } } diff --git a/fine-j2v8/src/com/eclipsesource/v8/JavaCallback.java b/fine-j2v8/src/com/eclipsesource/v8/JavaCallback.java new file mode 100644 index 000000000..2bf5a19b3 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/JavaCallback.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * Classes that implement this interface provide a method + * which can be invoked from JavaScript. The method can return + * a result. + * + * After creating an instance of a class that implements this + * interface it can be registered as a Callback on a V8Object. + */ +public interface JavaCallback { + + /** + * Called when a JS Function invokes a the registered Java + * method. + * + * @param receiver The V8Object that the function was called on. + * @param parameters The parameters passed to the JS Function. The + * parameter array does not need to be released, by any objects accessed + * from the array must be. + * + * @return A result that should be passed back to JavaScript. The + * result must be either an Integer, Double, Boolean, String or V8Value. + */ + public Object invoke(V8Object receiver, V8Array parameters); + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/JavaVoidCallback.java b/fine-j2v8/src/com/eclipsesource/v8/JavaVoidCallback.java new file mode 100644 index 000000000..7298d5a40 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/JavaVoidCallback.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * Classes that implement this interface provide a method + * which can be invoked from JavaScript. + * + * After creating an instance of a class that implements this + * interface it can be registered as a Callback on a V8Object. + */ +public interface JavaVoidCallback { + + /** + * Called when a JS Function invokes a the registered Java + * method. + * + * @param receiver The V8Object that the function was called on. + * @param parameters The parameters passed to the JS Function. The + * parameter array does not need to be released, by any objects accessed + * from the array must be. + */ + public void invoke(V8Object receiver, V8Array parameters); + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/LibraryLoader.java b/fine-j2v8/src/com/eclipsesource/v8/LibraryLoader.java new file mode 100644 index 000000000..84b9ba4aa --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/LibraryLoader.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +class LibraryLoader { + + static final String SEPARATOR; + static final String DELIMITER; + + static final String SWT_LIB_DIR = ".j2v8"; + + static { + DELIMITER = System.getProperty("line.separator"); //$NON-NLS-1$ + SEPARATOR = System.getProperty("file.separator"); //$NON-NLS-1$ + } + + private static String computeLibraryShortName() { + String base = "j2v8"; + String osSuffix = getOS(); + String archSuffix = getArchSuffix(); + return base + "_" + osSuffix + "_" + archSuffix; + } + + private static String computeLibraryFullName() { + return "lib" + computeLibraryShortName() + "." + getOSFileExtension(); + } + + static void loadLibrary(final String tempDirectory) { + if ( isAndroid() ) { + System.loadLibrary("j2v8"); + return; + } + StringBuffer message = new StringBuffer(); + String libShortName = computeLibraryShortName(); + String libFullName = computeLibraryFullName(); + String ideLocation = System.getProperty("user.dir") + SEPARATOR + "jni" + SEPARATOR + computeLibraryFullName(); + String path = null; + + /* Try loading library from java library path */ + if (load(libShortName, message)) { + return; + } + + /* Try loading library from the IDE location */ + if (new File(ideLocation).exists()) { + if (load(ideLocation, message)) { + return; + } + } + + if (tempDirectory != null) { + path = tempDirectory; + } else { + path = System.getProperty("user.home"); //$NON-NLS-1$ + } + + if (extract(path + SEPARATOR + libFullName, libFullName, message)) { + return; + } + + /* Failed to find the library */ + throw new UnsatisfiedLinkError("Could not load J2V8 library. Reasons: " + message.toString()); //$NON-NLS-1$ + } + + static boolean load(final String libName, final StringBuffer message) { + try { + if (libName.indexOf(SEPARATOR) != -1) { + System.load(libName); + } else { + System.loadLibrary(libName); + } + return true; + } catch (UnsatisfiedLinkError e) { + if (message.length() == 0) { + message.append(DELIMITER); + } + message.append('\t'); + message.append(e.getMessage()); + message.append(DELIMITER); + } + return false; + } + + static boolean extract(final String fileName, final String mappedName, final StringBuffer message) { + FileOutputStream os = null; + InputStream is = null; + File file = new File(fileName); + boolean extracted = false; + try { + if (file.exists()) { + file.delete(); + } + is = LibraryLoader.class.getResourceAsStream("/" + mappedName); //$NON-NLS-1$ + if (is != null) { + extracted = true; + int read; + byte[] buffer = new byte[4096]; + os = new FileOutputStream(fileName); + while ((read = is.read(buffer)) != -1) { + os.write(buffer, 0, read); + } + os.close(); + is.close(); + chmod("755", fileName); + if (load(fileName, message)) { + return true; + } + } + } catch (Throwable e) { + try { + if (os != null) { + os.close(); + } + } catch (IOException e1) { + } + try { + if (is != null) { + is.close(); + } + } catch (IOException e1) { + } + if (extracted && file.exists()) { + file.delete(); + } + } + return false; + } + + static void chmod(final String permision, final String path) { + if (isWindows()) { + return; + } + try { + Runtime.getRuntime().exec(new String[] { "chmod", permision, path }).waitFor(); //$NON-NLS-1$ + } catch (Throwable e) { + } + } + + static String getOsName() { + return System.getProperty("os.name") + System.getProperty("java.specification.vendor"); + } + + static boolean isWindows() { + return getOsName().startsWith("Windows"); + } + + static boolean isMac() { + return getOsName().startsWith("Mac"); + } + + static boolean isLinux() { + return getOsName().startsWith("Linux"); + } + + static boolean isNativeClient() { + return getOsName().startsWith("nacl"); + } + + static boolean isAndroid() { + return getOsName().contains("Android"); + } + + static String getArchSuffix() { + String arch = System.getProperty("os.arch"); + if (arch.equals("i686")) { + return "x86"; + } else if (arch.equals("amd64")) { + return "x86_64"; + } else if (arch.equals("nacl")) { + return "armv7l"; + } else if (arch.equals("aarch64")) { + return "armv7l"; + } + return arch; + } + + static String getOSFileExtension() { + if (isWindows()) { + return "dll"; + } else if (isMac()) { + return "dylib"; + } else if (isLinux()) { + return "so"; + } else if (isNativeClient()) { + return "so"; + } + throw new UnsatisfiedLinkError("Unsupported platform: " + getOsName()); + } + + static String getOS() { + if (isWindows()) { + return "win32"; + } else if (isMac()) { + return "macosx"; + } else if (isLinux() && !isAndroid()) { + return "linux"; + } else if (isAndroid()) { + return "android"; + } + throw new UnsatisfiedLinkError("Unsupported platform: " + getOsName()); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/NodeJS.java b/fine-j2v8/src/com/eclipsesource/v8/NodeJS.java new file mode 100644 index 000000000..0877ff026 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/NodeJS.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * An isolate NodeJS runtime. + * + * This class is only available on some platforms. In particular any methods + * on this class, on an Android device, will lead to an UnsupportedOperationException. + */ +public class NodeJS { + + private static final String TMP_JS_EXT = ".js.tmp"; + private static final String NEXT_TICK = "nextTick"; + private static final String PROCESS = "process"; + private static final String GLOBAL = "global"; + private static final String STARTUP_CALLBACK = "__run"; + private static final String STARTUP_SCRIPT = "global." + STARTUP_CALLBACK + "(require, exports, module, __filename, __dirname);"; + private static final String STARTUP_SCRIPT_NAME = "startup"; + + private V8 v8; + private V8Function require; + + /** + * Creates a NodeJS Runtime + * + * @return The NodeJS runtime. + * + * May throw an UnsupportedOperationException if node.js integration has not + * been compiled for your platform. + */ + public static NodeJS createNodeJS() { + return createNodeJS(null); + } + + /** + * Creates a NodeJS runtime and executes a JS Script + * + * @param file The JavaScript to execute or null for no script. + * @return The NodeJS runtime. + * + * May throw an UnsupportedOperationException if node.js integration has not + * been compiled for your platform. + */ + public static NodeJS createNodeJS(final File file) { + V8 v8 = V8.createV8Runtime(GLOBAL); + final NodeJS node = new NodeJS(v8); + v8.registerJavaMethod(new JavaVoidCallback() { + + @Override + public void invoke(final V8Object receiver, final V8Array parameters) { + V8Function require = (V8Function) parameters.get(0); + try { + node.init(require.twin()); + } finally { + require.release(); + } + } + }, STARTUP_CALLBACK); + try { + File startupScript = createTemporaryScriptFile(STARTUP_SCRIPT, STARTUP_SCRIPT_NAME); + try { + v8.createNodeRuntime(startupScript.getAbsolutePath()); + } finally { + startupScript.delete(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + if (file != null) { + node.exec(file); + } + return node; + } + + /** + * Returns the V8 runtime being used for this NodeJS instance. + * + * @return The V8 Runtime. + */ + public V8 getRuntime() { + return v8; + } + + /** + * Handles the next message in the message loop. Returns True + * if there are more messages to handle, false otherwise. + * + * @return True if there are more messages to handle, false otherwise. + */ + public boolean handleMessage() { + v8.checkThread(); + return v8.pumpMessageLoop(); + } + + /** + * Releases the NodeJS runtime. + */ + public void release() { + v8.checkThread(); + if (!require.isReleased()) { + require.release(); + } + if (!v8.isReleased()) { + v8.release(); + } + } + + /** + * Returns true if there are more messages to process, false otherwise. + * + * @return True if there are more messages to process, false otherwise. + */ + public boolean isRunning() { + v8.checkThread(); + return v8.isRunning(); + } + + /** + * Invokes NodeJS require() on the specified file. This will load the module, execute + * it and return the exports object to the caller. The exports object must be released. + * + * @param file The module to load. + * @return The exports object. + */ + public V8Object require(final File file) { + v8.checkThread(); + V8Array requireParams = new V8Array(v8); + try { + requireParams.push(file.getAbsolutePath()); + return (V8Object) require.call(null, requireParams); + } finally { + requireParams.release(); + } + } + + /** + * Execute a NodeJS script. This will load the script and execute it on the + * next tick. This is the same as how NodeJS executes scripts at startup. Since + * the script won't actually run until the next tick, this method does not return + * a result. + * + * @param file The script to execute. + */ + public void exec(final File file) { + V8Function scriptExecution = createScriptExecutionCallback(file); + V8Object process = null; + V8Array parameters = null; + try { + process = v8.getObject(PROCESS); + parameters = new V8Array(v8); + parameters.push(scriptExecution); + process.executeObjectFunction(NEXT_TICK, parameters); + } finally { + safeRelease(process); + safeRelease(parameters); + safeRelease(scriptExecution); + } + } + + private V8Function createScriptExecutionCallback(final File file) { + V8Function v8Function = new V8Function(v8, new JavaCallback() { + @Override + public Object invoke(final V8Object receiver, final V8Array parameters) { + V8Array requireParams = new V8Array(v8); + try { + requireParams.push(file.getAbsolutePath()); + return require.call(null, requireParams); + } finally { + requireParams.release(); + } + } + }); + return v8Function; + } + + private void safeRelease(final Releasable releasable) { + if (releasable != null) { + releasable.release(); + } + } + + private NodeJS(final V8 v8) { + this.v8 = v8; + } + + private void init(final V8Function require) { + this.require = require; + } + + private static File createTemporaryScriptFile(final String script, final String name) throws IOException { + File tempFile = File.createTempFile(name, TMP_JS_EXT); + PrintWriter writer = new PrintWriter(tempFile, "UTF-8"); + try { + writer.print(script); + } finally { + writer.close(); + } + return tempFile; + } +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/ReferenceHandler.java b/fine-j2v8/src/com/eclipsesource/v8/ReferenceHandler.java new file mode 100644 index 000000000..740dc18ee --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/ReferenceHandler.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * Callback used to track when native handles are created and released. + */ +public interface ReferenceHandler { + + /** + * Called when a native handle is first created. The V8Value + * referenced by that handle is passed as a parameter. + * + * @param object The V8Value referenced by the handle + */ + public void v8HandleCreated(V8Value object); + + /** + * Called when a native handle is released. The V8Value + * referenced by that handle is passed as a parameter. + * + * @param object The V8Value referenced by the handle + */ + public void v8HandleDisposed(V8Value object); + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/Releasable.java b/fine-j2v8/src/com/eclipsesource/v8/Releasable.java new file mode 100644 index 000000000..0017787da --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/Releasable.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * An interface used to denote all V8 Classes which can be released. + */ +public interface Releasable { + + /** + * Release the underlying resources. Once an object is released + * it typically cannot be used again. + */ + void release(); + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8.java b/fine-j2v8/src/com/eclipsesource/v8/V8.java new file mode 100644 index 000000000..9d8d86849 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8.java @@ -0,0 +1,1435 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.eclipsesource.v8.utils.V8Executor; +import com.eclipsesource.v8.utils.V8Map; + +/** + * An isolated V8Runtime. All JavaScript execution must exist + * on a single runtime, and data is not shared between runtimes. + * A runtime must be created and released when finished. + * + * All access to a runtime must come from the same thread, unless + * the thread explicitly gives up control using the V8Locker. + * + * A public static factory method can be used to create the runtime. + * + * V8 runtime = V8.createV8Runtime(); + * + */ +public class V8 extends V8Object { + + private static Object lock = new Object(); + private volatile static int runtimeCounter = 0; + private static String v8Flags = null; + private static boolean initialized = false; + + private final V8Locker locker; + private long objectReferences = 0; + private long v8RuntimePtr = 0; + private List resources = null; + private V8Map executors = null; + private boolean forceTerminateExecutors = false; + private Map functionRegistry = new HashMap(); + private LinkedList referenceHandlers = new LinkedList(); + + private static boolean nativeLibraryLoaded = false; + private static Error nativeLoadError = null; + private static Exception nativeLoadException = null; + private static V8Value undefined = new Undefined(); + private static Object invalid = new Object(); + + private class MethodDescriptor { + Object object; + Method method; + JavaCallback callback; + JavaVoidCallback voidCallback; + boolean includeReceiver; + } + + private synchronized static void load(final String tmpDirectory) { + try { + LibraryLoader.loadLibrary(tmpDirectory); + nativeLibraryLoaded = true; + } catch (Error e) { + nativeLoadError = e; + } catch (Exception e) { + nativeLoadException = e; + } + } + + /** + * Determines if the native libraries are loaded. + * + * @return Returns true if the native libraries are loaded, + * false otherwise. + */ + public static boolean isLoaded() { + return nativeLibraryLoaded; + } + + /** + * Sets the V8 flags on the platform. All runtimes will be created + * with the same flags. Flags must be set before the runtime is + * created. + * + * @param flags The flags to set on V8 + */ + public static void setFlags(final String flags) { + v8Flags = flags; + initialized = false; + } + + /** + * Creates a new V8Runtime and loads the required + * native libraries if they are not already loaded. + * The current thread is given the lock to this runtime. + * + * @return A new isolated V8 Runtime. + */ + public static V8 createV8Runtime() { + return createV8Runtime(null, null); + } + + /** + * Creates a new V8Runtime and loads the required native libraries if they + * are not already loaded. An alias is also set for the global scope. For example, + * 'window' can be set as the global scope name. + * + * The current thread is given the lock to this runtime. + * + * @param globalAlias The name to associate with the global scope. + * + * @return A new isolated V8 Runtime. + */ + public static V8 createV8Runtime(final String globalAlias) { + return createV8Runtime(globalAlias, null); + } + + /** + * Creates a new V8Runtime and loads the required native libraries if they + * are not already loaded. An alias is also set for the global scope. For example, + * 'window' can be set as the global scope name. + * + * The current thread is given the lock to this runtime. + * + * @param globalAlias The name to associate with the global scope. + * @param tempDirectory The name of the directory to extract the native + * libraries too. + * + * @return A new isolated V8 Runtime. + */ + public static V8 createV8Runtime(final String globalAlias, final String tempDirectory) { + if (!nativeLibraryLoaded) { + synchronized (lock) { + if (!nativeLibraryLoaded) { + load(tempDirectory); + } + } + } + checkNativeLibraryLoaded(); + if (!initialized) { + _setFlags(v8Flags); + initialized = true; + } + V8 runtime = new V8(globalAlias); + synchronized (lock) { + runtimeCounter++; + } + return runtime; + } + + /** + * Adds a ReferenceHandler to track when new V8Objects are created. + * + * @param handler The ReferenceHandler to add + */ + public void addReferenceHandler(final ReferenceHandler handler) { + referenceHandlers.add(0, handler); + } + + /** + * Removes an existing ReferenceHandler from the collection of reference handlers. + * If the ReferenceHandler does not exist in the collection, it is ignored. + * + * @param handler The reference handler to remove + */ + public void removeReferenceHandler(final ReferenceHandler handler) { + referenceHandlers.remove(handler); + } + + private void notifyReferenceCreated(final V8Value object) { + for (ReferenceHandler referenceHandler : referenceHandlers) { + referenceHandler.v8HandleCreated(object); + } + } + + private void notifyReferenceDisposed(final V8Value object) { + for (ReferenceHandler referenceHandler : referenceHandlers) { + referenceHandler.v8HandleDisposed(object); + } + } + + private static void checkNativeLibraryLoaded() { + if (!nativeLibraryLoaded) { + if (nativeLoadError != null) { + throw new IllegalStateException("J2V8 native library not loaded", nativeLoadError); + } else if (nativeLoadException != null) { + throw new IllegalStateException("J2V8 native library not loaded", nativeLoadException); + } else { + throw new IllegalStateException("J2V8 native library not loaded"); + } + } + } + + protected V8() { + this(null); + } + + protected V8(final String globalAlias) { + super(null); + released = false; + locker = new V8Locker(); + checkThread(); + v8RuntimePtr = _createIsolate(globalAlias); + objectHandle = _getGlobalObject(v8RuntimePtr); + } + + /** + * Returns an UNDEFINED constant. + * + * @return The UNDEFINED constant value. + */ + public static V8Value getUndefined() { + return undefined; + } + + /** + * Returns the number of active runtimes. + * + * @return The number of active runtimes. + */ + public static int getActiveRuntimes() { + return runtimeCounter; + } + + /** + * Returns the number of Object References for this runtime. + * + * @return The number of Object References on this runtime. + */ + public long getObjectReferenceCount() { + return objectReferences; + } + + protected long getV8RuntimePtr() { + return v8RuntimePtr; + } + + /** + * Gets the version of the V8 engine + * + * @return The version of the V8 Engine. + */ + public static String getV8Version() { + return _getVersion(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#release() + */ + @Override + public void release() { + release(true); + } + + /** + * Terminates any JavaScript executing on this runtime. Once + * the runtime is released, any executors that were spawned + * will also be force terminated. + */ + public void terminateExecution() { + forceTerminateExecutors = true; + terminateExecution(v8RuntimePtr); + } + + /** + * Release native resources associated with this runtime. Once + * released, a runtime cannot be reused. + * + * @param reportMemoryLeaks True if memory leaks should be + * reported by throwing an IllegalStateException if any + * objects were not released. + */ + public void release(final boolean reportMemoryLeaks) { + if (isReleased()) { + return; + } + checkThread(); + releaseResources(); + shutdownExecutors(forceTerminateExecutors); + if (executors != null) { + executors.clear(); + } + releaseNativeMethodDescriptors(); + synchronized (lock) { + runtimeCounter--; + } + _releaseRuntime(v8RuntimePtr); + v8RuntimePtr = 0L; + released = true; + if (reportMemoryLeaks && (objectReferences > 0)) { + throw new IllegalStateException(objectReferences + " Object(s) still exist in runtime"); + } + } + + private void releaseNativeMethodDescriptors() { + Set nativeMethodDescriptors = functionRegistry.keySet(); + for (Long nativeMethodDescriptor : nativeMethodDescriptors) { + releaseMethodDescriptor(v8RuntimePtr, nativeMethodDescriptor); + } + } + + private void releaseResources() { + if (resources != null) { + for (Releasable releasable : resources) { + releasable.release(); + } + resources.clear(); + resources = null; + } + } + + /** + * Registers an executor with this runtime. An executor is another + * runtime with its own thread. By registering an executor, it can be + * terminated when this runtime is released. + * + * @param key The key to associate the executor with. + * @param executor The executor itself. + */ + public void registerV8Executor(final V8Object key, final V8Executor executor) { + checkThread(); + if (executors == null) { + executors = new V8Map(); + } + executors.put(key, executor); + } + + /** + * Removes the executor from this runtime. The executor is + * *NOT* shutdown, simply removed from the list of known + * executors. + * + * @param key The key the executor was associated with. + * @return The executor or null if it does not exist. + */ + public V8Executor removeExecutor(final V8Object key) { + checkThread(); + if (executors == null) { + return null; + } + return executors.remove(key); + } + + /** + * Returns the executor associated with the given key. + * + * @param key The key the executor was associated with. + * @return The executor or null if it does not exist. + */ + public V8Executor getExecutor(final V8Object key) { + checkThread(); + if (executors == null) { + return null; + } + return executors.get(key); + } + + /** + * Shutdown all executors associated with this runtime. + * If force terminate is specified, it will forcefully terminate + * the executors, otherwise it will simply signal that they + * should terminate. + * + * @param forceTerminate Specify if the executors should be + * forcefully terminated, or simply notified to shutdown when ready. + */ + public void shutdownExecutors(final boolean forceTerminate) { + checkThread(); + if (executors == null) { + return; + } + for (V8Executor executor : executors.values()) { + if (forceTerminate) { + executor.forceTermination(); + } else { + executor.shutdown(); + } + } + } + + /** + * Registers a resource with this runtime. All registered + * resources will be released before the runtime is released. + * + * @param resource The resource to register. + */ + public void registerResource(final Releasable resource) { + checkThread(); + if (resources == null) { + resources = new ArrayList(); + } + resources.add(resource); + } + + /** + * Executes a JS Script on this runtime and returns the result as an integer. + * If the result is not an integer, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * + * @return The result of the script as an integer, or V8ResultUndefinedException if + * the result is not an integer. + */ + public int executeIntegerScript(final String script) { + return executeIntegerScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime and returns the result as an integer. + * If the result is not an integer, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for excepton purposes. + * + * @return The result of the script as an integer, or V8ResultUndefinedException if + * the result is not an integer. + */ + public int executeIntegerScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + checkScript(script); + return executeIntegerScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + protected void createTwin(final V8Value value, final V8Value twin) { + checkThread(); + createTwin(v8RuntimePtr, value.getHandle(), twin.getHandle()); + } + + /** + * Executes a JS Script on this runtime and returns the result as a double. + * If the result is not a double, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * + * @return The result of the script as a double, or V8ResultUndefinedException if + * the result is not a double. + */ + public double executeDoubleScript(final String script) { + return executeDoubleScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime and returns the result as a double. + * If the result is not a double, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for exception stack trace purposes. + * + * @return The result of the script as a double, or V8ResultUndefinedException if + * the result is not a double. + */ + public double executeDoubleScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + checkScript(script); + return executeDoubleScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + /** + * Executes a JS Script on this runtime and returns the result as a String. + * If the result is not a String, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * + * @return The result of the script as a String, or V8ResultUndefinedException if + * the result is not a String. + */ + public String executeStringScript(final String script) { + return executeStringScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime and returns the result as a String. + * If the result is not a String, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for exception stack trace purposes. + * + * @return The result of the script as a String, or V8ResultUndefinedException if + * the result is not a String. + */ + public String executeStringScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + checkScript(script); + return executeStringScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + /** + * Executes a JS Script on this runtime and returns the result as a boolean. + * If the result is not a boolean, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * + * @return The result of the script as a boolean, or V8ResultUndefinedException if + * the result is not a boolean. + */ + public boolean executeBooleanScript(final String script) { + return executeBooleanScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime and returns the result as a boolean. + * If the result is not a boolean, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for exception stack trace purposes. + * + * @return The result of the script as a boolean, or V8ResultUndefinedException if + * the result is not a boolean. + */ + public boolean executeBooleanScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + checkScript(script); + return executeBooleanScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + /** + * Executes a JS Script on this runtime and returns the result as a V8Array. + * If the result is not a V8Array, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * + * @return The result of the script as a V8Array, or V8ResultUndefinedException if + * the result is not a V8Array. + */ + public V8Array executeArrayScript(final String script) { + return executeArrayScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime and returns the result as a V8Array. + * If the result is not a V8Array, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for exception stack trace purposes. + * + * @return The result of the script as a V8Array, or V8ResultUndefinedException if + * the result is not a V8Array. + */ + public V8Array executeArrayScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + Object result = this.executeScript(script, scriptName, lineNumber); + if (result instanceof V8Array) { + return (V8Array) result; + } + throw new V8ResultUndefined(); + } + + /** + * Executes a JS Script on this runtime and returns the result as a Java Object. + * Primitives will be boxed. + * + * @param script The script to execute. + * + * @return The result of the script as a Java Object. + */ + public Object executeScript(final String script) { + return executeScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime and returns the result as a Java Object. + * Primitives will be boxed. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for exception stack trace purposes. + * + * @return The result of the script as a Java Object. + */ + public Object executeScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + checkScript(script); + return executeScript(getV8RuntimePtr(), UNKNOWN, script, scriptName, lineNumber); + } + + /** + * Executes a JS Script on this runtime and returns the result as a V8Object. + * If the result is not a V8Object, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * + * @return The result of the script as a V8Object, or V8ResultUndefinedException if + * the result is not a V8Object. + */ + public V8Object executeObjectScript(final String script) { + return this.executeObjectScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime and returns the result as a V8Object. + * If the result is not a V8Object, then a V8ResultUndefinedException is thrown. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for exception stack trace purposes. + * + * @return The result of the script as a V8Object, or V8ResultUndefinedException if + * the result is not a V8Object. + */ + public V8Object executeObjectScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + Object result = this.executeScript(script, scriptName, lineNumber); + if (result instanceof V8Object) { + return (V8Object) result; + } + throw new V8ResultUndefined(); + } + + /** + * Executes a JS Script on this runtime. + * + * @param script The script to execute. + */ + public void executeVoidScript(final String script) { + executeVoidScript(script, null, 0); + } + + /** + * Executes a JS Script on this runtime. + * + * @param script The script to execute. + * @param scriptName The name of the script + * @param lineNumber The line number that is considered to be the first line of + * the script. Typically 0, but could be set to another value for exception stack trace purposes. + */ + public void executeVoidScript(final String script, final String scriptName, final int lineNumber) { + checkThread(); + checkScript(script); + executeVoidScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + /** + * Returns the locker associated with this runtime. The locker allows + * threads to give up control of the runtime and other threads to acquire + * control. + * + * @return The locker associated with this runtime. + */ + public V8Locker getLocker() { + return locker; + } + + /** + * Returns the unique build ID of the native library. + * + * @return The unique build ID of the Native library. + */ + public long getBuildID() { + return _getBuildID(); + } + + void checkThread() { + locker.checkThread(); + if (isReleased()) { + throw new Error("Runtime disposed error"); + } + } + + static void checkScript(final String script) { + if (script == null) { + throw new NullPointerException("Script is null"); + } + } + + void registerCallback(final Object object, final Method method, final long objectHandle, final String jsFunctionName, final boolean includeReceiver) { + MethodDescriptor methodDescriptor = new MethodDescriptor(); + methodDescriptor.object = object; + methodDescriptor.method = method; + methodDescriptor.includeReceiver = includeReceiver; + long methodID = registerJavaMethod(getV8RuntimePtr(), objectHandle, jsFunctionName, isVoidMethod(method)); + functionRegistry.put(methodID, methodDescriptor); + } + + void registerVoidCallback(final JavaVoidCallback callback, final long objectHandle, final String jsFunctionName) { + MethodDescriptor methodDescriptor = new MethodDescriptor(); + methodDescriptor.voidCallback = callback; + long methodID = registerJavaMethod(getV8RuntimePtr(), objectHandle, jsFunctionName, true); + functionRegistry.put(methodID, methodDescriptor); + } + + void registerCallback(final JavaCallback callback, final long objectHandle, final String jsFunctionName) { + long methodID = registerJavaMethod(getV8RuntimePtr(), objectHandle, jsFunctionName, false); + createAndRegisterMethodDescriptor(callback, methodID); + } + + void createAndRegisterMethodDescriptor(final JavaCallback callback, final long methodID) { + MethodDescriptor methodDescriptor = new MethodDescriptor(); + methodDescriptor.callback = callback; + functionRegistry.put(methodID, methodDescriptor); + } + + private boolean isVoidMethod(final Method method) { + Class returnType = method.getReturnType(); + if (returnType.equals(Void.TYPE)) { + return true; + } + return false; + } + + private Object getDefaultValue(final Class type) { + if (type.equals(V8Object.class)) { + return new Undefined(); + } else if (type.equals(V8Array.class)) { + return new V8Array.Undefined(); + } + return invalid; + } + + protected void disposeMethodID(final long methodID) { + functionRegistry.remove(methodID); + } + + protected Object callObjectJavaMethod(final long methodID, final V8Object receiver, final V8Array parameters) throws Throwable { + MethodDescriptor methodDescriptor = functionRegistry.get(methodID); + if (methodDescriptor.callback != null) { + return checkResult(methodDescriptor.callback.invoke(receiver, parameters)); + } + boolean hasVarArgs = methodDescriptor.method.isVarArgs(); + Object[] args = getArgs(receiver, methodDescriptor, parameters, hasVarArgs); + checkArgs(args); + try { + Object result = methodDescriptor.method.invoke(methodDescriptor.object, args); + return checkResult(result); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } catch (IllegalAccessException e) { + throw e; + } catch (IllegalArgumentException e) { + throw e; + } finally { + releaseArguments(args, hasVarArgs); + } + } + + private Object checkResult(final Object result) { + if (result == null) { + return result; + } + if (result instanceof Float) { + return ((Float) result).doubleValue(); + } + if ((result instanceof Integer) || (result instanceof Double) || (result instanceof Boolean) + || (result instanceof String)) { + return result; + } + if (result instanceof V8Value) { + if (((V8Value) result).isReleased()) { + throw new V8RuntimeException("V8Value already released"); + } + return result; + } + throw new V8RuntimeException("Unknown return type: " + result.getClass()); + } + + protected void callVoidJavaMethod(final long methodID, final V8Object receiver, final V8Array parameters) throws Throwable { + MethodDescriptor methodDescriptor = functionRegistry.get(methodID); + if (methodDescriptor.voidCallback != null) { + methodDescriptor.voidCallback.invoke(receiver, parameters); + return; + } + boolean hasVarArgs = methodDescriptor.method.isVarArgs(); + Object[] args = getArgs(receiver, methodDescriptor, parameters, hasVarArgs); + checkArgs(args); + try { + methodDescriptor.method.invoke(methodDescriptor.object, args); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } catch (IllegalAccessException e) { + throw e; + } catch (IllegalArgumentException e) { + throw e; + } finally { + releaseArguments(args, hasVarArgs); + } + } + + private void checkArgs(final Object[] args) { + for (Object argument : args) { + if (argument == invalid) { + throw new IllegalArgumentException("argument type mismatch"); + } + } + } + + private void releaseArguments(final Object[] args, final boolean hasVarArgs) { + if (hasVarArgs && ((args.length > 0) && (args[args.length - 1] instanceof Object[]))) { + Object[] varArgs = (Object[]) args[args.length - 1]; + for (Object object : varArgs) { + if (object instanceof V8Value) { + ((V8Value) object).release(); + } + } + } + for (Object arg : args) { + if (arg instanceof V8Value) { + ((V8Value) arg).release(); + } + } + } + + private Object[] getArgs(final V8Object receiver, final MethodDescriptor methodDescriptor, final V8Array parameters, final boolean hasVarArgs) { + int numberOfParameters = methodDescriptor.method.getParameterTypes().length; + int varArgIndex = hasVarArgs ? numberOfParameters - 1 : numberOfParameters; + Object[] args = setDefaultValues(new Object[numberOfParameters], methodDescriptor.method.getParameterTypes(), receiver, methodDescriptor.includeReceiver); + List varArgs = new ArrayList(); + populateParamters(parameters, varArgIndex, args, varArgs, methodDescriptor.includeReceiver); + if (hasVarArgs) { + Object varArgContainer = getVarArgContainer(methodDescriptor.method.getParameterTypes(), varArgs.size()); + System.arraycopy(varArgs.toArray(), 0, varArgContainer, 0, varArgs.size()); + args[varArgIndex] = varArgContainer; + } + return args; + } + + private Object getVarArgContainer(final Class[] parameterTypes, final int size) { + Class clazz = parameterTypes[parameterTypes.length - 1]; + if (clazz.isArray()) { + clazz = clazz.getComponentType(); + } + Object result = java.lang.reflect.Array.newInstance(clazz, size); + return result; + } + + private void populateParamters(final V8Array parameters, final int varArgIndex, final Object[] args, final List varArgs, final boolean includeReceiver) { + int start = 0; + if (includeReceiver) { + start = 1; + } + for (int i = start; i < (parameters.length() + start); i++) { + if (i >= varArgIndex) { + varArgs.add(getArrayItem(parameters, i - start)); + } else { + args[i] = getArrayItem(parameters, i - start); + } + } + } + + private Object[] setDefaultValues(final Object[] parameters, final Class[] parameterTypes, final V8Object receiver, final boolean includeReceiver) { + int start = 0; + if (includeReceiver) { + start = 1; + parameters[0] = receiver; + } + for (int i = start; i < parameters.length; i++) { + parameters[i] = getDefaultValue(parameterTypes[i]); + } + return parameters; + } + + private Object getArrayItem(final V8Array array, final int index) { + try { + int type = array.getType(index); + switch (type) { + case INTEGER: + return array.getInteger(index); + case DOUBLE: + return array.getDouble(index); + case BOOLEAN: + return array.getBoolean(index); + case STRING: + return array.getString(index); + case V8_ARRAY: + case V8_TYPED_ARRAY: + return array.getArray(index); + case V8_OBJECT: + return array.getObject(index); + case V8_FUNCTION: + return array.getObject(index); + case V8_ARRAY_BUFFER: + return array.get(index); + case UNDEFINED: + return V8.getUndefined(); + } + } catch (V8ResultUndefined e) { + // do nothing + } + return null; + } + + void createNodeRuntime(final String fileName) { + _startNodeJS(v8RuntimePtr, fileName); + } + + boolean pumpMessageLoop() { + return _pumpMessageLoop(v8RuntimePtr); + } + + boolean isRunning() { + return _isRunning(v8RuntimePtr); + } + + protected long initNewV8Object(final long v8RuntimePtr) { + return _initNewV8Object(v8RuntimePtr); + } + + protected void createTwin(final long v8RuntimePtr, final long objectHandle, final long twinHandle) { + _createTwin(v8RuntimePtr, objectHandle, twinHandle); + } + + protected int executeIntegerScript(final long v8RuntimePtr, final String script, final String scriptName, final int lineNumber) { + return _executeIntegerScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + protected double executeDoubleScript(final long v8RuntimePtr, final String script, final String scriptName, final int lineNumber) { + return _executeDoubleScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + protected String executeStringScript(final long v8RuntimePtr, final String script, final String scriptName, final int lineNumber) { + return _executeStringScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + protected boolean executeBooleanScript(final long v8RuntimePtr, final String script, final String scriptName, final int lineNumber) { + return _executeBooleanScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + protected Object executeScript(final long v8RuntimePtr, final int expectedType, final String script, final String scriptName, final int lineNumber) { + return _executeScript(v8RuntimePtr, expectedType, script, scriptName, lineNumber); + } + + protected void executeVoidScript(final long v8RuntimePtr, final String script, final String scriptName, final int lineNumber) { + _executeVoidScript(v8RuntimePtr, script, scriptName, lineNumber); + } + + protected void release(final long v8RuntimePtr, final long objectHandle) { + _release(v8RuntimePtr, objectHandle); + } + + protected boolean contains(final long v8RuntimePtr, final long objectHandle, final String key) { + return _contains(v8RuntimePtr, objectHandle, key); + } + + protected String[] getKeys(final long v8RuntimePtr, final long objectHandle) { + return _getKeys(v8RuntimePtr, objectHandle); + } + + protected int getInteger(final long v8RuntimePtr, final long objectHandle, final String key) { + return _getInteger(v8RuntimePtr, objectHandle, key); + } + + protected boolean getBoolean(final long v8RuntimePtr, final long objectHandle, final String key) { + return _getBoolean(v8RuntimePtr, objectHandle, key); + } + + protected double getDouble(final long v8RuntimePtr, final long objectHandle, final String key) { + return _getDouble(v8RuntimePtr, objectHandle, key); + } + + protected String getString(final long v8RuntimePtr, final long objectHandle, final String key) { + return _getString(v8RuntimePtr, objectHandle, key); + } + + protected Object get(final long v8RuntimePtr, final int expectedType, final long objectHandle, final String key) { + return _get(v8RuntimePtr, expectedType, objectHandle, key); + } + + protected int executeIntegerFunction(final long v8RuntimePtr, final long objectHandle, final String name, final long parametersHandle) { + return _executeIntegerFunction(v8RuntimePtr, objectHandle, name, parametersHandle); + } + + protected double executeDoubleFunction(final long v8RuntimePtr, final long objectHandle, final String name, final long parametersHandle) { + return _executeDoubleFunction(v8RuntimePtr, objectHandle, name, parametersHandle); + } + + protected String executeStringFunction(final long v8RuntimePtr, final long handle, final String name, final long parametersHandle) { + return _executeStringFunction(v8RuntimePtr, handle, name, parametersHandle); + } + + protected boolean executeBooleanFunction(final long v8RuntimePtr, final long handle, final String name, final long parametersHandle) { + return _executeBooleanFunction(v8RuntimePtr, handle, name, parametersHandle); + } + + protected Object executeFunction(final long v8RuntimePtr, final int expectedType, final long objectHandle, final String name, final long parametersHandle) { + return _executeFunction(v8RuntimePtr, expectedType, objectHandle, name, parametersHandle); + } + + protected Object executeFunction(final long v8RuntimePtr, final long receiverHandle, final long functionHandle, final long parametersHandle) { + return _executeFunction(v8RuntimePtr, receiverHandle, functionHandle, parametersHandle); + } + + protected void executeVoidFunction(final long v8RuntimePtr, final long objectHandle, final String name, final long parametersHandle) { + _executeVoidFunction(v8RuntimePtr, objectHandle, name, parametersHandle); + } + + protected boolean equals(final long v8RuntimePtr, final long objectHandle, final long that) { + return _equals(v8RuntimePtr, objectHandle, that); + } + + protected String toString(final long v8RuntimePtr, final long objectHandle) { + return _toString(v8RuntimePtr, objectHandle); + } + + protected boolean strictEquals(final long v8RuntimePtr, final long objectHandle, final long that) { + return _strictEquals(v8RuntimePtr, objectHandle, that); + } + + protected boolean sameValue(final long v8RuntimePtr, final long objectHandle, final long that) { + return _sameValue(v8RuntimePtr, objectHandle, that); + } + + protected int identityHash(final long v8RuntimePtr, final long objectHandle) { + return _identityHash(v8RuntimePtr, objectHandle); + } + + protected void add(final long v8RuntimePtr, final long objectHandle, final String key, final int value) { + _add(v8RuntimePtr, objectHandle, key, value); + } + + protected void addObject(final long v8RuntimePtr, final long objectHandle, final String key, final long value) { + _addObject(v8RuntimePtr, objectHandle, key, value); + } + + protected void add(final long v8RuntimePtr, final long objectHandle, final String key, final boolean value) { + _add(v8RuntimePtr, objectHandle, key, value); + } + + protected void add(final long v8RuntimePtr, final long objectHandle, final String key, final double value) { + _add(v8RuntimePtr, objectHandle, key, value); + } + + protected void add(final long v8RuntimePtr, final long objectHandle, final String key, final String value) { + _add(v8RuntimePtr, objectHandle, key, value); + } + + protected void addUndefined(final long v8RuntimePtr, final long objectHandle, final String key) { + _addUndefined(v8RuntimePtr, objectHandle, key); + } + + protected void addNull(final long v8RuntimePtr, final long objectHandle, final String key) { + _addNull(v8RuntimePtr, objectHandle, key); + } + + protected long registerJavaMethod(final long v8RuntimePtr, final long objectHandle, final String functionName, final boolean voidMethod) { + return _registerJavaMethod(v8RuntimePtr, objectHandle, functionName, voidMethod); + } + + protected long initNewV8ArrayBuffer(final long v8RuntimePtr, final ByteBuffer buffer, final int capacity) { + return _initNewV8ArrayBuffer(v8RuntimePtr, buffer, capacity); + } + + protected long initNewV8ArrayBuffer(final long v8RuntimePtr, final int capacity) { + return _initNewV8ArrayBuffer(v8RuntimePtr, capacity); + } + + public long initNewV8Int32Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8Int32Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8Float32Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8Float32Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8Float64Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8Float64Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8UInt32Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8UInt32Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8UInt16Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8UInt16Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8Int16Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8Int16Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8UInt8Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8UInt8Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8Int8Array(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8Int8Array(runtimePtr, bufferHandle, offset, size); + } + + public long initNewV8UInt8ClampedArray(final long runtimePtr, final long bufferHandle, final int offset, final int size) { + return _initNewV8UInt8ClampedArray(runtimePtr, bufferHandle, offset, size); + } + + + protected ByteBuffer createV8ArrayBufferBackingStore(final long v8RuntimePtr, final long objectHandle, final int capacity) { + return _createV8ArrayBufferBackingStore(v8RuntimePtr, objectHandle, capacity); + } + + protected long initNewV8Array(final long v8RuntimePtr) { + return _initNewV8Array(v8RuntimePtr); + } + + protected long[] initNewV8Function(final long v8RuntimePtr) { + checkThread(); + return _initNewV8Function(v8RuntimePtr); + } + + protected int arrayGetSize(final long v8RuntimePtr, final long arrayHandle) { + return _arrayGetSize(v8RuntimePtr, arrayHandle); + } + + protected int arrayGetInteger(final long v8RuntimePtr, final long arrayHandle, final int index) { + return _arrayGetInteger(v8RuntimePtr, arrayHandle, index); + } + + protected boolean arrayGetBoolean(final long v8RuntimePtr, final long arrayHandle, final int index) { + return _arrayGetBoolean(v8RuntimePtr, arrayHandle, index); + } + + protected byte arrayGetByte(final long v8RuntimePtr, final long arrayHandle, final int index) { + return _arrayGetByte(v8RuntimePtr, arrayHandle, index); + } + + protected double arrayGetDouble(final long v8RuntimePtr, final long arrayHandle, final int index) { + return _arrayGetDouble(v8RuntimePtr, arrayHandle, index); + } + + protected String arrayGetString(final long v8RuntimePtr, final long arrayHandle, final int index) { + return _arrayGetString(v8RuntimePtr, arrayHandle, index); + } + + protected Object arrayGet(final long v8RuntimePtr, final int expectedType, final long arrayHandle, final int index) { + return _arrayGet(v8RuntimePtr, expectedType, arrayHandle, index); + } + + protected void addArrayIntItem(final long v8RuntimePtr, final long arrayHandle, final int value) { + _addArrayIntItem(v8RuntimePtr, arrayHandle, value); + } + + protected void addArrayBooleanItem(final long v8RuntimePtr, final long arrayHandle, final boolean value) { + _addArrayBooleanItem(v8RuntimePtr, arrayHandle, value); + } + + protected void addArrayDoubleItem(final long v8RuntimePtr, final long arrayHandle, final double value) { + _addArrayDoubleItem(v8RuntimePtr, arrayHandle, value); + } + + protected void addArrayStringItem(final long v8RuntimePtr, final long arrayHandle, final String value) { + _addArrayStringItem(v8RuntimePtr, arrayHandle, value); + } + + protected void addArrayObjectItem(final long v8RuntimePtr, final long arrayHandle, final long value) { + _addArrayObjectItem(v8RuntimePtr, arrayHandle, value); + } + + protected void addArrayUndefinedItem(final long v8RuntimePtr, final long arrayHandle) { + _addArrayUndefinedItem(v8RuntimePtr, arrayHandle); + } + + protected void addArrayNullItem(final long v8RuntimePtr, final long arrayHandle) { + _addArrayNullItem(v8RuntimePtr, arrayHandle); + } + + protected int getType(final long v8RuntimePtr, final long objectHandle, final String key) { + return _getType(v8RuntimePtr, objectHandle, key); + } + + protected int getType(final long v8RuntimePtr, final long objectHandle, final int index) { + return _getType(v8RuntimePtr, objectHandle, index); + } + + protected int getArrayType(final long v8RuntimePtr, final long objectHandle) { + return _getArrayType(v8RuntimePtr, objectHandle); + } + + protected int getType(final long v8RuntimePtr, final long objectHandle, final int index, final int length) { + return _getType(v8RuntimePtr, objectHandle, index, length); + } + + protected void setPrototype(final long v8RuntimePtr, final long objectHandle, final long prototypeHandle) { + _setPrototype(v8RuntimePtr, objectHandle, prototypeHandle); + } + + protected int[] arrayGetIntegers(final long v8RuntimePtr, final long objectHandle, final int index, final int length) { + return _arrayGetIntegers(v8RuntimePtr, objectHandle, index, length); + } + + protected double[] arrayGetDoubles(final long v8RuntimePtr, final long objectHandle, final int index, final int length) { + return _arrayGetDoubles(v8RuntimePtr, objectHandle, index, length); + } + + protected boolean[] arrayGetBooleans(final long v8RuntimePtr, final long objectHandle, final int index, final int length) { + return _arrayGetBooleans(v8RuntimePtr, objectHandle, index, length); + } + + protected byte[] arrayGetBytes(final long v8RuntimePtr, final long objectHandle, final int index, final int length) { + return _arrayGetBytes(v8RuntimePtr, objectHandle, index, length); + } + + protected String[] arrayGetStrings(final long v8RuntimePtr, final long objectHandle, final int index, final int length) { + return _arrayGetStrings(v8RuntimePtr, objectHandle, index, length); + } + + protected int arrayGetIntegers(final long v8RuntimePtr, final long objectHandle, final int index, final int length, final int[] resultArray) { + return _arrayGetIntegers(v8RuntimePtr, objectHandle, index, length, resultArray); + } + + protected int arrayGetDoubles(final long v8RuntimePtr, final long objectHandle, final int index, final int length, final double[] resultArray) { + return _arrayGetDoubles(v8RuntimePtr, objectHandle, index, length, resultArray); + } + + protected int arrayGetBooleans(final long v8RuntimePtr, final long objectHandle, final int index, final int length, final boolean[] resultArray) { + return _arrayGetBooleans(v8RuntimePtr, objectHandle, index, length, resultArray); + } + + protected int arrayGetBytes(final long v8RuntimePtr, final long objectHandle, final int index, final int length, final byte[] resultArray) { + return _arrayGetBytes(v8RuntimePtr, objectHandle, index, length, resultArray); + } + + protected int arrayGetStrings(final long v8RuntimePtr, final long objectHandle, final int index, final int length, final String[] resultArray) { + return _arrayGetStrings(v8RuntimePtr, objectHandle, index, length, resultArray); + } + + protected void terminateExecution(final long v8RuntimePtr) { + _terminateExecution(v8RuntimePtr); + } + + protected void releaseMethodDescriptor(final long v8RuntimePtr, final long methodDescriptor) { + _releaseMethodDescriptor(v8RuntimePtr, methodDescriptor); + } + + private native long _initNewV8Object(long v8RuntimePtr); + + private native void _createTwin(long v8RuntimePtr, long objectHandle, long twinHandle); + + private native void _releaseRuntime(long v8RuntimePtr); + + private native long _createIsolate(String globalAlias); + + private native int _executeIntegerScript(long v8RuntimePtr, final String script, final String scriptName, final int lineNumber); + + private native double _executeDoubleScript(long v8RuntimePtr, final String script, final String scriptName, final int lineNumber); + + private native String _executeStringScript(long v8RuntimePtr, final String script, final String scriptName, final int lineNumber); + + private native boolean _executeBooleanScript(long v8RuntimePtr, final String script, final String scriptName, final int lineNumber); + + private native Object _executeScript(long v8RuntimePtr, int expectedType, String script, String scriptName, int lineNumber); + + private native void _executeVoidScript(long v8RuntimePtr, String script, String scriptName, int lineNumber); + + private native void _release(long v8RuntimePtr, long objectHandle); + + private native void _releaseMethodDescriptor(long v8RuntimePtr, long methodDescriptor); + + private native boolean _contains(long v8RuntimePtr, long objectHandle, final String key); + + private native String[] _getKeys(long v8RuntimePtr, long objectHandle); + + private native int _getInteger(long v8RuntimePtr, long objectHandle, final String key); + + private native boolean _getBoolean(long v8RuntimePtr, long objectHandle, final String key); + + private native double _getDouble(long v8RuntimePtr, long objectHandle, final String key); + + private native String _getString(long v8RuntimePtr, long objectHandle, final String key); + + private native Object _get(long v8RuntimePtr, int expectedType, long objectHandle, final String key); + + private native int _executeIntegerFunction(long v8RuntimePtr, long objectHandle, String name, long parametersHandle); + + private native double _executeDoubleFunction(long v8RuntimePtr, long objectHandle, String name, long parametersHandle); + + private native String _executeStringFunction(long v8RuntimePtr2, long handle, String name, long parametersHandle); + + private native boolean _executeBooleanFunction(long v8RuntimePtr2, long handle, String name, long parametersHandle); + + private native Object _executeFunction(long v8RuntimePtr, int expectedType, long objectHandle, String name, long parametersHandle); + + private native Object _executeFunction(long v8RuntimePtr, long receiverHandle, long functionHandle, long parametersHandle); + + private native void _executeVoidFunction(long v8RuntimePtr, long objectHandle, final String name, final long parametersHandle); + + private native boolean _equals(long v8RuntimePtr, long objectHandle, long that); + + private native String _toString(long v8RuntimePtr, long ObjectHandle); + + private native boolean _strictEquals(long v8RuntimePtr, long objectHandle, long that); + + private native boolean _sameValue(long v8RuntimePtr, long objectHandle, long that); + + private native int _identityHash(long v8RuntimePtr, long objectHandle); + + private native void _add(long v8RuntimePtr, long objectHandle, final String key, final int value); + + private native void _addObject(long v8RuntimePtr, long objectHandle, final String key, final long value); + + private native void _add(long v8RuntimePtr, long objectHandle, final String key, final boolean value); + + private native void _add(long v8RuntimePtr, long objectHandle, final String key, final double value); + + private native void _add(long v8RuntimePtr, long objectHandle, final String key, final String value); + + private native void _addUndefined(long v8RuntimePtr, long objectHandle, final String key); + + private native void _addNull(long v8RuntimePtr, long objectHandle, final String key); + + private native long _registerJavaMethod(long v8RuntimePtr, long objectHandle, final String functionName, final boolean voidMethod); + + private native long _initNewV8Array(long v8RuntimePtr); + + private native long[] _initNewV8Function(long v8RuntimePtr); + + private native int _arrayGetSize(long v8RuntimePtr, long arrayHandle); + + private native int _arrayGetInteger(long v8RuntimePtr, long arrayHandle, int index); + + private native boolean _arrayGetBoolean(long v8RuntimePtr, long arrayHandle, int index); + + private native byte _arrayGetByte(long v8RuntimePtr, long arrayHandle, int index); + + private native double _arrayGetDouble(long v8RuntimePtr, long arrayHandle, int index); + + private native String _arrayGetString(long v8RuntimePtr, long arrayHandle, int index); + + private native Object _arrayGet(long v8RuntimePtr, int expectedType, long arrayHandle, int index); + + private native void _addArrayIntItem(long v8RuntimePtr, long arrayHandle, int value); + + private native void _addArrayBooleanItem(long v8RuntimePtr, long arrayHandle, boolean value); + + private native void _addArrayDoubleItem(long v8RuntimePtr, long arrayHandle, double value); + + private native void _addArrayStringItem(long v8RuntimePtr, long arrayHandle, String value); + + private native void _addArrayObjectItem(long v8RuntimePtr, long arrayHandle, long value); + + private native void _addArrayUndefinedItem(long v8RuntimePtr, long arrayHandle); + + private native void _addArrayNullItem(long v8RuntimePtr, long arrayHandle); + + private native int _getType(long v8RuntimePtr, long objectHandle, final String key); + + private native int _getType(long v8RuntimePtr, long objectHandle, final int index); + + private native int _getArrayType(long v8RuntimePtr, long objectHandle); + + private native void _setPrototype(long v8RuntimePtr, long objectHandle, long prototypeHandle); + + private native int _getType(long v8RuntimePtr, long objectHandle, final int index, final int length); + + private native double[] _arrayGetDoubles(final long v8RuntimePtr, final long objectHandle, final int index, final int length); + + private native int[] _arrayGetIntegers(final long v8RuntimePtr, final long objectHandle, final int index, final int length); + + private native boolean[] _arrayGetBooleans(final long v8RuntimePtr, final long objectHandle, final int index, final int length); + + private native byte[] _arrayGetBytes(final long v8RuntimePtr, final long objectHandle, final int index, final int length); + + private native String[] _arrayGetStrings(final long v8RuntimePtr, final long objectHandle, final int index, final int length); + + private native int _arrayGetIntegers(final long v8RuntimePtr, final long objectHandle, final int index, final int length, int[] resultArray); + + private native int _arrayGetDoubles(final long v8RuntimePtr, final long objectHandle, final int index, final int length, double[] resultArray); + + private native int _arrayGetBooleans(final long v8RuntimePtr, final long objectHandle, final int index, final int length, boolean[] resultArray); + + private native int _arrayGetBytes(final long v8RuntimePtr, final long objectHandle, final int index, final int length, byte[] resultArray); + + private native int _arrayGetStrings(final long v8RuntimePtr, final long objectHandle, final int index, final int length, String[] resultArray); + + private native long _initNewV8ArrayBuffer(long v8RuntimePtr, int capacity); + + private native long _initNewV8ArrayBuffer(long v8RuntimePtr, ByteBuffer buffer, int capacity); + + private native long _initNewV8Int32Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8UInt32Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8Float32Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8Float64Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8Int16Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8UInt16Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8Int8Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8UInt8Array(long runtimePtr, long bufferHandle, int offset, int size); + + private native long _initNewV8UInt8ClampedArray(long runtimePtr, long bufferHandle, int offset, int size); + + private native ByteBuffer _createV8ArrayBufferBackingStore(final long v8RuntimePtr, final long objectHandle, final int capacity); + + private native static String _getVersion(); + + private static native void _setFlags(String v8flags); + + private native void _terminateExecution(final long v8RuntimePtr); + + private native long _getGlobalObject(final long v8RuntimePtr); + + private native long _getBuildID(); + + private native static void _startNodeJS(final long v8RuntimePtr, final String fileName); + + private native static boolean _pumpMessageLoop(final long v8RuntimePtr); + + private native static boolean _isRunning(final long v8RuntimePtr); + + void addObjRef(final V8Value reference) { + objectReferences++; + if (!referenceHandlers.isEmpty()) { + notifyReferenceCreated(reference); + } + } + + void releaseObjRef(final V8Value reference) { + if (!referenceHandlers.isEmpty()) { + notifyReferenceDisposed(reference); + } + objectReferences--; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8Array.java b/fine-j2v8/src/com/eclipsesource/v8/V8Array.java new file mode 100644 index 000000000..548302cf5 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8Array.java @@ -0,0 +1,1127 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * A V8Value that represents a JavaScript array. + * JavaScript Arrays contain elements by index, but + * can also contain elements by 'key' which is why V8Array + * extends V8Object. + */ +public class V8Array extends V8Object { + + protected V8Array() { + + } + + /** + * Creates a new V8Array and associates it with the given runtime. + * V8Arrays have native resources and as such, must be released. + * + * @param v8 The runtime on which to associate the V8Array. + */ + public V8Array(final V8 v8) { + super(v8); + v8.checkThread(); + } + + protected V8Array(final V8 v8, final Object data) { + super(v8, data); + } + + @Override + protected V8Value createTwin() { + return new V8Array(v8); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#twin() + */ + @Override + public V8Array twin() { + return (V8Array) super.twin(); + } + + @Override + protected void initialize(final long runtimePtr, final Object data) { + long handle = v8.initNewV8Array(runtimePtr); + released = false; + addObjectReference(handle); + } + + /** + * Returns the length of this array. + * + * @return The length of the array. + */ + public int length() { + v8.checkThread(); + checkReleased(); + return v8.arrayGetSize(v8.getV8RuntimePtr(), getHandle()); + } + + /** + * Returns the type of element at this given index. + * + * @param index The index at which to lookup the type of. + * + * @return The type of the element at the index. + */ + public int getType(final int index) { + v8.checkThread(); + checkReleased(); + return v8.getType(v8.getV8RuntimePtr(), getHandle(), index); + } + + /** + * Gets the type of the array. Returns a 'type' if all the elements in the array + * have the same type, otherwise UNDEFINED is returned. + * + * @return The type of all the elements of the array, or UNDEFINED if they + * are not all the same type. + */ + public int getType() { + v8.checkThread(); + checkReleased(); + return v8.getArrayType(v8.getV8RuntimePtr(), getHandle()); + } + + /** + * Gets the type of a subset of the array. The subset is specified by a start index + * and a length. UNDEFINED is returned if all the elements in the subset are not + * of the same type. + * + * @param index The start index. + * @param length The length. + * + * @return The type of the subset of the array or UNDEFINED if the subset is not + * all the same type. + */ + public int getType(final int index, final int length) { + v8.checkThread(); + checkReleased(); + return v8.getType(v8.getV8RuntimePtr(), getHandle(), index, length); + } + + /** + * Returns the integer value associated at this index. If the value + * at this index does not exist, or if it's not an integer, then + * V8ResultUndefined exception is thrown. + * + * @param index The index whose value to return. + * + * @return The integer value at this index or V8ResultUndefined + * if the index does not exist or the value is not an integer. + */ + public int getInteger(final int index) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetInteger(v8.getV8RuntimePtr(), getHandle(), index); + } + + /** + * Returns the boolean value associated at this index. If the value + * at this index does not exist, or if it's not a boolean, then + * V8ResultUndefined exception is thrown. + * + * @param index The index whose value to return. + * + * @return The boolean value at this index or V8ResultUndefined + * if the index does not exist or the value is not a boolean. + */ + public boolean getBoolean(final int index) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetBoolean(v8.getV8RuntimePtr(), getHandle(), index); + } + + /** + * Returns the byte value associated at this index. If the value at + * this index does not exist, or cannot be cast to a byte, then + * V8ResultUndefined exception is thrown. + * + * @param index The index whose value to return + * @return The byte value at this index or V8ResultUndefined + * if the index does not exist or the value cannot be cast to a byte. + */ + public byte getByte(final int index) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetByte(v8.getV8RuntimePtr(), getHandle(), index); + } + + /** + * Returns the double value associated at this index. If the value + * at this index does not exist, or if it's not a double, then + * V8ResultUndefined exception is thrown. + * + * @param index The index whose value to return. + * + * @return The double value at this index or V8ResultUndefined + * if the index does not exist or the value is not a double. + */ + public double getDouble(final int index) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetDouble(v8.getV8RuntimePtr(), getHandle(), index); + } + + /** + * Returns the String value associated at this index. If the value + * at this index does not exist, or if it's not a String, then + * V8ResultUndefined exception is thrown. + * + * @param index The index whose value to return. + * + * @return The String value at this index or V8ResultUndefined + * if the index does not exist or the value is not a String. + */ + public String getString(final int index) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetString(v8.getV8RuntimePtr(), getHandle(), index); + } + + /** + * Returns the integers contained in a subset of a V8Array. If the subset + * contains elements other than integers, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. + * + * @param index The starting index. + * @param length The length. + * + * @return The integers contained in the subset of the array, or V8ResultUndefined + * exception. + */ + public int[] getIntegers(final int index, final int length) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetIntegers(v8.getV8RuntimePtr(), getHandle(), index, length); + } + + /** + * Gets the integers contained in a subset of a V8Array. If the subset + * contains elements other than integers, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. Finally, if the resultArray + * is not large enough to hold the results then IndexOutOfBoundsException is thrown. + * + * @param index The starting index. + * @param length The length. + * @param resultArray The array to put the results in. + * + * @return The number of elements added to the array. + */ + public int getIntegers(final int index, final int length, final int[] resultArray) { + v8.checkThread(); + checkReleased(); + if (length > resultArray.length) { + throw new IndexOutOfBoundsException(); + } + return v8.arrayGetIntegers(v8.getV8RuntimePtr(), getHandle(), index, length, resultArray); + } + + /** + * Returns the doubles contained in a subset of a V8Array. If the subset + * contains elements other than doubles, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. + * + * @param index The starting index. + * @param length The length. + * + * @return The doubles contained in the subset of the array, or V8ResultUndefined + * exception. + */ + public double[] getDoubles(final int index, final int length) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetDoubles(v8.getV8RuntimePtr(), getHandle(), index, length); + } + + /** + * Gets the doubles contained in a subset of a V8Array. If the subset + * contains elements other than doubles, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. Finally, if the resultArray + * is not large enough to hold the results then IndexOutOfBoundsException is thrown. + * + * @param index The starting index. + * @param length The length. + * @param resultArray The array to put the results in. + * + * @return The number of elements added to the array. + */ + public int getDoubles(final int index, final int length, final double[] resultArray) { + v8.checkThread(); + checkReleased(); + if (length > resultArray.length) { + throw new IndexOutOfBoundsException(); + } + return v8.arrayGetDoubles(v8.getV8RuntimePtr(), getHandle(), index, length, resultArray); + } + + /** + * Returns the booleans contained in a subset of a V8Array. If the subset + * contains elements other than booleans, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. + * + * @param index The starting index. + * @param length The length. + * + * @return The booleans contained in the subset of the array, or V8ResultUndefined + * exception. + */ + public boolean[] getBooleans(final int index, final int length) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetBooleans(v8.getV8RuntimePtr(), getHandle(), index, length); + } + + /** + * Returns the bytes contained in a subset of a V8Array. If the subset + * contains elements that cannot be cast to bytes, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. + * + * @param index The starting index. + * @param length The length. + * + * @return The bytes contained in the subset of the array, or V8ResultUndefined + * exception. + */ + public byte[] getBytes(final int index, final int length) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetBytes(v8.getV8RuntimePtr(), getHandle(), index, length); + } + + /** + * Gets the booleans contained in a subset of a V8Array. If the subset + * contains elements other than booleans, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. Finally, if the resultArray + * is not large enough to hold the results then IndexOutOfBoundsException is thrown. + * + * @param index The starting index. + * @param length The length. + * @param resultArray The array to put the results in. + * + * @return The number of elements added to the array. + */ + public int getBooleans(final int index, final int length, final boolean[] resultArray) { + v8.checkThread(); + checkReleased(); + if (length > resultArray.length) { + throw new IndexOutOfBoundsException(); + } + return v8.arrayGetBooleans(v8.getV8RuntimePtr(), getHandle(), index, length, resultArray); + } + + /** + * Gets the bytes contained in a subset of a V8Array. If the subset + * contains elements that cannot be cast to bytes, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. Finally, if the resultArray + * is not large enough to hold the results then IndexOutOfBoundsException is thrown. + * + * @param index The starting index. + * @param length The length. + * @param resultArray The array to put the results in. + * + * @return The number of elements added to the array. + */ + public int getBytes(final int index, final int length, final byte[] resultArray) { + v8.checkThread(); + checkReleased(); + if (length > resultArray.length) { + throw new IndexOutOfBoundsException(); + } + return v8.arrayGetBytes(v8.getV8RuntimePtr(), getHandle(), index, length, resultArray); + } + + /** + * Returns the Strings contained in a subset of a V8Array. If the subset + * contains elements other than Strings, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. + * + * @param index The starting index. + * @param length The length. + * + * @return The Strings contained in the subset of the array, or V8ResultUndefined + * exception. + */ + public String[] getStrings(final int index, final int length) { + v8.checkThread(); + checkReleased(); + return v8.arrayGetStrings(v8.getV8RuntimePtr(), getHandle(), index, length); + } + + /** + * Gets the Strings contained in a subset of a V8Array. If the subset + * contains elements other than Strings, then a V8ResultUndefined exception + * is thrown. Furthermore, if the subset is not entirely contained within the array, + * then V8ResultUndefined exception is also thrown. Finally, if the resultArray + * is not large enough to hold the results then IndexOutOfBoundsException is thrown. + * + * @param index The starting index. + * @param length The length. + * @param resultArray The array to put the results in. + * + * @return The number of elements added to the array. + */ + public int getStrings(final int index, final int length, final String[] resultArray) { + v8.checkThread(); + checkReleased(); + if (length > resultArray.length) { + throw new IndexOutOfBoundsException(); + } + return v8.arrayGetStrings(v8.getV8RuntimePtr(), getHandle(), index, length, resultArray); + } + + /** + * Gets the value at a given index as a Java Object. Primitives are boxed. + * + * @param index The index to get the value at. + * + * @return The value at the given index. + */ + public Object get(final int index) { + v8.checkThread(); + checkReleased(); + return v8.arrayGet(v8.getV8RuntimePtr(), V8_OBJECT, objectHandle, index); + } + + /** + * Returns the V8Array value associated at this index. If the value + * at this index does not exist, or if it's not a V8Array, then + * V8ResultUndefined exception is thrown. + * + * @param index The index whose value to return. + * + * @return The V8Array value at this index or V8ResultUndefined + * if the index does not exist or the value is not a V8Array. + */ + public V8Array getArray(final int index) { + v8.checkThread(); + checkReleased(); + Object result = v8.arrayGet(v8.getV8RuntimePtr(), V8_ARRAY, objectHandle, index); + if ((result == null) || (result instanceof V8Array)) { + return (V8Array) result; + } + throw new V8ResultUndefined(); + } + + /** + * Returns the V8Object value associated at this index. If the value + * at this index does not exist, or if it's not a V8Object, then + * V8ResultUndefined exception is thrown. + * + * @param index The index whose value to return. + * + * @return The V8Object value at this index or V8ResultUndefined + * if the index does not exist or the value is not a V8Object. + */ + public V8Object getObject(final int index) { + v8.checkThread(); + checkReleased(); + Object result = v8.arrayGet(v8.getV8RuntimePtr(), V8_OBJECT, objectHandle, index); + if ((result == null) || (result instanceof V8Object)) { + return (V8Object) result; + } + throw new V8ResultUndefined(); + } + + /** + * Pushes an integer value to the next available spot in the Array. In + * particular, this[length] = value; + * + * @param value The value to push to the array. + * + * @return The receiver. + */ + public V8Array push(final int value) { + v8.checkThread(); + checkReleased(); + v8.addArrayIntItem(v8.getV8RuntimePtr(), getHandle(), value); + return this; + } + + /** + * Pushes a boolean value to the next available spot in the Array. In + * particular, this[length] = value; + * + * @param value The value to push to the array. + * + * @return The receiver. + */ + public V8Array push(final boolean value) { + v8.checkThread(); + checkReleased(); + v8.addArrayBooleanItem(v8.getV8RuntimePtr(), getHandle(), value); + return this; + } + + /** + * Pushes a double value to the next available spot in the Array. In + * particular, this[length] = value; + * + * @param value The value to push to the array. + * + * @return The receiver. + */ + public V8Array push(final double value) { + v8.checkThread(); + checkReleased(); + v8.addArrayDoubleItem(v8.getV8RuntimePtr(), getHandle(), value); + return this; + } + + /** + * Pushes a String value to the next available spot in the Array. In + * particular, this[length] = value; + * + * @param value The value to push to the array. + * + * @return The receiver. + */ + public V8Array push(final String value) { + v8.checkThread(); + checkReleased(); + if (value == null) { + v8.addArrayNullItem(v8.getV8RuntimePtr(), getHandle()); + } else if (value.equals(V8.getUndefined())) { + v8.addArrayUndefinedItem(v8.getV8RuntimePtr(), getHandle()); + } else { + v8.addArrayStringItem(v8.getV8RuntimePtr(), getHandle(), value); + } + return this; + } + + /** + * Pushes a V8Value to the next available spot in the Array. In + * particular, this[length] = value; + * + * @param value The value to push to the array. + * + * @return The receiver. + */ + public V8Array push(final V8Value value) { + v8.checkThread(); + checkReleased(); + if (value == null) { + v8.addArrayNullItem(v8.getV8RuntimePtr(), getHandle()); + } else if (value.equals(V8.getUndefined())) { + v8.addArrayUndefinedItem(v8.getV8RuntimePtr(), getHandle()); + } else { + v8.addArrayObjectItem(v8.getV8RuntimePtr(), getHandle(), value.getHandle()); + } + return this; + } + + /** + * Pushes null to the next available spot in the Array. In + * particular, this[length] = null; + * + * @return The receiver. + */ + public V8Array pushNull() { + v8.checkThread(); + checkReleased(); + v8.addArrayNullItem(v8.getV8RuntimePtr(), getHandle()); + return this; + } + + /** + * Pushes undefined to the next available spot in the Array. In + * particular, this[length] = undefined; + * + * @return The receiver. + */ + public V8Array pushUndefined() { + v8.checkThread(); + checkReleased(); + v8.addArrayUndefinedItem(v8.getV8RuntimePtr(), getHandle()); + return this; + } + + static class Undefined extends V8Array { + + public Undefined() { + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#isUndefined() + */ + @Override + public boolean isUndefined() { + return true; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#isReleased() + */ + @Override + public boolean isReleased() { + return false; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#release() + */ + @Override + public void release() { + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#twin() + */ + @Override + public V8Array.Undefined twin() { + return (V8Array.Undefined) super.twin(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#toString() + */ + @Override + public String toString() { + return "undefined"; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object that) { + if ((that instanceof V8Object) && ((V8Object) that).isUndefined()) { + return true; + } + return false; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#hashCode() + */ + @Override + public int hashCode() { + return 919; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#getRuntime() + */ + @Override + public V8 getRuntime() { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, boolean) + */ + @Override + public V8Object add(final String key, final boolean value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, double) + */ + @Override + public V8Object add(final String key, final double value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, int) + */ + @Override + public V8Object add(final String key, final int value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, java.lang.String) + */ + @Override + public V8Object add(final String key, final String value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, com.eclipsesource.v8.V8Value) + */ + @Override + public V8Object add(final String key, final V8Value value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#addUndefined(java.lang.String) + */ + @Override + public V8Object addUndefined(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#contains(java.lang.String) + */ + @Override + public boolean contains(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeArrayFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public V8Array executeArrayFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeBooleanFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public boolean executeBooleanFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeDoubleFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public double executeDoubleFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeIntegerFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public int executeIntegerFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeObjectFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public V8Object executeObjectFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeStringFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public String executeStringFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeVoidFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public void executeVoidFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getArray(java.lang.String) + */ + @Override + public V8Array getArray(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getBoolean(java.lang.String) + */ + @Override + public boolean getBoolean(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getDouble(java.lang.String) + */ + @Override + public double getDouble(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getInteger(java.lang.String) + */ + @Override + public int getInteger(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getKeys() + */ + @Override + public String[] getKeys() { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getObject(java.lang.String) + */ + @Override + public V8Object getObject(final String key) throws V8ResultUndefined { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getString(java.lang.String) + */ + @Override + public String getString(final String key) throws V8ResultUndefined { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getType(java.lang.String) + */ + @Override + public int getType(final String key) throws V8ResultUndefined { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#registerJavaMethod(com.eclipsesource.v8.JavaCallback, java.lang.String) + */ + @Override + public V8Object registerJavaMethod(final JavaCallback callback, final String jsFunctionName) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#registerJavaMethod(com.eclipsesource.v8.JavaVoidCallback, java.lang.String) + */ + @Override + public V8Object registerJavaMethod(final JavaVoidCallback callback, final String jsFunctionName) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#registerJavaMethod(java.lang.Object, java.lang.String, java.lang.String, java.lang.Class[], boolean) + */ + @Override + public V8Object registerJavaMethod(final Object object, final String methodName, final String jsFunctionName, final Class[] parameterTypes, final boolean includeReceiver) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#setPrototype(com.eclipsesource.v8.V8Object) + */ + @Override + public V8Object setPrototype(final V8Object value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#get(int) + */ + @Override + public Object get(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getArray(int) + */ + @Override + public V8Array getArray(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getBoolean(int) + */ + @Override + public boolean getBoolean(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getBooleans(int, int) + */ + @Override + public boolean[] getBooleans(final int index, final int length) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getBytes(int, int) + */ + @Override + public byte[] getBytes(final int index, final int length) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getBytes(int, int) + */ + @Override + public int getBytes(final int index, final int length, final byte[] resultArray) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getByte(int) + */ + @Override + public byte getByte(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getBooleans(int, int, boolean[]) + */ + @Override + public int getBooleans(final int index, final int length, final boolean[] resultArray) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getDouble(int) + */ + @Override + public double getDouble(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getDoubles(int, int) + */ + @Override + public double[] getDoubles(final int index, final int length) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getDoubles(int, int, double[]) + */ + @Override + public int getDoubles(final int index, final int length, final double[] resultArray) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getInteger(int) + */ + @Override + public int getInteger(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getIntegers(int, int) + */ + @Override + public int[] getIntegers(final int index, final int length) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getIntegers(int, int, int[]) + */ + @Override + public int getIntegers(final int index, final int length, final int[] resultArray) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getObject(int) + */ + @Override + public V8Object getObject(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getString(int) + */ + @Override + public String getString(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getStrings(int, int) + */ + @Override + public String[] getStrings(final int index, final int length) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getStrings(int, int, java.lang.String[]) + */ + @Override + public int getStrings(final int index, final int length, final String[] resultArray) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getType() + */ + @Override + public int getType() { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getType(int) + */ + @Override + public int getType(final int index) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#getType(int, int) + */ + @Override + public int getType(final int index, final int length) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#length() + */ + @Override + public int length() { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#push(boolean) + */ + @Override + public V8Array push(final boolean value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#push(double) + */ + @Override + public V8Array push(final double value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#push(int) + */ + @Override + public V8Array push(final int value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#push(java.lang.String) + */ + @Override + public V8Array push(final String value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#push(com.eclipsesource.v8.V8Value) + */ + @Override + public V8Array push(final V8Value value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Array#pushUndefined() + */ + @Override + public V8Array pushUndefined() { + throw new UnsupportedOperationException(); + } + + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8ArrayBuffer.java b/fine-j2v8/src/com/eclipsesource/v8/V8ArrayBuffer.java new file mode 100644 index 000000000..46df2dc7b --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8ArrayBuffer.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * V8ArrayBuffers represent ArrayBuffers from V8, but are backed by a + * java.nio.ByteBuffer. This means that any data stored in a TypedArray + * can be accessed by the java.nio.ByteBuffer. This significantly improves + * performance of data access from Java to JavaScript. + * + * V8ArrayBuffers can either be constructed in Java, or returned from + * JavaScript. + * + */ +public class V8ArrayBuffer extends V8Value { + + private ByteBuffer byteBuffer; + + /** + * Creates a new V8ArrayBuffer on a given V8Runtime with a + * given capacity. + * + * @param v8 The runtime on which to create the ArrayBuffer + * @param capacity The capacity of the buffer + */ + public V8ArrayBuffer(final V8 v8, final int capacity) { + super(v8); + initialize(v8.getV8RuntimePtr(), capacity); + byteBuffer = v8.createV8ArrayBufferBackingStore(v8.getV8RuntimePtr(), objectHandle, capacity); + byteBuffer.order(ByteOrder.nativeOrder()); + } + + /** + * Creates a new V8ArrayBuffer with the provided ByteBuffer as the backing store. + * The ByteBuffer must be allocated as a DirectBuffer. If the ByteBuffer is not + * a DirectBuffer an IllegalArgumentException will be thrown. + * + * @param v8 The runtime on which to create the ArrayBuffer + * @param byteBuffer The ByteBuffer to use as the backing store. The ByteBuffer must + * be allocated as a DirectBuffer. + */ + public V8ArrayBuffer(final V8 v8, final ByteBuffer byteBuffer) { + super(v8); + if (!byteBuffer.isDirect()) { + throw new IllegalArgumentException("ByteBuffer must be a allocated as a direct ByteBuffer"); + } + initialize(v8.getV8RuntimePtr(), byteBuffer); + this.byteBuffer = byteBuffer; + byteBuffer.order(ByteOrder.nativeOrder()); + } + + @Override + protected void initialize(final long runtimePtr, final Object data) { + v8.checkThread(); + if (data instanceof ByteBuffer) { + ByteBuffer buffer = (ByteBuffer) data; + int capacity = buffer.limit(); + objectHandle = v8.initNewV8ArrayBuffer(v8.getV8RuntimePtr(), buffer, capacity); + } else { + int capacity = (Integer) data; + objectHandle = v8.initNewV8ArrayBuffer(v8.getV8RuntimePtr(), capacity); + } + released = false; + addObjectReference(objectHandle); + } + + @Override + protected V8Value createTwin() { + return new V8ArrayBuffer(v8, byteBuffer); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#twin() + */ + @Override + public V8ArrayBuffer twin() { + return (V8ArrayBuffer) super.twin(); + } + + /** + * Returns the backing store used for this ArrayBuffer. + * + * @return The backing store used for this ArrayBuffer. + */ + public ByteBuffer getBackingStore() { + v8.checkReleased(); + v8.checkThread(); + return byteBuffer; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8Function.java b/fine-j2v8/src/com/eclipsesource/v8/V8Function.java new file mode 100644 index 000000000..0f3dc965f --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8Function.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * A V8Value that represents a JavaScript function. + * JavaScript functions cannot be created in Java, but + * can be returned as the result of invoking a JS script + * or JS Function. + */ +public class V8Function extends V8Object { + + /** + * Create a JavaScript function, that when invoked will call + * the javaCallback passed to the receiver. + * + * @param v8 The v8 runtime on which to create this function + * @param javaCallback The callback to invoke + */ + public V8Function(final V8 v8, final JavaCallback javaCallback) { + super(v8, javaCallback); + } + + protected V8Function(final V8 v8) { + this(v8, null); + } + + @Override + protected V8Value createTwin() { + return new V8Function(v8); + } + + @Override + protected void initialize(final long runtimePtr, final Object data) { + if (data == null) { + super.initialize(runtimePtr, null); + return; + } + JavaCallback javaCallback = (JavaCallback) data; + long[] pointers = v8.initNewV8Function(runtimePtr); + // position 0 is the object reference, position 1 is the function reference + v8.createAndRegisterMethodDescriptor(javaCallback, pointers[1]); + released = false; + addObjectReference(pointers[0]); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#twin() + */ + @Override + public V8Function twin() { + return (V8Function) super.twin(); + } + + /** + * Invoke the JavaScript function on the current runtime. + * + * @param receiver The object on which to call the function on. The + * receiver will be mapped to 'this' in JavaScript. If receiver is null + * or undefined, then the V8 runtime will be used instead. + * @param parameters The parameters passed to the JS Function. + * + * @return The result of JavaScript function. + */ + public Object call(V8Object receiver, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + receiver = receiver != null ? receiver : v8; + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + long receiverHandle = receiver.isUndefined() ? v8.getHandle() : receiver.getHandle(); + return v8.executeFunction(v8.getV8RuntimePtr(), receiverHandle, objectHandle, parametersHandle); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8Locker.java b/fine-j2v8/src/com/eclipsesource/v8/V8Locker.java new file mode 100644 index 000000000..f0ab0749f --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8Locker.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * Represents a lock for a V8Runtime that can be moved between + * threads. When instantiated, the lock is automatically assigned + * to the current thread. If another thread wishes to acquire the + * lock, it must first be released. + */ +public class V8Locker { + + private Thread thread = null; + + V8Locker() { + acquire(); + } + + /** + * Acquire the lock if it's currently not acquired by another + * thread. If it's current held by another thread, an + * Error will be thrown. + */ + public synchronized void acquire() { + if ((thread != null) && (thread != Thread.currentThread())) { + throw new Error("Invalid V8 thread access"); + } + thread = Thread.currentThread(); + } + + /** + * Release the lock if it's currently held by the calling thread. + * If the current thread does not hold the lock, and error will be + * thrown. + */ + public synchronized void release() { + checkThread(); + thread = null; + } + + /** + * Checks if the locker has access to the current thread. + * If the locker holds a different thread, than an Error + * is thrown. + */ + public void checkThread() { + if ((thread != Thread.currentThread())) { + throw new Error("Invalid V8 thread access"); + } + } + + /** + * Check if the current thread holds this lock. + * + * @return Returns true if the current thread holds the lock, + * false otherwise. + */ + public boolean hasLock() { + return thread == Thread.currentThread(); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8Object.java b/fine-j2v8/src/com/eclipsesource/v8/V8Object.java new file mode 100644 index 000000000..b043be5c4 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8Object.java @@ -0,0 +1,970 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +import java.lang.reflect.Method; + +/** + * The concrete class for all V8 Objects. V8Objects are + * JavaScript objects accessible in java. Specialized + * subclasses exist for V8Arrays and V8Functions. + * + * V8Object are JavaScript object with key value pairs. + * Specific get methods exist to access values as primitives. + * General get methods also exist, which return Java Objects + * and can be casted to the correct subclass. + * + * V8Object have native resources and must be released + * when they are no longer need in Java. + */ +public class V8Object extends V8Value { + + /** + * Create a new V8Object and associate it with a runtime. + * Once created, it must be released. + * + * @param v8 The runtime on which to associate the V8Object. + */ + public V8Object(final V8 v8) { + this(v8, null); + } + + protected V8Object(final V8 v8, final Object data) { + super(v8); + if (v8 != null) { + this.v8.checkThread(); + initialize(this.v8.getV8RuntimePtr(), data); + } + } + + protected V8Object() { + + } + + @Override + protected V8Value createTwin() { + return new V8Object(v8); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#twin() + */ + @Override + public V8Object twin() { + return (V8Object) super.twin(); + } + + /** + * Determine if a key/value pair with this key exists in + * the Object. + * + * @param key The key to check + * @return True if the key exists, false otherwise. + */ + public boolean contains(final String key) { + v8.checkThread(); + checkReleased(); + return v8.contains(v8.getV8RuntimePtr(), objectHandle, key); + } + + /** + * Returns all the keys associated with this JavaScript Object. + * Keys associated with the objects prototype are not returned. + * + * @return The keys associated with this JavaScript Object. + */ + public String[] getKeys() { + v8.checkThread(); + checkReleased(); + return v8.getKeys(v8.getV8RuntimePtr(), objectHandle); + } + + /** + * Returns the type of the value associated with this Key, or + * UNDEFINED if the key does not exist. Types are specified as + * integer constants. The types are all defined in V8Value. + * + * @param key The key whose type to lookup. + * + * @return The Type of the value associated with this key + */ + public int getType(final String key) { + v8.checkThread(); + checkReleased(); + return v8.getType(v8.getV8RuntimePtr(), objectHandle, key); + } + + /** + * Returns the value associated with this key. Values are Java Objects. + * If the value is a primitive, its boxed type is returned. If the + * value is a V8Value, it must be released. + * + * @param key The key whose value to return. + * + * @return The value associated with this key. + */ + public Object get(final String key) { + v8.checkThread(); + checkReleased(); + return v8.get(v8.getV8RuntimePtr(), V8_OBJECT, objectHandle, key); + } + + /** + * Returns the integer value associated with this key. If the value + * associated with this key does not exist, or if it's not an integer, then + * V8ResultUndefined exception is thrown. + * + * @param key The key whose value to return. + * + * @return The integer value associated with this key, or V8ResultUndefined + * if the key does not exist or the value is not an integer. + */ + public int getInteger(final String key) { + v8.checkThread(); + checkReleased(); + return v8.getInteger(v8.getV8RuntimePtr(), objectHandle, key); + } + + /** + * Returns the boolean value associated with this key. If the value + * associated with this key does not exist, or if it's not a boolean, then + * V8ResultUndefined exception is thrown. + * + * @param key The key whose value to return. + * + * @return The boolean value associated with this key, or V8ResultUndefined + * if the key does not exist or the value is not a boolean. + */ + public boolean getBoolean(final String key) { + v8.checkThread(); + checkReleased(); + return v8.getBoolean(v8.getV8RuntimePtr(), objectHandle, key); + } + + /** + * Returns the double value associated with this key. If the value + * associated with this key does not exist, or if it's not a double, then + * V8ResultUndefined exception is thrown. + * + * @param key The key whose value to return. + * + * @return The double value associated with this key, or V8ResultUndefined + * if the key does not exist or the value is not a double. + */ + public double getDouble(final String key) { + v8.checkThread(); + checkReleased(); + return v8.getDouble(v8.getV8RuntimePtr(), objectHandle, key); + } + + /** + * Returns the String value associated with this key. If the value + * associated with this key does not exist, or if it's not a String, then + * V8ResultUndefined exception is thrown. + * + * @param key The key whose value to return. + * + * @return The String value associated with this key, or V8ResultUndefined + * if the key does not exist or the value is not a String. + */ + public String getString(final String key) { + v8.checkThread(); + checkReleased(); + return v8.getString(v8.getV8RuntimePtr(), objectHandle, key); + } + + /** + * Returns the V8Array value associated with this key. If the value + * associated with this key does not exist then UNDEFINED is returned. + * If the value exists but is not an array then + * V8ResultUndefined exception is thrown. + * + * @param key The key whose value to return. + * + * @return The V8Array value associated with this key. + */ + public V8Array getArray(final String key) { + v8.checkThread(); + checkReleased(); + Object result = v8.get(v8.getV8RuntimePtr(), V8_ARRAY, objectHandle, key); + if ((result == null) || (result instanceof V8Array)) { + return (V8Array) result; + } + throw new V8ResultUndefined(); + } + + /** + * Returns the V8Object value associated with this key. If the value + * associated with this key does not exist then UNDEFINED is returned. + * If the value exists but is not an JS Object then + * V8ResultUndefined exception is thrown. + * + * @param key The key whose value to return. + * + * @return The V8Object value associated with this key. + */ + public V8Object getObject(final String key) { + v8.checkThread(); + checkReleased(); + Object result = v8.get(v8.getV8RuntimePtr(), V8_OBJECT, objectHandle, key); + if ((result == null) || (result instanceof V8Object)) { + return (V8Object) result; + } + throw new V8ResultUndefined(); + } + + /** + * Invoke a JavaScript function and return the result as a integer. If the + * result is not an integer, or does not exist, then V8ResultUndefined is thrown. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + * + * @return An integer representing the result of the function call or V8ResultUndefined + * if the result is not an integer. + */ + public int executeIntegerFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + return v8.executeIntegerFunction(v8.getV8RuntimePtr(), getHandle(), name, parametersHandle); + } + + /** + * Invoke a JavaScript function and return the result as a double. If the + * result is not a double, or does not exist, then V8ResultUndefined is thrown. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + * + * @return A double representing the result of the function call or V8ResultUndefined + * if the result is not a double. + */ + public double executeDoubleFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + return v8.executeDoubleFunction(v8.getV8RuntimePtr(), getHandle(), name, parametersHandle); + } + + /** + * Invoke a JavaScript function and return the result as a String. If the + * result is not a String, or does not exist, then V8ResultUndefined is thrown. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + * + * @return A String representing the result of the function call or V8ResultUndefined + * if the result is not a String. + */ + public String executeStringFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + return v8.executeStringFunction(v8.getV8RuntimePtr(), getHandle(), name, parametersHandle); + } + + /** + * Invoke a JavaScript function and return the result as a boolean. If the + * result is not a boolean, or does not exist, then V8ResultUndefined is thrown. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + * + * @return A boolean representing the result of the function call or V8ResultUndefined + * if the result is not a boolean. + */ + public boolean executeBooleanFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + return v8.executeBooleanFunction(v8.getV8RuntimePtr(), getHandle(), name, parametersHandle); + } + + /** + * Invoke a JavaScript function and return the result as a V8Array. If the + * result is not a V8Array then V8ResultUndefined is thrown. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + * + * @return A V8Array representing the result of the function call or V8ResultUndefined + * if the result is not a V8Array. The result must be released. + */ + public V8Array executeArrayFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + Object result = v8.executeFunction(v8.getV8RuntimePtr(), V8_ARRAY, objectHandle, name, parametersHandle); + if (result instanceof V8Array) { + return (V8Array) result; + } + throw new V8ResultUndefined(); + } + + /** + * Invoke a JavaScript function and return the result as a V8Object. If the + * result is not a V8Object then V8ResultUndefined is thrown. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + * + * @return A V8Object representing the result of the function call or V8ResultUndefined + * if the result is not a V8Object. The result must be released. + */ + public V8Object executeObjectFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + Object result = v8.executeFunction(v8.getV8RuntimePtr(), V8_OBJECT, objectHandle, name, parametersHandle); + if (result instanceof V8Object) { + return (V8Object) result; + } + throw new V8ResultUndefined(); + } + + /** + * Invoke a JavaScript function and return the result as a Java Object. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + * + * @return A Java Object representing the result of the function call. + */ + public Object executeFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + return v8.executeFunction(v8.getV8RuntimePtr(), UNKNOWN, objectHandle, name, parametersHandle); + } + + /** + * Invoke a JavaScript function and return the result as a Java Object. + * + * @param name The name of the JS Function to call + * @return The result of this JS Function + */ + public Object executeJSFunction(final String name) { + return executeFunction(name, null); + } + + /** + * Invoke a JavaScript function and return the result as a Java Object. + * + * @param name The name of the JS Function to call. + * @param parameters The parameters to pass to the function. + * @return A Java Object representing the result of the function call. + */ + public Object executeJSFunction(final String name, final Object... parameters) { + if (parameters == null) { + return executeFunction(name, null); + } + V8Array parameterArray = new V8Array(v8.getRuntime()); + try { + for (Object object : parameters) { + if (object == null) { + parameterArray.pushNull(); + } else if (object instanceof V8Value) { + parameterArray.push((V8Value) object); + } else if (object instanceof Integer) { + parameterArray.push((Integer) object); + } else if (object instanceof Double) { + parameterArray.push((Double) object); + } else if (object instanceof Long) { + parameterArray.push(((Long) object).doubleValue()); + } else if (object instanceof Float) { + parameterArray.push(((Float) object).floatValue()); + } else if (object instanceof Boolean) { + parameterArray.push((Boolean) object); + } else if (object instanceof String) { + parameterArray.push((String) object); + } else { + throw new IllegalArgumentException("Unsupported Object of type: " + object.getClass()); + } + } + return executeFunction(name, parameterArray); + } finally { + parameterArray.release(); + } + } + + /** + * Invokes a JavaScript function which does not return a result. + * + * @param name The name of the JS Function to call. + * + * @param parameters The parameters to pass to the function. Parameters must be released. + */ + public void executeVoidFunction(final String name, final V8Array parameters) { + v8.checkThread(); + checkReleased(); + long parametersHandle = parameters == null ? 0 : parameters.getHandle(); + v8.executeVoidFunction(v8.getV8RuntimePtr(), objectHandle, name, parametersHandle); + } + + /** + * Adds a key value pair to the receiver where the value is an integer. + * + * @param key The key to associate the value with. + * @param value The value to add. + * + * @return The receiver. + */ + public V8Object add(final String key, final int value) { + v8.checkThread(); + checkReleased(); + v8.add(v8.getV8RuntimePtr(), objectHandle, key, value); + return this; + } + + /** + * Adds a key value pair to the receiver where the value is a boolean. + * + * @param key The key to associate the value with. + * @param value The value to add. + * + * @return The receiver. + */ + public V8Object add(final String key, final boolean value) { + v8.checkThread(); + checkReleased(); + v8.add(v8.getV8RuntimePtr(), objectHandle, key, value); + return this; + } + + /** + * Adds a key value pair to the receiver where the value is a double. + * + * @param key The key to associate the value with. + * @param value The value to add. + * + * @return The receiver. + */ + public V8Object add(final String key, final double value) { + v8.checkThread(); + checkReleased(); + v8.add(v8.getV8RuntimePtr(), objectHandle, key, value); + return this; + } + + /** + * Adds a key value pair to the receiver where the value is a String. + * + * @param key The key to associate the value with. + * @param value The value to add. + * + * @return The receiver. + */ + public V8Object add(final String key, final String value) { + v8.checkThread(); + checkReleased(); + if (value == null) { + v8.addNull(v8.getV8RuntimePtr(), objectHandle, key); + } else if (value.equals(V8.getUndefined())) { + v8.addUndefined(v8.getV8RuntimePtr(), objectHandle, key); + } else { + v8.add(v8.getV8RuntimePtr(), objectHandle, key, value); + } + return this; + } + + /** + * Adds a key value pair to the receiver where the value is a V8Value. + * + * @param key The key to associate the value with. + * @param value The value to add. + * + * @return The receiver. + */ + public V8Object add(final String key, final V8Value value) { + v8.checkThread(); + checkReleased(); + if (value == null) { + v8.addNull(v8.getV8RuntimePtr(), objectHandle, key); + } else if (value.equals(V8.getUndefined())) { + v8.addUndefined(v8.getV8RuntimePtr(), objectHandle, key); + } else { + v8.addObject(v8.getV8RuntimePtr(), objectHandle, key, value.getHandle()); + } + return this; + } + + /** + * Associate UNDEFINED with the given key. + * + * @param key The key to associate UNDEFINED with. + * + * @return The receiver. + */ + public V8Object addUndefined(final String key) { + v8.checkThread(); + checkReleased(); + v8.addUndefined(v8.getV8RuntimePtr(), objectHandle, key); + return this; + } + + /** + * Associate NULL with the given key. + * + * @param key The key to associate NULL with. + * + * @return The receiver. + */ + public V8Object addNull(final String key) { + v8.checkThread(); + checkReleased(); + v8.addNull(v8.getV8RuntimePtr(), objectHandle, key); + return this; + } + + /** + * Sets the prototype of the receiver. + * + * @param value The prototype to associate with this V8Object. + * + * @return The receiver. + */ + public V8Object setPrototype(final V8Object value) { + v8.checkThread(); + checkReleased(); + v8.setPrototype(v8.getV8RuntimePtr(), objectHandle, value.getHandle()); + return this; + } + + /** + * Register a Java method as a JavaScript function. When the JS Function is invoked + * the Java method will be called. + * + * @param callback The JavaCallback to call when the JSFunction is invoked. + * @param jsFunctionName The name of the JSFunction. + * + * @return The receiver. + */ + public V8Object registerJavaMethod(final JavaCallback callback, final String jsFunctionName) { + v8.checkThread(); + checkReleased(); + v8.registerCallback(callback, getHandle(), jsFunctionName); + return this; + } + + /** + * Register a void Java method as a JavaScript function. When the JS Function is invoked + * the Java method will be called. + * + * @param callback The JavaVoidCallback to call when the JSFunction is invoked. + * @param jsFunctionName The name of the JSFunction. + * + * @return The receiver. + */ + public V8Object registerJavaMethod(final JavaVoidCallback callback, final String jsFunctionName) { + v8.checkThread(); + checkReleased(); + v8.registerVoidCallback(callback, getHandle(), jsFunctionName); + return this; + } + + /** + * Register a Java method reflectively given it's name a signature. + * + * @param object The Java Object on which the method is defined. + * @param methodName The name of the method to register. + * @param jsFunctionName The name of the JavaScript function to register the + * method with. + * @param parameterTypes The parameter types of the method. + * + * @return The receiver. + */ + public V8Object registerJavaMethod(final Object object, final String methodName, final String jsFunctionName, final Class[] parameterTypes) { + return registerJavaMethod(object, methodName, jsFunctionName, parameterTypes, false); + } + + /** + * Register a Java method reflectively given it's name a signature. The option to include + * the JS Object in the callback can be specified by setting includeReceiver true. + * + * @param object The Java Object on which the method is defined. + * @param methodName The name of the method to register. + * @param jsFunctionName The name of the JavaScript function to register the + * method with. + * @param parameterTypes The parameter types of the method. + * @param includeReceiver True if the first parameter should include the JS Object, + * false otherwise. + * + * @return The receiver. + */ + public V8Object registerJavaMethod(final Object object, final String methodName, final String jsFunctionName, final Class[] parameterTypes, final boolean includeReceiver) { + v8.checkThread(); + checkReleased(); + try { + Method method = object.getClass().getMethod(methodName, parameterTypes); + method.setAccessible(true); + v8.registerCallback(object, method, getHandle(), jsFunctionName, includeReceiver); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (SecurityException e) { + throw new IllegalStateException(e); + } + return this; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + v8.checkThread(); + checkReleased(); + return v8.toString(v8.getV8RuntimePtr(), getHandle()); + } + + static class Undefined extends V8Object { + + public Undefined() { + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#isUndefined() + */ + @Override + public boolean isUndefined() { + return true; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#isReleased() + */ + @Override + public boolean isReleased() { + return false; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#release() + */ + @Override + public void release() { + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#twin() + */ + @Override + public Undefined twin() { + return (Undefined) super.twin(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#toString() + */ + @Override + public String toString() { + return "undefined"; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object that) { + if ((that instanceof V8Object) && ((V8Object) that).isUndefined()) { + return true; + } + return false; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#hashCode() + */ + @Override + public int hashCode() { + return 919; + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, boolean) + */ + @Override + public V8Object add(final String key, final boolean value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Value#getRuntime() + */ + @Override + public V8 getRuntime() { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, double) + */ + @Override + public V8Object add(final String key, final double value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, int) + */ + @Override + public V8Object add(final String key, final int value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeJSFunction(java.lang.String, java.lang.Object[]) + */ + @Override + public Object executeJSFunction(final String name, final Object... parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public Object executeFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, java.lang.String) + */ + @Override + public V8Object add(final String key, final String value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#add(java.lang.String, com.eclipsesource.v8.V8Value) + */ + @Override + public V8Object add(final String key, final V8Value value) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#addUndefined(java.lang.String) + */ + @Override + public V8Object addUndefined(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#contains(java.lang.String) + */ + @Override + public boolean contains(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeArrayFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public V8Array executeArrayFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeBooleanFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public boolean executeBooleanFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeDoubleFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public double executeDoubleFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeIntegerFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public int executeIntegerFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeObjectFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public V8Object executeObjectFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeStringFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public String executeStringFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#executeVoidFunction(java.lang.String, com.eclipsesource.v8.V8Array) + */ + @Override + public void executeVoidFunction(final String name, final V8Array parameters) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getArray(java.lang.String) + */ + @Override + public V8Array getArray(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getBoolean(java.lang.String) + */ + @Override + public boolean getBoolean(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getDouble(java.lang.String) + */ + @Override + public double getDouble(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getInteger(java.lang.String) + */ + @Override + public int getInteger(final String key) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getKeys() + */ + @Override + public String[] getKeys() { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getObject(java.lang.String) + */ + @Override + public V8Object getObject(final String key) throws V8ResultUndefined { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getString(java.lang.String) + */ + @Override + public String getString(final String key) throws V8ResultUndefined { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#getType(java.lang.String) + */ + @Override + public int getType(final String key) throws V8ResultUndefined { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#registerJavaMethod(com.eclipsesource.v8.JavaCallback, java.lang.String) + */ + @Override + public V8Object registerJavaMethod(final JavaCallback callback, final String jsFunctionName) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#registerJavaMethod(com.eclipsesource.v8.JavaVoidCallback, java.lang.String) + */ + @Override + public V8Object registerJavaMethod(final JavaVoidCallback callback, final String jsFunctionName) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#registerJavaMethod(java.lang.Object, java.lang.String, java.lang.String, java.lang.Class[], boolean) + */ + @Override + public V8Object registerJavaMethod(final Object object, final String methodName, final String jsFunctionName, final Class[] parameterTypes, final boolean includeReceiver) { + throw new UnsupportedOperationException(); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.V8Object#setPrototype(com.eclipsesource.v8.V8Object) + */ + @Override + public V8Object setPrototype(final V8Object value) { + throw new UnsupportedOperationException(); + } + + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8ResultUndefined.java b/fine-j2v8/src/com/eclipsesource/v8/V8ResultUndefined.java new file mode 100644 index 000000000..4d15d6378 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8ResultUndefined.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * An exception that's used to indicate that method that should have returned a + * primitive, returned an Undefined instead. + * + * In Java, Undefined cannot be returned for all methods, especially if + * the method returns a primitive (int, double, boolean) or a String. + * In this case, if an Undefined should be returned from JS, then an instance + * of this exception is thrown. + */ +@SuppressWarnings("serial") +public class V8ResultUndefined extends V8RuntimeException { + + V8ResultUndefined(final String message) { + super(message); + } + + V8ResultUndefined() { + super(); + } +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8RuntimeException.java b/fine-j2v8/src/com/eclipsesource/v8/V8RuntimeException.java new file mode 100644 index 000000000..2ea34af12 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8RuntimeException.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * A top-level exception used to indicate that a script failed. In most cases + * a more specific exception will be thrown. + */ +@SuppressWarnings("serial") +public class V8RuntimeException extends RuntimeException { + + V8RuntimeException() { + } + + V8RuntimeException(final String message) { + super(message); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8ScriptCompilationException.java b/fine-j2v8/src/com/eclipsesource/v8/V8ScriptCompilationException.java new file mode 100644 index 000000000..48f188d49 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8ScriptCompilationException.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * An exception used to indicate that a script failed to compile. + */ +@SuppressWarnings("serial") +public class V8ScriptCompilationException extends V8ScriptException { + + V8ScriptCompilationException(final String fileName, final int lineNumber, + final String message, final String sourceLine, final int startColumn, final int endColumn) { + super(fileName, lineNumber, message, sourceLine, startColumn, endColumn, null, null); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8ScriptException.java b/fine-j2v8/src/com/eclipsesource/v8/V8ScriptException.java new file mode 100644 index 000000000..aa59be0bf --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8ScriptException.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * An exception that indicates that the execution of a script failed. + * Details about the exception, such as the line number, stack trace, and + * message can retrieved using the accessors. + */ +@SuppressWarnings("serial") +public abstract class V8ScriptException extends V8RuntimeException { + + private final String fileName; + private final int lineNumber; + private final String jsMessage; + private final String sourceLine; + private final int startColumn; + private final int endColumn; + private final String jsStackTrace; + + V8ScriptException(final String fileName, + final int lineNumber, + final String jsMessage, + final String sourceLine, + final int startColumn, + final int endColumn, + final String jsStackTrace, + final Throwable cause) { + this.fileName = fileName; + this.lineNumber = lineNumber; + this.jsMessage = jsMessage; + this.sourceLine = sourceLine; + this.startColumn = startColumn; + this.endColumn = endColumn; + this.jsStackTrace = jsStackTrace; + if (cause != null) { + initCause(cause); + } + } + + /** + * Get the JavaScript Stack as a String. + * + * @return The JavaScript stack. + */ + public String getJSStackTrace() { + return jsStackTrace; + } + + /** + * Get the file name contains the script that was currently executing. + * + * @return The file name that contains the script. + */ + public String getFileName() { + return fileName; + } + + /** + * Get the line number that the failure occurred on. + * + * @return The line number the failure occurred on. + */ + public int getLineNumber() { + return lineNumber; + } + + /** + * Get the JavaScript column where the error begins. + * + * @return The JavaScript column where the error begins. + */ + public int getStartColumn() { + return startColumn; + } + + /** + * Get the JavaScript column where the error ends. + * + * @return The JavaScript column where the error ends. + */ + public int getEndColumn() { + return endColumn; + } + + /** + * Get the JavaScript line of source that caused the error. + * + * @return The JavaScript line of source that caused the error. + */ + public String getSourceLine() { + return sourceLine; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append(createMessageLine()); + result.append(createMessageDetails()); + result.append(createJSStackDetails()); + result.append("\n"); + result.append(this.getClass().getName()); + return result.toString(); + } + + /* + * (non-Javadoc) + * @see java.lang.Throwable#getMessage() + */ + @Override + public String getMessage() { + return createMessageLine(); + } + + /** + * Get the message set by the JavaScript exception. + * + * @return The message set by the JavaScript exception. + */ + public String getJSMessage() { + return jsMessage; + } + + private String createMessageLine() { + return fileName + ":" + lineNumber + ": " + jsMessage; + } + + private String createJSStackDetails() { + if (jsStackTrace != null) { + return "\n" + jsStackTrace; + } + return ""; + } + + private String createMessageDetails() { + StringBuilder result = new StringBuilder(); + if ((sourceLine != null) && !sourceLine.isEmpty()) { + result.append('\n'); + result.append(sourceLine); + result.append('\n'); + if (startColumn >= 0) { + result.append(createCharSequence(startColumn, ' ')); + result.append(createCharSequence(endColumn - startColumn, '^')); + } + } + return result.toString(); + } + + private char[] createCharSequence(final int length, final char c) { + char[] result = new char[length]; + for (int i = 0; i < length; i++) { + result[i] = c; + } + return result; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8ScriptExecutionException.java b/fine-j2v8/src/com/eclipsesource/v8/V8ScriptExecutionException.java new file mode 100644 index 000000000..de56724a3 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8ScriptExecutionException.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * An exception used to indicate that a script failed to execute. + */ +@SuppressWarnings("serial") +public class V8ScriptExecutionException extends V8ScriptException { + + V8ScriptExecutionException(final String fileName, + final int lineNumber, + final String message, + final String sourceLine, + final int startColumn, + final int endColumn, + final String jsStackTrace) { + this(fileName, lineNumber, message, sourceLine, startColumn, endColumn, jsStackTrace, null); + } + + V8ScriptExecutionException(final String fileName, + final int lineNumber, + final String message, + final String sourceLine, + final int startColumn, + final int endColumn, + final String jsStackTrace, + final Throwable cause) { + super(fileName, lineNumber, message, sourceLine, startColumn, endColumn, jsStackTrace, cause); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8TypedArray.java b/fine-j2v8/src/com/eclipsesource/v8/V8TypedArray.java new file mode 100644 index 000000000..342439e10 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8TypedArray.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +import java.nio.ByteBuffer; + +/** + * A representation of a JS TypedArray in Java. The typed array is simply a 'view' onto + * a back buffer. + */ +public class V8TypedArray extends V8Array { + + /** + * Create a new TypedArray from a specified ArrayBuffer, type, offset and size. For + * example, a V8Int32Array is a typed array where each value is a 32-bit integer. The + * typed array is backed by the V8ArrayBuffer. + * + * @param v8 The V8Runtime on which to create this Int32Array + * @param type The type of Array to create. Currently Integer and Byte are supported. + * @param buffer The buffer used to back the typed array + * @param offset The offset into the buffer at which to start the the array + * @param size The size of the typed array + */ + public V8TypedArray(final V8 v8, final V8ArrayBuffer buffer, final int type, final int offset, final int size) { + super(v8, new V8ArrayData(buffer, offset, size, type)); + } + + private V8TypedArray(final V8 v8) { + super(v8); + } + + /** + * Provide access to the underlying ByteBuffer used for this TypedArray. + * The V8ArrayBuffer must be released. + * + * @return The V8ArrayBuffer used to back this TypedArray. + */ + public V8ArrayBuffer getBuffer() { + return (V8ArrayBuffer) get("buffer"); + } + + /** + * Returns the underlying ByteBuffer used to back this TypedArray. + * + * @return The ByteBuffer used as the backing store for this TypedArray + */ + public ByteBuffer getByteBuffer() { + V8ArrayBuffer buffer = getBuffer(); + try { + return buffer.getBackingStore(); + } finally { + buffer.release(); + } + } + + @Override + protected void initialize(final long runtimePtr, final Object data) { + v8.checkThread(); + if (data == null) { + super.initialize(runtimePtr, data); + return; + } + V8ArrayData arrayData = (V8ArrayData) data; + checkArrayProperties(arrayData); + long handle = createTypedArray(runtimePtr, arrayData); + released = false; + addObjectReference(handle); + } + + private long createTypedArray(final long runtimePtr, final V8ArrayData arrayData) { + switch (arrayData.type) { + case V8Value.FLOAT_32_ARRAY: + return v8.initNewV8Float32Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.FLOAT_64_ARRAY: + return v8.initNewV8Float64Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.UNSIGNED_INT_32_ARRAY: + return v8.initNewV8UInt32Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.INT_16_ARRAY: + return v8.initNewV8Int16Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.UNSIGNED_INT_16_ARRAY: + return v8.initNewV8UInt16Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.INTEGER: + return v8.initNewV8Int32Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.UNSIGNED_INT_8_ARRAY: + return v8.initNewV8UInt8Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.INT_8_ARRAY: + return v8.initNewV8Int8Array(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + case V8Value.UNSIGNED_INT_8_CLAMPED_ARRAY: + return v8.initNewV8UInt8ClampedArray(runtimePtr, arrayData.buffer.objectHandle, arrayData.offset, arrayData.size); + default: + throw new IllegalArgumentException("Cannot create a typed array of type " + V8Value.getStringRepresentaion(arrayData.type)); + } + } + + /** + * Computes the size of the structures required for each TypedArray variation. + * + * @param type The type of the TypeArray + * @return The size of the structures required + */ + public static int getStructureSize(final int type) { + switch (type) { + case V8Value.FLOAT_64_ARRAY: + return 8; + case V8Value.INT_32_ARRAY: + case V8Value.UNSIGNED_INT_32_ARRAY: + case V8Value.FLOAT_32_ARRAY: + return 4; + case V8Value.UNSIGNED_INT_16_ARRAY: + case V8Value.INT_16_ARRAY: + return 2; + case V8Value.INT_8_ARRAY: + case V8Value.UNSIGNED_INT_8_ARRAY: + case V8Value.UNSIGNED_INT_8_CLAMPED_ARRAY: + return 1; + default: + throw new IllegalArgumentException("Cannot create a typed array of type " + V8Value.getStringRepresentaion(type)); + } + } + + private void checkArrayProperties(final V8ArrayData arrayData) { + checkOffset(arrayData); + checkSize(arrayData); + } + + private void checkSize(final V8ArrayData arrayData) { + if (arrayData.size < 0) { + throw new IllegalStateException("RangeError: Invalid typed array length"); + } + int limit = (arrayData.size * getStructureSize(arrayData.type)) + arrayData.offset; + if (limit > arrayData.buffer.getBackingStore().limit()) { + throw new IllegalStateException("RangeError: Invalid typed array length"); + } + } + + private void checkOffset(final V8ArrayData arrayData) { + if ((arrayData.offset % getStructureSize(arrayData.type)) != 0) { + throw new IllegalStateException("RangeError: Start offset of Int32Array must be a multiple of " + getStructureSize(arrayData.type)); + } + } + + @Override + protected V8Value createTwin() { + return new V8TypedArray(v8); + } + + private static class V8ArrayData { + private V8ArrayBuffer buffer; + private int offset; + private int size; + private int type; + + public V8ArrayData(final V8ArrayBuffer buffer, final int offset, final int size, final int type) { + this.buffer = buffer; + this.offset = offset; + this.size = size; + this.type = type; + } + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/V8Value.java b/fine-j2v8/src/com/eclipsesource/v8/V8Value.java new file mode 100644 index 000000000..3952716d2 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/V8Value.java @@ -0,0 +1,289 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8; + +/** + * A base class for all V8 resources. V8 resources must + * be released. The rules for releasing resources is as + * follows: + * + * 1. If you created it, you must release it, with one exception; + * if the object is being passed pack via a return statement, + * the system will release it for you. + * + * 2. If the system created it, you don’t need to worry about it, + * with one caveat; if the object was returned to you as a + * result of a method call, you must release it. + */ +abstract public class V8Value implements Releasable { + + public static final int NULL = 0; + public static final int UNKNOWN = 0; + public static final int INTEGER = 1; + public static final int INT_32_ARRAY = 1; + public static final int DOUBLE = 2; + public static final int FLOAT_64_ARRAY = 2; + public static final int BOOLEAN = 3; + public static final int STRING = 4; + public static final int V8_ARRAY = 5; + public static final int V8_OBJECT = 6; + public static final int V8_FUNCTION = 7; + public static final int V8_TYPED_ARRAY = 8; + public static final int BYTE = 9; + public static final int INT_8_ARRAY = 9; + public static final int V8_ARRAY_BUFFER = 10; + public static final int UNSIGNED_INT_8_ARRAY = 11; + public static final int UNSIGNED_INT_8_CLAMPED_ARRAY = 12; + public static final int INT_16_ARRAY = 13; + public static final int UNSIGNED_INT_16_ARRAY = 14; + public static final int UNSIGNED_INT_32_ARRAY = 15; + public static final int FLOAT_32_ARRAY = 16; + public static final int UNDEFINED = 99; + + protected V8 v8; + protected long objectHandle; + protected boolean released = true; + + protected V8Value() { + super(); + } + + protected V8Value(final V8 v8) { + if (v8 == null) { + this.v8 = (V8) this; + } else { + this.v8 = v8; + } + } + + protected void initialize(final long runtimePtr, final Object data) { + long objectHandle = v8.initNewV8Object(runtimePtr); + released = false; + addObjectReference(objectHandle); + } + + protected void addObjectReference(final long objectHandle) throws Error { + this.objectHandle = objectHandle; + try { + v8.addObjRef(this); + } catch (Error e) { + release(); + throw e; + } catch (RuntimeException e) { + release(); + throw e; + } + } + + /** + * Returns a string representation of the V8 Type. + * @param type Type to return as a string. See constants in V8Value. + * @return The V8Value type as a string. + */ + public static String getStringRepresentaion(final int type) { + switch (type) { + case NULL: + return "Null"; + case INTEGER: + return "Integer"; + case DOUBLE: + return "Double"; + case BOOLEAN: + return "Boolean"; + case STRING: + return "String"; + case V8_ARRAY: + return "V8Array"; + case V8_OBJECT: + return "V8Object"; + case V8_FUNCTION: + return "V8Function"; + case V8_TYPED_ARRAY: + return "V8TypedArray"; + case BYTE: + return "Byte"; + case V8_ARRAY_BUFFER: + return "V8ArrayBuffer"; + case UNSIGNED_INT_8_ARRAY: + return "UInt8Array"; + case UNSIGNED_INT_8_CLAMPED_ARRAY: + return "UInt8ClampedArray"; + case INT_16_ARRAY: + return "Int16Array"; + case UNSIGNED_INT_16_ARRAY: + return "UInt16Array"; + case UNSIGNED_INT_32_ARRAY: + return "UInt32Array"; + case FLOAT_32_ARRAY: + return "Float32Array"; + case UNDEFINED: + return "Undefined"; + default: + throw new IllegalArgumentException("Invalid V8 type: " + type); + } + } + + /** + * Determines if this value is undefined. + * + * @return Returns true if the value is undefined, false otherwise + */ + public boolean isUndefined() { + return false; + } + + /** + * Gets the runtime this Value was created on. + * + * @return Returns the V8 runtime this value is associated with. + */ + public V8 getRuntime() { + return v8; + } + + /** + * Creates a new Java object pointing at the same V8 Value + * as this. If the value is mutated (by adding new members or + * changing existing ones) then both the original and twin + * will be updated. Twins are .equal and .strict equals, but + * not == in Java. + * + * Twins must be released separately since they have their own + * native resources. + * + * @return A new Java object pointing at the same V8 Value + * as this. + */ + public V8Value twin() { + if (isUndefined()) { + return this; + } + v8.checkThread(); + v8.checkReleased(); + V8Value twin = createTwin(); + v8.createTwin(this, twin); + return twin; + } + + /** + * Releases the native resources associated with this V8Value. + */ + @Override + public void release() { + v8.checkThread(); + if (!released) { + try { + v8.releaseObjRef(this); + } finally { + released = true; + v8.release(v8.getV8RuntimePtr(), objectHandle); + } + } + } + + /** + * Determine if the native resources have been released. Once released + * a V8 Value can no longer be used. + * + * @return Returns true if this object has been released, false otherwise. + */ + public boolean isReleased() { + return released; + } + + /** + * Performs a JS === on the parameter and the receiver. + * + * @param that The Object to compare this object against. + * @return Returns true iff this === that + */ + public boolean strictEquals(final Object that) { + v8.checkThread(); + checkReleased(); + if (that == this) { + return true; + } + if (that == null) { + return false; + } + if (!(that instanceof V8Value)) { + return false; + } + if (isUndefined() && ((V8Value) that).isUndefined()) { + return true; + } + if (((V8Value) that).isUndefined()) { + return false; + } + return v8.strictEquals(v8.getV8RuntimePtr(), getHandle(), ((V8Value) that).getHandle()); + } + + protected long getHandle() { + checkReleased(); + return objectHandle; + } + + protected abstract V8Value createTwin(); + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object that) { + return strictEquals(that); + } + + /** + * Performs a JS == on the parameter and the receiver. + * + * @param that The Object to compare this object against. + * @return Returns true iff this == that + */ + public boolean jsEquals(final Object that) { + v8.checkThread(); + checkReleased(); + if (that == this) { + return true; + } + if (that == null) { + return false; + } + if (!(that instanceof V8Value)) { + return false; + } + if (isUndefined() && ((V8Value) that).isUndefined()) { + return true; + } + if (((V8Value) that).isUndefined()) { + return false; + } + return v8.equals(v8.getV8RuntimePtr(), getHandle(), ((V8Value) that).getHandle()); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + v8.checkThread(); + checkReleased(); + return v8.identityHash(v8.getV8RuntimePtr(), getHandle()); + } + + protected void checkReleased() { + if (released) { + throw new IllegalStateException("Object released"); + } + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/BreakEvent.java b/fine-j2v8/src/com/eclipsesource/v8/debug/BreakEvent.java new file mode 100644 index 000000000..2e8728807 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/BreakEvent.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import com.eclipsesource.v8.V8Object; + +/** + * Holds information about break events. + */ +public class BreakEvent extends EventData { + + private static final String SOURCE_LINE_TEXT = "sourceLineText"; + private static final String SOURCE_COLUMN = "sourceColumn"; + private static final String SOURCE_LINE = "sourceLine"; + + BreakEvent(final V8Object eventData) { + super(eventData); + } + + /** + * Returns the source line that this break event occurred on. + * + * @return The line number that this break event occurred on. + */ + public int getSourceLine() { + return v8Object.executeIntegerFunction(SOURCE_LINE, null); + } + + /** + * Returns the source column that this break event occurred on. + * + * @return The column number that this break event occurred on. + */ + public int getSourceColumn() { + return v8Object.executeIntegerFunction(SOURCE_COLUMN, null); + } + + /** + * Returns the text of the line that this event occurred on. + * + * @return The text of the line that this event occurred on. + */ + public String getSourceLineText() { + return v8Object.executeStringFunction(SOURCE_LINE_TEXT, null); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/BreakHandler.java b/fine-j2v8/src/com/eclipsesource/v8/debug/BreakHandler.java new file mode 100644 index 000000000..01d670249 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/BreakHandler.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import com.eclipsesource.v8.V8Object; +import com.eclipsesource.v8.debug.DebugHandler.DebugEvent; + +public interface BreakHandler { + + public void onBreak(DebugEvent type, ExecutionState state, EventData eventData, V8Object data); + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/CompileEvent.java b/fine-j2v8/src/com/eclipsesource/v8/debug/CompileEvent.java new file mode 100644 index 000000000..855a9b2d2 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/CompileEvent.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import com.eclipsesource.v8.V8Object; + +/** + * Holds information about Compile Events. + */ +public class CompileEvent extends EventData { + + CompileEvent(final V8Object eventData) { + super(eventData); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/DebugHandler.java b/fine-j2v8/src/com/eclipsesource/v8/debug/DebugHandler.java new file mode 100644 index 000000000..6346d40df --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/DebugHandler.java @@ -0,0 +1,352 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import java.util.ArrayList; +import java.util.List; + +import com.eclipsesource.v8.JavaVoidCallback; +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8; +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Function; +import com.eclipsesource.v8.V8Object; + +/** + * The entry point for the Debug API. The debug API is a Java API + * that exposes V8's JavaScript API. + * + * The API requires that V8 be initialized with the runtime flag + * '--expose-debug-as=__j2v8_debug_handler'. + */ +public class DebugHandler implements Releasable { + + public static enum DebugEvent { + Undefined(0), Break(1), Exception(2), NewFunction(3), BeforeCompile(4), AfterCompile(5), CompileError(6), PromiseError(7), AsyncTaskEvent(8); + int index; + + DebugEvent(final int index) { + this.index = index; + } + } + + public static String DEBUG_OBJECT_NAME = "__j2v8_Debug"; + + private static final String DEBUG_BREAK_HANDLER = "__j2v8_debug_handler"; + private static final String SET_SCRIPT_BREAK_POINT_BY_NAME = "setScriptBreakPointByName"; + private static final String SET_BREAK_POINT = "setBreakPoint"; + private static final String SET_LISTENER = "setListener"; + private static final String V8_DEBUG_OBJECT = "Debug"; + private static final String DISABLE_SCRIPT_BREAK_POINT = "disableScriptBreakPoint"; + private static final String ENABLE_SCRIPT_BREAK_POINT = "enableScriptBreakPoint"; + private static final String CLEAR_BREAK_POINT = "clearBreakPoint"; + private static final String DISABLE_ALL_BREAK_POINTS = "disableAllBreakPoints"; + private static final String SCRIPT_BREAK_POINTS = "scriptBreakPoints"; + private static final String FIND_SCRIPT_BREAK_POINT = "findScriptBreakPoint"; + private static final String NUMBER = "number"; + private static final String CHANGE_BREAK_POINT_CONDITION = "changeBreakPointCondition"; + + private V8 runtime; + private V8Object debugObject; + private List breakHandlers = new ArrayList(); + + /** + * Creates the Debug Handler for a particular V8 runtime. + * Before the runtime was created, V8.setFlags("expose-debug-as=__j2v8_debug_handler"); + * must be called. + * + * @param runtime The runtime on which to create the Debug Handler. + */ + public DebugHandler(final V8 runtime) { + this.runtime = runtime; + setupDebugObject(runtime); + setupBreakpointHandler(); + } + + /** + * Adds a handler to be notified when a breakpoint is hit. + * + * @param handler The handler to notify. + */ + public void addBreakHandler(final BreakHandler handler) { + runtime.getLocker().checkThread(); + breakHandlers.add(handler); + } + + /** + * Removes a handler from the list of breakpoint handlers. + * If the handler is not present in the list, the list is unchanged. + * + * @param handler The handler to remove. + */ + public void removeBreakHandler(final BreakHandler handler) { + runtime.getLocker().checkThread(); + breakHandlers.remove(handler); + } + + /** + * Registers a function breakpoint. When the JavaScript function + * is invoked, the breakpoint will be 'hit'. + * + * @param function The function on which to register the breakpoint. + * @return The berakpointID. + */ + public int setBreakpoint(final V8Function function) { + V8Array parameters = new V8Array(runtime); + parameters.push(function); + try { + return debugObject.executeIntegerFunction(SET_BREAK_POINT, parameters); + } finally { + parameters.release(); + } + } + + /** + * Registers a breakpoint given a scriptID and line number. The breakpoint + * will be 'hit' when the script is executed and the given line is reached. + * + * @param scriptID The ID of the script on which to set the breakpoint. + * @param lineNumber The line number on which to set the breakpoint. + * @return The berakpointID. + */ + public int setScriptBreakpoint(final String scriptID, final int lineNumber) { + V8Array parameters = new V8Array(runtime); + parameters.push(scriptID); + parameters.push(lineNumber); + try { + return debugObject.executeIntegerFunction(SET_SCRIPT_BREAK_POINT_BY_NAME, parameters); + } finally { + parameters.release(); + } + } + + /** + * Enables a breakpoint. + * + * @param breakpointID The breakpoint to enable. + */ + public void enableScriptBreakPoint(final int breakpointID) { + V8Array parameters = new V8Array(runtime); + parameters.push(breakpointID); + try { + debugObject.executeVoidFunction(ENABLE_SCRIPT_BREAK_POINT, parameters); + } finally { + parameters.release(); + } + } + + /** + * Disables a breakpoint. + * + * @param breakpointID The breakpoint to disable + */ + public void disableScriptBreakPoint(final int breakpointID) { + V8Array parameters = new V8Array(runtime); + parameters.push(breakpointID); + try { + debugObject.executeVoidFunction(DISABLE_SCRIPT_BREAK_POINT, parameters); + } finally { + parameters.release(); + } + } + + /** + * Removes a Breakpoint. + * + * @param breakpointID The ID of the breakpoint to remove. + */ + public void clearBreakPoint(final int breakpointID) { + V8Array parameters = new V8Array(runtime); + parameters.push(breakpointID); + try { + debugObject.executeVoidFunction(CLEAR_BREAK_POINT, parameters); + } finally { + parameters.release(); + } + } + + /** + * Disables all breakpoints. + */ + public void disableAllBreakPoints() { + debugObject.executeVoidFunction(DISABLE_ALL_BREAK_POINTS, null); + } + + /** + * Returns a count of all the breakpoints + * + * @return A V8Array of Breakpoints. + */ + public int getScriptBreakPointCount() { + V8Array breakPoints = debugObject.executeArrayFunction(SCRIPT_BREAK_POINTS, null); + try { + return breakPoints.length(); + } finally { + breakPoints.release(); + } + } + + /** + * Get all the BreakPoint IDs as an array. + * + * @return A list of BreakPoint IDs. + */ + public int[] getScriptBreakPointIDs() { + V8Array breakPoints = debugObject.executeArrayFunction(SCRIPT_BREAK_POINTS, null); + try { + int[] result = new int[breakPoints.length()]; + for (int i = 0; i < breakPoints.length(); i++) { + V8Object breakPoint = breakPoints.getObject(i); + try { + result[i] = breakPoint.executeIntegerFunction(NUMBER, null); + } finally { + breakPoint.release(); + } + } + return result; + } finally { + breakPoints.release(); + } + } + + /** + * Get the BreakPoint as referenced by the given ID. + * + * @param breakPointID The BreakPoint ID. + * @return The BreakPoint as referenced by the given ID. + */ + public ScriptBreakPoint getScriptBreakPoint(final int breakPointID) { + V8Array parameters = new V8Array(runtime); + parameters.push(breakPointID); + parameters.push(false); + V8Object scriptBreakPoint = null; + try { + scriptBreakPoint = debugObject.executeObjectFunction(FIND_SCRIPT_BREAK_POINT, parameters); + return new ScriptBreakPoint(scriptBreakPoint); + } finally { + parameters.release(); + if (scriptBreakPoint != null) { + scriptBreakPoint.release(); + } + } + } + + /** + * Changes the current condition on the breakpoint as specified by the breakpoint ID + * + * @param breakpointID The ID of the breakpoint of which to change the condition on + * @param condition The new condition to set + */ + public void changeBreakPointCondition(final int breakpointID, final String condition) { + V8Array parameters = new V8Array(runtime); + parameters.push(breakpointID); + parameters.push(condition); + try { + debugObject.executeVoidFunction(CHANGE_BREAK_POINT_CONDITION, parameters); + } finally { + parameters.release(); + } + } + + @Override + public void release() { + debugObject.release(); + } + + private void setupDebugObject(final V8 runtime) { + V8Object outerDebug = runtime.getObject(DEBUG_OBJECT_NAME); + try { + debugObject = outerDebug.getObject(V8_DEBUG_OBJECT); + } finally { + outerDebug.release(); + } + } + + private void setupBreakpointHandler() { + BreakpointHandler handler = new BreakpointHandler(); + debugObject.registerJavaMethod(handler, DEBUG_BREAK_HANDLER); + V8Function debugHandler = null; + V8Array parameters = null; + try { + debugHandler = (V8Function) debugObject.getObject(DEBUG_BREAK_HANDLER); + parameters = new V8Array(runtime).push(debugHandler); + debugObject.executeFunction(SET_LISTENER, parameters); + } finally { + if ((debugHandler != null) && !debugHandler.isReleased()) { + debugHandler.release(); + } + if ((parameters != null) && !parameters.isReleased()) { + parameters.release(); + } + } + } + + private class BreakpointHandler implements JavaVoidCallback { + + @Override + public void invoke(final V8Object receiver, final V8Array parameters) { + if ((parameters == null) || parameters.isUndefined()) { + return; + } + int event = parameters.getInteger(0); + for (BreakHandler handler : breakHandlers) { + invokeHandler(parameters, event, handler); + } + } + + private void invokeHandler(final V8Array parameters, final int event, final BreakHandler handler) { + V8Object execState = null; + V8Object eventData = null; + V8Object data = null; + ExecutionState state = null; + EventData typedEventData = null; + try { + execState = parameters.getObject(1); + eventData = parameters.getObject(2); + data = parameters.getObject(3); + state = new ExecutionState(execState); + DebugEvent type = DebugEvent.values()[event]; + typedEventData = createDebugEvent(type, eventData); + handler.onBreak(type, state, typedEventData, data); + } finally { + safeRelease(execState); + safeRelease(eventData); + safeRelease(data); + safeRelease(state); + safeRelease(typedEventData); + } + } + + private EventData createDebugEvent(final DebugEvent type, final V8Object eventData) { + switch (type) { + case Break: + return new BreakEvent(eventData); + case BeforeCompile: + return new CompileEvent(eventData); + case AfterCompile: + return new CompileEvent(eventData); + case Exception: + return new ExceptionEvent(eventData); + default: + break; + } + return new EventData(eventData); + } + + private void safeRelease(final Releasable object) { + if ((object != null)) { + object.release(); + } + } + + } + +} \ No newline at end of file diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/EventData.java b/fine-j2v8/src/com/eclipsesource/v8/debug/EventData.java new file mode 100644 index 000000000..e31342ebc --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/EventData.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8Object; + +/** + * Typed information about different debug events. + */ +public class EventData implements Releasable { + + protected V8Object v8Object; + + EventData(final V8Object eventData) { + v8Object = eventData.twin(); + } + + @Override + public void release() { + if (!v8Object.isReleased()) { + v8Object.release(); + } + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/ExceptionEvent.java b/fine-j2v8/src/com/eclipsesource/v8/debug/ExceptionEvent.java new file mode 100644 index 000000000..4ead02000 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/ExceptionEvent.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import com.eclipsesource.v8.V8Object; + +/** + * Holds information about Exception Events. + */ +public class ExceptionEvent extends EventData { + + ExceptionEvent(final V8Object eventData) { + super(eventData); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/ExecutionState.java b/fine-j2v8/src/com/eclipsesource/v8/debug/ExecutionState.java new file mode 100644 index 000000000..77dad6fa1 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/ExecutionState.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; +import com.eclipsesource.v8.debug.mirror.Frame; + +/** + * Represents the current execution state at a break. + * The execution state provides methods for inspecting + * the stack, variables and scopes. + * + * The ExecutionState should not be persisted as it + * will be released when the debugger continues. + * + */ +public class ExecutionState implements Releasable { + + private static final String FRAME = "frame"; + private static final String PREPARE_STEP = "prepareStep"; + private static final String FRAME_COUNT = "frameCount"; + + private V8Object v8Object; + + ExecutionState(final V8Object v8Object) { + this.v8Object = v8Object.twin(); + } + + /** + * Returns the current stack frame count. + * + * @return The stack frame count. + */ + public int getFrameCount() { + return v8Object.executeIntegerFunction(FRAME_COUNT, null); + } + + /** + * Indicates to the debugger how to proceed. If not called, + * the debugger will continue running until the next breakpoint + * is hit. + * + * @param action The step action to use. + */ + public void prepareStep(final StepAction action) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(action.index); + try { + v8Object.executeVoidFunction(PREPARE_STEP, parameters); + } finally { + parameters.release(); + } + } + + /** + * Returns the Frame at a given index + * + * @param index The stack index + * @return The stack frame at a given index + */ + public Frame getFrame(final int index) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(index); + V8Object frame = null; + try { + frame = v8Object.executeObjectFunction(FRAME, parameters); + return new Frame(frame); + } finally { + parameters.release(); + if (frame != null) { + frame.release(); + } + } + } + + @Override + public void release() { + if ((v8Object != null) && !v8Object.isReleased()) { + v8Object.release(); + v8Object = null; + } + } + +} \ No newline at end of file diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/ScriptBreakPoint.java b/fine-j2v8/src/com/eclipsesource/v8/debug/ScriptBreakPoint.java new file mode 100644 index 000000000..850c14bdb --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/ScriptBreakPoint.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; +import com.eclipsesource.v8.V8ResultUndefined; + +/** + * Represents a BreakPoint. + */ +public class ScriptBreakPoint implements Releasable { + + private static final String CONDITION = "condition"; + private static final String LINE = "line"; + private static final String NUMBER = "number"; + private static final String SET_CONDITION = "setCondition"; + + private V8Object v8Object; + + ScriptBreakPoint(final V8Object v8Object) { + this.v8Object = v8Object.twin(); + } + + /** + * Returns the ID of this breakpoint. + * + * @return The ID (breakpoint number) of this breakpoint. + */ + public int getBreakPointNumber() { + return v8Object.executeIntegerFunction(NUMBER, null); + } + + /** + * Returns the line number of this breakpoint. + * + * @return The line number of this breakpoint. + */ + public int getLine() { + return v8Object.executeIntegerFunction(LINE, null); + } + + /** + * Sets a condition to be evaluated before determining if + * the breakpoint event should be fired. + * + * @param condition A JavaScript condition to be evaluated. + */ + public void setCondition(final String condition) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(condition); + try { + v8Object.executeVoidFunction(SET_CONDITION, parameters); + } finally { + parameters.release(); + } + } + + /** + * Returns the condition set on this breakpoint or the String + * 'undefined' if a condition was not set. + * + * @return The condition set on this breakpoint. + */ + public String getCondition() { + try { + return v8Object.executeStringFunction(CONDITION, null); + } catch (V8ResultUndefined e) { + return "undefined"; + } + } + + @Override + public void release() { + if ((v8Object != null) && !v8Object.isReleased()) { + v8Object.release(); + v8Object = null; + } + } +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/StepAction.java b/fine-j2v8/src/com/eclipsesource/v8/debug/StepAction.java new file mode 100644 index 000000000..177b5fde9 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/StepAction.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug; + +/** + * An enumeration of possible Step Actions. A step action indicates to the + * debugger how to proceed with the next step. + */ +public enum StepAction { + STEP_OUT(0), STEP_NEXT(1), STEP_IN(2), STEP_FRAME(3); + int index; + + StepAction(final int index) { + this.index = index; + } + +} \ No newline at end of file diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ArrayMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ArrayMirror.java new file mode 100644 index 000000000..9bb67ad80 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ArrayMirror.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents 'Array' mirrors. + */ +public class ArrayMirror extends ObjectMirror { + + private static final String LENGTH = "length"; + + ArrayMirror(final V8Object v8Object) { + super(v8Object); + } + + @Override + public boolean isArray() { + return true; + } + + /** + * Returns the length of the array pointed to by this Array Mirror + * + * @return The length of the array. + */ + public int length() { + return v8Object.executeIntegerFunction(LENGTH, null); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/BooleanMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/BooleanMirror.java new file mode 100644 index 000000000..5c6739b2f --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/BooleanMirror.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents JavaScript 'Boolean' Mirrors + */ +public class BooleanMirror extends ValueMirror { + + BooleanMirror(final V8Object v8Object) { + super(v8Object); + } + + @Override + public boolean isBoolean() { + return true; + } + + @Override + public String toString() { + return v8Object.executeStringFunction("toText", null); + } +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Frame.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Frame.java new file mode 100644 index 000000000..ad1f14371 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Frame.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; + +/** + * Represents a single stack frame accessible from the + * current execution state. + */ +public class Frame extends Mirror { + + private static final String END = "end"; + private static final String START = "start"; + private static final String COLUMN = "column"; + private static final String LINE = "line"; + private static final String POSITION = "position"; + private static final String NAME = "name"; + private static final String SCRIPT = "script"; + private static final String SCOPE = "scope"; + private static final String ARGUMENT_VALUE = "argumentValue"; + private static final String ARGUMENT_NAME = "argumentName"; + private static final String LOCAL_COUNT = "localCount"; + private static final String ARGUMENT_COUNT = "argumentCount"; + private static final String SCOPE_COUNT = "scopeCount"; + private static final String LOCAL_NAME = "localName"; + private static final String LOCAL_VALUE = "localValue"; + private static final String SOURCE_LOCATION = "sourceLocation"; + + public Frame(final V8Object v8Object) { + super(v8Object); + } + + /** + * Returns the number of accessible scopes from this stack frame. + * + * @return The number of accessible scopes + */ + public int getScopeCount() { + return v8Object.executeIntegerFunction(SCOPE_COUNT, null); + } + + /** + * Returns the SourceLocation of this Frame. + * + * @return The SourceLocation of this Frame. + */ + public SourceLocation getSourceLocation() { + V8Object sourceLocation = v8Object.executeObjectFunction(SOURCE_LOCATION, null); + try { + V8Object scriptObject = (V8Object) sourceLocation.get(SCRIPT); + String scriptName = scriptObject.getString(NAME); + scriptObject.release(); + return new SourceLocation(scriptName, + sourceLocation.getInteger(POSITION), + sourceLocation.getInteger(LINE), + sourceLocation.getInteger(COLUMN), + sourceLocation.getInteger(START), + sourceLocation.getInteger(END)); + } finally { + sourceLocation.release(); + } + } + + /** + * Returns the number of arguments to this frame. + * + * @return The number of arguments passed to this frame. + */ + public int getArgumentCount() { + return v8Object.executeIntegerFunction(ARGUMENT_COUNT, null); + } + + /** + * Returns the name of the argument at the given index. + * + * @param index The index of the argument name to return. + * @return The name of argument at the given index. + */ + public String getArgumentName(final int index) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(index); + try { + return v8Object.executeStringFunction(ARGUMENT_NAME, parameters); + } finally { + parameters.release(); + } + } + + /** + * Returns the value of the argument at the given index. + * + * @param index The index of the argument value to return. + * @return The value of argument at the given index. + */ + public ValueMirror getArgumentValue(final int index) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(index); + V8Object result = null; + try { + result = v8Object.executeObjectFunction(ARGUMENT_VALUE, parameters); + if (!isValue(result)) { + throw new IllegalStateException("Argument value is not a ValueMirror"); + } + return new ValueMirror(result); + } finally { + parameters.release(); + if (result != null) { + result.release(); + } + } + } + + /** + * Returns the value of the local variable at the given index. + * + * @param index The index of the local to return. + * @return The value of local at the given index. + */ + public ValueMirror getLocalValue(final int index) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(index); + V8Object result = null; + try { + result = v8Object.executeObjectFunction(LOCAL_VALUE, parameters); + if (!isValue(result)) { + throw new IllegalStateException("Local value is not a ValueMirror"); + } + return createMirror(result); + } finally { + parameters.release(); + if (result != null) { + result.release(); + } + } + } + + /** + * Returns the number of local variables in this frame. + * + * @return The number of local variables accessible from this stack frame. + */ + public int getLocalCount() { + return v8Object.executeIntegerFunction(LOCAL_COUNT, null); + } + + /** + * Returns the name of the local variable at the given index. + * + * @param index The index of the local variable name to return. + * @return The name of local variable at the given index. + */ + public String getLocalName(final int index) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(index); + try { + return v8Object.executeStringFunction(LOCAL_NAME, parameters); + } finally { + parameters.release(); + } + } + + /** + * Returns the scope at a given index. + * + * @param index The index + * @return The scope + */ + public Scope getScope(final int index) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(index); + V8Object scope = null; + try { + scope = v8Object.executeObjectFunction(SCOPE, parameters); + return new Scope(scope); + } finally { + parameters.release(); + if (scope != null) { + scope.release(); + } + } + } + + /** + * Returns the Function associated with this particular debug frame. + * + * @return The Function for this debug frame. + */ + public FunctionMirror getFunction() { + V8Object function = null; + try { + function = v8Object.executeObjectFunction("func", null); + return new FunctionMirror(function); + } finally { + if (function != null) { + function.release(); + } + } + } + + @Override + public boolean isFrame() { + return true; + } + +} \ No newline at end of file diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/FunctionMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/FunctionMirror.java new file mode 100644 index 000000000..f340f82c8 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/FunctionMirror.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents JavaScript 'Function' Mirrors + */ +public class FunctionMirror extends ObjectMirror { + + FunctionMirror(final V8Object v8Object) { + super(v8Object); + } + + /** + * Returns the name of this Function. + * + * @return The name of this function + */ + public String getName() { + return v8Object.executeStringFunction("name", null); + } + + @Override + public boolean isFunction() { + return true; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Mirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Mirror.java new file mode 100644 index 000000000..9b8eaa380 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Mirror.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8Object; +import com.eclipsesource.v8.V8ResultUndefined; + +/** + * A mirror is used to represent a copy (mirror) of a runtime object + * during a debug session. + * + * Mirror hierarchy: + * - Mirror + * - ValueMirror + * - UndefinedMirror + * - NullMirror + * - NumberMirror + * - StringMirror + * - ObjectMirror + * - FunctionMirror + * - UnresolvedFunctionMirror + * - ArrayMirror + * - DateMirror + * - RegExpMirror + * - ErrorMirror + * - PromiseMirror + * - PropertyMirror + * - InternalPropertyMirror + * - FrameMirror + * - ScriptMirror + */ +public class Mirror implements Releasable { + + private static final String IS_UNDEFINED = "isUndefined"; + private static final String IS_NULL = "isNull"; + private static final String IS_STRING = "isString"; + private static final String IS_ARRAY = "isArray"; + private static final String IS_FUNCTION = "isFunction"; + private static final String IS_BOOLEAN = "isBoolean"; + private static final String IS_NUMBER = "isNumber"; + private static final String IS_OBJECT = "isObject"; + private static final String IS_VALUE = "isValue"; + + protected V8Object v8Object; + + Mirror(final V8Object v8Object) { + this.v8Object = v8Object.twin(); + } + + /** + * Returns true if this mirror object points to the type 'undefined'. + * False otherwise. + * + * @return True iff this mirror object points to an 'undefined' type. + */ + public boolean isUndefined() { + return v8Object.executeBooleanFunction(IS_UNDEFINED, null); + } + + /** + * Returns true if this mirror object points to a 'value' type. + * + * @return True iff this mirror object points to a 'value' type. + */ + public boolean isValue() { + return false; + } + + /** + * Returns true if this mirror object points to 'null'. + * + * @return True iff this mirror object points to a 'null'. + */ + public boolean isNull() { + return false; + } + + /** + * Returns true if this mirror object points to a 'boolean' type. + * + * @return True iff this mirror object points to a 'boolean' type. + */ + public boolean isBoolean() { + return false; + } + + /** + * Returns true if this mirror object points to a 'number' type. + * + * @return True iff this mirror object points to a 'number' type. + */ + public boolean isNumber() { + return false; + } + + /** + * Returns true if this mirror object points to a 'String' type. + * + * @return True iff this mirror object points to a 'String' type. + */ + public boolean isString() { + return false; + } + + /** + * Returns true if this mirror object points to an 'Object' type. + * + * @return True iff this mirror object points to an 'Object' type. + */ + public boolean isObject() { + return false; + } + + /** + * Returns true if this mirror object points to a 'Function' type. + * + * @return True iff this mirror object points to a 'Function' type. + */ + public boolean isFunction() { + return false; + } + + /** + * Returns true if this mirror object points to an 'Array' type. + * + * @return True iff this mirror object points to an 'Array' type. + */ + public boolean isArray() { + return false; + } + + /** + * Returns true if this mirror object points to a 'Function' type. + * + * @return True iff this mirror object points to a 'Function' type. + */ + public boolean isFrame() { + return false; + } + + /** + * Returns true if this mirror object points to a 'Property' type. + * + * @return True iff this mirror object points to a 'Property' type. + */ + public boolean isProperty() { + return false; + } + + @Override + public void release() { + if ((v8Object != null) && !v8Object.isReleased()) { + v8Object.release(); + v8Object = null; + } + } + + protected static boolean isValue(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_VALUE, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isObject(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_OBJECT, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isNumber(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_NUMBER, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isBoolean(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_BOOLEAN, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isFunction(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_FUNCTION, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isArray(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_ARRAY, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isString(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_STRING, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isUndefined(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_UNDEFINED, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + private static boolean isNull(final V8Object mirror) { + try { + return mirror.executeBooleanFunction(IS_NULL, null); + } catch (V8ResultUndefined e) { + return false; + } + } + + protected static ValueMirror createMirror(final V8Object mirror) { + if (isNull(mirror)) { + return new NullMirror(mirror); + } else if (isUndefined(mirror)) { + return new UndefinedMirror(mirror); + } else if (isFunction(mirror)) { + return new FunctionMirror(mirror); + } else if (isArray(mirror)) { + return new ArrayMirror(mirror); + } else if (isObject(mirror)) { + return new ObjectMirror(mirror); + } else if (isString(mirror)) { + return new StringMirror(mirror); + } else if (isNumber(mirror)) { + return new NumberMirror(mirror); + } else if (isBoolean(mirror)) { + return new BooleanMirror(mirror); + } + return new ValueMirror(mirror); + } + + @Override + public String toString() { + return v8Object.toString(); + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof Mirror)) { + return false; + } + return v8Object.equals(((Mirror) obj).v8Object); + } + + @Override + public int hashCode() { + return v8Object.hashCode(); + } +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/NullMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/NullMirror.java new file mode 100644 index 000000000..6e43c2c14 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/NullMirror.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents 'Null' Mirrors + */ +public class NullMirror extends ValueMirror { + + + NullMirror(final V8Object v8Object) { + super(v8Object); + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public String toString() { + return "null"; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/NumberMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/NumberMirror.java new file mode 100644 index 000000000..12286abe6 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/NumberMirror.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents JavaScript 'Number' Mirrors + */ +public class NumberMirror extends ValueMirror { + + NumberMirror(final V8Object v8Object) { + super(v8Object); + } + + @Override + public boolean isNumber() { + return true; + } + + @Override + public String toString() { + return v8Object.executeStringFunction("toText", null); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ObjectMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ObjectMirror.java new file mode 100644 index 000000000..b9a5e8bf1 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ObjectMirror.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; + +/** + * Represents 'Object' mirrors. + */ +public class ObjectMirror extends ValueMirror { + + private static final String PROPERTIES = "properties"; + private static final String PROPERTY_NAMES = "propertyNames"; + + public enum PropertyKind { + Named(1), Indexed(2); + int index; + + private PropertyKind(final int index) { + this.index = index; + } + } + + @Override + public String toString() { + return v8Object.toString(); + } + + ObjectMirror(final V8Object v8Object) { + super(v8Object); + } + + @Override + public boolean isObject() { + return true; + } + + /** + * Returns all the property names for the given object. + * + * @param kind Indicate whether named, indexed or both kinds of properties are requested. + * @param limit Limit the number of properties returned to the specified value + * @return All the property names for a given object + */ + public String[] getPropertyNames(final PropertyKind kind, final int limit) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(kind.index); + parameters.push(limit); + V8Array propertyNames = null; + try { + propertyNames = v8Object.executeArrayFunction(PROPERTY_NAMES, parameters); + String[] result = new String[propertyNames.length()]; + for (int i = 0; i < result.length; i++) { + result[i] = propertyNames.getString(i); + } + return result; + } finally { + parameters.release(); + if (propertyNames != null) { + propertyNames.release(); + } + } + } + + /** + * Return the properties for this object as an array of PropertyMirror objects. + * + * @param kind Indicate whether named, indexed or both kinds of properties are requested + * @param limit Limit the number of properties returned to the specified value + * @return {Array} Property mirrors for this object + */ + public PropertiesArray getProperties(final PropertyKind kind, final int limit) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(kind.index); + parameters.push(limit); + V8Array result = null; + try { + result = v8Object.executeArrayFunction(PROPERTIES, parameters); + return new PropertiesArray(result); + } finally { + parameters.release(); + if ((result != null) && !result.isReleased()) { + result.release(); + result = null; + } + } + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/PropertiesArray.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/PropertiesArray.java new file mode 100644 index 000000000..c247e9e25 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/PropertiesArray.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; + +/** + * Provides typed access to a set of properties. + */ +public class PropertiesArray implements Releasable { + + private V8Array v8Array; + + PropertiesArray(final V8Array v8Object) { + v8Array = v8Object.twin(); + } + + /** + * Returns the PropertyMiror at a given index. + * + * @param index The index of the property + * @return The property at the given index + */ + public PropertyMirror getProperty(final int index) { + V8Object result = v8Array.getObject(index); + try { + return new PropertyMirror(result); + } finally { + result.release(); + } + } + + @Override + public void release() { + if (!v8Array.isReleased()) { + v8Array.release(); + } + } + + /** + * Returns the number of properties contained in this array. + * + * @return The length of this array. + */ + public int length() { + return v8Array.length(); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/PropertyMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/PropertyMirror.java new file mode 100644 index 000000000..be94c7669 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/PropertyMirror.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents JavaScript 'Property' Mirrors + */ +public class PropertyMirror extends Mirror { + + PropertyMirror(final V8Object v8Object) { + super(v8Object); + } + + /** + * Returns the name of this property. + * + * @return The name of this property. + */ + public String getName() { + return v8Object.executeStringFunction("name", null); + } + + /** + * Returns the value of this property. + * + * @return The value of this property. + */ + public Mirror getValue() { + V8Object mirror = v8Object.executeObjectFunction("value", null); + try { + return createMirror(mirror); + } finally { + mirror.release(); + } + } + + @Override + public boolean isProperty() { + return true; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Scope.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Scope.java new file mode 100644 index 000000000..820320600 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/Scope.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; +import com.eclipsesource.v8.V8Value; + +/** + * Represents a JavaScope scope accessible from the current stack frame + * during debug break. + * + */ +public class Scope extends Mirror { + + private static final String SCOPE_OBJECT = "scopeObject"; + private static final String SCOPE_TYPE = "scopeType"; + private static final String SET_VARIABLE_VALUE = "setVariableValue"; + + /** + * Represents the different types of scopes available. + */ + public static enum ScopeType { + Global(0), Local(1), With(2), Closure(3), Catch(4), Block(5), Script(6); + int index; + + private ScopeType(final int index) { + this.index = index; + } + } + + Scope(final V8Object v8Object) { + super(v8Object); + } + + /** + * Returns the type of this scope. + * + * @return The type of scope. + */ + public ScopeType getType() { + return ScopeType.values()[v8Object.executeIntegerFunction(SCOPE_TYPE, null)]; + } + + /** + * Sets the value of a variable in this scope. + * + * @param name The name of the variable + * @param value The value + */ + public void setVariableValue(final String name, final int value) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(name); + parameters.push(value); + try { + v8Object.executeVoidFunction(SET_VARIABLE_VALUE, parameters); + } finally { + parameters.release(); + } + } + + /** + * Sets the value of a variable in this scope. + * + * @param name The name of the variable + * @param value The value + */ + public void setVariableValue(final String name, final V8Value value) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(name); + parameters.push(value); + try { + v8Object.executeVoidFunction(SET_VARIABLE_VALUE, parameters); + } finally { + parameters.release(); + } + } + + /** + * Sets the value of a variable in this scope. + * + * @param name The name of the variable + * @param value The value + */ + public void setVariableValue(final String name, final boolean value) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(name); + parameters.push(value); + try { + v8Object.executeVoidFunction(SET_VARIABLE_VALUE, parameters); + } finally { + parameters.release(); + } + } + + /** + * Sets the value of a variable in this scope. + * + * @param name The name of the variable + * @param value The value + */ + public void setVariableValue(final String name, final String value) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(name); + parameters.push(value); + try { + v8Object.executeVoidFunction(SET_VARIABLE_VALUE, parameters); + } finally { + parameters.release(); + } + } + + /** + * Sets the value of a variable in this scope. + * + * @param name The name of the variable + * @param value The value + */ + public void setVariableValue(final String name, final double value) { + V8Array parameters = new V8Array(v8Object.getRuntime()); + parameters.push(name); + parameters.push(value); + try { + v8Object.executeVoidFunction(SET_VARIABLE_VALUE, parameters); + } finally { + parameters.release(); + } + } + + /** + * Returns the underlying V8Object that represents this scope. + * + * @return The underlying V8Object that represents this scope. + */ + public ObjectMirror getScopeObject() { + V8Object mirror = null; + try { + mirror = v8Object.executeObjectFunction(SCOPE_OBJECT, null); + return (ObjectMirror) createMirror(mirror); + } finally { + if ( mirror != null ) { + mirror.release(); + } + } + + } + +} \ No newline at end of file diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/SourceLocation.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/SourceLocation.java new file mode 100644 index 000000000..71bb31b4a --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/SourceLocation.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +/** + * Represents a JS Script location. + */ +public class SourceLocation { + + private final String scriptName; + private final int position; + private final int line; + private final int column; + private final int start; + private final int end; + + /** + * Represents a JS Script Source Location + * @param scriptName The name of the script + * @param position The position in the script + * @param line The line number + * @param column The column number + * @param start The start of this location + * @param end The end of this location + */ + public SourceLocation(final String scriptName, final int position, final int line, final int column, final int start, final int end) { + this.scriptName = scriptName; + this.position = position; + this.line = line; + this.column = column; + this.start = start; + this.end = end; + } + + @Override + public String toString() { + return scriptName + " : " + position + " : " + line + " : " + column + " : " + start + " : " + end; + } + + /** + * Returns the name of the script for this SourceLocation. + * @return The name of the script + */ + public String getScriptName() { + return scriptName; + } + + /** + * Returns the position of this SourceLocation. + * @return The position of this SourceLocation. + */ + public int getPosition() { + return position; + } + + /** + * Returns the line number of this SourceLocation. + * @return The line number of this SourceLocation. + */ + public int getLine() { + return line; + } + + /** + * Returns the column number of this SourceLocation. + * @return The column number of this SourceLocation. + */ + public int getColumn() { + return column; + } + + /** + * Returns the start of this SourceLocation. + * @return The start of this SourceLocation. + */ + public int getStart() { + return start; + } + + /** + * Returns the end of this SourceLocation. + * @return The end of this SourceLocation. + */ + public int getEnd() { + return end; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/StringMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/StringMirror.java new file mode 100644 index 000000000..4ba73d3b3 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/StringMirror.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents JavaScript 'String' Mirrors + */ +public class StringMirror extends ValueMirror { + + StringMirror(final V8Object v8Object) { + super(v8Object); + } + + @Override + public boolean isString() { + return true; + } + + @Override + public String toString() { + return v8Object.executeStringFunction("toText", null); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/UndefinedMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/UndefinedMirror.java new file mode 100644 index 000000000..04f133efc --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/UndefinedMirror.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents 'Undefined' Mirrors + */ +public class UndefinedMirror extends ValueMirror { + + + UndefinedMirror(final V8Object v8Object) { + super(v8Object); + } + + @Override + public boolean isUndefined() { + return true; + } + + @Override + public String toString() { + return "undefined"; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ValueMirror.java b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ValueMirror.java new file mode 100644 index 000000000..e5689e396 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/debug/mirror/ValueMirror.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.debug.mirror; + +import com.eclipsesource.v8.V8Object; + +/** + * Represents 'Value' Mirrors (Objects, Numbers, Strings, ...). + */ +public class ValueMirror extends Mirror { + + private static final String VALUE = "value"; + + ValueMirror(final V8Object v8Object) { + super(v8Object); + } + + /** + * Returns the Object that this mirror represents. + * + * @return The object that this mirror represents. + */ + public Object getValue() { + return v8Object.executeFunction(VALUE, null); + } + + @Override + public boolean isValue() { + return true; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/MemoryManager.java b/fine-j2v8/src/com/eclipsesource/v8/utils/MemoryManager.java new file mode 100644 index 000000000..ddb4f88df --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/MemoryManager.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils; + +import java.util.ArrayList; +import java.util.Iterator; + +import com.eclipsesource.v8.ReferenceHandler; +import com.eclipsesource.v8.V8; +import com.eclipsesource.v8.V8Value; + +/** + * A memory manager that tracks all V8 Handles while the object is registered. + * Once released, all V8 handles that were created while the memory manager + * was active, will be released. + * + * It is important that no V8 handles (V8Objects, V8Arrays, etc...) that are + * created while the memory manager is active, are persisted. + * + */ +public class MemoryManager { + + private MemoryManagerReferenceHandler memoryManagerReferenceHandler; + private V8 v8; + private ArrayList references = new ArrayList(); + private boolean releasing = false; + private boolean released = false; + + /** + * Creates and registered a Memory Manager. After this, all V8 handles will be + * tracked until release is called. + * + * @param v8 The V8 runtime to register this Memory Manager on + */ + public MemoryManager(final V8 v8) { + this.v8 = v8; + memoryManagerReferenceHandler = new MemoryManagerReferenceHandler(); + v8.addReferenceHandler(memoryManagerReferenceHandler); + } + + /** + * Returns the number of handles currently being tracked by this + * memory manager. + * + * Throws an IllegalStateException if the memory manager is used after it's + * been released. + * + * @return The object reference count + */ + public int getObjectReferenceCount() { + checkReleased(); + return references.size(); + } + + /** + * Persist an object that is currently being managed by this Manager. + * + * Objects that are being managed by a MemoryManager will be released + * once the MemoryManager is released. If an object is persisted, it will + * be remove from the MemoryManager's control and therefore will not + * be released. + * + * @param object The object to persist + */ + public void persist(final V8Value object) { + v8.getLocker().checkThread(); + checkReleased(); + references.remove(object); + } + + /** + * Checks if the memory manager has been released or not. Released memory + * managers can no longer be used. + * + * @return True if this memory manager has been released, false otherwise. + */ + public boolean isReleased() { + return released; + } + + /** + * Releases this Memory Manager and all V8Objects that were created while + * this memory manager was active. + */ + public void release() { + v8.getLocker().checkThread(); + if (released) { + return; + } + releasing = true; + try { + for (V8Value reference : references) { + reference.release(); + } + v8.removeReferenceHandler(memoryManagerReferenceHandler); + references.clear(); + } finally { + releasing = false; + } + released = true; + } + + private void checkReleased() { + if (released) { + throw new IllegalStateException("Memory manager released"); + } + } + + private class MemoryManagerReferenceHandler implements ReferenceHandler { + + @Override + public void v8HandleCreated(final V8Value object) { + references.add(object); + } + + @Override + public void v8HandleDisposed(final V8Value object) { + if (!releasing) { + Iterator iterator = references.iterator(); + while (iterator.hasNext()) { + if (iterator.next() == object) { + iterator.remove(); + return; + } + } + } + } + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/V8Executor.java b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Executor.java new file mode 100644 index 000000000..50f8c3490 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Executor.java @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils; + +import java.util.LinkedList; + +import com.eclipsesource.v8.JavaVoidCallback; +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8; +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; + +/** + * Executes a JS Script on a new V8 runtime in its own thread, and once finished, + * will optionally wait on a message queue. If the executor is *not* long running, + * when the JS Script finishes, the executor will shutdown. If the executor + * *is* long running, the the script will execute, and when finished, the executor + * will wait for messages to arrive. When messages arrive, the messageHandler + * will be invoked with the contents of the message. + * + * Executors can be shutdown in two different ways. forceTermination() will + * stop any executing scripts and immediately terminate the executor. shutdown() + * will indicate that the executor should shutdown, but this will only happen + * once any scripts finish executing and the message queue becomes empty. + */ +public class V8Executor extends Thread { + + private final String script; + private V8 runtime; + private String result; + private volatile boolean terminated = false; + private volatile boolean shuttingDown = false; + private volatile boolean forceTerminating = false; + private Exception exception = null; + private LinkedList messageQueue = new LinkedList(); + private boolean longRunning; + private String messageHandler; + + /** + * Create a new executor and execute the given script on it. Once + * the script has finished executing, the executor can optionally + * wait on a message queue. + * + * @param script The script to execute on this executor. + * @param longRunning True to indicate that this executor should be longRunning. + * @param messageHandler The name of the message handler that should be notified + * when messages are delivered. + */ + public V8Executor(final String script, final boolean longRunning, final String messageHandler) { + this.script = script; + this.longRunning = longRunning; + this.messageHandler = messageHandler; + } + + /** + * Create a new executor and execute the given script on it. + * + * @param script The script to execute on this executor. + */ + public V8Executor(final String script) { + this(script, false, null); + } + + /** + * Override to provide a custom setup for this V8 runtime. + * This method can be overridden to configure the V8 runtime, + * for example, to add callbacks or to add some additional + * functionality to the global scope. + * + * @param runtime The runtime to configure. + */ + protected void setup(final V8 runtime) { + + } + + /** + * Gets the result of the JavaScript that was executed + * on this executor. + * + * @return The result of the JS Script that was executed on + * this executor. + */ + public String getResult() { + return result; + } + + /** + * Posts a message to the receiver to be processed by the executor + * and sent to the V8 runtime via the messageHandler. + * + * @param message The message to send to the messageHandler + */ + public void postMessage(final String... message) { + synchronized (this) { + messageQueue.add(message); + notify(); + } + } + + /* + * (non-Javadoc) + * @see java.lang.Thread#run() + */ + @Override + public void run() { + synchronized (this) { + runtime = V8.createV8Runtime(); + runtime.registerJavaMethod(new ExecutorTermination(), "__j2v8__checkThreadTerminate"); + setup(runtime); + } + try { + if (!forceTerminating) { + Object scriptResult = runtime.executeScript("__j2v8__checkThreadTerminate();\n" + script, getName(), -1); + if (scriptResult != null) { + result = scriptResult.toString(); + } + if (scriptResult instanceof Releasable) { + ((Releasable) scriptResult).release(); + } + if (scriptResult instanceof Releasable) { + ((Releasable) scriptResult).release(); + } + } + while (!forceTerminating && longRunning) { + synchronized (this) { + if (messageQueue.isEmpty() && !shuttingDown) { + wait(); + } + if ((messageQueue.isEmpty() && shuttingDown) || forceTerminating) { + return; + } + } + if (!messageQueue.isEmpty()) { + String[] message = messageQueue.remove(0); + V8Array parameters = new V8Array(runtime); + V8Array strings = new V8Array(runtime); + try { + for (String string : message) { + strings.push(string); + } + parameters.push(strings); + runtime.executeVoidFunction(messageHandler, parameters); + } finally { + strings.release(); + parameters.release(); + } + } + } + } catch (Exception e) { + exception = e; + } finally { + synchronized (this) { + if (runtime.getLocker().hasLock()) { + runtime.release(); + runtime = null; + } + terminated = true; + } + } + } + + /** + * Determines if an exception was thrown during the JavaScript execution. + * + * @return True if an exception was thrown during the JavaScript execution, + * false otherwise. + */ + public boolean hasException() { + return exception != null; + } + + /** + * Gets the exception that was thrown during the JavaScript execution. + * + * @return The exception that was thrown during the JavaScript execution, + * or null if no such exception was thrown. + */ + public Exception getException() { + return exception; + } + + /** + * Determines if the executor has terminated. + * + * @return True if the executor has terminated, false otherwise. + */ + public boolean hasTerminated() { + return terminated; + } + + /** + * Forces the executor to shutdown immediately. Any currently executing + * JavaScript will be interrupted and all outstanding messages will be + * ignored. + */ + public void forceTermination() { + synchronized (this) { + forceTerminating = true; + shuttingDown = true; + if (runtime != null) { + runtime.terminateExecution(); + } + notify(); + } + } + + /** + * Indicates to the executor that it should shutdown. Any currently + * executing JavaScript will be allowed to finish, and any outstanding + * messages will be processed. Only once the message queue is empty, + * will the executor actually shtutdown. + */ + public void shutdown() { + synchronized (this) { + shuttingDown = true; + notify(); + } + } + + /** + * Returns true if shutdown() or forceTermination() was called to + * shutdown this executor. + * + * @return True if shutdown() or forceTermination() was called, false otherwise. + */ + public boolean isShuttingDown() { + return shuttingDown; + } + + /** + * Returns true if forceTermination was called to shutdown + * this executor. + * + * @return True if forceTermination() was called, false otherwise. + */ + public boolean isTerminating() { + return forceTerminating; + } + + class ExecutorTermination implements JavaVoidCallback { + @Override + public void invoke(final V8Object receiver, final V8Array parameters) { + if (forceTerminating) { + throw new RuntimeException("V8Thread Termination"); + } + } + } +} \ No newline at end of file diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/V8Map.java b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Map.java new file mode 100644 index 000000000..08343fb67 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Map.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.eclipsesource.v8.Releasable; +import com.eclipsesource.v8.V8Value; + +/** + * A Map that maps V8Values to arbitrary Java Objects. + * Once stored in the map, the keys (V8Values) can be released + * as the map will handle their resource management for you. + * + * Once the map is no longer needed, it should be released. To + * tie a map to the lifecycle of a V8 runtime, it can be registered + * as a resource with V8.registerResource. + */ +public class V8Map implements Map, Releasable { + + private Map map; + private Map twinMap; + + /** + * Creates a V8Map. + */ + public V8Map() { + map = new HashMap(); + twinMap = new HashMap(); + } + + /** + * Releases all the resources associated with this map. A + * map can be used again once it's released, although + * if it's used again it should be released again. + */ + @Override + public void release() { + this.clear(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#size() + */ + @Override + public int size() { + return map.size(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#isEmpty() + */ + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#containsKey(java.lang.Object) + */ + @Override + public boolean containsKey(final Object key) { + return map.containsKey(key); + } + + /* + * (non-Javadoc) + * @see java.util.Map#containsValue(java.lang.Object) + */ + @Override + public boolean containsValue(final Object value) { + return map.containsValue(value); + } + + /* + * (non-Javadoc) + * @see java.util.Map#get(java.lang.Object) + */ + @Override + public V get(final Object key) { + return map.get(key); + } + + /* + * (non-Javadoc) + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + @Override + public V put(final V8Value key, final V value) { + this.remove(key); + V8Value twin = key.twin(); + twinMap.put(twin, twin); + return map.put(twin, value); + } + + /* + * (non-Javadoc) + * @see java.util.Map#remove(java.lang.Object) + */ + @Override + public V remove(final Object key) { + V result = map.remove(key); + V8Value twin = twinMap.remove(key); + if (twin != null) { + twin.release(); + } + return result; + } + + /* + * (non-Javadoc) + * @see java.util.Map#putAll(java.util.Map) + */ + @Override + public void putAll(final Map m) { + for (Entry entry : m.entrySet()) { + this.put(entry.getKey(), entry.getValue()); + } + } + + /* + * (non-Javadoc) + * @see java.util.Map#clear() + */ + @Override + public void clear() { + map.clear(); + for (V8Value V8Value : twinMap.keySet()) { + V8Value.release(); + } + twinMap.clear(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#keySet() + */ + @Override + public Set keySet() { + return map.keySet(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#values() + */ + @Override + public Collection values() { + return map.values(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#entrySet() + */ + @Override + public Set> entrySet() { + return map.entrySet(); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/V8ObjectUtils.java b/fine-j2v8/src/com/eclipsesource/v8/utils/V8ObjectUtils.java new file mode 100644 index 000000000..7f8c888fb --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/V8ObjectUtils.java @@ -0,0 +1,649 @@ +/******************************************************************************* + * Copyright (c) 2014 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.eclipsesource.v8.V8; +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8ArrayBuffer; +import com.eclipsesource.v8.V8Object; +import com.eclipsesource.v8.V8TypedArray; +import com.eclipsesource.v8.V8Value; +import com.eclipsesource.v8.utils.typedarrays.ArrayBuffer; +import com.eclipsesource.v8.utils.typedarrays.Float32Array; +import com.eclipsesource.v8.utils.typedarrays.Float64Array; +import com.eclipsesource.v8.utils.typedarrays.Int16Array; +import com.eclipsesource.v8.utils.typedarrays.Int32Array; +import com.eclipsesource.v8.utils.typedarrays.Int8Array; +import com.eclipsesource.v8.utils.typedarrays.TypedArray; +import com.eclipsesource.v8.utils.typedarrays.UInt16Array; +import com.eclipsesource.v8.utils.typedarrays.UInt32Array; +import com.eclipsesource.v8.utils.typedarrays.UInt8Array; +import com.eclipsesource.v8.utils.typedarrays.UInt8ClampedArray; + +/** + * A set of static helper methods to convert V8Objects / V8Arrays to + * java.util Maps and Lists and back again. These conversions + * perform a deep copy. + */ +public class V8ObjectUtils { + + private static final Object IGNORE = new Object(); + + /** + * Creates a Map from a V8Object using a deep copy. All elements + * in the V8Object are released after they are accessed. However, the root + * object itself is not released. + * + * @param object The root of the V8Object graph. + * + * @return A map representing a deep copy of the V8Object rooted at 'object'. + */ + public static Map toMap(final V8Object object) { + V8Map cache = new V8Map(); + try { + return toMap(object, cache); + } finally { + cache.release(); + } + } + + /** + * Creates a List from a V8Array using a deep copy. All elements + * in the V8Array are released after they are accessed. However, the root + * array itself is not released. + * + * @param array The root of the V8Array graph. + * + * @return A list representing a deep copy of the V8Array rooted at 'array'. + */ + public static List toList(final V8Array array) { + V8Map cache = new V8Map(); + try { + return toList(array, cache); + } finally { + cache.release(); + } + } + + /** + * Populates a Java array from a V8Array. The type of the array must be specified. + * Currently, only INTEGER, DOUBLE, BOOLEAN and STRING are supported. + * The V8Array must only contain elements of type 'arrayType'. The result + * can be optionally passed in as a parameter. + * + * This method will use J2V8's bulk array copy making it faster than iterating over + * all the elements in the array. + * + * @param array The V8Array to convert to a Java Array. + * @param arrayType The type of the V8Array to convert. + * @param result The array to use as the result. If null, a new array will be created. + * + * @return A Java array representing a V8Array. + */ + public static Object getTypedArray(final V8Array array, final int arrayType, final Object result) { + int length = array.length(); + if (arrayType == V8Value.INTEGER) { + int[] intArray = (int[]) result; + if ((intArray == null) || (intArray.length < length)) { + intArray = new int[length]; + } + array.getIntegers(0, length, intArray); + return intArray; + } else if (arrayType == V8Value.DOUBLE) { + double[] doubleArray = (double[]) result; + if ((doubleArray == null) || (doubleArray.length < length)) { + doubleArray = new double[length]; + } + array.getDoubles(0, length, doubleArray); + return doubleArray; + } else if (arrayType == V8Value.BOOLEAN) { + boolean[] booleanArray = (boolean[]) result; + if ((booleanArray == null) || (booleanArray.length < length)) { + booleanArray = new boolean[length]; + } + array.getBooleans(0, length, booleanArray); + return booleanArray; + } else if (arrayType == V8Value.STRING) { + String[] stringArray = (String[]) result; + if ((stringArray == null) || (stringArray.length < length)) { + stringArray = new String[length]; + } + array.getStrings(0, length, stringArray); + return stringArray; + } else if (arrayType == V8Value.BYTE) { + byte[] byteArray = (byte[]) result; + if ((byteArray == null) || (byteArray.length < length)) { + byteArray = new byte[length]; + } + array.getBytes(0, length, byteArray); + return byteArray; + } + throw new RuntimeException("Unsupported bulk load type: " + arrayType); + } + + /** + * Creates a Java array from a V8Array. The type of the Array must be specified. + * Currently, only INTEGER, DOUBLE, BOOLEAN and STRING are supported. + * The V8Array must only contain elements of type 'arrayType'. + * + * This method will use J2V8's bulk array copy making it faster than iterating over + * all the elements in the array. + * + * @param array The V8Array to convert to a Java Array. + * @param arrayType The type of the V8Array to convert. + * + * @return A Java array representing a V8Array. + */ + public static Object getTypedArray(final V8Array array, final int arrayType) { + int length = array.length(); + if (arrayType == V8Value.INTEGER) { + return array.getIntegers(0, length); + } else if (arrayType == V8Value.DOUBLE) { + return array.getDoubles(0, length); + } else if (arrayType == V8Value.BOOLEAN) { + return array.getBooleans(0, length); + } else if (arrayType == V8Value.STRING) { + return array.getStrings(0, length); + } + throw new RuntimeException("Unsupported bulk load type: " + arrayType); + } + + /** + * Creates a V8Object from a java.util.Map. This is a deep copy, so if the map + * contains other maps (or lists) they will also be converted. + * + * @param v8 The runtime on which to create the result. + * @param map The map to convert to a V8Object. + * + * @return A V8Object representing the map. + */ + public static V8Object toV8Object(final V8 v8, final Map map) { + Map cache = new Hashtable(); + try { + return toV8Object(v8, map, cache).twin(); + } finally { + for (V8Value v8Object : cache.values()) { + v8Object.release(); + } + } + } + + /** + * Creates a V8Array from a java.util.List. This is a deep copy, so if the list + * contains other lists (or maps) they will also be converted. + * + * @param v8 The runtime on which to create the result. + * @param list The list to convert to a V8Array. + * + * @return A V8Array representing the list. + */ + public static V8Array toV8Array(final V8 v8, final List list) { + Map cache = new Hashtable(); + try { + return toV8Array(v8, list, cache).twin(); + } finally { + for (V8Value v8Object : cache.values()) { + v8Object.release(); + } + } + } + + /** + * Returns an object usable with a V8 Runtime which represents + * the parameter 'value'. If 'value' is an Integer, Boolean, Double + * or String, then 'value' is simply returned as these are directly + * usable on V8. If 'value' is a map / list, then it's converted to + * a V8Object / V8Array first. + * + * If the result is a V8Value, it must be released. + * + * @param v8 The runtime on which to create V8Values. + * @param value The value to convert to an object usable with V8 + * + * @return An object which can be used directly with a V8 runtime. + */ + public static Object getV8Result(final V8 v8, final Object value) { + if (value == null) { + return null; + } + Map cache = new Hashtable(); + try { + Object result = getV8Result(v8, value, cache); + if (result instanceof V8Object) { + return ((V8Object) result).twin(); + } + return result; + } finally { + for (V8Value v8Object : cache.values()) { + v8Object.release(); + } + } + } + + /** + * Pushes a Java Object to a V8Array by first converting it to a V8Value if needed. + * If the value is a boxed primitive, then the primitive will be pushed. If the object + * is a Map / List then a deep copy will be performed, converting the object to a + * V8Object / V8Array first. + * + * @param v8 The runtime on which to create any needed V8Values. + * @param array The array to push the elements to. + * @param value The value to push to the array. + */ + public static void pushValue(final V8 v8, final V8Array array, final Object value) { + Map cache = new Hashtable(); + try { + pushValue(v8, array, value, cache); + } finally { + for (V8Value v8Object : cache.values()) { + v8Object.release(); + } + } + } + + /** + * Gets a Java Object representing the value at the given index in the V8Array. + * If the value is a primitive (int, boolean or double) then a boxed instance + * is returned. If the value is a String, then a String is returned. If + * the value is a V8Object or V8Array, then a Map or List is returned. + * + * @param array The array on which to lookup the value. The array is not + * released. + * @param index The index whose element to lookup. + * + * @return A Java Object representing the value at a given index. + */ + public static Object getValue(final V8Array array, final int index) { + V8Map cache = new V8Map(); + try { + return getValue(array, index, cache); + } finally { + cache.release(); + } + } + + /** + * Gets a Java Object representing the value with the given key in the V8Object. + * If the value is a primitive (int, boolean or double) then a boxed instance + * is returned. If the value is a String, then a String is returned. If + * the value is a V8Object or V8Array, then a Map or List is returned. + * + * @param object The object on which to lookup the value. The object is not + * released. + * @param key The key to use to lookup the value. + * + * @return A Java Object representing the value at a given key. + */ + public static Object getValue(final V8Object object, final String key) { + V8Map cache = new V8Map(); + try { + return getValue(object, key, cache); + } finally { + cache.release(); + } + } + + @SuppressWarnings("unchecked") + private static Map toMap(final V8Object object, final V8Map cache) { + if (object == null) { + return Collections.emptyMap(); + } + if (cache.containsKey(object)) { + return (Map) cache.get(object); + } + Map result = new V8PropertyMap(); + cache.put(object, result); + String[] keys = object.getKeys(); + for (String key : keys) { + Object value = getValue(object, key, cache); + if (value != IGNORE) { + result.put(key, value); + } + } + return result; + } + + @SuppressWarnings("unchecked") + private static List toList(final V8Array array, final V8Map cache) { + if (array == null) { + return Collections.emptyList(); + } + if (cache.containsKey(array)) { + return (List) cache.get(array); + } + List result = new ArrayList(); + cache.put(array, result); + for (int i = 0; i < array.length(); i++) { + Object value = getValue(array, i, cache); + if (value != IGNORE) { + result.add(getValue(array, i, cache)); + } + } + return result; + } + + private static V8Object toV8Object(final V8 v8, final Map map, final Map cache) { + if (cache.containsKey(map)) { + return (V8Object) cache.get(map); + } + V8Object result = new V8Object(v8); + cache.put(map, result); + try { + for (Entry entry : map.entrySet()) { + setValue(v8, result, entry.getKey(), entry.getValue(), cache); + } + } catch (IllegalStateException e) { + result.release(); + throw e; + } + return result; + } + + private static V8Array toV8Array(final V8 v8, final List list, final Map cache) { + if (cache.containsKey(new ListWrapper(list))) { + return (V8Array) cache.get(new ListWrapper(list)); + } + V8Array result = new V8Array(v8); + cache.put(new ListWrapper(list), result); + try { + for (int i = 0; i < list.size(); i++) { + Object value = list.get(i); + pushValue(v8, result, value, cache); + } + } catch (IllegalStateException e) { + result.release(); + throw e; + } + return result; + } + + private static V8ArrayBuffer toV8ArrayBuffer(final V8 v8, final ArrayBuffer arrayBuffer, final Map cache) { + if (cache.containsKey(arrayBuffer)) { + return (V8ArrayBuffer) cache.get(arrayBuffer); + } + V8ArrayBuffer result = new V8ArrayBuffer(v8, arrayBuffer.getByteBuffer()); + cache.put(arrayBuffer, result); + return result; + } + + private static V8TypedArray toV8TypedArray(final V8 v8, final TypedArray typedArray, final Map cache) { + if (cache.containsKey(typedArray)) { + return (V8TypedArray) cache.get(typedArray); + } + V8ArrayBuffer arrayBuffer = new V8ArrayBuffer(v8, typedArray.getByteBuffer()); + try { + V8TypedArray result = new V8TypedArray(v8, arrayBuffer, typedArray.getType(), 0, typedArray.length()); + cache.put(typedArray, result); + return result; + } finally { + arrayBuffer.release(); + } + } + + @SuppressWarnings("unchecked") + private static Object getV8Result(final V8 v8, final Object value, final Map cache) { + if (cache.containsKey(value)) { + return cache.get(value); + } + if (value instanceof Map) { + return toV8Object(v8, (Map) value, cache); + } else if (value instanceof List) { + return toV8Array(v8, (List) value, cache); + } else if (value instanceof TypedArray) { + return toV8TypedArray(v8, (TypedArray) value, cache); + } else if (value instanceof ArrayBuffer) { + return toV8ArrayBuffer(v8, (ArrayBuffer) value, cache); + } + return value; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static void pushValue(final V8 v8, final V8Array result, final Object value, final Map cache) { + if (value == null) { + result.pushUndefined(); + } else if (value instanceof Integer) { + result.push((Integer) value); + } else if (value instanceof Long) { + result.push(new Double((Long) value)); + } else if (value instanceof Double) { + result.push((Double) value); + } else if (value instanceof Float) { + result.push((Float) value); + } else if (value instanceof String) { + result.push((String) value); + } else if (value instanceof Boolean) { + result.push((Boolean) value); + } else if (value instanceof V8Object) { + result.push((V8Object) value); + } else if (value instanceof TypedArray) { + V8TypedArray v8TypedArray = toV8TypedArray(v8, (TypedArray) value, cache); + result.push(v8TypedArray); + } else if (value instanceof ArrayBuffer) { + V8ArrayBuffer v8ArrayBuffer = toV8ArrayBuffer(v8, (ArrayBuffer) value, cache); + result.push(v8ArrayBuffer); + } else if (value instanceof Map) { + V8Object object = toV8Object(v8, (Map) value, cache); + result.push(object); + } else if (value instanceof List) { + V8Array array = toV8Array(v8, (List) value, cache); + result.push(array); + } else { + throw new IllegalStateException("Unsupported Object of type: " + value.getClass()); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static void setValue(final V8 v8, final V8Object result, final String key, final Object value, final Map cache) { + if (value == null) { + result.addUndefined(key); + } else if (value instanceof Integer) { + result.add(key, (Integer) value); + } else if (value instanceof Long) { + result.add(key, (int) (long) (Long) value); + } else if (value instanceof Double) { + result.add(key, (Double) value); + } else if (value instanceof Float) { + result.add(key, (Float) value); + } else if (value instanceof String) { + result.add(key, (String) value); + } else if (value instanceof Boolean) { + result.add(key, (Boolean) value); + } else if (value instanceof V8Object) { + result.add(key, (V8Object) value); + } else if (value instanceof TypedArray) { + V8TypedArray typedArray = toV8TypedArray(v8, (TypedArray) value, cache); + result.add(key, typedArray); + } else if (value instanceof ArrayBuffer) { + V8ArrayBuffer v8ArrayBuffer = toV8ArrayBuffer(v8, (ArrayBuffer) value, cache); + result.add(key, v8ArrayBuffer); + } else if (value instanceof Map) { + V8Object object = toV8Object(v8, (Map) value, cache); + result.add(key, object); + } else if (value instanceof List) { + V8Array array = toV8Array(v8, (List) value, cache); + result.add(key, array); + } else { + throw new IllegalStateException("Unsupported Object of type: " + value.getClass()); + } + } + + private static Object getValue(final V8Array array, final int index, final V8Map cache) { + int valueType = array.getType(index); + switch (valueType) { + case V8Value.INTEGER: + return array.getInteger(index); + case V8Value.DOUBLE: + return array.getDouble(index); + case V8Value.BOOLEAN: + return array.getBoolean(index); + case V8Value.STRING: + return array.getString(index); + case V8Value.V8_FUNCTION: + return IGNORE; + case V8Value.V8_ARRAY_BUFFER: + V8ArrayBuffer buffer = (V8ArrayBuffer) array.get(index); + try { + return new ArrayBuffer(buffer.getBackingStore()); + } finally { + buffer.release(); + } + case V8Value.V8_TYPED_ARRAY: + V8Array typedArray = array.getArray(index); + try { + return toTypedArray(typedArray); + } finally { + if (typedArray instanceof V8Array) { + typedArray.release(); + } + } + case V8Value.V8_ARRAY: + V8Array arrayValue = array.getArray(index); + try { + return toList(arrayValue, cache); + } finally { + if (arrayValue instanceof V8Array) { + arrayValue.release(); + } + } + case V8Value.V8_OBJECT: + V8Object objectValue = array.getObject(index); + try { + return toMap(objectValue, cache); + } finally { + if (objectValue instanceof V8Object) { + objectValue.release(); + } + } + case V8Value.NULL: + return null; + case V8Value.UNDEFINED: + return V8.getUndefined(); + default: + throw new IllegalStateException("Cannot find type for index: " + index); + } + } + + private static Object toTypedArray(final V8Array typedArray) { + int arrayType = typedArray.getType(); + ByteBuffer buffer = ((V8TypedArray) typedArray).getByteBuffer(); + switch (arrayType) { + case V8Value.INT_8_ARRAY: + return new Int8Array(buffer); + case V8Value.UNSIGNED_INT_8_ARRAY: + return new UInt8Array(buffer); + case V8Value.UNSIGNED_INT_8_CLAMPED_ARRAY: + return new UInt8ClampedArray(buffer); + case V8Value.INT_16_ARRAY: + return new Int16Array(buffer); + case V8Value.UNSIGNED_INT_16_ARRAY: + return new UInt16Array(buffer); + case V8Value.INT_32_ARRAY: + return new Int32Array(buffer); + case V8Value.UNSIGNED_INT_32_ARRAY: + return new UInt32Array(buffer); + case V8Value.FLOAT_32_ARRAY: + return new Float32Array(buffer); + case V8Value.FLOAT_64_ARRAY: + return new Float64Array(buffer); + default: + throw new IllegalStateException("Known Typed Array type: " + V8Value.getStringRepresentaion(arrayType)); + } + } + + private static Object getValue(final V8Object object, final String key, final V8Map cache) { + int valueType = object.getType(key); + switch (valueType) { + case V8Value.INTEGER: + return object.getInteger(key); + case V8Value.DOUBLE: + return object.getDouble(key); + case V8Value.BOOLEAN: + return object.getBoolean(key); + case V8Value.STRING: + return object.getString(key); + case V8Value.V8_FUNCTION: + return IGNORE; + case V8Value.V8_ARRAY_BUFFER: + V8ArrayBuffer buffer = (V8ArrayBuffer) object.get(key); + try { + return new ArrayBuffer(buffer.getBackingStore()); + } finally { + buffer.release(); + } + case V8Value.V8_TYPED_ARRAY: + V8Array typedArray = object.getArray(key); + try { + return toTypedArray(typedArray); + } finally { + if (typedArray instanceof V8Array) { + typedArray.release(); + } + } + case V8Value.V8_ARRAY: + V8Array array = object.getArray(key); + try { + return toList(array, cache); + } finally { + if (array instanceof V8Array) { + array.release(); + } + } + case V8Value.V8_OBJECT: + V8Object child = object.getObject(key); + try { + return toMap(child, cache); + } finally { + if (child instanceof V8Object) { + child.release(); + } + } + case V8Value.NULL: + return null; + case V8Value.UNDEFINED: + return V8.getUndefined(); + default: + throw new IllegalStateException("Cannot find type for key: " + key); + } + } + + private V8ObjectUtils() { + + } + + static class ListWrapper { + private List list; + + public ListWrapper(final List list) { + this.list = list; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof ListWrapper) { + return ((ListWrapper) obj).list == list; + } + return false; + } + + @Override + public int hashCode() { + return System.identityHashCode(list); + } + } +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/V8PropertyMap.java b/fine-j2v8/src/com/eclipsesource/v8/utils/V8PropertyMap.java new file mode 100644 index 000000000..3b69784aa --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/V8PropertyMap.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils; + +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; + +/** + * A custom map is needed because the existing HashMaps + * do not self containment, and Hashtables do not + * allow nulls as values. + * + * This class is not considered API. + */ +class V8PropertyMap implements Map { + + private Hashtable map = new Hashtable(); + private Set nulls = new HashSet(); + + /* + * (non-Javadoc) + * @see java.util.Map#size() + */ + @Override + public int size() { + return map.size() + nulls.size(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#isEmpty() + */ + @Override + public boolean isEmpty() { + return map.isEmpty() && nulls.isEmpty(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#containsKey(java.lang.Object) + */ + @Override + public boolean containsKey(final Object key) { + return map.containsKey(key) || nulls.contains(key); + } + + /* + * (non-Javadoc) + * @see java.util.Map#containsValue(java.lang.Object) + */ + @Override + public boolean containsValue(final Object value) { + if ((value == null) && !nulls.isEmpty()) { + return true; + } else if (value == null) { + return false; + } + return map.containsValue(value); + } + + /* + * (non-Javadoc) + * @see java.util.Map#get(java.lang.Object) + */ + @Override + public V get(final Object key) { + if (nulls.contains(key)) { + return null; + } + return map.get(key); + } + + /* + * (non-Javadoc) + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + @Override + public V put(final String key, final V value) { + if (value == null) { + if (map.containsKey(key)) { + map.remove(key); + } + nulls.add(key); + return null; + } + if (nulls.contains(key)) { + nulls.remove(key); + } + return map.put(key, value); + } + + /* + * (non-Javadoc) + * @see java.util.Map#remove(java.lang.Object) + */ + @Override + public V remove(final Object key) { + if (nulls.contains(key)) { + nulls.remove(key); + return null; + } + return map.remove(key); + } + + /* + * (non-Javadoc) + * @see java.util.Map#putAll(java.util.Map) + */ + @Override + public void putAll(final Map m) { + for (Entry entry : m.entrySet()) { + this.put(entry.getKey(), entry.getValue()); + } + } + + /* + * (non-Javadoc) + * @see java.util.Map#clear() + */ + @Override + public void clear() { + map.clear(); + nulls.clear(); + } + + /* + * (non-Javadoc) + * @see java.util.Map#keySet() + */ + @Override + public Set keySet() { + HashSet result = new HashSet(map.keySet()); + result.addAll(nulls); + return result; + } + + /* + * (non-Javadoc) + * @see java.util.Map#values() + */ + @Override + public Collection values() { + ArrayList result = new ArrayList(map.values()); + for (int i = 0; i < nulls.size(); i++) { + result.add(null); + } + return result; + } + + /* + * (non-Javadoc) + * @see java.util.Map#entrySet() + */ + @Override + public Set> entrySet() { + HashSet> result = new HashSet>(map.entrySet()); + for (String nullKey : nulls) { + result.add(new SimpleEntry(nullKey, null)); + } + return result; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/V8Runnable.java b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Runnable.java new file mode 100644 index 000000000..7df197a5b --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Runnable.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils; + +import com.eclipsesource.v8.V8; + +/** + * Classes can implement this interface to execute arbitrary code on + * isolated V8 runtime on its own thread. Instances of classes that + * implement this interface can be passed to V8Thread. + */ +public interface V8Runnable { + + /** + * Execute the code on the provided runtime. + * + * @param runtime The V8 runtime assigned to this runnable. + */ + public void run(final V8 runtime); + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/V8Thread.java b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Thread.java new file mode 100644 index 000000000..5f0096f16 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/V8Thread.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2015 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils; + +import com.eclipsesource.v8.V8; + +/** + * A Thread with its own V8 runtime. The thread will create a runtime, + * and execute a runnable on that runtime. When the thread ends, + * the runtime will be released. + * + * It's suggested that you *DO NOT* release the lock on the runtime. + * If the lock is released, you will need to ensure that the runtime + * is properly released. + */ +public class V8Thread extends Thread { + + private final V8Runnable target; + private V8 runtime; + + /** + * Create as new Thread with its own V8Runtime. + * + * @param target The code to execute with the given runtime. + */ + public V8Thread(final V8Runnable target) { + this.target = target; + } + + /* + * (non-Javadoc) + * @see java.lang.Thread#run() + */ + @Override + public void run() { + runtime = V8.createV8Runtime(); + try { + target.run(runtime); + } finally { + synchronized (this) { + if (runtime.getLocker().hasLock()) { + runtime.release(); + runtime = null; + } + } + } + } + +} \ No newline at end of file diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/ArrayBuffer.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/ArrayBuffer.java new file mode 100644 index 000000000..ccc1d34a6 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/ArrayBuffer.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +/** + * A wrapper class for java.nio.ByteBuffer. This class provides some convenience methods + * for working with the ByteBuffer. Furthermore, this class can be converted to a + * V8ByteBuffer using V8ObjectUtils. + */ +public class ArrayBuffer { + + private ByteBuffer byteBuffer; + + /** + * Create a new ArrayBuffer with an initial capacity. + * + * @param capacity The capacity of this ByteBuffer. + */ + public ArrayBuffer(final int capacity) { + byteBuffer = ByteBuffer.allocateDirect(capacity); + } + + /** + * Create a new ArrayBuffer from a byte array. The array buffer will be allocated with the same + * size as the byte array, and the contents of the byte array will be copied to the ArrayBuffer. + * + * @param src The byte array from which the ArrayBuffer will be initialized. + */ + public ArrayBuffer(final byte[] src) { + byteBuffer = ByteBuffer.allocateDirect(src.length); + byteBuffer.put(src, 0, src.length); + } + + /** + * Create a new ArrayBuffer with the given ByteBuffer as the backing store. The ByteBuffer must + * be created as a DirectBuffer. + * + * @param byteBuffer The ByteBuffer to back this ArrayBuffer. + */ + public ArrayBuffer(final ByteBuffer byteBuffer) { + this.byteBuffer = validateByteBuffer(byteBuffer); + } + + private ByteBuffer validateByteBuffer(final ByteBuffer byteBuffer) { + if (!byteBuffer.isDirect()) { + throw new IllegalArgumentException("ByteBuffer must be a allocated as a direct ByteBuffer"); + } + return byteBuffer; + } + + /** + * Returns the ByteBuffer backing this ArrayBuffer. + * + * @return The ByteBuffer backing this ArrayBuffer. + */ + public ByteBuffer getByteBuffer() { + return byteBuffer; + } + + /** + * Returns the byte at a given index. + * + * @param index The index at which to return the byte. + * @return The byte at the given index. + */ + public byte getByte(final int index) { + return byteBuffer.get(index); + } + + /** + * Returns the byte at a given index as an unsigned integer. + * + * @param index The index at which to return the byte. + * @return The unsigned byte at the given index. + */ + public short getUnsignedByte(final int index) { + return (short) (0xFF & byteBuffer.get(index)); + } + + /** + * Puts a byte into the ByteBuffer at the given index. + * + * @param index The index at which to put the byte. + * @param value The value to put at the index. + */ + public void put(final int index, final byte value) { + byteBuffer.put(index, value); + } + + /** + * Returns this ArrayBuffers limit. + * + * @return This ArrayBuffers limit. + */ + public int limit() { + return byteBuffer.limit(); + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Float32Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Float32Array.java new file mode 100644 index 000000000..a5ab991c5 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Float32Array.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Float32Array typed array represents an array of 32-bit floating + * point numbers. + */ +public class Float32Array extends TypedArray { + + /** + * Creates a Float32Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public Float32Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a Float32Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public Float32Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the floating point (Float32) value at a given index. + * + * @param index The index at which to return the value. + * @return The Float32 value at the given index. + */ + public float get(final int index) { + return buffer.asFloatBuffer().get(index); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.asFloatBuffer().limit(); + } + + /** + * Puts a Float32 value at a particular index. + * + * @param index The index at which to place the value. + * @param value The Float32 value to place into buffer. + */ + public void put(final int index, final float value) { + buffer.asFloatBuffer().put(index, value); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.FLOAT_32_ARRAY; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Float64Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Float64Array.java new file mode 100644 index 000000000..af7c67099 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Float64Array.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Float64Array typed array represents an array of 64-bit floating + * point numbers. + */ +public class Float64Array extends TypedArray { + + /** + * Creates a Float64Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public Float64Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a Float64Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public Float64Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the floating point (Float64) value at a given index. + * + * @param index The index at which to return the value. + * @return The Double (Float64) value at the given index. + */ + public double get(final int index) { + return buffer.asDoubleBuffer().get(index); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.asDoubleBuffer().limit(); + } + + /** + * Puts a Double (Float64) value at a particular index. + * + * @param index The index at which to place the value. + * @param value The Double to put into the buffer. + */ + public void put(final int index, final double value) { + buffer.asDoubleBuffer().put(index, value); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.FLOAT_64_ARRAY; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int16Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int16Array.java new file mode 100644 index 000000000..ae365be59 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int16Array.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Int16Array typed array represents an array of twos-complement + * 16-bit signed integers in the platform byte order. + */ +public class Int16Array extends TypedArray { + + /** + * Creates an Int16Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public Int16Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a Int16Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public Int16Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the 16-bit signed integer at the given index + * + * @param index The index at which to return the value. + * @return The 16-bit integer at the index. + */ + public short get(final int index) { + return buffer.asShortBuffer().get(index); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.asShortBuffer().limit(); + } + + /** + * Puts a 16-bit integer at a particular index. + * + * @param index The index at which to place the value. + * @param value The 16-bit integer to put into buffer. + */ + public void put(final int index, final short value) { + buffer.asShortBuffer().put(index, value); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.INT_16_ARRAY; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int32Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int32Array.java new file mode 100644 index 000000000..4e69e7316 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int32Array.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Int32Array typed array represents an array of twos-complement 32-bit signed + * integers in the platform byte order. + */ +public class Int32Array extends TypedArray { + + /** + * Creates an Int32Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public Int32Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a Int32Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public Int32Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the 32-bit signed integer at the given index. + * + * @param index The index at which to return the value. + * @return The 32-bit integer at the index. + */ + public int get(final int index) { + return buffer.asIntBuffer().get(index); + } + + @Override + public int length() { + return buffer.asIntBuffer().limit(); + } + + /** + * Puts a 32-bit integer at a particular index. + * + * @param index The index at which to place the value. + * @param value The 32-bit integer to put into buffer. + */ + public void put(final int index, final int value) { + buffer.asIntBuffer().put(index, value); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.INT_32_ARRAY; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int8Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int8Array.java new file mode 100644 index 000000000..f75b61fd0 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/Int8Array.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Int8Array typed array represents an array of twos-complement + * 8-bit signed integers. + */ +public class Int8Array extends TypedArray { + + /** + * Creates an Int8Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public Int8Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a Int8Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public Int8Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the 8-bit signed integer at the given index. + * + * @param index The index at which to return the value. + * @return The 8-bit integer at the index. + */ + public byte get(final int index) { + return buffer.get(index); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.limit(); + } + + /** + * Puts an 8-bit integer at a particular index. + * + * @param index The index at which to place the value. + * @param value The 8-bit integer to put into buffer. + */ + public void put(final int index, final byte value) { + buffer.put(index, value); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.INT_8_ARRAY; + } +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/TypedArray.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/TypedArray.java new file mode 100644 index 000000000..567b87790 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/TypedArray.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8TypedArray; + +/** + * An abstract class that represents TypedArrays + */ +public abstract class TypedArray { + + protected ByteBuffer buffer; + + protected TypedArray(final ByteBuffer buffer) { + if (!buffer.isDirect()) { + throw new IllegalArgumentException("ByteBuffer must be a allocated as a direct ByteBuffer"); + } + if ((buffer.limit() % V8TypedArray.getStructureSize(getType())) != 0) { + throw new IllegalArgumentException("ByteBuffer must be a allocated as a direct ByteBuffer"); + } + this.buffer = buffer; + } + + /** + * Return the underlying ByteBuffer. + * + * @return The underlying ByteBuffer behind this view + */ + public ByteBuffer getByteBuffer() { + return buffer; + } + + /** + * Return the size of this view. The size of the view is determined by the size + * of the buffer, and the size of the data projected onto it. For example, for a + * buffer size of 8, and a view representing 16bit integers, the size would be 4. + * + * @return The size of this view + */ + public abstract int length(); + + /** + * Returns the 'Type' of this TypedArray using one of the constants defined in V8Value. + * + * @return The 'Type' of this typed array. + */ + public abstract int getType(); +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt16Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt16Array.java new file mode 100644 index 000000000..cd62d2c10 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt16Array.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Uint16Array typed array represents an array of 16-bit unsigned + * integers in the platform byte order. + */ +public class UInt16Array extends TypedArray { + + /** + * Creates an UInt16Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public UInt16Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a UInt16Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public UInt16Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the 16-bit unsigned integer at the given index. + * + * @param index The index at which to return the value. + * @return The 16-bit unsigned integer at the index. + */ + public int get(final int index) { + return 0xFFFF & buffer.asShortBuffer().get(index); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.asShortBuffer().limit(); + } + + /** + * Puts a 16-bit unsigned integer at a particular index. + * + * @param index The index at which to place the value. + * @param value The 16-bit unsigned integer to put into buffer. + */ + public void put(final int index, final int value) { + buffer.asShortBuffer().put(index, (short) (0x0000FFFF & value)); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.UNSIGNED_INT_16_ARRAY; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt32Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt32Array.java new file mode 100644 index 000000000..fd307e213 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt32Array.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Uint32Array typed array represents an array of 32-bit unsigned + * integers in the platform byte order. + */ +public class UInt32Array extends TypedArray { + + /** + * Creates an UInt32Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public UInt32Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a UInt32Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public UInt32Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the 32-bit unsigned integer at the given index. + * + * @param index The index at which to return the value. + * @return The 32-bit unsigned integer at the index. + */ + public long get(final int index) { + return 0x00000000FFFFFFFF & buffer.asIntBuffer().get(index); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.asIntBuffer().limit(); + } + + /** + * Puts a 32-bit unsigned integer at a particular index. + * + * @param index The index at which to place the value. + * @param value The 32-bit unsigned integer to put into buffer. + */ + public void put(final int index, final long value) { + buffer.asIntBuffer().put(index, (int) (0x00000000FFFFFFFF & value)); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.UNSIGNED_INT_32_ARRAY; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt8Array.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt8Array.java new file mode 100644 index 000000000..86e14ca5f --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt8Array.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Uint8Array typed array represents an array of 8-bit unsigned integers + */ +public class UInt8Array extends TypedArray { + + /** + * Creates an UInt8Array projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public UInt8Array(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a UInt8Array projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public UInt8Array(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the 8-bit unsigned integer at the given index. + * + * @param index The index at which to return the value. + * @return The 8-bit unsigned integer at the index. + */ + public short get(final int index) { + return (short) (0xFF & buffer.get(index)); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.limit(); + } + + /** + * Puts a 8-bit unsigned integer at a particular index. + * + * @param index The index at which to place the value. + * @param value The 8-bit unsigned integer to put into buffer. + */ + public void put(final int index, final short value) { + buffer.put(index, (byte) (0x00FF & value)); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.UNSIGNED_INT_8_ARRAY; + } + +} diff --git a/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt8ClampedArray.java b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt8ClampedArray.java new file mode 100644 index 000000000..7327ee676 --- /dev/null +++ b/fine-j2v8/src/com/eclipsesource/v8/utils/typedarrays/UInt8ClampedArray.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2016 EclipseSource and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * EclipseSource - initial API and implementation + ******************************************************************************/ +package com.eclipsesource.v8.utils.typedarrays; + +import java.nio.ByteBuffer; + +import com.eclipsesource.v8.V8Value; + +/** + * The Uint8ClampedArray typed array represents an array of 8-bit unsigned + * integers clamped to 0-255; if you specified a value that is out of the + * range of [0,255], 0 or 255 will be set instead. + */ +public class UInt8ClampedArray extends TypedArray { + + /** + * Creates an UInt8ClampedArray projected onto the given ByteBuffer. + * + * @param buffer The ByteBuffer on which the array is projected on. + */ + public UInt8ClampedArray(final ByteBuffer buffer) { + super(buffer); + } + + /** + * Creates a UInt8ClampedArray projected onto the given ArrayBuffer. + * + * @param arrayBuffer The ArrayBuffer on which the array is projected on. + */ + public UInt8ClampedArray(final ArrayBuffer arrayBuffer) { + this(arrayBuffer.getByteBuffer()); + } + + /** + * Returns the 8-bit unsigned integer at the given index. + * + * @param index The index at which to return the value. + * @return The 8-bit unsigned integer at the index. + */ + public short get(final int index) { + return (short) (0xFF & buffer.get(index)); + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#length() + */ + @Override + public int length() { + return buffer.limit(); + } + + /** + * Puts a 8-bit unsigned integer at a particular index. If the unsigned + * integer is outside the range [0,255], 0 or 255 will be used instead. + * + * @param index The index at which to place the value. + * @param value The 8-bit unsigned integer to put into buffer. + */ + public void put(final int index, final short value) { + if (value > 255) { + buffer.put(index, (byte) (255)); + } else if (value < 0) { + buffer.put(index, (byte) (0)); + } else { + buffer.put(index, (byte) (value)); + } + } + + /* + * (non-Javadoc) + * @see com.eclipsesource.v8.utils.typedarrays.TypedArray#getType() + */ + @Override + public int getType() { + return V8Value.UNSIGNED_INT_8_CLAMPED_ARRAY; + } + +} diff --git a/fine-j2v8/src/libj2v8_linux_x86_64.so b/fine-j2v8/src/libj2v8_linux_x86_64.so new file mode 100644 index 000000000..c2b38db5f Binary files /dev/null and b/fine-j2v8/src/libj2v8_linux_x86_64.so differ diff --git a/fine-j2v8/src/libj2v8_macosx_x86_64.dylib b/fine-j2v8/src/libj2v8_macosx_x86_64.dylib new file mode 100755 index 000000000..bd06c09ca Binary files /dev/null and b/fine-j2v8/src/libj2v8_macosx_x86_64.dylib differ diff --git a/fine-j2v8/src/libj2v8_win32_x86.dll b/fine-j2v8/src/libj2v8_win32_x86.dll new file mode 100644 index 000000000..02eb0538f Binary files /dev/null and b/fine-j2v8/src/libj2v8_win32_x86.dll differ diff --git a/fine-j2v8/src/libj2v8_win32_x86_64.dll b/fine-j2v8/src/libj2v8_win32_x86_64.dll new file mode 100644 index 000000000..ab4e79060 Binary files /dev/null and b/fine-j2v8/src/libj2v8_win32_x86_64.dll differ