rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java
branchclosure
changeset 967 f19f17f8f8dc
parent 882 60d9ea48ec99
child 1029 b1fe994d4267
     1.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java	Mon Mar 25 13:29:42 2013 +0100
     1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java	Fri Apr 12 18:48:48 2013 +0200
     1.3 @@ -20,14 +20,18 @@
     1.4  import com.google.javascript.jscomp.CommandLineRunner;
     1.5  import com.google.javascript.jscomp.SourceFile;
     1.6  import java.io.IOException;
     1.7 +import java.io.InputStream;
     1.8  import java.io.OutputStream;
     1.9  import java.io.PrintStream;
    1.10  import java.util.ArrayList;
    1.11  import java.util.Arrays;
    1.12  import java.util.Collection;
    1.13  import java.util.Collections;
    1.14 +import java.util.HashMap;
    1.15  import java.util.List;
    1.16 +import java.util.Map;
    1.17  import org.apidesign.bck2brwsr.core.ExtraJavaScript;
    1.18 +import org.apidesign.vm4brwsr.ByteCodeParser.AnnotationParser;
    1.19  import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
    1.20  import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
    1.21  import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
    1.22 @@ -163,12 +167,14 @@
    1.23  /*                
    1.24              case MEDIUM:
    1.25                  return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
    1.26 -                                          new MediumObfuscationDelegate(),
    1.27 +                                          new MediumObfuscationDelegate(
    1.28 +                                                  resources),
    1.29                                            resources, arr);
    1.30  */
    1.31              case FULL:
    1.32                  return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
    1.33 -                                          new FullObfuscationDelegate(),
    1.34 +                                          new FullObfuscationDelegate(
    1.35 +                                                  resources),
    1.36                                            resources, arr);
    1.37              default:
    1.38                  throw new IllegalArgumentException(
    1.39 @@ -264,10 +270,16 @@
    1.40              "clone__Ljava_lang_Object_2"
    1.41          };
    1.42  
    1.43 +        private final Bck2Brwsr.Resources resources;
    1.44 +
    1.45          private final Collection<String> externs;
    1.46 +        private final Map<Object, Boolean> isMarkedAsExportedCache;
    1.47  
    1.48 -        protected AdvancedObfuscationDelegate() {
    1.49 +        protected AdvancedObfuscationDelegate(Bck2Brwsr.Resources resources) {
    1.50 +            this.resources = resources;
    1.51 +
    1.52              externs = new ArrayList<String>(Arrays.asList(INITIAL_EXTERNS));
    1.53 +            isMarkedAsExportedCache = new HashMap<Object, Boolean>();
    1.54          }
    1.55  
    1.56          @Override
    1.57 @@ -275,7 +287,9 @@
    1.58                                  String destObject,
    1.59                                  String mangledName,
    1.60                                  ClassData classData) throws IOException {
    1.61 -            exportJSProperty(out, destObject, mangledName);
    1.62 +            if (isExportedClass(classData)) {
    1.63 +                exportJSProperty(out, destObject, mangledName);
    1.64 +            }
    1.65          }
    1.66  
    1.67          @Override
    1.68 @@ -283,7 +297,9 @@
    1.69                                   String destObject,
    1.70                                   String mangledName,
    1.71                                   MethodData methodData) throws IOException {
    1.72 -            if ((methodData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
    1.73 +            if (isAccessible(methodData.access)
    1.74 +                        && isExportedClass(methodData.cls)
    1.75 +                    || isMarkedAsExported(methodData)) {
    1.76                  exportJSProperty(out, destObject, mangledName);
    1.77              }
    1.78          }
    1.79 @@ -293,7 +309,9 @@
    1.80                                  String destObject,
    1.81                                  String mangledName,
    1.82                                  FieldData fieldData) throws IOException {
    1.83 -            if ((fieldData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
    1.84 +            if (isAccessible(fieldData.access)
    1.85 +                        && isExportedClass(fieldData.cls)
    1.86 +                    || isMarkedAsExported(fieldData)) {
    1.87                  exportJSProperty(out, destObject, mangledName);
    1.88              }
    1.89          }
    1.90 @@ -306,10 +324,110 @@
    1.91          protected void addExtern(String extern) {
    1.92              externs.add(extern);
    1.93          }
    1.94 +
    1.95 +        private boolean isExportedClass(ClassData classData)
    1.96 +                throws IOException {
    1.97 +            return classData.isPublic() && isMarkedAsExportedPackage(
    1.98 +                                               classData.getPkgName())
    1.99 +                       || isMarkedAsExported(classData);
   1.100 +        }
   1.101 +
   1.102 +        private boolean isMarkedAsExportedPackage(String pkgName) {
   1.103 +            if (pkgName == null) {
   1.104 +                return false;
   1.105 +            }
   1.106 +
   1.107 +            final Boolean cachedValue = isMarkedAsExportedCache.get(pkgName);
   1.108 +            if (cachedValue != null) {
   1.109 +                return cachedValue;
   1.110 +            }
   1.111 +
   1.112 +            final boolean newValue = resolveIsMarkedAsExportedPackage(pkgName);
   1.113 +            isMarkedAsExportedCache.put(pkgName, newValue);
   1.114 +
   1.115 +            return newValue;
   1.116 +        }
   1.117 +
   1.118 +        private boolean isMarkedAsExported(ClassData classData)
   1.119 +                throws IOException {
   1.120 +            final Boolean cachedValue = isMarkedAsExportedCache.get(classData);
   1.121 +            if (cachedValue != null) {
   1.122 +                return cachedValue;
   1.123 +            }
   1.124 +
   1.125 +            final boolean newValue =
   1.126 +                    isMarkedAsExported(classData.findAnnotationData(true),
   1.127 +                                       classData);
   1.128 +            isMarkedAsExportedCache.put(classData, newValue);
   1.129 +
   1.130 +            return newValue;
   1.131 +        }
   1.132 +
   1.133 +        private boolean isMarkedAsExported(MethodData methodData)
   1.134 +                throws IOException {
   1.135 +            return isMarkedAsExported(methodData.findAnnotationData(true),
   1.136 +                                      methodData.cls);
   1.137 +        }
   1.138 +
   1.139 +        private boolean isMarkedAsExported(FieldData fieldData)
   1.140 +                throws IOException {
   1.141 +            return isMarkedAsExported(fieldData.findAnnotationData(true),
   1.142 +                                      fieldData.cls);
   1.143 +        }
   1.144 +
   1.145 +        private boolean resolveIsMarkedAsExportedPackage(String pkgName) {
   1.146 +            try {
   1.147 +                final InputStream is =
   1.148 +                        resources.get(pkgName + "/package-info.class");
   1.149 +
   1.150 +                try {
   1.151 +                    final ClassData pkgInfoClass = new ClassData(is);
   1.152 +                    return isMarkedAsExported(
   1.153 +                                   pkgInfoClass.findAnnotationData(true),
   1.154 +                                   pkgInfoClass);
   1.155 +                } finally {
   1.156 +                    is.close();
   1.157 +                }
   1.158 +            } catch (final IOException e) {
   1.159 +                return false;
   1.160 +            }
   1.161 +        }
   1.162 +
   1.163 +        private boolean isMarkedAsExported(byte[] arrData, ClassData cd)
   1.164 +                throws IOException {
   1.165 +            if (arrData == null) {
   1.166 +                return false;
   1.167 +            }
   1.168 +
   1.169 +            final boolean[] found = { false };
   1.170 +            final AnnotationParser annotationParser =
   1.171 +                    new AnnotationParser(false, false) {
   1.172 +                        @Override
   1.173 +                        protected void visitAnnotationStart(
   1.174 +                                String type,
   1.175 +                                boolean top) {
   1.176 +                            if (top && type.equals("Lorg/apidesign/bck2brwsr"
   1.177 +                                                       + "/core/Exported;")) {
   1.178 +                                found[0] = true;
   1.179 +                            }
   1.180 +                        }
   1.181 +                    };
   1.182 +            annotationParser.parse(arrData, cd);
   1.183 +            return found[0];
   1.184 +        }
   1.185 +
   1.186 +        private static boolean isAccessible(int access) {
   1.187 +            return (access & (ByteCodeParser.ACC_PUBLIC
   1.188 +                                  | ByteCodeParser.ACC_PROTECTED)) != 0;
   1.189 +        }
   1.190      }
   1.191  
   1.192      private static final class MediumObfuscationDelegate
   1.193              extends AdvancedObfuscationDelegate {
   1.194 +        public MediumObfuscationDelegate(Bck2Brwsr.Resources resources) {
   1.195 +            super(resources);
   1.196 +        }
   1.197 +
   1.198          @Override
   1.199          public void exportJSProperty(Appendable out,
   1.200                                       String destObject,
   1.201 @@ -320,6 +438,10 @@
   1.202  
   1.203      private static final class FullObfuscationDelegate
   1.204              extends AdvancedObfuscationDelegate {
   1.205 +        public FullObfuscationDelegate(Bck2Brwsr.Resources resources) {
   1.206 +            super(resources);
   1.207 +        }
   1.208 +
   1.209          @Override
   1.210          public void exportJSProperty(Appendable out,
   1.211                                       String destObject,