# HG changeset patch # User Jaroslav Tulach # Date 1458457975 -3600 # Node ID cf6d5d3576962478f8fd39dd708e230244ba980e # Parent cb637833bfb3b3c9c13360fd629df373360506d2 Support new Class operations: isMemberClass, isAnonymousClass and isLocalClass diff -r cb637833bfb3 -r cf6d5d357696 rt/emul/compacttest/src/test/java/org/apidesign/bck2brwsr/tck/ClassTest.java --- a/rt/emul/compacttest/src/test/java/org/apidesign/bck2brwsr/tck/ClassTest.java Sun Mar 20 07:01:40 2016 +0100 +++ b/rt/emul/compacttest/src/test/java/org/apidesign/bck2brwsr/tck/ClassTest.java Sun Mar 20 08:12:55 2016 +0100 @@ -39,6 +39,45 @@ Class dblCls = dbl.getClass(); return String.class.isAssignableFrom(dblCls); } + + private String toClassInfo(Class c) { + StringBuilder sb = new StringBuilder(); + sb.append("\n"); + sb.append("name: ").append(c.getName()).append("\n"); + sb.append("local: ").append(c.isLocalClass()).append("\n"); + sb.append("member: ").append(c.isMemberClass()).append("\n"); + sb.append("annonymous: ").append(c.isAnonymousClass()).append("\n"); + return sb.toString(); + } + + + @Compare + public String globalClass() throws Exception { + return toClassInfo(ClassTest.class); + } + + @Compare + public String localClass() throws Exception { + class Local { + } + return toClassInfo(Local.class); + } + + class Member { + } + + @Compare + public String memberClass() throws Exception { + return toClassInfo(Member.class); + } + + static class NonMember { + } + + @Compare + public String nonMemberClass() throws Exception { + return toClassInfo(NonMember.class); + } @Factory public static Object[] create() { diff -r cb637833bfb3 -r cf6d5d357696 rt/emul/mini/src/main/java/java/lang/Class.java --- a/rt/emul/mini/src/main/java/java/lang/Class.java Sun Mar 20 07:01:40 2016 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Sun Mar 20 08:12:55 2016 +0100 @@ -721,15 +721,12 @@ * class. */ private String getSimpleBinaryName() { - Class enclosingClass = null; // XXX getEnclosingClass(); - if (enclosingClass == null) // top level class + final String name = getName(); + int dolar = name.lastIndexOf('$'); + if (dolar == -1) { return null; - // Otherwise, strip the enclosing class' name - try { - return getName().substring(enclosingClass.getName().length()); - } catch (IndexOutOfBoundsException ex) { - throw new IllegalStateException("Malformed class name"); } + return name.substring(dolar); } /** @@ -1350,8 +1347,8 @@ else return null; } -// if (isLocalOrAnonymousClass()) -// return null; + if (isLocalOrAnonymousClass()) + return null; // Class enclosingClass = getEnclosingClass(); Class enclosingClass = null; if (enclosingClass == null) { // top level class @@ -1365,6 +1362,47 @@ } /** + * Returns {@code true} if and only if the underlying class is an anonymous + * class. + * + * @return {@code true} if and only if this class is an anonymous class. + * @since 1.5 + */ + public boolean isAnonymousClass() { + return "".equals(getSimpleName()); + } + + /** + * Returns {@code true} if and only if the underlying class is a local + * class. + * + * @return {@code true} if and only if this class is a local class. + * @since 1.5 + */ + public boolean isLocalClass() { + return isLocalOrAnonymousClass() && !isAnonymousClass(); + } + + /** + * Returns {@code true} if and only if the underlying class is a member + * class. + * + * @return {@code true} if and only if this class is a member class. + * @since 1.5 + */ + public boolean isMemberClass() { + return getSimpleBinaryName() != null && !isLocalOrAnonymousClass(); + } + + /** + * Returns {@code true} if this is a local class or an anonymous class. + * Returns {@code false} otherwise. + */ + private boolean isLocalOrAnonymousClass() { + return (getAccess() & 0x10000) != 0; + } + + /** * Finds a resource with a given name. The rules for searching resources * associated with a given class are implemented by the defining * {@linkplain ClassLoader class loader} of the class. This method diff -r cb637833bfb3 -r cf6d5d357696 rt/emul/mini/src/main/java/java/lang/ClassLoader.java --- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Sun Mar 20 07:01:40 2016 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Sun Mar 20 08:12:55 2016 +0100 @@ -24,7 +24,6 @@ */ package java.lang; -import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; import java.net.URL; diff -r cb637833bfb3 -r cf6d5d357696 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sun Mar 20 07:01:40 2016 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sun Mar 20 08:12:55 2016 +0100 @@ -570,6 +570,7 @@ private Hashtable indexHashAscii = new Hashtable(); private String pkgPrefix = ""; private int pkgPrefixLen = 0; + private boolean hasEnclosingMethod; /** * Read classfile to disassemble. @@ -620,42 +621,45 @@ attrs = new AttrData[attributes_count]; for (int k = 0; k < attributes_count; k++) { int name_cpx = in.readUnsignedShort(); - if (getTag(name_cpx) == CONSTANT_UTF8 - && getString(name_cpx).equals("SourceFile")) { - if (in.readInt() != 2) { - throw new ClassFormatError("invalid attr length"); + if (getTag(name_cpx) == CONSTANT_UTF8) { + final String attrName = getString(name_cpx); + if (attrName.equals("SourceFile")) { + if (in.readInt() != 2) { + throw new ClassFormatError("invalid attr length"); + } + source_cpx = in.readUnsignedShort(); + AttrData attr = new AttrData(this); + attr.read(name_cpx); + attrs[k] = attr; + + } else if (attrName.equals("InnerClasses")) { + int length = in.readInt(); + int num = in.readUnsignedShort(); + if (2 + num * 8 != length) { + throw new ClassFormatError("invalid attr length"); + } + innerClasses = new InnerClassData[num]; + for (int j = 0; j < num; j++) { + InnerClassData innerClass = new InnerClassData(this); + innerClass.read(in); + innerClasses[j] = innerClass; + } + AttrData attr = new AttrData(this); + attr.read(name_cpx); + attrs[k] = attr; + } else if (attrName.equals("BootstrapMethods")) { + AttrData attr = new AttrData(this); + bootMethods = readBootstrapMethods(in); + attr.read(name_cpx); + attrs[k] = attr; + } else { + if (attrName.equals("EnclosingMethod")) { + hasEnclosingMethod = true; + } + AttrData attr = new AttrData(this); + attr.read(name_cpx, in); + attrs[k] = attr; } - source_cpx = in.readUnsignedShort(); - AttrData attr = new AttrData(this); - attr.read(name_cpx); - attrs[k] = attr; - - } else if (getTag(name_cpx) == CONSTANT_UTF8 - && getString(name_cpx).equals("InnerClasses")) { - int length = in.readInt(); - int num = in.readUnsignedShort(); - if (2 + num * 8 != length) { - throw new ClassFormatError("invalid attr length"); - } - innerClasses = new InnerClassData[num]; - for (int j = 0; j < num; j++) { - InnerClassData innerClass = new InnerClassData(this); - innerClass.read(in); - innerClasses[j] = innerClass; - } - AttrData attr = new AttrData(this); - attr.read(name_cpx); - attrs[k] = attr; - } else if (getTag(name_cpx) == CONSTANT_UTF8 - && getString(name_cpx).equals("BootstrapMethods")) { - AttrData attr = new AttrData(this); - bootMethods = readBootstrapMethods(in); - attr.read(name_cpx); - attrs[k] = attr; - } else { - AttrData attr = new AttrData(this); - attr.read(name_cpx, in); - attrs[k] = attr; } } in.close(); @@ -876,6 +880,10 @@ return access; } + public boolean hasEnclosingMethod() { + return hasEnclosingMethod; + } + /** * Returns true if it is a class */ diff -r cb637833bfb3 -r cf6d5d357696 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Mar 20 07:01:40 2016 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Mar 20 08:12:55 2016 +0100 @@ -339,7 +339,11 @@ } } append("\n ]; };"); - append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";"); + int flags = jc.getAccessFlags(); + if (jc.hasEnclosingMethod()) { + flags |= 0x10000; + } + append("\n CLS.$class.access = ").append(flags+";"); append("\n CLS.$class.cnstr = CLS;"); byte[] classAnno = jc.findAnnotationData(false); if (classAnno != null) {