Skip to content

Commit

Permalink
[GR-46029] Providing context and engine global bindings in ScriptEngine.
Browse files Browse the repository at this point in the history
PullRequest: js/2809
  • Loading branch information
iamstolis committed May 8, 2023
2 parents 30c650d + f8bbc1e commit 27063eb
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
Expand Down Expand Up @@ -482,4 +483,71 @@ public void sharedEngineScope() throws ScriptException {
assertTrue((boolean) engine.eval("typeof key === 'undefined'"));
}

@Test
public void testEngineBinding() throws ScriptException {
ScriptEngine engine = getEngine();
assertSame(engine, engine.eval("engine"));
assertSame(engine, engine.getBindings(ScriptContext.ENGINE_SCOPE).get("engine"));
}

@Test
public void testContextBinding() throws ScriptException {
ScriptEngine engine = getEngine();
ScriptContext context = engine.getContext();
assertSame(context, engine.eval("context"));
assertSame(context, engine.getBindings(ScriptContext.ENGINE_SCOPE).get("context"));
ScriptContext anotherContext = new SimpleScriptContext();
assertSame(anotherContext, engine.eval("context", anotherContext));
}

public void testBindingOverride1(String name) throws ScriptException {
ScriptEngine engine = getEngine();
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put(name, "foo");
assertEquals("foo", engine.eval(name));
}

public void testBindingOverride2(String name) throws ScriptException {
ScriptEngine engine = getEngine();
Bindings bindings = new SimpleBindings();
bindings.put(name, "foo");
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
assertEquals("foo", engine.eval(name));
}

public void testBindingOverride3(String name) throws ScriptException {
ScriptEngine engine = getEngine();
assertEquals("foo", engine.eval(name + " = 'foo'; " + name));
}

@Test
public void testEngineBindingOverride1() throws ScriptException {
testBindingOverride1("engine");
}

@Test
public void testEngineBindingOverride2() throws ScriptException {
testBindingOverride2("engine");
}

@Test
public void testEngineBindingOverride3() throws ScriptException {
testBindingOverride3("engine");
}

@Test
public void testContextBindingOverride1() throws ScriptException {
testBindingOverride1("context");
}

@Test
public void testContextBindingOverride2() throws ScriptException {
testBindingOverride2("context");
}

@Test
public void testContextBindingOverride3() throws ScriptException {
testBindingOverride3("context");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.TypeLiteral;
Expand All @@ -69,16 +70,19 @@ final class GraalJSBindings extends AbstractMap<String, Object> implements Bindi
private Context.Builder contextBuilder;
// ScriptContext of the ScriptEngine where these bindings form ENGINE_SCOPE bindings
private ScriptContext engineScriptContext;
private ScriptEngine engineBinding;

GraalJSBindings(Context.Builder contextBuilder, ScriptContext scriptContext) {
GraalJSBindings(Context.Builder contextBuilder, ScriptContext scriptContext, ScriptEngine engine) {
this.contextBuilder = contextBuilder;
this.engineScriptContext = scriptContext;
this.engineBinding = engine;
}

GraalJSBindings(Context context, ScriptContext scriptContext) {
GraalJSBindings(Context context, ScriptContext scriptContext, ScriptEngine engine) {
this.context = context;
initGlobal();
this.engineScriptContext = scriptContext;
this.engineBinding = engine;
initGlobal();
}

private void requireContext() {
Expand All @@ -94,6 +98,27 @@ private void initContext() {

private void initGlobal() {
this.global = GraalJSScriptEngine.evalInternal(context, "this").as(STRING_MAP);
updateEngineBinding();
updateContextBinding();
}

private void updateEngineBinding() {
updateBinding("engine", engineBinding);
}

private void updateContextBinding() {
if (engineScriptContext != null) {
updateBinding("context", engineScriptContext);
}
}

private void updateBinding(String key, Object value) {
String code = "(function(key, value) {" +
"try {" +
" Object.defineProperty(this, key, { value: value, writable: true, configurable: true });" +
"} catch (e) {}" +
"})";
GraalJSScriptEngine.evalInternal(context, code).execute(key, value);
}

private Value deletePropertyFunction() {
Expand Down Expand Up @@ -194,6 +219,7 @@ void importGlobalBindings(ScriptContext scriptContext) {

void updateEngineScriptContext(ScriptContext scriptContext) {
engineScriptContext = scriptContext;
updateContextBinding();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ public Builder setOption(Builder builder, Object value) {
}
this.factory = (factory == null) ? new GraalJSEngineFactory(engineToUse) : factory;
this.contextConfig = contextConfigToUse.option(JS_SCRIPT_ENGINE_GLOBAL_SCOPE_IMPORT_OPTION, "true").engine(engineToUse);
this.context.setBindings(new GraalJSBindings(this.contextConfig, this.context), ScriptContext.ENGINE_SCOPE);
this.context.setBindings(new GraalJSBindings(this.contextConfig, this.context, this), ScriptContext.ENGINE_SCOPE);
}

private static void updateForNashornCompatibilityMode(Context.Builder builder) {
Expand Down Expand Up @@ -410,7 +410,7 @@ static Value evalInternal(Context context, String script) {

@Override
public Bindings createBindings() {
return new GraalJSBindings(contextConfig, null);
return new GraalJSBindings(contextConfig, null, this);
}

@Override
Expand Down Expand Up @@ -535,7 +535,7 @@ private GraalJSBindings getOrCreateGraalJSBindings(ScriptContext scriptContext)
if (engineB instanceof GraalJSBindings) {
return ((GraalJSBindings) engineB);
} else {
GraalJSBindings bindings = new GraalJSBindings(createContext(engineB), scriptContext);
GraalJSBindings bindings = new GraalJSBindings(createContext(engineB), scriptContext, this);
bindings.putAll(engineB);
return bindings;
}
Expand Down

0 comments on commit 27063eb

Please sign in to comment.