1.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Wed Mar 13 16:17:47 2013 +0100
1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Thu Mar 21 18:48:46 2013 +0100
1.3 @@ -22,27 +22,40 @@
1.4 import java.io.IOException;
1.5 import java.io.OutputStream;
1.6 import java.io.PrintStream;
1.7 +import java.util.ArrayList;
1.8 +import java.util.Arrays;
1.9 +import java.util.Collection;
1.10 import java.util.Collections;
1.11 import java.util.List;
1.12 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
1.13 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
1.14 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
1.15 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
1.16
1.17 /**
1.18 *
1.19 * @author Jaroslav Tulach <jtulach@netbeans.org>
1.20 */
1.21 @ExtraJavaScript(processByteCode = false, resource="")
1.22 -final class ClosureWrapper extends CommandLineRunner implements SourceFile.Generator {
1.23 - private static final String[] ARGS = { "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--js", "bck2brwsr-raw.js" };
1.24 +final class ClosureWrapper extends CommandLineRunner {
1.25 + private static final String[] ARGS = { "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--js", "bck2brwsr-raw.js" /*, "--debug", "--formatting", "PRETTY_PRINT" */ };
1.26
1.27 - private String code;
1.28 + private final ClosuresObfuscationDelegate obfuscationDelegate;
1.29 private final Bck2Brwsr.Resources res;
1.30 private final StringArray classes;
1.31 - private ClosureWrapper(Appendable out, ObfuscationLevel obfuscationLevel,
1.32 +
1.33 + private String compiledCode;
1.34 + private String externsCode;
1.35 +
1.36 + private ClosureWrapper(Appendable out,
1.37 + String compilationLevel,
1.38 + ClosuresObfuscationDelegate obfuscationDelegate,
1.39 Bck2Brwsr.Resources res, StringArray classes) {
1.40 super(
1.41 - generateArguments(obfuscationLevel),
1.42 + generateArguments(compilationLevel),
1.43 new PrintStream(new APS(out)), System.err
1.44 );
1.45 + this.obfuscationDelegate = obfuscationDelegate;
1.46 this.res = res;
1.47 this.classes = classes;
1.48 }
1.49 @@ -52,21 +65,62 @@
1.50 if (files.size() != 1 || !"bck2brwsr-raw.js".equals(files.get(0))) {
1.51 throw new IOException("Unexpected files: " + files);
1.52 }
1.53 - return Collections.nCopies(1, SourceFile.fromGenerator("bck2brwsr-raw.js", this));
1.54 + return Collections.nCopies(
1.55 + 1,
1.56 + SourceFile.fromGenerator(
1.57 + "bck2brwsr-raw.js",
1.58 + new SourceFile.Generator() {
1.59 + @Override
1.60 + public String getCode() {
1.61 + return getCompiledCode();
1.62 + }
1.63 + }));
1.64 }
1.65
1.66 +
1.67 @Override
1.68 - public String getCode() {
1.69 - if (code == null) {
1.70 + protected List<SourceFile> createExterns()
1.71 + throws FlagUsageException, IOException {
1.72 + final List<SourceFile> externsFiles =
1.73 + new ArrayList<SourceFile>(super.createExterns());
1.74 +
1.75 + externsFiles.add(
1.76 + SourceFile.fromGenerator(
1.77 + "bck2brwsr_externs.js",
1.78 + new SourceFile.Generator() {
1.79 + @Override
1.80 + public String getCode() {
1.81 + return getExternsCode();
1.82 + }
1.83 + }));
1.84 + return externsFiles;
1.85 + }
1.86 +
1.87 + private String getCompiledCode() {
1.88 + if (compiledCode == null) {
1.89 StringBuilder sb = new StringBuilder();
1.90 try {
1.91 - VM.compile(res, sb, classes);
1.92 + VM.compile(res, sb, classes, obfuscationDelegate);
1.93 + compiledCode = sb.toString();
1.94 } catch (IOException ex) {
1.95 - code = ex.getMessage();
1.96 + compiledCode = ex.getMessage();
1.97 }
1.98 - code = sb.toString();
1.99 }
1.100 - return code;
1.101 + return compiledCode;
1.102 + }
1.103 +
1.104 + private String getExternsCode() {
1.105 + if (externsCode == null) {
1.106 + // need compiled code at this point
1.107 + getCompiledCode();
1.108 +
1.109 + final StringBuilder sb = new StringBuilder("function RAW() {};\n");
1.110 + for (final String extern: obfuscationDelegate.getExterns()) {
1.111 + sb.append("RAW.prototype.").append(extern).append(";\n");
1.112 + }
1.113 + externsCode = sb.toString();
1.114 + }
1.115 + return externsCode;
1.116 }
1.117
1.118 private static final class APS extends OutputStream {
1.119 @@ -81,21 +135,198 @@
1.120 }
1.121 }
1.122
1.123 - private static String[] generateArguments(
1.124 - ObfuscationLevel obfuscationLevel) {
1.125 + private static String[] generateArguments(String compilationLevel) {
1.126 String[] finalArgs = ARGS.clone();
1.127 - finalArgs[1] = obfuscationLevel.toString();
1.128 + finalArgs[1] = compilationLevel;
1.129
1.130 return finalArgs;
1.131 }
1.132
1.133 static int produceTo(Appendable w, ObfuscationLevel obfuscationLevel, Bck2Brwsr.Resources resources, StringArray arr) throws IOException {
1.134 - ClosureWrapper cw = new ClosureWrapper(w, obfuscationLevel, resources,
1.135 - arr);
1.136 + ClosureWrapper cw = create(w, obfuscationLevel, resources, arr);
1.137 try {
1.138 return cw.doRun();
1.139 } catch (FlagUsageException ex) {
1.140 throw new IOException(ex);
1.141 }
1.142 }
1.143 +
1.144 + private static ClosureWrapper create(Appendable w,
1.145 + ObfuscationLevel obfuscationLevel,
1.146 + Bck2Brwsr.Resources resources,
1.147 + StringArray arr) {
1.148 + switch (obfuscationLevel) {
1.149 + case MINIMAL:
1.150 + return new ClosureWrapper(w, "SIMPLE_OPTIMIZATIONS",
1.151 + new SimpleObfuscationDelegate(),
1.152 + resources, arr);
1.153 + case MEDIUM:
1.154 + return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
1.155 + new MediumObfuscationDelegate(),
1.156 + resources, arr);
1.157 + case FULL:
1.158 + return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
1.159 + new FullObfuscationDelegate(),
1.160 + resources, arr);
1.161 + default:
1.162 + throw new IllegalArgumentException(
1.163 + "Unsupported level: " + obfuscationLevel);
1.164 + }
1.165 + }
1.166 +
1.167 + private static abstract class ClosuresObfuscationDelegate
1.168 + extends ObfuscationDelegate {
1.169 + public abstract Collection<String> getExterns();
1.170 + }
1.171 +
1.172 + private static final class SimpleObfuscationDelegate
1.173 + extends ClosuresObfuscationDelegate {
1.174 + @Override
1.175 + public void exportJSProperty(Appendable out,
1.176 + String destObject,
1.177 + String propertyName) throws IOException {
1.178 + }
1.179 +
1.180 + @Override
1.181 + public void exportClass(Appendable out,
1.182 + String destObject,
1.183 + String mangledName,
1.184 + ClassData classData) throws IOException {
1.185 + }
1.186 +
1.187 + @Override
1.188 + public void exportMethod(Appendable out,
1.189 + String destObject,
1.190 + String mangledName,
1.191 + MethodData methodData) throws IOException {
1.192 + }
1.193 +
1.194 + @Override
1.195 + public void exportField(Appendable out,
1.196 + String destObject,
1.197 + String mangledName,
1.198 + FieldData fieldData) throws IOException {
1.199 + }
1.200 +
1.201 + @Override
1.202 + public Collection<String> getExterns() {
1.203 + return Collections.EMPTY_LIST;
1.204 + }
1.205 + }
1.206 +
1.207 + private static abstract class AdvancedObfuscationDelegate
1.208 + extends ClosuresObfuscationDelegate {
1.209 + private static final String[] INITIAL_EXTERNS = {
1.210 + "bck2brwsr",
1.211 + "$class",
1.212 + "anno",
1.213 + "array",
1.214 + "access",
1.215 + "cls",
1.216 + "vm",
1.217 + "loadClass",
1.218 + "loadBytes",
1.219 + "jvmName",
1.220 + "primitive",
1.221 + "superclass",
1.222 + "cnstr",
1.223 + "add32",
1.224 + "sub32",
1.225 + "mul32",
1.226 + "neg32",
1.227 + "toInt8",
1.228 + "toInt16",
1.229 + "next32",
1.230 + "high32",
1.231 + "toInt32",
1.232 + "toFP",
1.233 + "toLong",
1.234 + "toExactString",
1.235 + "add64",
1.236 + "sub64",
1.237 + "mul64",
1.238 + "and64",
1.239 + "or64",
1.240 + "xor64",
1.241 + "shl64",
1.242 + "shr64",
1.243 + "ushr64",
1.244 + "compare64",
1.245 + "neg64",
1.246 + "div32",
1.247 + "mod32",
1.248 + "div64",
1.249 + "mod64",
1.250 + "at",
1.251 + "getClass__Ljava_lang_Class_2",
1.252 + "clone__Ljava_lang_Object_2"
1.253 + };
1.254 +
1.255 + private final Collection<String> externs;
1.256 +
1.257 + protected AdvancedObfuscationDelegate() {
1.258 + externs = new ArrayList<String>(Arrays.asList(INITIAL_EXTERNS));
1.259 + }
1.260 +
1.261 + @Override
1.262 + public void exportClass(Appendable out,
1.263 + String destObject,
1.264 + String mangledName,
1.265 + ClassData classData) throws IOException {
1.266 + exportJSProperty(out, destObject, mangledName);
1.267 + }
1.268 +
1.269 + @Override
1.270 + public void exportMethod(Appendable out,
1.271 + String destObject,
1.272 + String mangledName,
1.273 + MethodData methodData) throws IOException {
1.274 + if ((methodData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
1.275 + exportJSProperty(out, destObject, mangledName);
1.276 + }
1.277 + }
1.278 +
1.279 + @Override
1.280 + public void exportField(Appendable out,
1.281 + String destObject,
1.282 + String mangledName,
1.283 + FieldData fieldData) throws IOException {
1.284 + if ((fieldData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
1.285 + exportJSProperty(out, destObject, mangledName);
1.286 + }
1.287 + }
1.288 +
1.289 + @Override
1.290 + public Collection<String> getExterns() {
1.291 + return externs;
1.292 + }
1.293 +
1.294 + protected void addExtern(String extern) {
1.295 + externs.add(extern);
1.296 + }
1.297 + }
1.298 +
1.299 + private static final class MediumObfuscationDelegate
1.300 + extends AdvancedObfuscationDelegate {
1.301 + @Override
1.302 + public void exportJSProperty(Appendable out,
1.303 + String destObject,
1.304 + String propertyName) {
1.305 + addExtern(propertyName);
1.306 + }
1.307 + }
1.308 +
1.309 + private static final class FullObfuscationDelegate
1.310 + extends AdvancedObfuscationDelegate {
1.311 + @Override
1.312 + public void exportJSProperty(Appendable out,
1.313 + String destObject,
1.314 + String propertyName) throws IOException {
1.315 + out.append("\n").append(destObject).append("['")
1.316 + .append(propertyName)
1.317 + .append("'] = ")
1.318 + .append(destObject).append(".").append(propertyName)
1.319 + .append(";\n");
1.320 + }
1.321 + }
1.322 }