# HG changeset patch # User Michael Van De Vanter # Date 1444338053 14400 # Node ID 9f478b9db4f7793a5f3bbd5ad75b926709952e12 # Parent 260e3cdf11ec01e7a9f33f581244142959209bef# Parent 0e13cbebc04cdabf404d15d2e05aca152880d772 Merge with 0e13cbebc04cdabf404d15d2e05aca152880d772 diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java --- a/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.interop.java/src/com/oracle/truffle/api/interop/java/JavaInterop.java Thu Oct 08 17:00:53 2015 -0400 @@ -135,9 +135,12 @@ * * @param type of requested and returned value * @param type interface modeling structure of foreignObject in Java - * @param foreignObject object coming from a {@link TruffleObject Truffle language} + * @param foreignObject object coming from a {@link TruffleObject Truffle language}, can be + * null, in such case the returned value will likely be + * null as well * @return instance of requested interface granting access to specified - * foreignObject + * foreignObject, can be null, if the foreignObject parameter + * was null */ public static T asJavaObject(Class type, TruffleObject foreignObject) { return asJavaObject(type, null, foreignObject); @@ -151,6 +154,9 @@ if (!clazz.isInterface()) { throw new IllegalArgumentException(); } + if (foreignObject == null) { + return null; + } if (clazz == List.class && Boolean.TRUE.equals(message(Message.HAS_SIZE, foreignObject))) { Class elementType = Object.class; if (type instanceof ParameterizedType) { diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java --- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/Message.java Thu Oct 08 17:00:53 2015 -0400 @@ -413,7 +413,11 @@ return (Message) Message.class.getMethod(factory, int.class).invoke(null, 0); } catch (Exception ex2) { try { - return (Message) Class.forName(message).newInstance(); + ClassLoader l = Message.class.getClassLoader(); + if (l == null) { + l = ClassLoader.getSystemClassLoader(); + } + return (Message) Class.forName(message, false, l).newInstance(); } catch (Exception ex1) { throw new IllegalArgumentException("Cannot find message for " + message, ex); } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Layout.java --- a/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Layout.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Layout.java Thu Oct 08 17:00:53 2015 -0400 @@ -35,9 +35,9 @@ * An object may change its shape but only to shapes of the same layout. */ public abstract class Layout { - public static final EnumSet NONE = EnumSet.noneOf(ImplicitCast.class); - public static final EnumSet INT_TO_DOUBLE = EnumSet.of(ImplicitCast.IntToDouble); - public static final EnumSet INT_TO_LONG = EnumSet.of(ImplicitCast.IntToLong); + @Deprecated public static final EnumSet NONE = EnumSet.noneOf(ImplicitCast.class); + @Deprecated public static final EnumSet INT_TO_DOUBLE = EnumSet.of(ImplicitCast.IntToDouble); + @Deprecated public static final EnumSet INT_TO_LONG = EnumSet.of(ImplicitCast.IntToLong); public static final String OPTION_PREFIX = "truffle.object."; @@ -62,7 +62,7 @@ * Equivalent to {@code Layout.newLayout().build()}. */ public static Layout createLayout() { - return createLayout(NONE); + return newLayout().build(); } /** @@ -139,7 +139,7 @@ * Create a new layout builder. */ private Builder() { - this.allowedImplicitCasts = Layout.NONE; + this.allowedImplicitCasts = EnumSet.noneOf(ImplicitCast.class); } /** @@ -159,6 +159,16 @@ return this; } + /** + * Add an allowed implicit cast in this layout. + * + * @see Layout.ImplicitCast + */ + public Builder addAllowedImplicitCast(ImplicitCast allowedImplicitCast) { + this.allowedImplicitCasts.add(allowedImplicitCast); + return this; + } + public EnumSet getAllowedImplicitCasts() { return allowedImplicitCasts; } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java --- a/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java Thu Oct 08 17:00:53 2015 -0400 @@ -25,6 +25,7 @@ package com.oracle.truffle.api.object; import com.oracle.truffle.api.Assumption; + import java.util.EnumSet; import java.util.List; @@ -57,6 +58,20 @@ public abstract Shape addProperty(Property property); /** + * Add or change property in the map, yielding a new or cached Shape object. + * + * @return the shape after defining the property + */ + public abstract Shape defineProperty(Object key, Object value, int flags); + + /** + * Add or change property in the map, yielding a new or cached Shape object. + * + * @return the shape after defining the property + */ + public abstract Shape defineProperty(Object key, Object value, int flags, LocationFactory locationFactory); + + /** * An {@link Iterable} over the shape's properties in insertion order. */ public abstract Iterable getProperties(); diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/MessageStringTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/MessageStringTest.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/interop/MessageStringTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -31,7 +31,6 @@ import java.lang.reflect.Modifier; import java.util.Locale; -import org.junit.Ignore; import org.junit.Test; import com.oracle.truffle.api.interop.Message; @@ -88,7 +87,6 @@ } } - @Ignore @Test public void specialMessagePersitance() { SpecialMsg msg = new SpecialMsg(); diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceSectionTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceSectionTest.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceSectionTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -22,12 +22,13 @@ */ package com.oracle.truffle.api.test.source; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import org.junit.Ignore; -import org.junit.Test; public class SourceSectionTest { @@ -56,14 +57,6 @@ assertEquals(section.getStartColumn(), 1); } - @Ignore - @Test - public void emptyLineTest0a() { - SourceSection section = emptyLineSource.createSection("test", 0, 0); - assertEquals(section.getEndLine(), 1); - assertEquals(section.getEndColumn(), 1); - } - @Test public void emptyLineTest1() { SourceSection section = emptyLineSource.createSection("test", 0, 1); @@ -77,20 +70,6 @@ assertEquals(section.getEndColumn(), 1); } - @Ignore - @Test - public void emptyLineTest2() { - SourceSection section = emptyLineSource.createSection("test", 1, 0); - assertNotNull(section); - assertEquals(section.getCode(), ""); - assertEquals(section.getCharIndex(), 1); - assertEquals(section.getCharLength(), 0); - assertEquals(section.getStartLine(), 1); - assertEquals(section.getStartColumn(), 1); - assertEquals(section.getEndLine(), 1); - assertEquals(section.getEndColumn(), 1); - } - @Test public void emptySectionTest2() { SourceSection section = shortSource.createSection("test", 0, 0); diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -54,8 +54,8 @@ PolyglotEngine.Language language = vm.getLanguages().get(L1); assertNotNull("L1 language is defined", language); - Source s = Source.fromText("return nothing", "nothing").withMimeType(L1); - Object ret = vm.eval(s).get(); + Source s = Source.fromText("return nothing", "nothing"); + Object ret = language.eval(s).get(); assertNull("nothing is returned", ret); Object afterInitialization = findLanguageByClass(vm); diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -51,6 +51,7 @@ import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.PolyglotEngine; +import java.util.Objects; public class ImplicitExplicitExportTest { private static Thread mainThread; @@ -268,6 +269,19 @@ public ExportImportLanguage1() { } + + @Override + protected String toString(Ctx ctx, Object value) { + if (value instanceof String) { + try { + int number = Integer.parseInt((String) value); + return number + ": Int"; + } catch (NumberFormatException ex) { + // go on + } + } + return Objects.toString(value); + } } @TruffleLanguage.Registration(mimeType = L2, name = "ImportExport2", version = "0") @@ -276,6 +290,19 @@ public ExportImportLanguage2() { } + + @Override + protected String toString(Ctx ctx, Object value) { + if (value instanceof String) { + try { + double number = Double.parseDouble((String) value); + return number + ": Double"; + } catch (NumberFormatException ex) { + // go on + } + } + return Objects.toString(value); + } } @TruffleLanguage.Registration(mimeType = L3, name = "ImportExport3", version = "0") diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ToStringTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ToStringTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.vm; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class ToStringTest { + @Test + public void valueToStringValueWith1() throws Exception { + PolyglotEngine engine = PolyglotEngine.buildNew().build(); + PolyglotEngine.Language language1 = engine.getLanguages().get("application/x-test-import-export-1"); + PolyglotEngine.Language language2 = engine.getLanguages().get("application/x-test-import-export-2"); + language2.eval(Source.fromText("explicit.value=42", "define 42")); + PolyglotEngine.Value value = language1.eval(Source.fromText("return=value", "42.value")); + assertEquals("It's fourtytwo", "42", value.get()); + + String textual = value.as(String.class); + assertEquals("Nicely formated as by L1", "42: Int", textual); + } + + @Test + public void valueToStringValueWith2() throws Exception { + PolyglotEngine engine = PolyglotEngine.buildNew().build(); + PolyglotEngine.Language language1 = engine.getLanguages().get("application/x-test-import-export-1"); + PolyglotEngine.Language language2 = engine.getLanguages().get("application/x-test-import-export-2"); + language1.eval(Source.fromText("explicit.value=42", "define 42")); + PolyglotEngine.Value value = language2.eval(Source.fromText("return=value", "42.value")); + assertEquals("It's fourtytwo", "42", value.get()); + + String textual = value.as(String.class); + assertEquals("Nicely formated as by L2", "42.0: Double", textual); + } + +} diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ValueTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ValueTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.vm; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Executor; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import org.junit.Test; + +public class ValueTest implements Executor { + private List pending = new LinkedList<>(); + + @Test + public void valueToStringValue() throws Exception { + PolyglotEngine engine = PolyglotEngine.buildNew().build(); + PolyglotEngine.Language language1 = engine.getLanguages().get("application/x-test-import-export-1"); + PolyglotEngine.Language language2 = engine.getLanguages().get("application/x-test-import-export-2"); + language2.eval(Source.fromText("explicit.value=42", "define 42")); + PolyglotEngine.Value value = language1.eval(Source.fromText("return=value", "42.value")); + assertEquals("It's fourtytwo", "42", value.get()); + + String textual = value.toString(); + assertTrue("Contains the value " + textual, textual.contains("value=42")); + assertTrue("Is computed " + textual, textual.contains("computed=true")); + assertTrue("No error " + textual, textual.contains("exception=null")); + } + + @Test + public void valueToStringException() throws Exception { + PolyglotEngine engine = PolyglotEngine.buildNew().build(); + PolyglotEngine.Language language1 = engine.getLanguages().get("application/x-test-import-export-1"); + PolyglotEngine.Value value = null; + try { + value = language1.eval(Source.fromText("parse=does not work", "error.value")); + Object res = value.get(); + fail("Should throw an exception: " + res); + } catch (IOException ex) { + assertTrue("Message contains the right text: " + ex.getMessage(), ex.getMessage().contains("does not work")); + } + + assertNull("No value returned", value); + } + + @Test + public void valueToStringValueAsync() throws Exception { + PolyglotEngine engine = PolyglotEngine.buildNew().executor(this).build(); + PolyglotEngine.Language language1 = engine.getLanguages().get("application/x-test-import-export-1"); + PolyglotEngine.Language language2 = engine.getLanguages().get("application/x-test-import-export-2"); + language2.eval(Source.fromText("explicit.value=42", "define 42")); + flush(); + + PolyglotEngine.Value value = language1.eval(Source.fromText("return=value", "42.value")); + + String textual = value.toString(); + assertFalse("Doesn't contain the value " + textual, textual.contains("value=42")); + assertTrue("Is not computed " + textual, textual.contains("computed=false")); + assertTrue("No error " + textual, textual.contains("exception=null")); + assertTrue("No value yet " + textual, textual.contains("value=null")); + + flush(); + + textual = value.toString(); + assertTrue("Is computed " + textual, textual.contains("computed=true")); + assertTrue("No error " + textual, textual.contains("exception=null")); + assertTrue("value computed " + textual, textual.contains("value=42")); + } + + @Test + public void valueToStringExceptionAsync() throws Exception { + PolyglotEngine engine = PolyglotEngine.buildNew().executor(this).build(); + PolyglotEngine.Language language1 = engine.getLanguages().get("application/x-test-import-export-1"); + PolyglotEngine.Value value = language1.eval(Source.fromText("parse=does not work", "error.value")); + assertNotNull("Value returned", value); + + String textual = value.toString(); + assertTrue("Is not computed " + textual, textual.contains("computed=false")); + assertTrue("No error " + textual, textual.contains("exception=null")); + assertTrue("No value yet " + textual, textual.contains("value=null")); + + flush(); + + textual = value.toString(); + assertTrue("Is computed " + textual, textual.contains("computed=true")); + assertTrue("No value at all" + textual, textual.contains("value=null")); + assertTrue("Error " + textual, textual.contains("exception=java.io.IOException: does not work")); + } + + @Override + public void execute(Runnable command) { + pending.add(command); + } + + private void flush() { + for (Runnable r : pending) { + r.run(); + } + } +} diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EngineTruffleObject.java --- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EngineTruffleObject.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EngineTruffleObject.java Thu Oct 08 17:00:53 2015 -0400 @@ -34,6 +34,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import java.io.IOException; +import java.util.Objects; final class EngineTruffleObject implements TruffleObject, ForeignAccess.Factory { private final PolyglotEngine engine; @@ -63,6 +64,31 @@ return Truffle.getRuntime().createCallTarget(new WrappingRoot(TruffleLanguage.class, tree.createNode())); } + @Override + public int hashCode() { + int hash = 7; + hash = 89 * hash + Objects.hashCode(this.engine); + hash = 89 * hash + Objects.hashCode(this.delegate); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof EngineTruffleObject) { + final EngineTruffleObject other = (EngineTruffleObject) obj; + return engine == other.engine && Objects.equals(this.delegate, other.delegate); + } + return false; + } + + @Override + public String toString() { + return delegate.toString(); + } + static class WrappingRoot extends RootNode { @Child private Node foreignAccess; diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java --- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java Thu Oct 08 17:00:53 2015 -0400 @@ -510,7 +510,7 @@ @SuppressWarnings("try") private void evalImpl(TruffleLanguage[] fillLang, Source s, Object[] result, Language l, CountDownLatch ready) { - try (Closeable d = SPI.executionStart(this, debugger, s)) { + try (Closeable d = SPI.executionStart(this, -1, debugger, s)) { TruffleLanguage langImpl = l.getImpl(true); fillLang[0] = langImpl; result[0] = SPI.eval(langImpl, s); @@ -527,7 +527,7 @@ executor.execute(new Runnable() { @Override public void run() { - try (final Closeable c = SPI.executionStart(PolyglotEngine.this, debugger, null)) { + try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) { res[0] = ForeignAccess.execute(foreignNode, frame, receiver, ForeignAccess.getArguments(frame).toArray()); } catch (IOException ex) { res[1] = ex; @@ -707,7 +707,10 @@ * Obtains Java view of the object represented by this symbol. The method basically * delegates to * {@link JavaInterop#asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)} - * just handles primitive types as well. + * . The method handles primitive types (like {@link Number}, etc.) by casting and returning + * them. When a {@link String}.class is requested, the method let's the + * language that produced the value to do the + * {@link TruffleLanguage#toString(java.lang.Object, java.lang.Object) necessary formating}. * * @param the type of the view one wants to obtain * @param representation the class of the view interface (it has to be an interface) @@ -723,6 +726,10 @@ return representation.cast(eto.getDelegate()); } } + if (representation == String.class) { + final Class clazz = language.getClass(); + return representation.cast(SPI.toString(language, findEnv(clazz), obj)); + } if (representation.isInstance(obj)) { return representation.cast(obj); } @@ -758,7 +765,7 @@ @SuppressWarnings("try") private void invokeImpl(Object thiz, Object[] args, Object[] res, CountDownLatch done) { - try (final Closeable c = SPI.executionStart(PolyglotEngine.this, debugger, null)) { + try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) { List arr = new ArrayList<>(); if (thiz == null) { if (language != null) { @@ -794,11 +801,18 @@ private void waitForSymbol() throws InterruptedIOException { checkThread(); try { - ready.await(); + if (ready != null) { + ready.await(); + } } catch (InterruptedException ex) { throw (InterruptedIOException) new InterruptedIOException(ex.getMessage()).initCause(ex); } } + + @Override + public String toString() { + return "PolyglotEngine.Value[value=" + result[0] + ",exception=" + result[1] + ",computed=" + (ready.getCount() == 0) + "]"; + } } /** @@ -847,10 +861,38 @@ } /** - * Human readable string that identifies the language and version. + * Evaluates provided source. Ignores the particular {@link Source#getMimeType() MIME type} + * and forces evaluation in the context of this language. + * + * @param source code snippet to execute + * @return a {@link Value} object that holds result of an execution, never null + * @throws IOException thrown to signal errors while processing the code + */ + public Value eval(Source source) throws IOException { + checkThread(); + return PolyglotEngine.this.eval(this, source); + } + + /** + * Returns value representing global object of the language. + *

