1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/core/src/main/java/org/apidesign/bck2brwsr/core/Exported.java Fri Apr 12 18:48:48 2013 +0200
1.3 @@ -0,0 +1,38 @@
1.4 +/**
1.5 + * Back 2 Browser Bytecode Translator
1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, version 2 of the License.
1.11 + *
1.12 + * This program is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.15 + * GNU General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU General Public License
1.18 + * along with this program. Look for COPYING file in the top folder.
1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
1.20 + */
1.21 +package org.apidesign.bck2brwsr.core;
1.22 +
1.23 +import java.lang.annotation.ElementType;
1.24 +import java.lang.annotation.Retention;
1.25 +import java.lang.annotation.RetentionPolicy;
1.26 +import java.lang.annotation.Target;
1.27 +
1.28 +/**
1.29 + * Marks the corresponding program element as exported. Exported elements are
1.30 + * visible from other modules. Can be used on packages, classes, methods,
1.31 + * constructors and fields.
1.32 + *
1.33 + * @since 0.6
1.34 + */
1.35 +@Retention(RetentionPolicy.CLASS)
1.36 +@Target({ ElementType.PACKAGE, ElementType.TYPE,
1.37 + ElementType.METHOD, ElementType.CONSTRUCTOR,
1.38 + ElementType.FIELD })
1.39 +public @interface Exported {
1.40 +
1.41 +}
2.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Thu Apr 11 16:59:42 2013 +0200
2.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Fri Apr 12 18:48:48 2013 +0200
2.3 @@ -25,6 +25,7 @@
2.4
2.5 package java.lang.reflect;
2.6
2.7 +import org.apidesign.bck2brwsr.core.Exported;
2.8 import org.apidesign.bck2brwsr.core.JavaScriptBody;
2.9 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
2.10
2.11 @@ -636,9 +637,12 @@
2.12 + "arr.jvmName = sig;\n"
2.13 + "return arr;"
2.14 )
2.15 - static native Object newArray(boolean primitive, String sig, int length);
2.16 + @Exported
2.17 + private static native Object newArray(boolean primitive, String sig, int length);
2.18
2.19 - static Object multiNewArray(String sig, int[] dims, int index)
2.20 +
2.21 + @Exported
2.22 + private static Object multiNewArray(String sig, int[] dims, int index)
2.23 throws IllegalArgumentException, NegativeArraySizeException {
2.24 if (dims.length == index + 1) {
2.25 return newArray(sig.length() == 2, sig, dims[index]);
3.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Thu Apr 11 16:59:42 2013 +0200
3.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Fri Apr 12 18:48:48 2013 +0200
3.3 @@ -1981,7 +1981,7 @@
3.4 pkgPrefixLen = classname.lastIndexOf("/") + 1;
3.5 if (pkgPrefixLen != 0) {
3.6 pkgPrefix = classname.substring(0, pkgPrefixLen);
3.7 - return ("package " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n");
3.8 + return /* ("package " + */ pkgPrefix.substring(0, pkgPrefixLen - 1) /* + ";\n") */;
3.9 } else {
3.10 return null;
3.11 }
4.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Thu Apr 11 16:59:42 2013 +0200
4.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Fri Apr 12 18:48:48 2013 +0200
4.3 @@ -20,14 +20,18 @@
4.4 import com.google.javascript.jscomp.CommandLineRunner;
4.5 import com.google.javascript.jscomp.SourceFile;
4.6 import java.io.IOException;
4.7 +import java.io.InputStream;
4.8 import java.io.OutputStream;
4.9 import java.io.PrintStream;
4.10 import java.util.ArrayList;
4.11 import java.util.Arrays;
4.12 import java.util.Collection;
4.13 import java.util.Collections;
4.14 +import java.util.HashMap;
4.15 import java.util.List;
4.16 +import java.util.Map;
4.17 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
4.18 +import org.apidesign.vm4brwsr.ByteCodeParser.AnnotationParser;
4.19 import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
4.20 import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
4.21 import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
4.22 @@ -163,12 +167,14 @@
4.23 /*
4.24 case MEDIUM:
4.25 return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
4.26 - new MediumObfuscationDelegate(),
4.27 + new MediumObfuscationDelegate(
4.28 + resources),
4.29 resources, arr);
4.30 */
4.31 case FULL:
4.32 return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
4.33 - new FullObfuscationDelegate(),
4.34 + new FullObfuscationDelegate(
4.35 + resources),
4.36 resources, arr);
4.37 default:
4.38 throw new IllegalArgumentException(
4.39 @@ -264,10 +270,16 @@
4.40 "clone__Ljava_lang_Object_2"
4.41 };
4.42
4.43 + private final Bck2Brwsr.Resources resources;
4.44 +
4.45 private final Collection<String> externs;
4.46 + private final Map<Object, Boolean> isMarkedAsExportedCache;
4.47
4.48 - protected AdvancedObfuscationDelegate() {
4.49 + protected AdvancedObfuscationDelegate(Bck2Brwsr.Resources resources) {
4.50 + this.resources = resources;
4.51 +
4.52 externs = new ArrayList<String>(Arrays.asList(INITIAL_EXTERNS));
4.53 + isMarkedAsExportedCache = new HashMap<Object, Boolean>();
4.54 }
4.55
4.56 @Override
4.57 @@ -275,7 +287,9 @@
4.58 String destObject,
4.59 String mangledName,
4.60 ClassData classData) throws IOException {
4.61 - exportJSProperty(out, destObject, mangledName);
4.62 + if (isExportedClass(classData)) {
4.63 + exportJSProperty(out, destObject, mangledName);
4.64 + }
4.65 }
4.66
4.67 @Override
4.68 @@ -283,7 +297,9 @@
4.69 String destObject,
4.70 String mangledName,
4.71 MethodData methodData) throws IOException {
4.72 - if ((methodData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
4.73 + if (isAccessible(methodData.access)
4.74 + && isExportedClass(methodData.cls)
4.75 + || isMarkedAsExported(methodData)) {
4.76 exportJSProperty(out, destObject, mangledName);
4.77 }
4.78 }
4.79 @@ -293,7 +309,9 @@
4.80 String destObject,
4.81 String mangledName,
4.82 FieldData fieldData) throws IOException {
4.83 - if ((fieldData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
4.84 + if (isAccessible(fieldData.access)
4.85 + && isExportedClass(fieldData.cls)
4.86 + || isMarkedAsExported(fieldData)) {
4.87 exportJSProperty(out, destObject, mangledName);
4.88 }
4.89 }
4.90 @@ -306,10 +324,110 @@
4.91 protected void addExtern(String extern) {
4.92 externs.add(extern);
4.93 }
4.94 +
4.95 + private boolean isExportedClass(ClassData classData)
4.96 + throws IOException {
4.97 + return classData.isPublic() && isMarkedAsExportedPackage(
4.98 + classData.getPkgName())
4.99 + || isMarkedAsExported(classData);
4.100 + }
4.101 +
4.102 + private boolean isMarkedAsExportedPackage(String pkgName) {
4.103 + if (pkgName == null) {
4.104 + return false;
4.105 + }
4.106 +
4.107 + final Boolean cachedValue = isMarkedAsExportedCache.get(pkgName);
4.108 + if (cachedValue != null) {
4.109 + return cachedValue;
4.110 + }
4.111 +
4.112 + final boolean newValue = resolveIsMarkedAsExportedPackage(pkgName);
4.113 + isMarkedAsExportedCache.put(pkgName, newValue);
4.114 +
4.115 + return newValue;
4.116 + }
4.117 +
4.118 + private boolean isMarkedAsExported(ClassData classData)
4.119 + throws IOException {
4.120 + final Boolean cachedValue = isMarkedAsExportedCache.get(classData);
4.121 + if (cachedValue != null) {
4.122 + return cachedValue;
4.123 + }
4.124 +
4.125 + final boolean newValue =
4.126 + isMarkedAsExported(classData.findAnnotationData(true),
4.127 + classData);
4.128 + isMarkedAsExportedCache.put(classData, newValue);
4.129 +
4.130 + return newValue;
4.131 + }
4.132 +
4.133 + private boolean isMarkedAsExported(MethodData methodData)
4.134 + throws IOException {
4.135 + return isMarkedAsExported(methodData.findAnnotationData(true),
4.136 + methodData.cls);
4.137 + }
4.138 +
4.139 + private boolean isMarkedAsExported(FieldData fieldData)
4.140 + throws IOException {
4.141 + return isMarkedAsExported(fieldData.findAnnotationData(true),
4.142 + fieldData.cls);
4.143 + }
4.144 +
4.145 + private boolean resolveIsMarkedAsExportedPackage(String pkgName) {
4.146 + try {
4.147 + final InputStream is =
4.148 + resources.get(pkgName + "/package-info.class");
4.149 +
4.150 + try {
4.151 + final ClassData pkgInfoClass = new ClassData(is);
4.152 + return isMarkedAsExported(
4.153 + pkgInfoClass.findAnnotationData(true),
4.154 + pkgInfoClass);
4.155 + } finally {
4.156 + is.close();
4.157 + }
4.158 + } catch (final IOException e) {
4.159 + return false;
4.160 + }
4.161 + }
4.162 +
4.163 + private boolean isMarkedAsExported(byte[] arrData, ClassData cd)
4.164 + throws IOException {
4.165 + if (arrData == null) {
4.166 + return false;
4.167 + }
4.168 +
4.169 + final boolean[] found = { false };
4.170 + final AnnotationParser annotationParser =
4.171 + new AnnotationParser(false, false) {
4.172 + @Override
4.173 + protected void visitAnnotationStart(
4.174 + String type,
4.175 + boolean top) {
4.176 + if (top && type.equals("Lorg/apidesign/bck2brwsr"
4.177 + + "/core/Exported;")) {
4.178 + found[0] = true;
4.179 + }
4.180 + }
4.181 + };
4.182 + annotationParser.parse(arrData, cd);
4.183 + return found[0];
4.184 + }
4.185 +
4.186 + private static boolean isAccessible(int access) {
4.187 + return (access & (ByteCodeParser.ACC_PUBLIC
4.188 + | ByteCodeParser.ACC_PROTECTED)) != 0;
4.189 + }
4.190 }
4.191
4.192 private static final class MediumObfuscationDelegate
4.193 extends AdvancedObfuscationDelegate {
4.194 + public MediumObfuscationDelegate(Bck2Brwsr.Resources resources) {
4.195 + super(resources);
4.196 + }
4.197 +
4.198 @Override
4.199 public void exportJSProperty(Appendable out,
4.200 String destObject,
4.201 @@ -320,6 +438,10 @@
4.202
4.203 private static final class FullObfuscationDelegate
4.204 extends AdvancedObfuscationDelegate {
4.205 + public FullObfuscationDelegate(Bck2Brwsr.Resources resources) {
4.206 + super(resources);
4.207 + }
4.208 +
4.209 @Override
4.210 public void exportJSProperty(Appendable out,
4.211 String destObject,