Skip to content

Commit

Permalink
A clone of Basho's erlang_js driver based on Mozilla Rhino.
Browse files Browse the repository at this point in the history
  • Loading branch information
krestenkrab committed Jun 16, 2010
1 parent 8d87f12 commit 1cbc07d
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 2 deletions.
17 changes: 17 additions & 0 deletions NOTICE
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions build.xml
Expand Up @@ -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" />
Expand Down
Binary file added lib/js.jar
Binary file not shown.
6 changes: 4 additions & 2 deletions src/main/java/erjang/OTPMain.java
Expand Up @@ -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;
Expand All @@ -42,15 +43,16 @@ public class OTPMain {
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));
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/erjang/driver/js/EJSDriver.java
@@ -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;
}

}
224 changes: 224 additions & 0 deletions src/main/java/erjang/driver/js/EJSDriverInstance.java
@@ -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.