1.1 --- a/rt/emul/compacttest/src/test/java/org/apidesign/bck2brwsr/tck/ClassTest.java Sun Mar 20 07:01:40 2016 +0100
1.2 +++ b/rt/emul/compacttest/src/test/java/org/apidesign/bck2brwsr/tck/ClassTest.java Sun Mar 20 08:12:55 2016 +0100
1.3 @@ -39,6 +39,45 @@
1.4 Class<?> dblCls = dbl.getClass();
1.5 return String.class.isAssignableFrom(dblCls);
1.6 }
1.7 +
1.8 + private String toClassInfo(Class<?> c) {
1.9 + StringBuilder sb = new StringBuilder();
1.10 + sb.append("\n");
1.11 + sb.append("name: ").append(c.getName()).append("\n");
1.12 + sb.append("local: ").append(c.isLocalClass()).append("\n");
1.13 + sb.append("member: ").append(c.isMemberClass()).append("\n");
1.14 + sb.append("annonymous: ").append(c.isAnonymousClass()).append("\n");
1.15 + return sb.toString();
1.16 + }
1.17 +
1.18 +
1.19 + @Compare
1.20 + public String globalClass() throws Exception {
1.21 + return toClassInfo(ClassTest.class);
1.22 + }
1.23 +
1.24 + @Compare
1.25 + public String localClass() throws Exception {
1.26 + class Local {
1.27 + }
1.28 + return toClassInfo(Local.class);
1.29 + }
1.30 +
1.31 + class Member {
1.32 + }
1.33 +
1.34 + @Compare
1.35 + public String memberClass() throws Exception {
1.36 + return toClassInfo(Member.class);
1.37 + }
1.38 +
1.39 + static class NonMember {
1.40 + }
1.41 +
1.42 + @Compare
1.43 + public String nonMemberClass() throws Exception {
1.44 + return toClassInfo(NonMember.class);
1.45 + }
1.46
1.47 @Factory
1.48 public static Object[] create() {
2.1 --- a/rt/emul/mini/src/main/java/java/lang/Class.java Sun Mar 20 07:01:40 2016 +0100
2.2 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Sun Mar 20 08:12:55 2016 +0100
2.3 @@ -721,15 +721,12 @@
2.4 * class.
2.5 */
2.6 private String getSimpleBinaryName() {
2.7 - Class<?> enclosingClass = null; // XXX getEnclosingClass();
2.8 - if (enclosingClass == null) // top level class
2.9 + final String name = getName();
2.10 + int dolar = name.lastIndexOf('$');
2.11 + if (dolar == -1) {
2.12 return null;
2.13 - // Otherwise, strip the enclosing class' name
2.14 - try {
2.15 - return getName().substring(enclosingClass.getName().length());
2.16 - } catch (IndexOutOfBoundsException ex) {
2.17 - throw new IllegalStateException("Malformed class name");
2.18 }
2.19 + return name.substring(dolar);
2.20 }
2.21
2.22 /**
2.23 @@ -1350,8 +1347,8 @@
2.24 else
2.25 return null;
2.26 }
2.27 -// if (isLocalOrAnonymousClass())
2.28 -// return null;
2.29 + if (isLocalOrAnonymousClass())
2.30 + return null;
2.31 // Class<?> enclosingClass = getEnclosingClass();
2.32 Class<?> enclosingClass = null;
2.33 if (enclosingClass == null) { // top level class
2.34 @@ -1365,6 +1362,47 @@
2.35 }
2.36
2.37 /**
2.38 + * Returns {@code true} if and only if the underlying class is an anonymous
2.39 + * class.
2.40 + *
2.41 + * @return {@code true} if and only if this class is an anonymous class.
2.42 + * @since 1.5
2.43 + */
2.44 + public boolean isAnonymousClass() {
2.45 + return "".equals(getSimpleName());
2.46 + }
2.47 +
2.48 + /**
2.49 + * Returns {@code true} if and only if the underlying class is a local
2.50 + * class.
2.51 + *
2.52 + * @return {@code true} if and only if this class is a local class.
2.53 + * @since 1.5
2.54 + */
2.55 + public boolean isLocalClass() {
2.56 + return isLocalOrAnonymousClass() && !isAnonymousClass();
2.57 + }
2.58 +
2.59 + /**
2.60 + * Returns {@code true} if and only if the underlying class is a member
2.61 + * class.
2.62 + *
2.63 + * @return {@code true} if and only if this class is a member class.
2.64 + * @since 1.5
2.65 + */
2.66 + public boolean isMemberClass() {
2.67 + return getSimpleBinaryName() != null && !isLocalOrAnonymousClass();
2.68 + }
2.69 +
2.70 + /**
2.71 + * Returns {@code true} if this is a local class or an anonymous class.
2.72 + * Returns {@code false} otherwise.
2.73 + */
2.74 + private boolean isLocalOrAnonymousClass() {
2.75 + return (getAccess() & 0x10000) != 0;
2.76 + }
2.77 +
2.78 + /**
2.79 * Finds a resource with a given name. The rules for searching resources
2.80 * associated with a given class are implemented by the defining
2.81 * {@linkplain ClassLoader class loader} of the class. This method
3.1 --- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Sun Mar 20 07:01:40 2016 +0100
3.2 +++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Sun Mar 20 08:12:55 2016 +0100
3.3 @@ -24,7 +24,6 @@
3.4 */
3.5 package java.lang;
3.6
3.7 -import java.io.ByteArrayInputStream;
3.8 import java.io.InputStream;
3.9 import java.io.IOException;
3.10 import java.net.URL;
4.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sun Mar 20 07:01:40 2016 +0100
4.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sun Mar 20 08:12:55 2016 +0100
4.3 @@ -570,6 +570,7 @@
4.4 private Hashtable indexHashAscii = new Hashtable();
4.5 private String pkgPrefix = "";
4.6 private int pkgPrefixLen = 0;
4.7 + private boolean hasEnclosingMethod;
4.8
4.9 /**
4.10 * Read classfile to disassemble.
4.11 @@ -620,42 +621,45 @@
4.12 attrs = new AttrData[attributes_count];
4.13 for (int k = 0; k < attributes_count; k++) {
4.14 int name_cpx = in.readUnsignedShort();
4.15 - if (getTag(name_cpx) == CONSTANT_UTF8
4.16 - && getString(name_cpx).equals("SourceFile")) {
4.17 - if (in.readInt() != 2) {
4.18 - throw new ClassFormatError("invalid attr length");
4.19 + if (getTag(name_cpx) == CONSTANT_UTF8) {
4.20 + final String attrName = getString(name_cpx);
4.21 + if (attrName.equals("SourceFile")) {
4.22 + if (in.readInt() != 2) {
4.23 + throw new ClassFormatError("invalid attr length");
4.24 + }
4.25 + source_cpx = in.readUnsignedShort();
4.26 + AttrData attr = new AttrData(this);
4.27 + attr.read(name_cpx);
4.28 + attrs[k] = attr;
4.29 +
4.30 + } else if (attrName.equals("InnerClasses")) {
4.31 + int length = in.readInt();
4.32 + int num = in.readUnsignedShort();
4.33 + if (2 + num * 8 != length) {
4.34 + throw new ClassFormatError("invalid attr length");
4.35 + }
4.36 + innerClasses = new InnerClassData[num];
4.37 + for (int j = 0; j < num; j++) {
4.38 + InnerClassData innerClass = new InnerClassData(this);
4.39 + innerClass.read(in);
4.40 + innerClasses[j] = innerClass;
4.41 + }
4.42 + AttrData attr = new AttrData(this);
4.43 + attr.read(name_cpx);
4.44 + attrs[k] = attr;
4.45 + } else if (attrName.equals("BootstrapMethods")) {
4.46 + AttrData attr = new AttrData(this);
4.47 + bootMethods = readBootstrapMethods(in);
4.48 + attr.read(name_cpx);
4.49 + attrs[k] = attr;
4.50 + } else {
4.51 + if (attrName.equals("EnclosingMethod")) {
4.52 + hasEnclosingMethod = true;
4.53 + }
4.54 + AttrData attr = new AttrData(this);
4.55 + attr.read(name_cpx, in);
4.56 + attrs[k] = attr;
4.57 }
4.58 - source_cpx = in.readUnsignedShort();
4.59 - AttrData attr = new AttrData(this);
4.60 - attr.read(name_cpx);
4.61 - attrs[k] = attr;
4.62 -
4.63 - } else if (getTag(name_cpx) == CONSTANT_UTF8
4.64 - && getString(name_cpx).equals("InnerClasses")) {
4.65 - int length = in.readInt();
4.66 - int num = in.readUnsignedShort();
4.67 - if (2 + num * 8 != length) {
4.68 - throw new ClassFormatError("invalid attr length");
4.69 - }
4.70 - innerClasses = new InnerClassData[num];
4.71 - for (int j = 0; j < num; j++) {
4.72 - InnerClassData innerClass = new InnerClassData(this);
4.73 - innerClass.read(in);
4.74 - innerClasses[j] = innerClass;
4.75 - }
4.76 - AttrData attr = new AttrData(this);
4.77 - attr.read(name_cpx);
4.78 - attrs[k] = attr;
4.79 - } else if (getTag(name_cpx) == CONSTANT_UTF8
4.80 - && getString(name_cpx).equals("BootstrapMethods")) {
4.81 - AttrData attr = new AttrData(this);
4.82 - bootMethods = readBootstrapMethods(in);
4.83 - attr.read(name_cpx);
4.84 - attrs[k] = attr;
4.85 - } else {
4.86 - AttrData attr = new AttrData(this);
4.87 - attr.read(name_cpx, in);
4.88 - attrs[k] = attr;
4.89 }
4.90 }
4.91 in.close();
4.92 @@ -876,6 +880,10 @@
4.93 return access;
4.94 }
4.95
4.96 + public boolean hasEnclosingMethod() {
4.97 + return hasEnclosingMethod;
4.98 + }
4.99 +
4.100 /**
4.101 * Returns true if it is a class
4.102 */
5.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Mar 20 07:01:40 2016 +0100
5.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Mar 20 08:12:55 2016 +0100
5.3 @@ -339,7 +339,11 @@
5.4 }
5.5 }
5.6 append("\n ]; };");
5.7 - append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";");
5.8 + int flags = jc.getAccessFlags();
5.9 + if (jc.hasEnclosingMethod()) {
5.10 + flags |= 0x10000;
5.11 + }
5.12 + append("\n CLS.$class.access = ").append(flags+";");
5.13 append("\n CLS.$class.cnstr = CLS;");
5.14 byte[] classAnno = jc.findAnnotationData(false);
5.15 if (classAnno != null) {