+ * The object is expected to be TruffleObject (e.g. a native object from the + * other language) but technically it can be one of Java primitive wrappers ({@link Integer}, {@link Double}, {@link Short}, etc.). * - * @return string describing the specific language version + * @return the global object or null if the language does not support such + * concept */ + public Value getGlobalObject() { + checkThread(); + + Object[] res = {SPI.languageGlobal(getEnv(true)), null}; + return res[0] == null ? null : new Value(info.getImpl(true), res, null); + } + + /** + * @deprecated concatenate {@link #getName()} and {@link #getVersion()} the way you want. + */ + @Deprecated public String getShortName() { return getName() + "(" + getVersion() + ")"; } @@ -993,9 +1035,9 @@ } @Override - protected Closeable executionStart(Object obj, Debugger debugger, Source s) { + protected Closeable executionStart(Object obj, int currentDepth, Debugger debugger, Source s) { PolyglotEngine vm = (PolyglotEngine) obj; - return super.executionStart(vm, debugger, s); + return super.executionStart(vm, -1, debugger, s); } @Override @@ -1008,5 +1050,10 @@ protected void dispose(TruffleLanguage impl, TruffleLanguage.Env env) { super.dispose(impl, env); } + + @Override + protected String toString(TruffleLanguage language, TruffleLanguage.Env env, Object obj) { + return super.toString(language, env, obj); + } } // end of SPIAccessor } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Thu Oct 08 17:00:53 2015 -0400 @@ -53,6 +53,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.Source; +import java.util.Objects; /** * An entry point for everyone who wants to implement a Truffle based language. By providing an @@ -75,6 +76,8 @@ */ @SuppressWarnings("javadoc") public abstract class TruffleLanguage { + private final Map compiled = Collections.synchronizedMap(new WeakHashMap()); + /** * Constructor to be called by subclasses. */ @@ -266,6 +269,23 @@ protected abstract Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws IOException; /** + * Generates language specific textual representation of a value. Each language may have special + * formating conventions - even primitive values may not follow the traditional Java formating + * rules. As such when + * {@link com.oracle.truffle.api.vm.PolyglotEngine.Value#as(java.lang.Class) + * value.as(String.class)} is requested, it consults the language that produced the value by + * calling this method. By default this method calls {@link Objects#toString(java.lang.Object)}. + * + * @param context the execution context for doing the conversion + * @param value the value to convert. Either primitive type or + * {@link com.oracle.truffle.api.interop.TruffleObject} + * @return textual representation of the value in this language + */ + protected String toString(C context, Object value) { + return Objects.toString(value); + } + + /** * Allows a language implementor to create a node that can effectively lookup up the context * associated with current execution. The context is created by * {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)} method. @@ -323,6 +343,11 @@ void dispose() { lang.disposeContext(ctx); } + + String toString(TruffleLanguage language, Object obj) { + assert lang == language; + return lang.toString(ctx, obj); + } } /** @@ -428,8 +453,6 @@ return super.importSymbol(vm, queryingLang, globalName); } - private static final Map COMPILED = Collections.synchronizedMap(new WeakHashMap()); - @Override protected CallTarget parse(TruffleLanguage truffleLanguage, Source code, Node context, String... argumentNames) throws IOException { return truffleLanguage.parse(code, context, argumentNames); @@ -437,13 +460,13 @@ @Override protected Object eval(TruffleLanguage language, Source source) throws IOException { - CallTarget target = COMPILED.get(source); + CallTarget target = language.compiled.get(source); if (target == null) { target = language.parse(source, null); if (target == null) { throw new IOException("Parsing has not produced a CallTarget for " + source); } - COMPILED.put(source, target); + language.compiled.put(source, target); } try { return target.call(); @@ -504,6 +527,11 @@ assert impl == env.langCtx.lang; env.langCtx.dispose(); } + + @Override + protected String toString(TruffleLanguage language, Env env, Object obj) { + return env.langCtx.toString(language, obj); + } } } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java Thu Oct 08 17:00:53 2015 -0400 @@ -118,8 +118,8 @@ Source.setFileCaching(true); // Initialize execution context stack - debugContext = new DebugExecutionContext(null, null); - prepareContinue(); + debugContext = new DebugExecutionContext(null, null, 0); + debugContext.setStrategy(0, new Continue()); debugContext.contextTrace("START EXEC DEFAULT"); breakpointCallback = new BreakpointCallback() { @@ -194,8 +194,8 @@ * */ @TruffleBoundary - void prepareContinue() { - debugContext.setStrategy(new Continue()); + void prepareContinue(int depth) { + debugContext.setStrategy(depth, new Continue()); } /** @@ -679,12 +679,16 @@ private MaterializedFrame haltedFrame; private DebugExecutionContext(Source executionSource, DebugExecutionContext previousContext) { + this(executionSource, previousContext, -1); + } + + private DebugExecutionContext(Source executionSource, DebugExecutionContext previousContext, int depth) { this.source = executionSource; this.predecessor = previousContext; this.level = previousContext == null ? 0 : previousContext.level + 1; // "Base" is the number of stack frames for all nested (halted) executions. - this.contextStackBase = currentStackDepth(); + this.contextStackBase = depth == -1 ? currentStackDepth() : depth; this.running = true; contextTrace("NEW CONTEXT"); } @@ -695,9 +699,13 @@ * @param stepStrategy */ void setStrategy(StepStrategy stepStrategy) { + setStrategy(currentStackDepth(), stepStrategy); + } + + void setStrategy(int depth, StepStrategy stepStrategy) { if (this.strategy == null) { this.strategy = stepStrategy; - this.strategy.enable(this, currentStackDepth()); + this.strategy.enable(this, depth); if (TRACE) { contextTrace("SET MODE -->" + stepStrategy.getName()); } @@ -809,7 +817,7 @@ } - void executionStarted(Source source) { + void executionStarted(int depth, Source source) { Source execSource = source; if (execSource == null) { execSource = lastSource; @@ -817,8 +825,8 @@ lastSource = execSource; } // Push a new execution context onto stack - debugContext = new DebugExecutionContext(execSource, debugContext); - prepareContinue(); + debugContext = new DebugExecutionContext(execSource, debugContext, depth); + prepareContinue(depth); debugContext.contextTrace("START EXEC "); ACCESSOR.dispatchEvent(vm, new ExecutionEvent(this)); } @@ -840,8 +848,8 @@ static final class AccessorDebug extends Accessor { @Override - protected Closeable executionStart(Object vm, final Debugger debugger, Source s) { - debugger.executionStarted(s); + protected Closeable executionStart(Object vm, int currentDepth, final Debugger debugger, Source s) { + debugger.executionStarted(currentDepth, s); return new Closeable() { @Override public void close() throws IOException { diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ExecutionEvent.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ExecutionEvent.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ExecutionEvent.java Thu Oct 08 17:00:53 2015 -0400 @@ -70,7 +70,7 @@ * */ public void prepareContinue() { - debugger.prepareContinue(); + debugger.prepareContinue(-1); } /** diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java Thu Oct 08 17:00:53 2015 -0400 @@ -128,7 +128,7 @@ * */ public void prepareContinue() { - debugger.prepareContinue(); + debugger.prepareContinue(-1); } /** diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Thu Oct 08 17:00:53 2015 -0400 @@ -267,10 +267,11 @@ private static Reference previousVM = new WeakReference<>(null); private static Assumption oneVM = Truffle.getRuntime().createAssumption(); - protected Closeable executionStart(Object vm, Debugger debugger, Source s) { + @SuppressWarnings("unused") + protected Closeable executionStart(Object vm, int currentDepth, Debugger debugger, Source s) { vm.getClass(); - final Closeable debugClose = DEBUG.executionStart(vm, debugger, s); final Object prev = CURRENT_VM.get(); + final Closeable debugClose = DEBUG.executionStart(vm, prev == null ? 0 : -1, debugger, s); if (!(vm == previousVM.get())) { previousVM = new WeakReference<>(vm); oneVM.invalidate(); @@ -338,4 +339,7 @@ return API.parse(truffleLanguage, code, context, argumentNames); } + protected String toString(TruffleLanguage language, Env env, Object obj) { + return API.toString(language, env, obj); + } } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/DefaultStrategy.java --- a/truffle/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/DefaultStrategy.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object.basic/src/com/oracle/truffle/object/basic/DefaultStrategy.java Thu Oct 08 17:00:53 2015 -0400 @@ -22,8 +22,9 @@ */ package com.oracle.truffle.object.basic; +import java.util.Objects; + import com.oracle.truffle.api.object.DynamicObject; -import com.oracle.truffle.api.object.Layout; import com.oracle.truffle.api.object.Location; import com.oracle.truffle.api.object.Property; import com.oracle.truffle.api.object.Shape; @@ -32,61 +33,56 @@ import com.oracle.truffle.object.LocationImpl; import com.oracle.truffle.object.ShapeImpl; import com.oracle.truffle.object.ShapeImpl.BaseAllocator; -import java.util.Objects; -class DefaultStrategy implements LayoutStrategy { +class DefaultStrategy extends LayoutStrategy { + @Override public boolean updateShape(DynamicObject object) { assert object.getShape().isValid(); return false; } - public Shape returnCached(Shape newShape) { + @Override + public ShapeImpl ensureValid(ShapeImpl newShape) { assert newShape.isValid(); return newShape; } - private static boolean assertLocationInRange(Shape shape, Location location) { + private static boolean assertLocationInRange(ShapeImpl shape, Location location) { BasicLayout layout = (BasicLayout) shape.getLayout(); - assert (((ShapeImpl) shape).getPrimitiveFieldSize() + ((LocationImpl) location).primitiveFieldCount() <= layout.getPrimitiveFieldCount()); - assert (((ShapeImpl) shape).getObjectFieldSize() + ((LocationImpl) location).objectFieldCount() <= layout.getObjectFieldCount()); + assert (shape.getPrimitiveFieldSize() + ((LocationImpl) location).primitiveFieldCount() <= layout.getPrimitiveFieldCount()); + assert (shape.getObjectFieldSize() + ((LocationImpl) location).objectFieldCount() <= layout.getObjectFieldCount()); return true; } - public Shape ensureSpace(Shape shape, Location location) { + @Override + public ShapeImpl ensureSpace(ShapeImpl shape, Location location) { Objects.requireNonNull(location); assert assertLocationInRange(shape, location); return shape; } + @Override public boolean isAutoExtArray() { return false; } - public Property generalizeProperty(DynamicObject object, Property oldProperty, Object value) { - Shape oldShape = object.getShape(); - Location oldLocation = oldProperty.getLocation(); - Location newLocation = ((BasicAllocator) oldShape.allocator()).locationForValueUpcast(value, oldLocation); - Property newProperty = oldProperty.relocate(newLocation); - Shape newShape = oldShape.replaceProperty(oldProperty, newProperty); - newProperty.setSafe(object, value, oldShape, newShape); - return newProperty; - } - - public Property generalizeProperty(DynamicObject object, Property oldProperty, Object value, Shape currentShape, Shape oldNewShape) { + @Override + public ShapeAndProperty generalizeProperty(Property oldProperty, Object value, ShapeImpl currentShape, ShapeImpl nextShape) { Location oldLocation = oldProperty.getLocation(); Location newLocation = ((BasicAllocator) currentShape.allocator()).locationForValueUpcast(value, oldLocation); Property newProperty = oldProperty.relocate(newLocation); - Shape newShape = oldNewShape.replaceProperty(oldProperty, newProperty); - newProperty.setSafe(object, value, currentShape, newShape); - return newProperty; + Shape newShape = nextShape.replaceProperty(oldProperty, newProperty); + return new ShapeAndProperty(newShape, newProperty); } - public BaseAllocator createAllocator(Shape shape) { - return new DefaultAllocatorImpl((ShapeImpl) shape); + @Override + public BaseAllocator createAllocator(ShapeImpl shape) { + return new DefaultAllocatorImpl(shape); } - public BaseAllocator createAllocator(Layout layout) { - return new DefaultAllocatorImpl((LayoutImpl) layout); + @Override + public BaseAllocator createAllocator(LayoutImpl layout) { + return new DefaultAllocatorImpl(layout); } public static class DefaultAllocatorImpl extends BasicAllocator { diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DebugCounter.java --- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DebugCounter.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DebugCounter.java Thu Oct 08 17:00:53 2015 -0400 @@ -26,42 +26,75 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicLong; -public final class DebugCounter { - private static final ArrayList allCounters = new ArrayList<>(); - - private final String name; - private final AtomicLong value; +public abstract class DebugCounter { + private DebugCounter() { + } - private DebugCounter(String name) { - this.name = name; - this.value = new AtomicLong(); - allCounters.add(this); - } + public abstract long get(); + + public abstract void inc(); public static DebugCounter create(String name) { - return new DebugCounter(name); - } - - public long get() { - return value.get(); - } - - public void inc() { - value.incrementAndGet(); - } - - @Override - public String toString() { - return name + ": " + value; + return ObjectStorageOptions.DebugCounters ? DebugCounterImpl.createImpl(name) : Dummy.INSTANCE; } public static void dumpCounters() { - dumpCounters(System.out); + if (ObjectStorageOptions.DebugCounters) { + DebugCounterImpl.dumpCounters(System.out); + } } - public static void dumpCounters(PrintStream out) { - for (DebugCounter counter : allCounters) { - out.println(counter); + private static final class DebugCounterImpl extends DebugCounter { + private static final ArrayList allCounters = new ArrayList<>(); + + private final String name; + private final AtomicLong value; + + private DebugCounterImpl(String name) { + this.name = name; + this.value = new AtomicLong(); + allCounters.add(this); + } + + private static DebugCounter createImpl(String name) { + return new DebugCounterImpl(name); + } + + @Override + public long get() { + return value.get(); + } + + @Override + public void inc() { + value.incrementAndGet(); + } + + @Override + public String toString() { + return name + ": " + get(); + } + + private static void dumpCounters(PrintStream out) { + for (DebugCounter counter : allCounters) { + out.println(counter); + } + } + } + + private static final class Dummy extends DebugCounter { + static final DebugCounter INSTANCE = new Dummy(); + + private Dummy() { + } + + @Override + public long get() { + return 0; + } + + @Override + public void inc() { } } } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java --- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java Thu Oct 08 17:00:53 2015 -0400 @@ -283,43 +283,23 @@ @Override @TruffleBoundary public void define(Object id, Object value, int flags) { - ShapeImpl oldShape = getShape(); - Property existing = oldShape.getProperty(id); - if (existing == null) { - updateShape(); - oldShape = getShape(); - Shape newShape = oldShape.addProperty(Property.create(id, oldShape.allocator().locationForValue(value, true, value != null), flags)); - updateShape(); - newShape.getLastProperty().setGeneric(this, value, oldShape, newShape); - } else { - defineExisting(id, value, flags, existing, oldShape); - } - } - - private void defineExisting(Object id, Object value, int flags, Property existing, ShapeImpl oldShape) { - if (existing.getFlags() == flags) { - existing.setGeneric(this, value, null); - } else { - Property newProperty = Property.create(id, oldShape.getLayout().existingLocationForValue(value, existing.getLocation(), oldShape), flags); - Shape newShape = oldShape.replaceProperty(existing, newProperty); - this.setShapeAndResize(newShape); - newProperty.setInternal(this, value); - } + define(id, value, flags, ShapeImpl.DEFAULT_LAYOUT_FACTORY); } @Override @TruffleBoundary public void define(Object id, Object value, int flags, LocationFactory locationFactory) { ShapeImpl oldShape = getShape(); - Property existing = oldShape.getProperty(id); - if (existing == null) { - updateShape(); + ShapeImpl newShape = oldShape.defineProperty(id, value, flags, locationFactory); + if (updateShape()) { oldShape = getShape(); - Shape newShape = oldShape.addProperty(Property.create(id, locationFactory.createLocation(oldShape, value), flags)); - updateShape(); - newShape.getLastProperty().setGeneric(this, value, oldShape, newShape); + } + Property property = newShape.getProperty(id); + + if (oldShape == newShape) { + property.setSafe(this, value, oldShape); } else { - defineExisting(id, value, flags, existing, oldShape); + property.setSafe(this, value, oldShape, newShape); } } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutImpl.java --- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutImpl.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutImpl.java Thu Oct 08 17:00:53 2015 -0400 @@ -48,8 +48,8 @@ private static final int INT_TO_DOUBLE_FLAG = 1; private static final int INT_TO_LONG_FLAG = 2; - private final LayoutStrategy strategy; - private final Class clazz; + protected final LayoutStrategy strategy; + protected final Class clazz; private final int allowedImplicitCasts; protected LayoutImpl(EnumSet allowedImplicitCasts, Class clazz, LayoutStrategy strategy) { diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutStrategy.java --- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutStrategy.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/LayoutStrategy.java Thu Oct 08 17:00:53 2015 -0400 @@ -23,26 +23,41 @@ package com.oracle.truffle.object; import com.oracle.truffle.api.object.DynamicObject; -import com.oracle.truffle.api.object.Layout; import com.oracle.truffle.api.object.Location; import com.oracle.truffle.api.object.Property; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.object.ShapeImpl.BaseAllocator; -public interface LayoutStrategy { - boolean updateShape(DynamicObject object); +public abstract class LayoutStrategy { + public abstract boolean updateShape(DynamicObject object); + + public abstract ShapeImpl ensureValid(ShapeImpl newShape); + + public abstract ShapeImpl ensureSpace(ShapeImpl shape, Location location); - Shape returnCached(Shape newShape); + public abstract boolean isAutoExtArray(); + + public abstract BaseAllocator createAllocator(LayoutImpl shape); - Shape ensureSpace(Shape shape, Location location); + public abstract BaseAllocator createAllocator(ShapeImpl shape); - boolean isAutoExtArray(); + protected abstract ShapeAndProperty generalizeProperty(Property oldProperty, Object value, ShapeImpl currentShape, ShapeImpl nextShape); - Property generalizeProperty(DynamicObject object, Property oldProperty, Object value); + public static class ShapeAndProperty { + private final Shape shape; + private final Property property; - Property generalizeProperty(DynamicObject object, Property oldProperty, Object value, Shape oldShape, Shape newShape); + public ShapeAndProperty(Shape shape, Property property) { + this.shape = shape; + this.property = property; + } - BaseAllocator createAllocator(Layout shape); + public Shape getShape() { + return shape; + } - BaseAllocator createAllocator(Shape shape); + public Property getProperty() { + return property; + } + } } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ObjectStorageOptions.java --- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ObjectStorageOptions.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ObjectStorageOptions.java Thu Oct 08 17:00:53 2015 -0400 @@ -38,6 +38,7 @@ public static boolean InObjectFields = booleanOption(OPTION_PREFIX + "InObjectFields", true); // Debug options (should be final) + public static final boolean DebugCounters = booleanOption(OPTION_PREFIX + "DebugCounters", true); public static final boolean TraceReshape = booleanOption(OPTION_PREFIX + "TraceReshape", false); public static final boolean DumpShapes = booleanOption(OPTION_PREFIX + "DumpShapes", false); diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/PropertyImpl.java --- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/PropertyImpl.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/PropertyImpl.java Thu Oct 08 17:00:53 2015 -0400 @@ -22,17 +22,16 @@ */ package com.oracle.truffle.object; +import java.util.Objects; + import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.FinalLocationException; import com.oracle.truffle.api.object.HiddenKey; import com.oracle.truffle.api.object.IncompatibleLocationException; import com.oracle.truffle.api.object.Location; -import com.oracle.truffle.api.object.LocationModifier; import com.oracle.truffle.api.object.Property; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.object.Locations.DeclaredLocation; -import java.util.EnumSet; -import java.util.Objects; /** * Property objects represent the mapping between property identifiers (keys) and storage locations. @@ -213,27 +212,32 @@ } private void setSlowCase(DynamicObject store, Object value) { - if (getLocation() instanceof DeclaredLocation) { - setDeclaredLocation(store, value); - } else { - generalize(store, value); + Shape oldShape = store.getShape(); + Shape newShape = oldShape.defineProperty(getKey(), value, getFlags()); + if (store.updateShape()) { + oldShape = store.getShape(); } + assert newShape.isValid() && oldShape.isValid(); + Property newProperty = newShape.getProperty(getKey()); + newProperty.setSafe(store, value, oldShape, newShape); } - private void setDeclaredLocation(DynamicObject store, Object value) { - store.updateShape(); - Shape oldShape = store.getShape(); - Shape newShape = oldShape.addProperty(this.relocateShadow(oldShape.allocator().locationForValue(value, EnumSet.of(LocationModifier.Final, LocationModifier.NonNull)))); - store.updateShape(); - newShape.getLastProperty().setGeneric(store, value, oldShape, newShape); - } + private void setWithShapeSlowCase(DynamicObject store, Object value, Shape currentShape, Shape nextShape) { + Shape oldShape = currentShape; + if (store.updateShape()) { + oldShape = store.getShape(); + } + LayoutStrategy strategy = ((LayoutImpl) currentShape.getLayout()).getStrategy(); + LayoutStrategy.ShapeAndProperty newShapeAndProperty = strategy.generalizeProperty(this, value, (ShapeImpl) oldShape, (ShapeImpl) nextShape); + if (store.updateShape()) { + oldShape = store.getShape(); + } - private Property generalize(DynamicObject store, Object value) { - return ((LayoutImpl) store.getShape().getLayout()).getStrategy().generalizeProperty(store, this, value); - } + Shape newNextShape = newShapeAndProperty.getShape(); + Property newProperty = newShapeAndProperty.getProperty(); - private void setWithShapeSlowCase(DynamicObject store, Object value, Shape oldShape, Shape newShape) { - ((LayoutImpl) store.getShape().getLayout()).getStrategy().generalizeProperty(store, this, value, oldShape, newShape); + assert newNextShape.isValid() && oldShape.isValid(); + newProperty.setSafe(store, value, oldShape, newNextShape); } @Override @@ -246,7 +250,7 @@ return shadow; } - private Property relocateShadow(Location newLocation) { + Property relocateShadow(Location newLocation) { assert !isShadow() && getLocation() instanceof DeclaredLocation && relocatable; return new PropertyImpl(key, newLocation, flags, true, relocatable); } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java --- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java Thu Oct 08 17:00:53 2015 -0400 @@ -22,6 +22,16 @@ */ package com.oracle.truffle.object; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; @@ -34,6 +44,7 @@ import com.oracle.truffle.api.object.DynamicObjectFactory; import com.oracle.truffle.api.object.Layout; import com.oracle.truffle.api.object.Location; +import com.oracle.truffle.api.object.LocationFactory; import com.oracle.truffle.api.object.ObjectLocation; import com.oracle.truffle.api.object.ObjectType; import com.oracle.truffle.api.object.Property; @@ -53,15 +64,6 @@ import com.oracle.truffle.object.Transition.PropertyTransition; import com.oracle.truffle.object.Transition.RemovePropertyTransition; import com.oracle.truffle.object.Transition.ReservePrimitiveArrayTransition; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Shape objects create a mapping of Property objects to indexes. The mapping of those indexes to an @@ -312,7 +314,7 @@ ShapeImpl cachedShape = this.getTransitionMapForRead().get(transition); if (cachedShape != null) { // Shape already exists? shapeCacheHitCount.inc(); - return (ShapeImpl) layout.getStrategy().returnCached(cachedShape); + return layout.getStrategy().ensureValid(cachedShape); } shapeCacheMissCount.inc(); @@ -339,6 +341,40 @@ } } + @TruffleBoundary + @Override + public ShapeImpl defineProperty(Object key, Object value, int flags) { + return defineProperty(key, value, flags, DEFAULT_LAYOUT_FACTORY); + } + + @TruffleBoundary + @Override + public ShapeImpl defineProperty(Object key, Object value, int flags, LocationFactory locationFactory) { + ShapeImpl oldShape = this; + if (!oldShape.isValid()) { + oldShape = layout.getStrategy().ensureValid(oldShape); + } + PropertyImpl existing = (PropertyImpl) oldShape.getProperty(key); + if (existing == null) { + return oldShape.addProperty(Property.create(key, locationFactory.createLocation(oldShape, value), flags)); + } else { + if (existing.getFlags() == flags) { + if (existing.getLocation().canSet(value)) { + return oldShape; + } else { + if (existing.getLocation() instanceof DeclaredLocation) { + return oldShape.addProperty(existing.relocateShadow(locationFactory.createLocation(oldShape, value))); + } else { + return (ShapeImpl) layout.getStrategy().generalizeProperty(existing, value, oldShape, oldShape).getShape(); + } + } + } else { + Property newProperty = Property.create(key, oldShape.getLayout().existingLocationForValue(value, existing.getLocation(), oldShape), flags); + return oldShape.replaceProperty(existing, newProperty); + } + } + } + /** * Add a new property in the map, yielding a new or cached Shape object. * @@ -357,7 +393,7 @@ return cachedShape; } - ShapeImpl oldShape = (ShapeImpl) layout.getStrategy().ensureSpace(this, prop.getLocation()); + ShapeImpl oldShape = layout.getStrategy().ensureSpace(this, prop.getLocation()); ShapeImpl newShape = makeShapeWithAddedProperty(oldShape, addTransition); oldShape.addDirectTransition(addTransition, newShape); @@ -424,7 +460,7 @@ return cachedShape; } - ShapeImpl oldShape = (ShapeImpl) layout.getStrategy().ensureSpace(this, layout.getPrimitiveArrayLocation()); + ShapeImpl oldShape = layout.getStrategy().ensureSpace(this, layout.getPrimitiveArrayLocation()); ShapeImpl newShape = makeShapeWithPrimitiveExtensionArray(oldShape, transition); oldShape.addDirectTransition(transition, newShape); return newShape; @@ -1105,6 +1141,12 @@ } }; + static final LocationFactory DEFAULT_LAYOUT_FACTORY = new LocationFactory() { + public Location createLocation(Shape shape, Object value) { + return ((ShapeImpl) shape).allocator().locationForValue(value, true, value != null); + } + }; + private static final DebugCounter shapeCount = DebugCounter.create("Shapes allocated total"); private static final DebugCounter shapeCloneCount = DebugCounter.create("Shapes allocated cloned"); private static final DebugCounter shapeCacheHitCount = DebugCounter.create("Shape cache hits"); diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLDebugTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLDebugTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.sl.test; + +import com.oracle.truffle.api.debug.Debugger; +import com.oracle.truffle.api.debug.ExecutionEvent; +import com.oracle.truffle.api.debug.SuspendedEvent; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.source.LineLocation; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.api.vm.EventConsumer; +import com.oracle.truffle.api.vm.PolyglotEngine; +import java.io.ByteArrayOutputStream; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class SLDebugTest { + private Source factorial; + private Debugger debugger; + private Callable run; + private SuspendedEvent suspendedEvent; + private Throwable ex; + private ExecutionEvent executionEvent; + + @Test + public void stepInStepOver() throws Throwable { + // @formatter:off + factorial = Source.fromText( + "function main() {\n" + + " res = fac(2);\n" + + " println(res);\n" + + " return res;\n" + + "}\n" + + "function fac(n) {\n" + + " if (n <= 1) {\n" + + " return 1;\n" + + " }\n" + + " nMinusOne = n - 1;\n" + + " nMOFact = fac(nMinusOne);\n" + + " res = n * nMOFact;\n" + + " return res;\n" + + "}\n" + + "", "factorial.sl" + ).withMimeType("application/x-sl"); + // @formatter:on + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + PolyglotEngine engine = PolyglotEngine.buildNew().executor(Executors.newSingleThreadExecutor()).onEvent(new EventConsumer(ExecutionEvent.class) { + @Override + protected void on(ExecutionEvent event) { + onExecution(event); + } + }).onEvent(new EventConsumer(SuspendedEvent.class) { + @Override + protected void on(SuspendedEvent event) { + onSuspended(event); + } + }).setOut(os).build(); + + PolyglotEngine.Value value; + synchronized (this) { + value = engine.eval(factorial); + wait(); + } + assertNotNull("Debugger initalized", debugger); + + run(new Callable() { + @Override + public Void call() throws Exception { + LineLocation nMinusOne = factorial.createLineLocation(7); + debugger.setLineBreakpoint(0, nMinusOne, true); + executionEvent.prepareContinue(); + return null; + } + }); + + assertNull("Parsing done", value.get()); + + PolyglotEngine.Value main = engine.findGlobalSymbol("main"); + value = main.invoke(null); + + run(new Callable() { + @Override + public Void call() throws Exception { + assertNull(suspendedEvent); + executionEvent.prepareStepInto(); + return null; + } + }); + + run(new Callable() { + @Override + public Void call() throws Exception { + assertNotNull(suspendedEvent); + final MaterializedFrame frame = suspendedEvent.getFrame(); + assertEquals("No arguments", 0, frame.getArguments().length); + assertEquals("one var slot", 1, frame.getFrameDescriptor().getSlots().size()); + Object resName = frame.getFrameDescriptor().getSlots().get(0).getFrameDescriptor().getIdentifiers().iterator().next(); + assertEquals("res", resName); + suspendedEvent.prepareStepInto(2); + suspendedEvent = null; + return null; + } + }); + + run(new Callable() { + @Override + public Void call() throws Exception { + assertLine(6); + + final MaterializedFrame frame = suspendedEvent.getFrame(); + assertEquals("One argument", 1, frame.getArguments().length); + assertEquals("One argument value 2", 2L, frame.getArguments()[0]); + suspendedEvent.prepareStepOver(1); + suspendedEvent = null; + return null; + } + }); + + run(new Callable() { + @Override + public Void call() throws Exception { + assertNotNull(suspendedEvent); + + // XXX wrong step over: + // assertLine(7); + + suspendedEvent.prepareContinue(); + suspendedEvent = null; + return null; + } + }); + + run(null); + + Number n = value.as(Number.class); + assertNotNull(n); + assertEquals("Factorial computed OK", 2, n.intValue()); + } + + synchronized void onExecution(ExecutionEvent event) { + executionEvent = event; + debugger = event.getDebugger(); + notifyAll(); + waitForWork(); + } + + synchronized void onSuspended(SuspendedEvent event) { + suspendedEvent = event; + notifyAll(); + waitForWork(); + } + + private synchronized void run(Callable callable) throws Throwable { + if (ex != null) { + throw ex; + } + while (run != null) { + wait(); + } + run = callable; + notifyAll(); + if (ex != null) { + throw ex; + } + } + + private void waitForWork() { + try { + waitForWork0().call(); + } catch (Throwable tmpEx) { + this.ex = tmpEx; + } + + } + + private synchronized Callable waitForWork0() { + while (run == null) { + try { + wait(); + } catch (InterruptedException tmpEx) { + throw new IllegalStateException(tmpEx); + } + } + Callable c = run; + run = null; + notifyAll(); + return c; + } + + void assertLine(int line) { + assertNotNull(suspendedEvent); + final SourceSection expLoc = factorial.createSection("Line " + line, line); + final SourceSection sourceLoc = suspendedEvent.getNode().getEncapsulatingSourceSection(); + assertEquals("Exp\n" + expLoc + "\nbut was\n" + sourceLoc, line, sourceLoc.getLineLocation().getLineNumber()); + } +} diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -165,6 +165,11 @@ return "count"; } + @Override + protected String globalObject() { + return null; + } + // // Ignore tests working on floats and double // diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/ToStringOfEvalTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/ToStringOfEvalTest.java Thu Oct 08 17:00:53 2015 -0400 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.sl.test; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import java.io.IOException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class ToStringOfEvalTest { + + @Test + public void checkToStringOnAFunction() throws IOException { + PolyglotEngine engine = PolyglotEngine.buildNew().build(); + PolyglotEngine.Language sl = engine.getLanguages().get("application/x-sl"); + sl.eval(Source.fromText("function checkName() {}", "defineFn")); + PolyglotEngine.Value value1 = engine.findGlobalSymbol("checkName"); + PolyglotEngine.Value value2 = engine.findGlobalSymbol("checkName"); + + assertNotNull("Symbol is not null", value1); + assertNotNull("Symbol is not null either", value2); + + Object global1 = value1.get(); + Object global2 = value2.get(); + + assertNotNull("Symbol is not null", global1); + assertNotNull("Symbol is not null either", global2); + + assertEquals("Symbols are the same", global1, global2); + + assertTrue("Contans checkName text: " + global2, global2.toString().contains("checkName")); + } +} diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLServer.java --- a/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLServer.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLServer.java Thu Oct 08 17:00:53 2015 -0400 @@ -78,7 +78,7 @@ public static void main(String[] args) { // Cheating for the prototype: start from SL, rather than from the client. final SLREPLServer server = new SLREPLServer(); - final SimpleREPLClient client = new SimpleREPLClient(server.language.getShortName(), server); + final SimpleREPLClient client = new SimpleREPLClient(getShortName(server.language), server); // Cheating for the prototype: allow server access to client for recursive debugging server.setClient(client); @@ -89,6 +89,10 @@ } } + private static String getShortName(Language language) { + return language.getName() + "(" + language.getVersion() + ")"; + } + private final Language language; private final PolyglotEngine vm; private Debugger db; @@ -145,7 +149,7 @@ assert language != null; this.vm = newVM; - this.statusPrefix = language.getShortName() + " REPL:"; + this.statusPrefix = getShortName(language) + " REPL:"; } private void setClient(SimpleREPLClient replClient) { @@ -160,7 +164,7 @@ // SL doesn't load modules (like other languages), so we just return a success final REPLMessage reply = new REPLMessage(); reply.put(REPLMessage.STATUS, REPLMessage.SUCCEEDED); - reply.put(REPLMessage.DISPLAY_MSG, language.getShortName() + " started"); + reply.put(REPLMessage.DISPLAY_MSG, getShortName(language) + " started"); return reply; } diff -r 260e3cdf11ec -r 9f478b9db4f7 truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java --- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java Thu Oct 08 16:48:42 2015 -0400 +++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java Thu Oct 08 17:00:53 2015 -0400 @@ -24,10 +24,12 @@ */ package com.oracle.truffle.tck; +import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.api.vm.PolyglotEngine.Language; import java.io.IOException; import java.lang.reflect.Field; import java.util.Random; @@ -142,6 +144,19 @@ } /** + * Name of a function to return global object. The function can be executed without providing + * any arguments and should return global object of the language, if the language supports it. + * Global object is the one accessible via + * {@link TruffleLanguage#getLanguageGlobal(java.lang.Object)}. + * + * @return name of globally exported symbol, return null if the language doesn't + * support the concept of global object + */ + protected String globalObject() { + throw new UnsupportedOperationException("globalObject() method not implemented"); + } + + /** * Name of a function that counts number of its invocations in current {@link PolyglotEngine} * context. Your function should somehow keep a counter to remember number of its invocations * and always increment it. The first invocation should return 1, the second @@ -232,6 +247,15 @@ } @Test + public void testNullCanBeCastToAnything() throws Exception { + PolyglotEngine.Value retNull = findGlobalSymbol(returnsNull()); + + Object res = retNull.invoke(null).as(CompoundObject.class); + + assertNull("Should yield real Java null", res); + } + + @Test public void testNullInCompoundObject() throws Exception { CompoundObject obj = findCompoundSymbol(); if (obj == null) { @@ -351,8 +375,8 @@ final PolyglotEngine.Value result = apply.invoke(null, fn); try { - String res = result.as(String.class); - fail("Cannot be converted to String: " + res); + Boolean res = result.as(Boolean.class); + fail("Cannot be converted to Boolean: " + res); } catch (ClassCastException ex) { // correct } @@ -553,7 +577,21 @@ } assert prev1 == prev2 : "At round " + i + " the same number of invocations " + prev1 + " vs. " + prev2; } + } + @Test + public void testGlobalObjectIsAccessible() throws Exception { + String globalObjectFunction = globalObject(); + if (globalObjectFunction == null) { + return; + } + + Language language = vm().getLanguages().get(mimeType()); + assertNotNull("Langugage for " + mimeType() + " found", language); + + PolyglotEngine.Value function = vm().findGlobalSymbol(globalObjectFunction); + Object global = function.invoke(null).get(); + assertEquals("Global from the language same with Java obtained one", language.getGlobalObject().get(), global); } private PolyglotEngine.Value findGlobalSymbol(String name) throws Exception {