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,