Permalink
Browse files

A clone of Basho's erlang_js driver based on Mozilla Rhino.

  • Loading branch information...
1 parent 8d87f12 commit 1cbc07d910f561c93a8e2766a6ea11e213fdcca7 @krestenkrab krestenkrab committed Jun 16, 2010
View
@@ -17,6 +17,23 @@ Erjang - A JVM-based Erlang VM
This product includes software covered by the following license
+[Mozzilla Rhino]
+
+ Mozilla Public License.
+
+ ``The contents of this file are subject to the Mozilla Public License
+ Version 1.1 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations
+ under the License.
+
+
+[Pieces of Erlang/OTP]
+
The contents of this file are subject to the Erlang Public License,
Version 1.1, (the "License"); you may not use this file except in
compliance with the License. You should have received a copy of the
View
@@ -3,6 +3,7 @@
<property name="erjang.version" value="0.1" />
<path id="erjang.classpath">
<pathelement location="target/classes/" />
+ <pathelement location="lib/js.jar" />
<pathelement location="lib/kilim-0.6-krab.jar" />
<pathelement location="lib/OtpErlang.jar" />
<pathelement location="lib/junit.jar" />
View
Binary file not shown.
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
+import java.util.logging.Level;
import java.util.logging.Logger;
import erjang.driver.EDriver;
@@ -42,15 +43,16 @@
new erjang.driver.efile.Driver(),
new erjang.driver.ram_file.Driver(),
new erjang.driver.tcp_inet.Driver(),
- new erjang.driver.inet_gethost.Driver()
+ new erjang.driver.inet_gethost.Driver(),
+ new erjang.driver.js.EJSDriver()
};
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
Handler fh = new FileHandler("erjang.log");
Logger.getLogger("").addHandler(fh);
// Logger.getLogger("erjang").setLevel(Level.FINE);
- // Logger.getLogger("kilim.Task").setLevel(Level.FINEST);
+ // Logger.getLogger("kilim.Task").setLevel(Level.FINEST);
for (String m : MODULES) {
ERT.load_module(EAtom.intern(m));
@@ -0,0 +1,40 @@
+package erjang.driver.js;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+import erjang.EString;
+import erjang.driver.EDriver;
+import erjang.driver.EDriverControl;
+
+public class EJSDriver implements EDriver {
+
+ private kilim.ReentrantLock lock;
+
+ @Override
+ public String driverName() {
+ return "erlang_js_drv";
+ }
+
+ @Override
+ public void finish() {
+ }
+
+ @Override
+ public ReentrantLock getLock() {
+ if (lock == null) {
+ lock = new kilim.ReentrantLock();
+ }
+ return lock;
+ }
+
+ @Override
+ public EDriverControl start(EString command) {
+ return new EJSDriverInstance(this);
+ }
+
+ @Override
+ public boolean useDriverLevelLocking() {
+ return false;
+ }
+
+}
@@ -0,0 +1,224 @@
+/**
+ */
+
+/* THIS FILE IS DERIVED FROM spidermonkey_drv.c
+ * ORIGINAL COPYRIGHT NOTICE
+
+ author Kevin Smith <ksmith@basho.com>
+ copyright 2009-2010 Basho Technologies
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. */
+
+package erjang.driver.js;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import kilim.Pausable;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.ContextFactory;
+import org.mozilla.javascript.Script;
+import org.mozilla.javascript.ScriptableObject;
+
+import erjang.EAtom;
+import erjang.EBinary;
+import erjang.EHandle;
+import erjang.ERT;
+import erjang.ETuple;
+import erjang.driver.EAsync;
+import erjang.driver.EDriver;
+import erjang.driver.EDriverInstance;
+import erjang.driver.IO;
+
+public class EJSDriverInstance extends EDriverInstance {
+
+ static final EAtom am_ok = ERT.am_ok;
+ static final EAtom am_error = ERT.am_error;
+ static final EAtom am_unknown_command = EAtom.intern("unknown_command");
+
+ static ContextFactory cf_global = ContextFactory.getGlobal();
+
+ static class EContext extends Context {
+ public EContext() {
+ super(cf_global);
+ }
+ }
+
+ public EJSDriverInstance(EDriver driver) {
+ super(driver);
+ }
+
+ void send_ok_response(EBinary call_id) throws Pausable {
+ driver_output_term(ETuple.make(call_id, am_ok));
+ }
+
+ void send_error_string_response(EBinary call_id, String msg)
+ throws Pausable {
+ driver_output_term(ETuple.make(call_id, am_error, EBinary
+ .fromString(msg)));
+ }
+
+ void send_string_response(EBinary call_id, String result) throws Pausable {
+ driver_output_term(ETuple.make(call_id, am_ok, EBinary
+ .fromString(result)));
+ }
+
+ void unknown_command(EBinary call_id) throws Pausable {
+ driver_output_term(ETuple.make(call_id, am_error, am_unknown_command));
+ }
+
+ short IJ = ('i' << 8) | 'j';
+ short EJ = ('e' << 8) | 'j';
+ short DJ = ('d' << 8) | 'j';
+ short SD = ('s' << 8) | 'd';
+
+ private VM vm;
+
+ @Override
+ protected void output(EHandle caller, final ByteBuffer buf) throws IOException,
+ Pausable {
+
+ final int cmd = buf.getShort();
+ final EBinary call_id = read_binary(buf);
+
+ if (cmd == IJ) {
+ int heap_size = buf.getInt();
+ vm = sm_initialize(heap_size * 1024 * 1024);
+ send_ok_response(call_id);
+
+ } else {
+
+ EAsync job = new EAsync() {
+
+ String err, resp;
+
+ // called in separate thread
+ @Override
+ public void async() {
+
+ if (cmd == EJ) {
+
+ String filename = read_string(buf);
+ String code = read_string(buf);
+
+ String result = sm_eval(filename, code, false);
+ if (result.startsWith("{\"error\"")) {
+ err = result;
+ } else {
+ resp = result;
+ }
+
+ } else if (cmd == DJ) {
+
+ String filename = read_string(buf);
+ String code = read_string(buf);
+
+ String result = sm_eval(filename, code, true);
+ if (result != null) {
+ err = result;
+ }
+
+
+ } else if (cmd == SD) {
+ vm = null;
+ }
+
+ }
+
+ // called when done
+ @Override
+ public void ready() throws Pausable {
+
+ if (err != null) {
+ send_error_string_response(call_id, err);
+ } else if (resp != null) {
+ send_string_response(call_id, err);
+ } else {
+ send_ok_response(call_id);
+ }
+
+ }
+
+ };
+
+ driver_async(job);
+
+ }
+ }
+
+ static class VM {
+ EContext cx;
+ ScriptableObject global;
+ }
+
+ private VM sm_initialize(int i) {
+
+ VM vm = new VM();
+
+ vm.cx = new EContext();
+ cf_global.enterContext(vm.cx);
+
+ try {
+ vm.global = vm.cx.initStandardObjects();
+
+ return vm;
+ } finally {
+ Context.exit();
+ }
+ }
+
+ private String sm_eval(String filename, String code, boolean handle_retval) {
+
+ Context ctx = cf_global.enterContext(vm.cx);
+ try {
+
+ Script scr = ctx.compileString(code, filename, 1, null);
+ Object result = scr.exec(ctx, vm.global);
+
+ if (handle_retval) {
+ if (result instanceof String) {
+ return (String) result;
+ } else if (result == Context.getUndefinedValue()){
+ return "{\"error\": \"Expression returned undefined\", \"lineno\": 0, \"source\": \"unknown\"}";
+ } else {
+ return "{\"error\": \"non-JSON return value\", \"lineno\": 0, \"source\": \"unknown\"}";
+ }
+ } else {
+ return null;
+ }
+
+ } finally {
+ Context.exit();
+ }
+
+ }
+
+
+ private EBinary read_binary(ByteBuffer buf) {
+ int str_len = buf.getInt();
+ EBinary str = new EBinary(buf.array(),
+ buf.position()+buf.arrayOffset(), str_len);
+ buf.position(buf.position()+str_len);
+ return str;
+ }
+
+ private String read_string(ByteBuffer buf) {
+ int str_len = buf.getInt();
+ byte[] data = new byte[str_len];
+ buf.get(data);
+ return new String(data, IO.UTF8);
+ }
+
+
+}

0 comments on commit 1cbc07d

Please sign in to comment.