Merge: changes/scottb/jso -r1776:1933 Into: trunk@1933 Review by: spoon git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1934 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/build.xml b/dev/core/build.xml index ae6e997..d95c206 100755 --- a/dev/core/build.xml +++ b/dev/core/build.xml
@@ -26,6 +26,8 @@ <zipfileset src="${gwt.tools.lib}/apache/tapestry-util-text-4.0.2.jar" /> <zipfileset src="${gwt.tools.lib}/apache/ant-1.6.5.jar" /> <zipfileset src="${gwt.tools.lib}/eclipse/jdt-3.3.1.jar" /> + <zipfileset src="${gwt.tools.lib}/objectweb/asm-3.1.jar" /> + <zipfileset src="${gwt.tools.lib}/objectweb/asm-commons-3.1.jar" /> <zipfileset src="${gwt.tools.lib}/tomcat/ant-launcher-1.6.5.jar" /> <zipfileset src="${gwt.tools.lib}/tomcat/catalina-1.0.jar" /> <zipfileset src="${gwt.tools.lib}/tomcat/catalina-optional-1.0.jar" />
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java index ea8406e..ea85b1e 100644 --- a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java +++ b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
@@ -177,6 +177,8 @@ resolvePossiblyNestedType(typeName); } + JSORestrictionsChecker.check(cud); + // Optionally remember this cud. // if (cuds != null) {
diff --git a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java b/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java index 5c1fe57..03be599 100644 --- a/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java +++ b/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
@@ -68,7 +68,7 @@ messageSend.sourceStart()); DefaultProblem problem = new DefaultProblem(compResult.fileName, message, IProblem.ExternalProblemNotFixable, null, ProblemSeverities.Error, - messageSend.sourceStart, messageSend.sourceEnd, startLine, startColumn); + messageSend.sourceStart(), messageSend.sourceEnd(), startLine, startColumn); compResult.record(problem, scope.referenceContext()); }
diff --git a/dev/core/src/com/google/gwt/dev/jdt/JSORestrictionsChecker.java b/dev/core/src/com/google/gwt/dev/jdt/JSORestrictionsChecker.java new file mode 100644 index 0000000..c560db8 --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/jdt/JSORestrictionsChecker.java
@@ -0,0 +1,226 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.jdt; + +import com.google.gwt.dev.shell.JsValueGlue; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; +import org.eclipse.jdt.internal.compiler.util.Util; + +/** + * Check a compilation unit for violations of + * {@link com.google.gwt.core.client.JavaScriptObject JavaScriptObject} (JSO) + * restrictions. The restrictions are: + * + * <ul> + * <li> All instance methods on JSO classes must be explicitly marked final. + * <li> JSO classes cannot implement interfaces that define methods. + * <li> No instance methods on JSO classes may override another method. (This + * catches accidents where JSO itself did not finalize some method from its + * superclass.) + * <li> JSO classes cannot have instance fields. + * <li> "new" operations cannot be used with JSO classes. + * <li> Every JSO class must have precisely one constructor, and it must be + * protected, empty, and no-argument. + * <li> Nested JSO classes must be static. + * </ul> + * + * Any violations found are attached as errors on the + * CompilationUnitDeclaration. + */ +class JSORestrictionsChecker { + + private class JSORestrictionsVisitor extends ASTVisitor implements + ClassFileConstants { + + @Override + public void endVisit(AllocationExpression exp, BlockScope scope) { + if (exp.type != null && isJSOSubclass(exp.type.resolveType(scope))) { + errorOn(exp, ERR_NEW_JSO); + } + } + + @Override + public void endVisit(ConstructorDeclaration meth, ClassScope scope) { + if (isForJSOSubclass(scope)) { + if ((meth.arguments != null) && (meth.arguments.length > 0)) { + errorOn(meth, ERR_CONSTRUCTOR_WITH_PARAMETERS); + } + if ((meth.modifiers & AccProtected) == 0) { + errorOn(meth, ERR_NONPROTECTED_CONSTRUCTOR); + } + if (meth.statements != null && meth.statements.length > 0) { + errorOn(meth, ERR_NONEMPTY_CONSTRUCTOR); + } + } + } + + @Override + public void endVisit(FieldDeclaration field, MethodScope scope) { + if (isForJSOSubclass(scope)) { + if (!field.isStatic()) { + errorOn(field, ERR_INSTANCE_FIELD); + } + } + } + + @Override + public void endVisit(MethodDeclaration meth, ClassScope scope) { + if (isForJSOSubclass(scope)) { + if (!meth.isStatic() && ((meth.modifiers & AccFinal) == 0)) { + errorOn(meth, ERR_INSTANCE_METHOD_NONFINAL); + } + + if (meth.binding != null && meth.binding.isOverriding()) { + errorOn(meth, ERR_OVERRIDDEN_METHOD); + } + } + } + + @Override + public void endVisit(TypeDeclaration type, BlockScope scope) { + checkType(type); + } + + @Override + public void endVisit(TypeDeclaration type, ClassScope scope) { + checkType(type); + } + + @Override + public void endVisit(TypeDeclaration type, CompilationUnitScope scope) { + checkType(type); + } + + private void checkType(TypeDeclaration type) { + if (isJSOSubclass(type)) { + if (type.enclosingType != null && !type.binding.isStatic()) { + errorOn(type, ERR_IS_NONSTATIC_NESTED); + } + + ReferenceBinding[] interfaces = type.binding.superInterfaces(); + if (interfaces != null) { + for (ReferenceBinding interf : interfaces) { + if (interf.methods() != null && interf.methods().length > 0) { + String intfName = String.copyValueOf(interf.shortReadableName()); + errorOn(type, errInterfaceWithMethods(intfName)); + } + } + } + } + } + } + + protected static final char[][] JSO_CLASS_CHARS = CharOperation.splitOn('.', + JsValueGlue.JSO_CLASS.toCharArray()); + static final String ERR_CONSTRUCTOR_WITH_PARAMETERS = "JavaScriptObject constructors should have no parameters"; + static final String ERR_INSTANCE_FIELD = "JavaScriptObject classes cannot have fields"; + static final String ERR_INSTANCE_METHOD_NONFINAL = "JavaScriptObject methods must be final"; + static final String ERR_IS_NONSTATIC_NESTED = "Nested JavaScriptObject classes must be static"; + static final String ERR_NEW_JSO = "JavaScriptObject classes cannot be instantiated with new"; + static final String ERR_NONEMPTY_CONSTRUCTOR = "JavaScriptObject constructors must be empty"; + static final String ERR_NONPROTECTED_CONSTRUCTOR = "JavaScriptObject constructors must be protected"; + + static final String ERR_OVERRIDDEN_METHOD = "JavaScriptObject classes cannot override methods"; + + /** + * Checks an entire + * {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration}. + * + */ + public static void check(CompilationUnitDeclaration cud) { + TypeBinding jsoType = cud.scope.environment().getType(JSO_CLASS_CHARS); + if (jsoType == null) { + // JavaScriptObject not available; do nothing + return; + } + + JSORestrictionsChecker checker = new JSORestrictionsChecker(cud, jsoType); + checker.check(); + } + + static String errInterfaceWithMethods(String intfName) { + return "JavaScriptObject classes cannot implement interfaces with methods (" + + intfName + ")"; + } + + private final CompilationUnitDeclaration cud; + + /** + * The type of the GWT JavaScriptObject class. Cannot be null. + */ + private final TypeBinding jsoType; + + private JSORestrictionsChecker(CompilationUnitDeclaration cud, + TypeBinding jsoType) { + assert jsoType != null; + this.cud = cud; + this.jsoType = jsoType; + } + + private void check() { + cud.traverse(new JSORestrictionsVisitor(), cud.scope); + } + + private TypeBinding classType(Scope scope) { + return scope.classScope().referenceType().binding; + } + + private void errorOn(ASTNode node, String error) { + CompilationResult compResult = cud.compilationResult(); + int[] lineEnds = compResult.getLineSeparatorPositions(); + int startLine = Util.getLineNumber(node.sourceStart(), lineEnds, 0, + lineEnds.length - 1); + int startColumn = Util.searchColumnNumber(lineEnds, startLine, + node.sourceStart()); + DefaultProblem problem = new DefaultProblem(compResult.fileName, error, + IProblem.ExternalProblemNotFixable, null, ProblemSeverities.Error, + node.sourceStart(), node.sourceEnd(), startLine, startColumn); + compResult.record(problem, cud); + } + + private boolean isForJSOSubclass(Scope scope) { + return isJSOSubclass(classType(scope)); + } + + private boolean isJSOSubclass(TypeBinding typeBinding) { + return typeBinding.isCompatibleWith(jsoType) && typeBinding != jsoType; + } + + private boolean isJSOSubclass(TypeDeclaration typeDecl) { + return isJSOSubclass(typeDecl.binding); + } +}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/StaticCompilationUnitProvider.java b/dev/core/src/com/google/gwt/dev/jdt/StaticCompilationUnitProvider.java index 75e4ef3..1b314a8 100644 --- a/dev/core/src/com/google/gwt/dev/jdt/StaticCompilationUnitProvider.java +++ b/dev/core/src/com/google/gwt/dev/jdt/StaticCompilationUnitProvider.java
@@ -50,7 +50,8 @@ * Creates a stable name for this compilation unit. */ public final String getLocation() { - return "transient source for " + packageName + "." + simpleTypeName; + String prefix = (packageName.length() > 0) ? packageName + "." : ""; + return "transient source for " + prefix + simpleTypeName; } public String getMainTypeName() {
diff --git a/dev/core/src/com/google/gwt/dev/jdt/TypeRefVisitor.java b/dev/core/src/com/google/gwt/dev/jdt/TypeRefVisitor.java index afbc73e..6ae0829 100644 --- a/dev/core/src/com/google/gwt/dev/jdt/TypeRefVisitor.java +++ b/dev/core/src/com/google/gwt/dev/jdt/TypeRefVisitor.java
@@ -1,5 +1,5 @@ /* - * Copyright 2006 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -19,6 +19,7 @@ import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; @@ -37,58 +38,79 @@ */ public abstract class TypeRefVisitor extends ASTVisitor { + @Override public void endVisit(ArrayQualifiedTypeReference x, BlockScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(ArrayQualifiedTypeReference x, ClassScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(ArrayTypeReference x, BlockScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(ArrayTypeReference x, ClassScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override + public void endVisit(MessageSend messageSend, BlockScope scope) { + if (messageSend.binding.isStatic()) { + maybeDispatch(scope, messageSend.actualReceiverType); + } + } + + @Override public void endVisit(ParameterizedQualifiedTypeReference x, BlockScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(ParameterizedQualifiedTypeReference x, ClassScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(ParameterizedSingleTypeReference x, BlockScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(ParameterizedSingleTypeReference x, ClassScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(QualifiedTypeReference x, BlockScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(QualifiedTypeReference x, ClassScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(SingleTypeReference x, BlockScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(SingleTypeReference x, ClassScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(Wildcard x, BlockScope scope) { maybeDispatch(scope, x.resolvedType); } + @Override public void endVisit(Wildcard x, ClassScope scope) { maybeDispatch(scope, x.resolvedType); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java index 1def354..9008025 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java +++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -41,7 +41,8 @@ import com.google.gwt.dev.jjs.impl.DeadCodeElimination; import com.google.gwt.dev.jjs.impl.GenerateJavaAST; import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST; -import com.google.gwt.dev.jjs.impl.JavaScriptObjectCaster; +import com.google.gwt.dev.jjs.impl.JavaScriptObjectNormalizer; +import com.google.gwt.dev.jjs.impl.JsoDevirtualizer; import com.google.gwt.dev.jjs.impl.MakeCallsStatic; import com.google.gwt.dev.jjs.impl.MethodAndClassFinalizer; import com.google.gwt.dev.jjs.impl.MethodCallTightener; @@ -293,7 +294,6 @@ goldenCuds, jsProgram); // BuildTypeMap can uncover syntactic JSNI errors; report & abort - // checkForErrors(logger, true); // Compute all super type/sub type info @@ -307,11 +307,10 @@ options.isEnableAssertions()); // GenerateJavaAST can uncover semantic JSNI errors; report & abort - // checkForErrors(logger, true); /* - * TODO: if we defer this until later, we could maybe use the results of + * TODO: If we defer this until later, we could maybe use the results of * the assertions to enable more optimizations. */ if (options.isEnableAssertions()) { @@ -331,9 +330,11 @@ } // Rebind each entry point. - // findEntryPoints(logger, rebindOracle, declEntryPoints, jprogram); + // Replace references to JSO subtypes with JSO itself. + JavaScriptObjectNormalizer.exec(jprogram); + // (4) Optimize the normalized Java AST boolean didChange; do { @@ -373,9 +374,9 @@ // (5) "Normalize" the high-level Java tree into a lower-level tree more // suited for JavaScript code generation. Don't go reordering these // willy-nilly because there are some subtle interdependencies. + JsoDevirtualizer.exec(jprogram); CatchBlockNormalizer.exec(jprogram); CompoundAssignmentNormalizer.exec(jprogram); - JavaScriptObjectCaster.exec(jprogram); CastNormalizer.exec(jprogram); ArrayNormalizer.exec(jprogram);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java index 271ef66..133ace5 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
@@ -32,14 +32,21 @@ return fullName.substring(0, pos + 1); } - private static String getTypeName(JType type) { + private static String getTypeName(JProgram program, JType type) { String typeName; if (type instanceof JArrayType) { typeName = type.getJsniSignatureName().replace('/', '.'); + // Mangle the class name to match hosted mode. + if (program.isJavaScriptObject(((JArrayType) type).getLeafType())) { + typeName = typeName.replace(";", "$;"); + } } else { typeName = type.getName(); + // Mangle the class name to match hosted mode. + if (program.isJavaScriptObject(type)) { + typeName += '$'; + } } - return typeName; } @@ -53,7 +60,7 @@ super(program); refType = type; - String typeName = getTypeName(type); + String typeName = getTypeName(program, type); JMethod method = program.getIndexedMethod(type.getClassLiteralFactoryMethod()); assert method != null;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java index b8c9ba0..715014d 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -39,6 +39,10 @@ this.info = info; } + public JProgram getProgram() { + return program; + } + public SourceInfo getSourceInfo() { return info; }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java index 6719dcc..c98ffb4 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -434,15 +434,30 @@ } public JField getIndexedField(String string) { - return indexedFields.get(string); + JField field = indexedFields.get(string); + if (field == null) { + throw new InternalCompilerException("Unable to locate index field: " + + string); + } + return field; } public JMethod getIndexedMethod(String string) { - return indexedMethods.get(string); + JMethod method = indexedMethods.get(string); + if (method == null) { + throw new InternalCompilerException("Unable to locate index method: " + + string); + } + return method; } public JReferenceType getIndexedType(String string) { - return indexedTypes.get(string); + JReferenceType type = indexedTypes.get(string); + if (type == null) { + throw new InternalCompilerException("Unable to locate index type: " + + string); + } + return type; } public JClassType getJavaScriptObject() { @@ -667,7 +682,7 @@ } public boolean isJavaScriptObject(JType type) { - if (type instanceof JClassType) { + if (type instanceof JClassType && typeSpecialJavaScriptObject != null) { return typeOracle.canTriviallyCast((JClassType) type, typeSpecialJavaScriptObject); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java index e6ceb60..b42d688 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -147,7 +147,16 @@ JClassType cType = (JClassType) type; if (qType instanceof JClassType) { - return isSuperClass(cType, (JClassType) qType); + JClassType qcType = (JClassType) qType; + if (isSuperClass(cType, qcType)) { + return true; + } + // All JavaScriptObject types can be freely cast to each other. + JClassType jsoType = program.getJavaScriptObject(); + if (jsoType != null) { + return isSameOrSuper(cType, jsoType) + && isSameOrSuper(qcType, jsoType); + } } else if (qType instanceof JInterfaceType) { return implementsInterface(cType, (JInterfaceType) qType); } @@ -487,6 +496,10 @@ return map2; } + private boolean isSameOrSuper(JClassType type, JClassType qType) { + return (type == qType || isSuperClass(type, qType)); + } + /** * Record the all of my super classes (and myself as a subclass of them). */
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java index c781389..37d1be2 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -36,7 +36,6 @@ import com.google.gwt.dev.jjs.ast.JType; import com.google.gwt.dev.jjs.ast.JTypeOracle; import com.google.gwt.dev.jjs.ast.JVisitor; -import com.google.gwt.dev.jjs.ast.js.JClassSeed; import com.google.gwt.dev.jjs.ast.js.JsonObject; import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit; @@ -110,6 +109,12 @@ // pass our info to JProgram program.initTypeInfo(classes, jsonObjects); + + // JSO's maker queryId is -1 (used for array stores). + JClassType jsoType = program.getJavaScriptObject(); + if (jsoType != null) { + queryIds.put(jsoType, -1); + } program.recordQueryIds(queryIds); } @@ -194,7 +199,8 @@ */ computeSourceClass(type.extnds); - if (!program.typeOracle.isInstantiatedType(type)) { + if (!program.typeOracle.isInstantiatedType(type) + || program.isJavaScriptObject(type)) { return; } @@ -221,13 +227,8 @@ } } - /* - * Weird: JavaScriptObjects MUST have a typeId, the implementation of - * Cast.wrapJSO depends on it. Object must also have a typeId, to force - * String to have an id of 2. - */ - if (yesSet == null && !program.isJavaScriptObject(type) - && (type != program.getTypeJavaLangObject())) { + // Object a typeId, to force String to have an id of 2. + if (yesSet == null && type != program.getTypeJavaLangObject()) { return; // won't satisfy anything } @@ -235,8 +236,7 @@ JReferenceType[] yesArray = new JReferenceType[nextQueryId]; if (yesSet != null) { for (JReferenceType yesType : yesSet) { - Integer boxedInt = queryIds.get(yesType); - yesArray[boxedInt.intValue()] = yesType; + yesArray[queryIds.get(yesType)] = yesType; } } @@ -268,6 +268,11 @@ } } + // If the target type is a JavaScriptObject, don't record an id. + if (program.isJavaScriptObject(targetType)) { + return; + } + recordCastInternal((JReferenceType) targetType, rhsType); } } @@ -277,7 +282,7 @@ JReferenceType toType = targetType; Set<JReferenceType> querySet = queriedTypes.get(toType); if (querySet == null) { - queryIds.put(toType, new Integer(nextQueryId++)); + queryIds.put(toType, nextQueryId++); querySet = new HashSet<JReferenceType>(); queriedTypes.put(toType, querySet); } @@ -385,39 +390,22 @@ } else if (toType instanceof JReferenceType) { JExpression curExpr = x.getExpr(); JReferenceType refType = (JReferenceType) toType; - JType argType = x.getExpr().getType(); - if (program.isJavaScriptObject(argType)) { - /* - * A JSO-derived class that is about to be cast must be "wrapped" - * first. Since a JSO was never constructed, it may not have an - * accessible prototype. Instead we copy fields from the seed - * function's prototype directly onto the target object as expandos. - * See com.google.gwt.lang.Cast.wrapJSO(). - */ - JMethod wrap = program.getIndexedMethod("Cast.wrapJSO"); - // override the type of the called method with the JSO's type - JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, - wrap, argType); - JClassSeed seed = program.getLiteralClassSeed((JClassType) argType); - call.getArgs().add(curExpr); - call.getArgs().add(seed); - curExpr = call; - } - if (argType instanceof JClassType - && program.typeOracle.canTriviallyCast((JClassType) argType, - refType)) { - // TODO(???): why is this only for JClassType? + JReferenceType argType = (JReferenceType) x.getExpr().getType(); + if (program.typeOracle.canTriviallyCast(argType, refType)) { // just remove the cast replaceExpr = curExpr; } else { - JMethod method = program.getIndexedMethod("Cast.dynamicCast"); + boolean isJsoCast = program.isJavaScriptObject(toType); + JMethod method = program.getIndexedMethod(isJsoCast + ? "Cast.dynamicCastJso" : "Cast.dynamicCast"); // override the type of the called method with the target cast type JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, method, toType); - Integer boxedInt = queryIds.get(refType); - JIntLiteral qId = program.getLiteralInt(boxedInt.intValue()); call.getArgs().add(curExpr); - call.getArgs().add(qId); + if (!isJsoCast) { + JIntLiteral qId = program.getLiteralInt(queryIds.get(refType)); + call.getArgs().add(qId); + } replaceExpr = call; } } else { @@ -482,10 +470,9 @@ @Override public void endVisit(JInstanceOf x, Context ctx) { - JType argType = x.getExpr().getType(); - if (argType instanceof JClassType - && program.typeOracle.canTriviallyCast((JClassType) argType, - x.getTestType())) { + JReferenceType argType = (JReferenceType) x.getExpr().getType(); + JReferenceType toType = x.getTestType(); + if (program.typeOracle.canTriviallyCast(argType, toType)) { // trivially true if non-null; replace with a null test JNullLiteral nullLit = program.getLiteralNull(); JBinaryOperation eq = new JBinaryOperation(program, x.getSourceInfo(), @@ -493,13 +480,16 @@ x.getExpr(), nullLit); ctx.replaceMe(eq); } else { - JMethod method = program.getIndexedMethod("Cast.instanceOf"); + boolean isJsoCast = program.isJavaScriptObject(toType); + JMethod method = program.getIndexedMethod(isJsoCast + ? "Cast.instanceOfJso" : "Cast.instanceOf"); JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, method); - Integer boxedInt = queryIds.get(x.getTestType()); - JIntLiteral qId = program.getLiteralInt(boxedInt.intValue()); call.getArgs().add(x.getExpr()); - call.getArgs().add(qId); + if (!isJsoCast) { + JIntLiteral qId = program.getLiteralInt(queryIds.get(toType)); + call.getArgs().add(qId); + } ctx.replaceMe(call); } }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java index 4880242..4687d70 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -237,20 +237,29 @@ String[] parts = ident.substring(1).split("::"); assert (parts.length == 2); String className = parts[0]; - JReferenceType type = program.getFromTypeMap(className); - if (type == null) { - reportJsniError(info, methodDecl, - "Unresolvable native reference to type '" + className + "'"); - return null; + JReferenceType type = null; + if (!className.equals("null")) { + type = program.getFromTypeMap(className); + if (type == null) { + reportJsniError(info, methodDecl, + "Unresolvable native reference to type '" + className + "'"); + return null; + } } String rhs = parts[1]; int parenPos = rhs.indexOf('('); if (parenPos < 0) { // look for a field - for (int i = 0; i < type.fields.size(); ++i) { - JField field = type.fields.get(i); - if (field.getName().equals(rhs)) { - return field; + if (type == null) { + if (rhs.equals("nullField")) { + return program.getNullField(); + } + } else { + for (int i = 0; i < type.fields.size(); ++i) { + JField field = type.fields.get(i); + if (field.getName().equals(rhs)) { + return field; + } } } @@ -259,18 +268,24 @@ + className + "'"); } else { // look for a method - String methodName = rhs.substring(0, parenPos); String almostMatches = null; - for (int i = 0; i < type.methods.size(); ++i) { - JMethod method = type.methods.get(i); - if (method.getName().equals(methodName)) { - String jsniSig = getJsniSig(method); - if (jsniSig.equals(rhs)) { - return method; - } else if (almostMatches == null) { - almostMatches = "'" + jsniSig + "'"; - } else { - almostMatches += ", '" + jsniSig + "'"; + String methodName = rhs.substring(0, parenPos); + if (type == null) { + if (rhs.equals("nullMethod()")) { + return program.getNullMethod(); + } + } else { + for (int i = 0; i < type.methods.size(); ++i) { + JMethod method = type.methods.get(i); + if (method.getName().equals(methodName)) { + String jsniSig = getJsniSig(method); + if (jsniSig.equals(rhs)) { + return method; + } else if (almostMatches == null) { + almostMatches = "'" + jsniSig + "'"; + } else { + almostMatches += ", '" + jsniSig + "'"; + } } } } @@ -291,14 +306,16 @@ private void processField(JsNameRef nameRef, SourceInfo info, JField field, JsContext<JsExpression> ctx) { - if (field.isStatic() && nameRef.getQualifier() != null) { - reportJsniError(info, methodDecl, - "Cannot make a qualified reference to the static field " - + field.getName()); - } else if (!field.isStatic() && nameRef.getQualifier() == null) { - reportJsniError(info, methodDecl, - "Cannot make an unqualified reference to the instance field " - + field.getName()); + if (field.getEnclosingType() != null) { + if (field.isStatic() && nameRef.getQualifier() != null) { + reportJsniError(info, methodDecl, + "Cannot make a qualified reference to the static field " + + field.getName()); + } else if (!field.isStatic() && nameRef.getQualifier() == null) { + reportJsniError(info, methodDecl, + "Cannot make an unqualified reference to the instance field " + + field.getName()); + } } /* @@ -328,14 +345,16 @@ private void processMethod(JsNameRef nameRef, SourceInfo info, JMethod method) { - if (method.isStatic() && nameRef.getQualifier() != null) { - reportJsniError(info, methodDecl, - "Cannot make a qualified reference to the static method " - + method.getName()); - } else if (!method.isStatic() && nameRef.getQualifier() == null) { - reportJsniError(info, methodDecl, - "Cannot make an unqualified reference to the instance method " - + method.getName()); + if (method.getEnclosingType() != null) { + if (method.isStatic() && nameRef.getQualifier() != null) { + reportJsniError(info, methodDecl, + "Cannot make a qualified reference to the static method " + + method.getName()); + } else if (!method.isStatic() && nameRef.getQualifier() == null) { + reportJsniError(info, methodDecl, + "Cannot make an unqualified reference to the instance method " + + method.getName()); + } } JsniMethodRef methodRef = new JsniMethodRef(program, info, @@ -531,12 +550,17 @@ JMethod method = currentClass.methods.get(2); assert ("getClass".equals(method.getName())); - tryFindUpRefs(method); - - JMethodBody body = (JMethodBody) method.getBody(); - JClassLiteral classLit = program.getLiteralClass(currentClass); - body.getStatements().add( - new JReturnStatement(program, null, classLit)); + if (program.isJavaScriptObject(currentClass) + && currentClass != program.getJavaScriptObject()) { + // Just use JavaScriptObject's implementation for all subclasses. + currentClass.methods.remove(2); + } else { + tryFindUpRefs(method); + JMethodBody body = (JMethodBody) method.getBody(); + JClassLiteral classLit = program.getLiteralClass(currentClass); + body.getStatements().add( + new JReturnStatement(program, null, classLit)); + } } // Implement Class.desiredAssertionStatus
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java index 38d9a42..e7baca2 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -507,7 +507,7 @@ } } - if (typeOracle.isInstantiatedType(x)) { + if (typeOracle.isInstantiatedType(x) && !program.isJavaScriptObject(x)) { generateClassSetup(x, globalStmts); } @@ -1211,6 +1211,8 @@ if (x == program.getTypeJavaLangObject()) { // special: setup a "toString" alias for java.lang.Object.toString() generateToStringAlias(x, globalStmts); + // special: setup the identifying typeMarker field + generateTypeMarker(x, globalStmts); } generateTypeId(x, globalStmts); @@ -1376,6 +1378,19 @@ } } + private void generateTypeMarker(JClassType x, List<JsStatement> globalStmts) { + JField typeMarkerField = program.getIndexedField("Object.typeMarker"); + JsName typeMarkerName = names.get(typeMarkerField); + if (typeMarkerName == null) { + // Was pruned; this compilation must have no JSO instanceof tests. + return; + } + JsNameRef fieldRef = typeMarkerName.makeRef(); + fieldRef.setQualifier(globalTemp.makeRef()); + JsExpression asg = createAssignment(fieldRef, nullMethodName.makeRef()); + globalStmts.add(new JsExprStmt(asg)); + } + private JsExpression generateTypeTable() { JsArrayLiteral arrayLit = new JsArrayLiteral(); for (int i = 0; i < program.getJsonTypeTable().size(); ++i) { @@ -1664,6 +1679,7 @@ // Object fields specialObfuscatedIdents.put("typeId", "tI"); + specialObfuscatedIdents.put("typeMarker", "tM"); // String polymorphic specialObfuscatedIdents.put("charAt", "cA");
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectCaster.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectCaster.java deleted file mode 100644 index b4f0a7c..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectCaster.java +++ /dev/null
@@ -1,237 +0,0 @@ -/* - * Copyright 2007 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.dev.jjs.impl; - -import com.google.gwt.dev.jjs.ast.Context; -import com.google.gwt.dev.jjs.ast.JArrayRef; -import com.google.gwt.dev.jjs.ast.JBinaryOperation; -import com.google.gwt.dev.jjs.ast.JCastOperation; -import com.google.gwt.dev.jjs.ast.JConditional; -import com.google.gwt.dev.jjs.ast.JExpression; -import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement; -import com.google.gwt.dev.jjs.ast.JMethod; -import com.google.gwt.dev.jjs.ast.JMethodCall; -import com.google.gwt.dev.jjs.ast.JModVisitor; -import com.google.gwt.dev.jjs.ast.JNewArray; -import com.google.gwt.dev.jjs.ast.JParameter; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.ast.JReferenceType; -import com.google.gwt.dev.jjs.ast.JReturnStatement; -import com.google.gwt.dev.jjs.ast.JType; - -import java.util.ArrayList; -import java.util.List; - -/** - * Synthesize casts for JavaScriptObject types in cases where dynamic type - * information may be necessary. - */ -public class JavaScriptObjectCaster { - - /** - * Synthesize casts from JavaScriptObjects to trigger wrapping. - */ - private class AssignmentVisitor extends JModVisitor { - - private JMethod currentMethod; - - @Override - public void endVisit(JBinaryOperation x, Context ctx) { - if (x.isAssignment()) { - JType lhsType = x.getLhs().getType(); - JExpression newRhs = checkAndReplaceJso(x.getRhs(), lhsType); - if (newRhs == x.getRhs()) { - // There's another case to check: if we have an array store that may - // trigger a type check, we need to wrap the rhs. - if (x.getLhs() instanceof JArrayRef) { - newRhs = checkAndReplaceJsoArrayStore(newRhs, lhsType); - } - } - if (newRhs != x.getRhs()) { - JBinaryOperation asg = new JBinaryOperation(program, - x.getSourceInfo(), lhsType, x.getOp(), x.getLhs(), newRhs); - ctx.replaceMe(asg); - } - } - } - - @Override - public void endVisit(JConditional x, Context ctx) { - JExpression newThen = checkAndReplaceJso(x.getThenExpr(), x.getType()); - JExpression newElse = checkAndReplaceJso(x.getElseExpr(), x.getType()); - if (newThen != x.getThenExpr() || newElse != x.getElseExpr()) { - JConditional newCond = new JConditional(program, x.getSourceInfo(), - x.getType(), x.getIfTest(), newThen, newElse); - ctx.replaceMe(newCond); - } - } - - @Override - public void endVisit(JLocalDeclarationStatement x, Context ctx) { - JExpression newInst = x.getInitializer(); - if (newInst != null) { - newInst = checkAndReplaceJso(newInst, x.getLocalRef().getType()); - if (newInst != x.getInitializer()) { - JLocalDeclarationStatement newStmt = new JLocalDeclarationStatement( - program, x.getSourceInfo(), x.getLocalRef(), newInst); - ctx.replaceMe(newStmt); - } - } - } - - @Override - public void endVisit(JMethod x, Context ctx) { - currentMethod = null; - } - - @Override - public void endVisit(JMethodCall x, Context ctx) { - // Check implicit assignments from argument and instance passing. - - ArrayList<JExpression> args = x.getArgs(); - JMethod target = x.getTarget(); - - for (int i = 0; i < target.params.size(); ++i) { - JParameter param = target.params.get(i); - JExpression arg = args.get(i); - JExpression newArg = checkAndReplaceJso(arg, param.getType(), - target.isNative()); - this.didChange |= (newArg != arg); - args.set(i, newArg); - } - - /* - * Virtual calls *require* wrapping to dispatch correctly. This should be - * a rare case since most call should get statically resolved already. - */ - if (!target.isStatic()) { - JExpression newInst = checkAndReplaceJso(x.getInstance(), - program.getTypeJavaLangObject()); - if (newInst != x.getInstance()) { - JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(), - newInst, target, x.isStaticDispatchOnly()); - newCall.getArgs().addAll(args); - ctx.replaceMe(newCall); - } - } - } - - @Override - public void endVisit(JNewArray x, Context ctx) { - List<JExpression> initializers = x.initializers; - if (initializers != null) { - for (int i = 0; i < initializers.size(); ++i) { - JExpression intializer = initializers.get(i); - JExpression newInitializer = checkAndReplaceJsoArrayStore(intializer, - x.getArrayType().getLeafType()); - if (intializer != newInitializer) { - initializers.set(i, newInitializer); - this.didChange = true; - } - } - } - } - - @Override - public void endVisit(JReturnStatement x, Context ctx) { - if (x.getExpr() != null) { - JExpression newExpr = checkAndReplaceJso(x.getExpr(), - currentMethod.getType()); - if (newExpr != x.getExpr()) { - JReturnStatement newStmt = new JReturnStatement(program, - x.getSourceInfo(), newExpr); - ctx.replaceMe(newStmt); - } - } - } - - @Override - public boolean visit(JMethod x, Context ctx) { - currentMethod = x; - return true; - } - - private JExpression checkAndReplaceJso(JExpression arg, JType targetType) { - return checkAndReplaceJso(arg, targetType, false); - } - - /** - * Wraps a JSO-typed argument if the target type is a different type. - */ - private JExpression checkAndReplaceJso(JExpression arg, JType targetType, - boolean nowrapJso) { - JType argType = arg.getType(); - if (argType == targetType) { - return arg; - } - if (!(targetType instanceof JReferenceType)) { - return arg; - } - if (!program.isJavaScriptObject(argType)) { - return arg; - } - /* - * Special case: when calling a native method, only force a wrapping if - * the type is explicitly Object. As long as the target type is a JSO - * subclass, don't bother wrapping since we're losing type information - * anyway. - */ - if (nowrapJso && program.isJavaScriptObject(targetType)) { - return arg; - } - // Synthesize a cast to the arg type to force a wrap - JCastOperation cast = new JCastOperation(program, arg.getSourceInfo(), - argType, arg); - return cast; - } - - /** - * Wraps a JSO-typed argument. - * - * TODO: We could eliminate casts cases where the array instance was never - * cast to a weaker type. - */ - private JExpression checkAndReplaceJsoArrayStore(JExpression arg, - JType targetType) { - if (!(targetType instanceof JReferenceType)) { - return arg; - } - if (!program.isJavaScriptObject(arg.getType())) { - return arg; - } - // Synthesize a cast to the target type - JCastOperation cast = new JCastOperation(program, arg.getSourceInfo(), - targetType, arg); - return cast; - } - } - - public static void exec(JProgram program) { - new JavaScriptObjectCaster(program).execImpl(); - } - - private final JProgram program; - - private JavaScriptObjectCaster(JProgram program) { - this.program = program; - } - - private void execImpl() { - AssignmentVisitor visitor = new AssignmentVisitor(); - visitor.accept(program); - } - -}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java new file mode 100644 index 0000000..5fc544d --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
@@ -0,0 +1,123 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.jjs.impl; + +import com.google.gwt.dev.jjs.ast.Context; +import com.google.gwt.dev.jjs.ast.JArrayType; +import com.google.gwt.dev.jjs.ast.JCastOperation; +import com.google.gwt.dev.jjs.ast.JClassLiteral; +import com.google.gwt.dev.jjs.ast.JField; +import com.google.gwt.dev.jjs.ast.JInstanceOf; +import com.google.gwt.dev.jjs.ast.JLocal; +import com.google.gwt.dev.jjs.ast.JMethod; +import com.google.gwt.dev.jjs.ast.JModVisitor; +import com.google.gwt.dev.jjs.ast.JNewArray; +import com.google.gwt.dev.jjs.ast.JParameter; +import com.google.gwt.dev.jjs.ast.JProgram; +import com.google.gwt.dev.jjs.ast.JReferenceType; +import com.google.gwt.dev.jjs.ast.JType; + +/** + * Replace references to JSO subtypes with JSO itself. + */ +public class JavaScriptObjectNormalizer { + + /** + * Map types from JSO subtypes to JSO itself. + */ + private class NormalizeVisitor extends JModVisitor { + + @Override + public void endVisit(JCastOperation x, Context ctx) { + JType newType = translate(x.getCastType()); + if (newType != x.getCastType()) { + ctx.replaceMe(new JCastOperation(program, x.getSourceInfo(), newType, + x.getExpr())); + } + } + + @Override + public void endVisit(JClassLiteral x, Context ctx) { + JType newType = translate(x.getRefType()); + if (newType != x.getRefType()) { + ctx.replaceMe(program.getLiteralClass(newType)); + } + } + + @Override + public void endVisit(JField x, Context ctx) { + x.setType(translate(x.getType())); + } + + @Override + public void endVisit(JInstanceOf x, Context ctx) { + JReferenceType newType = (JReferenceType) translate(x.getTestType()); + if (newType != x.getTestType()) { + ctx.replaceMe(new JInstanceOf(program, x.getSourceInfo(), newType, + x.getExpr())); + } + } + + @Override + public void endVisit(JLocal x, Context ctx) { + x.setType(translate(x.getType())); + } + + @Override + public void endVisit(JMethod x, Context ctx) { + x.setType(translate(x.getType())); + } + + @Override + public void endVisit(JNewArray x, Context ctx) { + x.setType(translate(x.getType())); + } + + @Override + public void endVisit(JParameter x, Context ctx) { + x.setType(translate(x.getType())); + } + + private JType translate(JType type) { + if (program.isJavaScriptObject(type)) { + return program.getJavaScriptObject(); + } else if (type instanceof JArrayType) { + JArrayType arrayType = (JArrayType) type; + if (program.isJavaScriptObject(arrayType.getLeafType())) { + return program.getTypeArray(program.getJavaScriptObject(), + arrayType.getDims()); + } + } + return type; + } + } + + public static void exec(JProgram program) { + new JavaScriptObjectNormalizer(program).execImpl(); + } + + private final JProgram program; + + private JavaScriptObjectNormalizer(JProgram program) { + this.program = program; + } + + private void execImpl() { + NormalizeVisitor visitor = new NormalizeVisitor(); + visitor.accept(program); + } + +}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java new file mode 100644 index 0000000..ff4610e --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
@@ -0,0 +1,229 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.jjs.impl; + +import com.google.gwt.dev.jjs.SourceInfo; +import com.google.gwt.dev.jjs.ast.Context; +import com.google.gwt.dev.jjs.ast.JClassType; +import com.google.gwt.dev.jjs.ast.JConditional; +import com.google.gwt.dev.jjs.ast.JMethod; +import com.google.gwt.dev.jjs.ast.JMethodBody; +import com.google.gwt.dev.jjs.ast.JMethodCall; +import com.google.gwt.dev.jjs.ast.JModVisitor; +import com.google.gwt.dev.jjs.ast.JParameter; +import com.google.gwt.dev.jjs.ast.JParameterRef; +import com.google.gwt.dev.jjs.ast.JProgram; +import com.google.gwt.dev.jjs.ast.JReturnStatement; +import com.google.gwt.dev.jjs.impl.MakeCallsStatic.CreateStaticImplsVisitor; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * All call sites that might result in virtual dispatch to a JSO must be + * rewritten to force static dispatch. This transform may NOT be run multiple + * times; it will create ever-expanding replacement expressions. + */ +public class JsoDevirtualizer { + + /** + * Rewrite any virtual dispatches to Object or JavaScriptObject such that + * dispatch occurs statically for JSOs. + */ + private class RewriteVirtualDispatches extends JModVisitor { + + @Override + public void endVisit(JMethodCall x, Context ctx) { + JMethod method = x.getTarget(); + JMethod newMethod; + if (virtualJsoMethods.contains(method)) { + /* + * Force a JSO call to be static. Really, this should never be necessary + * as long as MakeCallsStatic runs. However, we would rather not insist + * that normalization depends on optimization having been done. + */ + newMethod = program.getStaticImpl(method); + } else if (objectMethodToJsoMethod.keySet().contains(method)) { + /* + * Map the object call to its appropriate devirtualizing method. + */ + newMethod = objectMethodToJsoMethod.get(method); + } else { + return; + } + assert (newMethod != null); + ctx.replaceMe(MakeCallsStatic.makeStaticCall(x, newMethod)); + } + + @Override + public boolean visit(JMethod x, Context ctx) { + // Don't rewrite the polymorphic call inside of the devirtualizing method! + if (objectMethodToJsoMethod.values().contains(x)) { + return false; + } + return true; + } + } + + public static void exec(JProgram program) { + new JsoDevirtualizer(program).execImpl(); + } + + /** + * Maps each Object instance methods (ie, {@link Object#equals(Object)}) onto + * its corresponding devirtualizing method. + */ + protected Map<JMethod, JMethod> objectMethodToJsoMethod = new HashMap<JMethod, JMethod>(); + + /** + * Contains the set of live instance methods on JavaScriptObject; typically + * overrides of Object methods. + */ + protected Set<JMethod> virtualJsoMethods = new HashSet<JMethod>(); + + /** + * Contains the set of devirtualizing methods that replace polymorphic calls + * to Object methods. + */ + private Set<JMethod> devirtualMethods = new HashSet<JMethod>(); + + /** + * Contains the Cast.isJavaObject method. + */ + private final JMethod isJavaObjectMethod; + + private final JProgram program; + + private JsoDevirtualizer(JProgram program) { + this.program = program; + this.isJavaObjectMethod = program.getIndexedMethod("Cast.isJavaObject"); + } + + /** + * Create a conditional method to discriminate between static and virtual + * dispatch. + * + * <pre> + * static boolean equals__devirtual$(Object this, Object other) { + * return Cast.isJavaObject(this) ? this.equals(other) : JavaScriptObject.equals$(this, other); + * } + * </pre> + */ + private JMethod createDevirtualMethod(JMethod objectMethod, JMethod jsoImpl) { + JClassType jsoType = program.getJavaScriptObject(); + SourceInfo sourceInfo = null; + + // Create the new method. + String name = objectMethod.getName() + "__devirtual$"; + JMethod newMethod = program.createMethod(sourceInfo, name.toCharArray(), + jsoType, objectMethod.getType(), false, true, true, false, false); + + // Setup parameters. + JParameter thisParam = program.createParameter(null, + "this$static".toCharArray(), program.getTypeJavaLangObject(), true, + true, newMethod); + for (JParameter oldParam : objectMethod.params) { + program.createParameter(sourceInfo, oldParam.getName().toCharArray(), + oldParam.getType(), true, false, newMethod); + } + newMethod.freezeParamTypes(); + + // Build from bottom up. + JMethodCall condition = new JMethodCall(program, sourceInfo, null, + isJavaObjectMethod); + condition.getArgs().add(new JParameterRef(program, sourceInfo, thisParam)); + + JMethodCall thenValue = new JMethodCall(program, sourceInfo, + new JParameterRef(program, sourceInfo, thisParam), objectMethod); + for (JParameter param : newMethod.params) { + if (param != thisParam) { + thenValue.getArgs().add(new JParameterRef(program, sourceInfo, param)); + } + } + + JMethodCall elseValue = new JMethodCall(program, sourceInfo, null, jsoImpl); + for (JParameter param : newMethod.params) { + elseValue.getArgs().add(new JParameterRef(program, sourceInfo, param)); + } + + JConditional conditional = new JConditional(program, sourceInfo, + objectMethod.getType(), condition, thenValue, elseValue); + + JReturnStatement returnStatement = new JReturnStatement(program, + sourceInfo, conditional); + ((JMethodBody) newMethod.getBody()).getStatements().add(returnStatement); + return newMethod; + } + + private void execImpl() { + JClassType jsoType = program.getJavaScriptObject(); + if (jsoType == null) { + return; + } + + for (JMethod method : jsoType.methods) { + if (!method.isStatic()) { + virtualJsoMethods.add(method); + } + } + + if (virtualJsoMethods.isEmpty()) { + return; + } + + CreateStaticImplsVisitor creator = new CreateStaticImplsVisitor(); + for (JMethod method : virtualJsoMethods) { + // Ensure staticImpls exist for any instance methods. + JMethod jsoStaticImpl = program.getStaticImpl(method); + if (jsoStaticImpl == null) { + creator.accept(method); + jsoStaticImpl = program.getStaticImpl(method); + assert (jsoStaticImpl != null); + } + + // Find the object method this instance method overrides. + JMethod objectOverride = findObjectOverride(method); + if (objectOverride != null) { + JMethod devirtualizer = createDevirtualMethod(objectOverride, + jsoStaticImpl); + devirtualMethods.add(devirtualizer); + objectMethodToJsoMethod.put(objectOverride, devirtualizer); + } + } + + RewriteVirtualDispatches rewriter = new RewriteVirtualDispatches(); + rewriter.accept(program); + assert (rewriter.didChange()); + } + + /** + * Finds the object method this method overrides. + */ + private JMethod findObjectOverride(JMethod method) { + Set<JMethod> overrides = program.typeOracle.getAllRealOverrides(method); + JMethod objectOverride = null; + for (JMethod override : overrides) { + if (override.getEnclosingType() == program.getTypeJavaLangObject()) { + objectOverride = override; + break; + } + } + return objectOverride; + } + +}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java index e17dc6c..4ee80f6 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -50,14 +50,12 @@ * of itself, but it opens the door to other optimizations. The basic idea is * that you look for calls to instance methods that are not actually * polymorphic. In other words, the target method is (effectively) final, not - * overriden anywhere in the compilation. We rewrite the single instance method + * overridden anywhere in the compilation. We rewrite the single instance method * as a static method that contains the implementation plus an instance method * that delegates to the static method. Then we update any call sites to call * the static method instead. This opens the door to further optimizations, * reduces use of the long "this" keyword in the resulting JavaScript, and in * most cases the polymorphic version can be pruned later. - * - * TODO(later): make this work on JSNI methods! */ public class MakeCallsStatic { @@ -67,7 +65,7 @@ * it. Sometimes the instance method can be pruned later since we update all * non-polymorphic call sites. */ - private class CreateStaticImplsVisitor extends JVisitor { + static class CreateStaticImplsVisitor extends JVisitor { /** * When code is moved from an instance method to a static method, all @@ -112,15 +110,15 @@ @Override public void endVisit(JParameterRef x, Context ctx) { JParameter param = varMap.get(x.getTarget()); - JParameterRef paramRef = new JParameterRef(program, x.getSourceInfo(), - param); + JParameterRef paramRef = new JParameterRef(x.getProgram(), + x.getSourceInfo(), param); ctx.replaceMe(paramRef); } @Override public void endVisit(JThisRef x, Context ctx) { - JParameterRef paramRef = new JParameterRef(program, x.getSourceInfo(), - thisParam); + JParameterRef paramRef = new JParameterRef(x.getProgram(), + x.getSourceInfo(), thisParam); ctx.replaceMe(paramRef); } } @@ -141,6 +139,7 @@ * Don't use the JProgram helper because it auto-adds the new method to * its enclosing class. */ + JProgram program = x.getProgram(); JMethod newMethod = new JMethod(program, sourceInfo, newName, enclosingType, returnType, false, true, true, x.isPrivate()); @@ -266,17 +265,7 @@ return; } - // Update the call site - JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(), null, - newMethod); - - // The qualifier becomes the first arg - newCall.getArgs().add(x.getInstance()); - // Copy the rest of the args - for (int i = 0; i < x.getArgs().size(); ++i) { - newCall.getArgs().add(x.getArgs().get(i)); - } - ctx.replaceMe(newCall); + ctx.replaceMe(makeStaticCall(x, newMethod)); } } @@ -284,7 +273,18 @@ return new MakeCallsStatic(program).execImpl(); } - public Set<JMethod> toBeMadeStatic = new HashSet<JMethod>(); + static JMethodCall makeStaticCall(JMethodCall x, JMethod newMethod) { + // Update the call site + JMethodCall newCall = new JMethodCall(x.getProgram(), x.getSourceInfo(), + null, newMethod); + + // The qualifier becomes the first arg + newCall.getArgs().add(x.getInstance()); + newCall.getArgs().addAll(x.getArgs()); + return newCall; + } + + protected Set<JMethod> toBeMadeStatic = new HashSet<JMethod>(); private final JProgram program;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java index e0257e7..186890f 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -23,6 +23,7 @@ import com.google.gwt.dev.jjs.ast.JBinaryOperation; import com.google.gwt.dev.jjs.ast.JBinaryOperator; import com.google.gwt.dev.jjs.ast.JBlock; +import com.google.gwt.dev.jjs.ast.JCastOperation; import com.google.gwt.dev.jjs.ast.JClassType; import com.google.gwt.dev.jjs.ast.JExpression; import com.google.gwt.dev.jjs.ast.JField; @@ -619,11 +620,26 @@ } @Override + public boolean visit(JCastOperation x, Context ctx) { + // Rescue any JavaScriptObject type that is the target of a cast. + JType targetType = x.getCastType(); + if (program.isJavaScriptObject(targetType)) { + rescue((JReferenceType) targetType, true, true); + } + return true; + } + + @Override public boolean visit(JMethodCall call, Context ctx) { JMethod target = call.getTarget(); - // JLS 12.4.1: references to static methods rescue the enclosing class - if (target.isStatic()) { - rescue(target.getEnclosingType(), true, false); + JReferenceType enclosingType = target.getEnclosingType(); + if (program.isJavaScriptObject(enclosingType)) { + // Calls to JavaScriptObject types rescue those types. + boolean instance = !target.isStatic() || program.isStaticImpl(target); + rescue(enclosingType, true, instance); + } else if (target.isStatic()) { + // JLS 12.4.1: references to static methods rescue the enclosing class + rescue(enclosingType, true, false); } rescue(target); return true; @@ -716,20 +732,17 @@ /** * Subclasses of JavaScriptObject are never instantiated directly. They are * created "magically" when a JSNI method passes a reference to an existing - * JS object into Java code. The point at which a subclass of JSO is passed - * into Java code constitutes "instantiation". We must identify these points - * and trigger a rescue and instantiation of that particular JSO subclass. + * JS object into Java code. If any point in the program can pass a value + * from JS into Java which could potentially be cast to JavaScriptObject, we + * must rescue JavaScriptObject. * * @param type The type of the value passing from Java to JavaScript. * @see com.google.gwt.core.client.JavaScriptObject */ private void maybeRescueJavaScriptObjectPassingIntoJava(JType type) { - if (type instanceof JReferenceType) { - JReferenceType refType = (JReferenceType) type; - if (program.typeOracle.canTriviallyCast(refType, - program.getJavaScriptObject())) { - rescue(refType, true, true); - } + if (program.isJavaScriptObject(type) + || type == program.getTypeJavaLangObject()) { + rescue((JReferenceType) type, true, true); } }
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java index 3690d82..6ed5e5e 100644 --- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java +++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -18,21 +18,34 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JParameter; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.jdt.ByteCodeCompiler; import com.google.gwt.dev.jdt.CacheManager; +import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter; +import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodMapper; import com.google.gwt.util.tools.Utility; +import org.apache.commons.collections.map.ReferenceMap; + import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** + * An isolated {@link ClassLoader} for running all user code. All user files are + * compiled from source code byte a {@link ByteCodeCompiler}. After + * compilation, some byte code rewriting is performed to support + * <code>JavaScriptObject</code> and its subtypes. * - * TODO : we should refactor this class to move the getClassInfoByDispId, + * TODO: we should refactor this class to move the getClassInfoByDispId, * getDispId, getMethodDispatch and putMethodDispatch into a separate entity * since they really do not interact with the CompilingClassLoader * functionality. @@ -85,9 +98,6 @@ public synchronized int getDispId(String jsniMemberRef) { /* * Map JS toString() onto the Java toString() method. - * - * TODO : is it true that tostring is valid in JavaScript? JavaScript is - * case sensitive. */ if (jsniMemberRef.equals("toString")) { jsniMemberRef = "@java.lang.Object::toString()"; @@ -112,6 +122,13 @@ String memberName = jsniMemberRef.substring(endClassName + 2); int memberId = dispClassInfo.getMemberId(memberName); + if (memberId < 0) { + logger.log(TreeLogger.WARN, "Member '" + memberName + + "' in JSNI reference '" + jsniMemberRef + + "' could not be found; expect subsequent failures", + new NoSuchFieldError(memberName)); + } + return synthesizeDispId(dispClassInfo.getClassId(), memberId); } @@ -195,6 +212,11 @@ return null; } + // Map JSO type references to the appropriate impl class. + if (classRewriter.isJsoIntf(cls.getName())) { + cls = getClassFromBinaryName(cls.getName() + "$"); + } + /* * we need to create a new DispatchClassInfo since we have never seen this * class before under any source or binary class name @@ -225,6 +247,84 @@ } } + private class MyMethodDeclarationMapper implements InstanceMethodMapper { + + private final Map<String, Set<JClassType>> signatureToDeclaringClasses = new HashMap<String, Set<JClassType>>(); + + public MyMethodDeclarationMapper(Set<JClassType> jsoTypes, + JClassType javaLangObject) { + // Populate the map. + for (JClassType type : jsoTypes) { + for (JMethod method : type.getMethods()) { + if (!method.isStatic()) { + String signature = createSignature(method); + Set<JClassType> declaringClasses = signatureToDeclaringClasses.get(signature); + if (declaringClasses == null) { + declaringClasses = new HashSet<JClassType>(); + signatureToDeclaringClasses.put(signature, declaringClasses); + } + declaringClasses.add(type); + } + } + } + // Object clobbers everything. + for (JMethod method : javaLangObject.getMethods()) { + if (!method.isStatic()) { + String signature = createSignature(method); + Set<JClassType> declaringClasses = new HashSet<JClassType>(); + signatureToDeclaringClasses.put(signature, declaringClasses); + declaringClasses.add(javaLangObject); + } + } + } + + public String findDeclaringClass(String desc, String signature) { + // Lookup the method. + Set<JClassType> declaringClasses = signatureToDeclaringClasses.get(signature); + if (declaringClasses.size() == 1) { + // Shortcut: if there's only one answer, it must be right. + return createDescriptor(declaringClasses.iterator().next()); + } + // Must check for assignability. + String sourceName = desc.replace('/', '.'); + sourceName = sourceName.replace('$', '.'); + JClassType declaredType = typeOracle.findType(sourceName); + + // Check if I declare this directly. + if (declaringClasses.contains(declaredType)) { + return desc; + } + + // Check to see what type I am assignable to. + for (JClassType possibleSupertype : declaringClasses) { + if (declaredType.isAssignableTo(possibleSupertype)) { + return createDescriptor(possibleSupertype); + } + } + throw new IllegalArgumentException("Could not resolve signature '" + + signature + "' from class '" + desc + "'"); + } + + private String createDescriptor(JClassType type) { + String jniSignature = type.getJNISignature(); + return jniSignature.substring(1, jniSignature.length() - 1); + } + + private String createSignature(JMethod method) { + StringBuffer sb = new StringBuffer(method.getName()); + sb.append('('); + for (JParameter param : method.getParameters()) { + sb.append(param.getType().getJNISignature()); + } + sb.append(')'); + sb.append(method.getReturnType().getJNISignature()); + String signature = sb.toString(); + return signature; + } + } + + private final HostedModeClassRewriter classRewriter; + private final ByteCodeCompiler compiler; private final DispatchClassInfoOracle dispClassInfoOracle = new DispatchClassInfoOracle(); @@ -235,6 +335,9 @@ private final TypeOracle typeOracle; + private final ReferenceMap weakJsoCache = new ReferenceMap(ReferenceMap.HARD, + ReferenceMap.WEAK); + public CompilingClassLoader(TreeLogger logger, ByteCodeCompiler compiler, TypeOracle typeOracle) throws UnableToCompleteException { super(null); @@ -276,6 +379,41 @@ } } compiler.removeStaleByteCode(logger); + + // Create a class rewriter based on all the subtypes of the JSO class. + JClassType jsoType = typeOracle.findType(JsValueGlue.JSO_CLASS); + if (jsoType != null) { + + // Create a set of binary names. + Set<JClassType> jsoTypes = new HashSet<JClassType>(); + JClassType[] jsoSubtypes = jsoType.getSubtypes(); + Collections.addAll(jsoTypes, jsoSubtypes); + jsoTypes.add(jsoType); + + Set<String> jsoTypeNames = new HashSet<String>(); + for (JClassType type : jsoTypes) { + jsoTypeNames.add(getBinaryName(type)); + } + + MyMethodDeclarationMapper mapper = new MyMethodDeclarationMapper( + jsoTypes, typeOracle.getJavaLangObject()); + classRewriter = new HostedModeClassRewriter(jsoTypeNames, mapper); + } else { + // If we couldn't find the JSO class, we don't need to do any rewrites. + classRewriter = null; + } + } + + /** + * Retrieves the mapped JSO for a given unique id, provided the id was + * previously cached and the JSO has not been garbage collected. + * + * @param uniqueId the previously stored unique id + * @return the mapped JSO, or <code>null</code> if the id was not previously + * mapped or if the JSO has been garbage collected + */ + public Object getCachedJso(int uniqueId) { + return weakJsoCache.get(uniqueId); } /** @@ -305,6 +443,17 @@ } } + /** + * Weakly caches a given JSO by unique id. A cached JSO can be looked up by + * unique id until it is garbage collected. + * + * @param uniqueId a unique id associated with the JSO + * @param jso the value to cache + */ + public void putCachedJso(int uniqueId, Object jso) { + weakJsoCache.put(uniqueId, jso); + } + public void putMethodDispatch(MethodAdaptor method, Object methodDispatch) { synchronized (methodToDispatch) { methodToDispatch.put(method, methodDispatch); @@ -334,10 +483,17 @@ } // Get the bytes, compiling if necessary. - // Define the class from bytes. - // + byte[] classBytes; try { - byte[] classBytes = compiler.getClassBytes(logger, className); + // A JSO impl class needs the class bytes for the original class. + String lookupClassName = className; + if (classRewriter != null && classRewriter.isJsoImpl(className)) { + lookupClassName = className.substring(0, className.length() - 1); + } + classBytes = compiler.getClassBytes(logger, lookupClassName); + if (classRewriter != null) { + classBytes = classRewriter.rewrite(className, classBytes); + } return defineClass(className, classBytes, 0, classBytes.length); } catch (UnableToCompleteException e) { throw new ClassNotFoundException(className); @@ -345,6 +501,7 @@ } void clear() { + weakJsoCache.clear(); dispClassInfoOracle.clear(); synchronized (methodToDispatch) { @@ -352,6 +509,12 @@ } } + private String getBinaryName(JClassType type) { + String name = type.getPackage().getName() + '.'; + name += type.getName().replace('.', '$'); + return name; + } + private byte[] getClassBytesFromStream(InputStream is) throws IOException { try { byte classBytes[] = new byte[is.available()];
diff --git a/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java b/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java index 8526c7c..42eadf4 100644 --- a/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java +++ b/dev/core/src/com/google/gwt/dev/shell/JavaScriptHost.java
@@ -82,14 +82,6 @@ } /** - * Invoke a native JavaScript function that returns a handle value. - */ - public static Object invokeNativeHandle(String name, Object jthis, - Class<?> returnType, Class<?>[] types, Object[] args) throws Throwable { - return sHost.invokeNativeHandle(name, jthis, returnType, types, args); - } - - /** * Invoke a native JavaScript function that returns an integer value. */ public static int invokeNativeInt(String name, Object jthis, @@ -122,14 +114,6 @@ } /** - * Invoke a native JavaScript function that returns a string value. - */ - public static String invokeNativeString(String name, Object jthis, - Class<?>[] types, Object[] args) throws Throwable { - return sHost.invokeNativeString(name, jthis, types, args); - } - - /** * Invoke a native JavaScript function that returns no value. */ public static void invokeNativeVoid(String name, Object jthis,
diff --git a/dev/core/src/com/google/gwt/dev/shell/JsValue.java b/dev/core/src/com/google/gwt/dev/shell/JsValue.java index 6b2d9f4..7cda3d6 100644 --- a/dev/core/src/com/google/gwt/dev/shell/JsValue.java +++ b/dev/core/src/com/google/gwt/dev/shell/JsValue.java
@@ -1,5 +1,5 @@ /* - * Copyright 2006 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -105,6 +105,17 @@ public abstract int getInt(); /** + * Returns a unique value corresponding to the underlying JavaScript object. + * In general, two different JsValues will return the same value IFF the + * underlying JavaScript objects are identical (===). + * + * @return a unique number corresponding to the underlying object, or + * <code>0</code> if {@link #isJavaScriptObject()} is + * <code>false</code> + */ + public abstract int getJavaScriptObjectPointer(); + + /** * Get the value of the object as a double. May attempt to convert the value * to a double if it is not a double. * @@ -113,9 +124,9 @@ public abstract double getNumber(); /** - * Get the value of the object as a string. Tries very hard to return a - * reasonable value for any underyling type, but this should only be used for - * human consumption as the exact format is not reliable across platforms. + * Get the value of the object as a string. Will coerce the underlying type to + * a string, but stable cross-platform behavior is only guaranteed when + * {@link #isString()} is <code>true</code>. * * @return the value of the underlying object as a string */ @@ -246,17 +257,6 @@ public abstract void setValue(JsValue other); /** - * Wrap a Java method as a JavaScript function pointer. - * - * @param string the name of the method - * @param dispMethod the DispatchMethod object describing the method tow wrap - */ - // TODO(jat): platform-independent version of this? - // The problem is that each platform has different conventions for passing - // JavaScript values back into a Java method. - // public abstract void setWrappedFunction(String string, - // DispatchMethod dispMethod); - /** * Set the JS object to the supplied object, which will be wrapped in a * platform-dependent JavaScript class. *
diff --git a/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java b/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java index 4382e31..b93250f 100644 --- a/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java +++ b/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -26,60 +26,10 @@ * Glue layer that performs GWT-specific operations on JsValues. Used to isolate * HostedModeExceptions/etc from JsValue code */ -public class JsValueGlue { +public final class JsValueGlue { + public static final String HOSTED_MODE_REFERENCE = "hostedModeReference"; public static final String JSO_CLASS = "com.google.gwt.core.client.JavaScriptObject"; - - /** - * Create a JavaScriptObject instance referring to this JavaScript object. - * - * The caller is responsible for ensuring that the requested type is a - * subclass of JavaScriptObject. - * - * @param type The subclass of JavaScriptObject to create - * @return the constructed JavaScriptObject - */ - public static <T> T createJavaScriptObject(JsValue value, - Class<? extends T> type) { - try { - // checkThread(); - if (!value.isJavaScriptObject()) { - throw new RuntimeException( - "Only Object type JavaScript objects can be made into JavaScriptObject"); - } - - /* find the JavaScriptObject type, while verifying this is a subclass */ - Class<?> jsoType = getJavaScriptObjectSuperclass(type); - if (jsoType == null) { - throw new RuntimeException("Requested type " + type.getName() - + " not a subclass of JavaScriptObject"); - } - - /* create the object using the default constructor */ - Constructor<? extends T> ctor = type.getDeclaredConstructor(); - ctor.setAccessible(true); - T jso = ctor.newInstance(); - - /* set the hostedModeReference field to this JsValue using reflection */ - Field referenceField = jsoType.getDeclaredField("hostedModeReference"); - referenceField.setAccessible(true); - referenceField.set(jso, value); - return jso; - } catch (InstantiationException e) { - throw new RuntimeException("Error creating JavaScript object", e); - } catch (IllegalAccessException e) { - throw new RuntimeException("Error creating JavaScript object", e); - } catch (SecurityException e) { - throw new RuntimeException("Error creating JavaScript object", e); - } catch (NoSuchFieldException e) { - throw new RuntimeException("Error creating JavaScript object", e); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Error creating JavaScript object", e); - } catch (IllegalArgumentException e) { - throw new RuntimeException("Error creating JavaScript object", e); - } catch (InvocationTargetException e) { - throw new RuntimeException("Error creating JavaScript object", e); - } - } + public static final String JSO_IMPL_CLASS = "com.google.gwt.core.client.JavaScriptObject$"; /** * Return an object containing the value JavaScript object as a specified @@ -92,73 +42,52 @@ * @throws HostedModeException if the JavaScript object is not assignable to * the supplied type. */ - public static <T> T get(JsValue value, Class<? extends T> type, - String msgPrefix) { - double doubleVal; - if (value.isNull()) { - return null; - } + @SuppressWarnings("unchecked") + public static <T> T get(JsValue value, CompilingClassLoader cl, + Class<T> type, String msgPrefix) { + if (value.isUndefined()) { // undefined is never legal to return from JavaScript into Java throw new HostedModeException(msgPrefix + ": JavaScript undefined, expected " + type.getName()); } - if (value.isWrappedJavaObject()) { - T origObject = (T) value.getWrappedJavaObject(); - if (!type.isAssignableFrom(origObject.getClass())) { - throw new HostedModeException(msgPrefix + ": Java object of type " - + origObject.getClass().getName() + ", expected " + type.getName()); + + if (type.isPrimitive()) { + if (value.isNull()) { + throw new HostedModeException("Expected primitive type " + type + + "; actual value was null"); } - return origObject; - } - if (getJavaScriptObjectSuperclass(type) != null) { - if (!value.isJavaScriptObject()) { - throw new HostedModeException(msgPrefix + ": JS object of type " - + value.getTypeString() + ", expected " + type.getName()); - } - return createJavaScriptObject(value, type); - } - switch (TypeInfo.classifyType(type)) { - case TypeInfo.TYPE_WRAP_BOOLEAN: - case TypeInfo.TYPE_PRIM_BOOLEAN: + if (type == Boolean.TYPE) { if (!value.isBoolean()) { throw new HostedModeException(msgPrefix + ": JS value of type " + value.getTypeString() + ", expected boolean"); } return (T) Boolean.valueOf(value.getBoolean()); - - case TypeInfo.TYPE_WRAP_BYTE: - case TypeInfo.TYPE_PRIM_BYTE: - return (T) new Byte((byte) getIntRange(value, Byte.MIN_VALUE, + } else if (type == Byte.TYPE) { + return (T) Byte.valueOf((byte) getIntRange(value, Byte.MIN_VALUE, Byte.MAX_VALUE, "byte", msgPrefix)); - - case TypeInfo.TYPE_WRAP_CHAR: - case TypeInfo.TYPE_PRIM_CHAR: - return (T) new Character((char) getIntRange(value, Character.MIN_VALUE, - Character.MAX_VALUE, "char", msgPrefix)); - - case TypeInfo.TYPE_WRAP_DOUBLE: - case TypeInfo.TYPE_PRIM_DOUBLE: + } else if (type == Character.TYPE) { + return (T) Character.valueOf((char) getIntRange(value, + Character.MIN_VALUE, Character.MAX_VALUE, "char", msgPrefix)); + } else if (type == Double.TYPE) { if (!value.isNumber()) { throw new HostedModeException(msgPrefix + ": JS value of type " + value.getTypeString() + ", expected double"); } - return (T) new Double(value.getNumber()); - - case TypeInfo.TYPE_WRAP_FLOAT: - case TypeInfo.TYPE_PRIM_FLOAT: + return (T) Double.valueOf(value.getNumber()); + } else if (type == Float.TYPE) { if (!value.isNumber()) { throw new HostedModeException(msgPrefix + ": JS value of type " + value.getTypeString() + ", expected float"); } - doubleVal = value.getNumber(); + double doubleVal = value.getNumber(); // Check for small changes near MIN_VALUE and replace with the - // actual endpoint value, in case it is being used as a sentinel + // actual end point value, in case it is being used as a sentinel // value. This test works by the subtraction result rounding off to // zero if the delta is not representable in a float. // TODO(jat): add similar test for MAX_VALUE if we have a JS - // platform that munges the value while converting to/from strings. + // platform that alters the value while converting to/from strings. if ((float) (doubleVal - Float.MIN_VALUE) == 0.0f) { doubleVal = Float.MIN_VALUE; } @@ -172,20 +101,16 @@ throw new HostedModeException(msgPrefix + ": JS value " + doubleVal + " out of range for a float"); } - return (T) new Float(floatVal); - - case TypeInfo.TYPE_WRAP_INT: - case TypeInfo.TYPE_PRIM_INT: - return (T) new Integer(getIntRange(value, Integer.MIN_VALUE, + return (T) Float.valueOf(floatVal); + } else if (type == Integer.TYPE) { + return (T) Integer.valueOf(getIntRange(value, Integer.MIN_VALUE, Integer.MAX_VALUE, "int", msgPrefix)); - - case TypeInfo.TYPE_WRAP_LONG: - case TypeInfo.TYPE_PRIM_LONG: + } else if (type == Long.TYPE) { if (!value.isNumber()) { throw new HostedModeException(msgPrefix + ": JS value of type " + value.getTypeString() + ", expected long"); } - doubleVal = value.getNumber(); + double doubleVal = value.getNumber(); if (doubleVal < Long.MIN_VALUE || doubleVal > Long.MAX_VALUE) { throw new HostedModeException(msgPrefix + ": JS double value " + doubleVal + " out of range for a long"); @@ -197,26 +122,24 @@ ModuleSpace.getLogger().log(TreeLogger.WARN, msgPrefix + ": Loss of precision converting double to long", null); } - return (T) new Long(longVal); - - case TypeInfo.TYPE_WRAP_SHORT: - case TypeInfo.TYPE_PRIM_SHORT: - return (T) new Short((short) getIntRange(value, Short.MIN_VALUE, + return (T) Long.valueOf(longVal); + } else if (type == Short.TYPE) { + return (T) Short.valueOf((short) getIntRange(value, Short.MIN_VALUE, Short.MAX_VALUE, "short", msgPrefix)); + } + } - case TypeInfo.TYPE_WRAP_STRING: - if (!value.isString()) { - throw new HostedModeException(msgPrefix + ": JS value of type " - + value.getTypeString() + ", expected string"); - } - return (T) value.getString(); - - case TypeInfo.TYPE_USER: - if (value.isString()) { - return (T) value.getString(); - } - // if it isn't a String, it's an error, break to error - break; + if (value.isNull()) { + return null; + } + if (value.isWrappedJavaObject()) { + return type.cast(value.getWrappedJavaObject()); + } + if (value.isString()) { + return type.cast(value.getString()); + } + if (value.isJavaScriptObject()) { + return type.cast(createJavaScriptObject(value, cl)); } // Just don't know what do to with this. @@ -226,81 +149,50 @@ } /** - * Returns the underlying JsValue from a JavaScriptObject instance. - * - * The tricky part is that it is in a different classloader so therefore can't - * be specified directly. The type is specified as Object, and reflection is - * used to retrieve the hostedModeReference field. - * - * @param jso the instance of JavaScriptObject to retrieve the JsValue from. - * @return the JsValue representing the JavaScript object - */ - public static JsValue getUnderlyingObject(Object jso) { - try { - /* - * verify that jso is assignable to - * com.google.gwt.core.client.JavaScriptObject - */ - Class<?> type = getJavaScriptObjectSuperclass(jso.getClass()); - - if (type == null) { - throw new HostedModeException( - "Underlying JSO not a subclass of JavaScriptObject"); - } - - Field referenceField = type.getDeclaredField("hostedModeReference"); - referenceField.setAccessible(true); - return (JsValue) referenceField.get(jso); - } catch (IllegalAccessException e) { - throw new RuntimeException("Error reading handle", e); - } catch (SecurityException e) { - throw new RuntimeException("Error reading handle", e); - } catch (NoSuchFieldException e) { - throw new RuntimeException("Error reading handle", e); - } - } - - /** * Set the underlying value. * * @param value JsValue to set * @param type static type of the object * @param obj the object to store in the JS value */ - public static <T> void set(JsValue value, CompilingClassLoader cl, - Class<?> type, T obj) { - if (obj == null) { - value.setNull(); - } else if (type.equals(String.class)) { - value.setString((String) obj); - } else if (type.equals(boolean.class)) { - value.setBoolean(((Boolean) obj).booleanValue()); - } else if (type.equals(short.class)) { - value.setInt(((Short) obj).shortValue()); - } else if (type.equals(int.class)) { - value.setInt(((Integer) obj).intValue()); - } else if (type.equals(byte.class)) { - value.setInt(((Byte) obj).byteValue()); - } else if (type.equals(char.class)) { - value.setInt(((Character) obj).charValue()); - } else if (type.equals(long.class)) { - long longVal = ((Long) obj).longValue(); - double doubleVal = longVal; - if ((long) doubleVal != longVal) { - // TODO(jat): should this be an error or exception? - ModuleSpace.getLogger().log(TreeLogger.WARN, - "Loss of precision converting long to double", null); + public static void set(JsValue value, CompilingClassLoader cl, Class<?> type, + Object obj) { + if (type.isPrimitive()) { + if (type == Boolean.TYPE) { + value.setBoolean(((Boolean) obj).booleanValue()); + } else if (type == Byte.TYPE) { + value.setInt(((Byte) obj).byteValue()); + } else if (type == Character.TYPE) { + value.setInt(((Character) obj).charValue()); + } else if (type == Double.TYPE) { + value.setDouble(((Double) obj).doubleValue()); + } else if (type == Float.TYPE) { + value.setDouble(((Float) obj).floatValue()); + } else if (type == Integer.TYPE) { + value.setInt(((Integer) obj).intValue()); + } else if (type == Long.TYPE) { + long longVal = ((Long) obj).longValue(); + double doubleVal = longVal; + if ((long) doubleVal != longVal) { + // TODO(jat): should this be an error or exception? + ModuleSpace.getLogger().log(TreeLogger.WARN, + "Loss of precision converting long to double", null); + } + value.setDouble(doubleVal); + } else if (type == Short.TYPE) { + value.setInt(((Short) obj).shortValue()); + } else if (type == Void.TYPE) { + value.setUndefined(); + } else { + throw new HostedModeException("Cannot marshal primitive type " + type); } - value.setDouble(doubleVal); - } else if (type.equals(float.class)) { - value.setDouble(((Float) obj).floatValue()); - } else if (type.equals(double.class)) { - value.setDouble(((Double) obj).doubleValue()); + } else if (obj == null) { + value.setNull(); } else { // not a boxed primitive try { - Class<?> jso = Class.forName(JSO_CLASS, true, cl); - if (jso.isAssignableFrom(type) && jso.isAssignableFrom(obj.getClass())) { + Class<?> jsoType = Class.forName(JSO_IMPL_CLASS, true, cl); + if (jsoType == obj.getClass()) { JsValue jsObject = getUnderlyingObject(obj); value.setValue(jsObject); return; @@ -310,15 +202,73 @@ // don't have to worry about o being one } - // Fallthrough case: Object. - if (!type.isAssignableFrom(obj.getClass())) { + // Fall through case: Object. + if (!type.isInstance(obj)) { throw new HostedModeException("object is of type " + obj.getClass().getName() + ", expected " + type.getName()); } - value.setWrappedJavaObject(cl, obj); + if (obj instanceof String) { + value.setString((String) obj); + } else { + value.setWrappedJavaObject(cl, obj); + } } } + /** + * Create a JavaScriptObject instance referring to this JavaScript object. + * + * @param classLoader the classLoader to create from + * @return the constructed JavaScriptObject + */ + private static Object createJavaScriptObject(JsValue value, + CompilingClassLoader classLoader) { + Throwable caught; + try { + // checkThread(); + if (!value.isJavaScriptObject()) { + throw new RuntimeException( + "Only Object type JavaScript objects can be made into JavaScriptObject"); + } + + // See if there's already a wrapper object (assures identity comparison). + Object jso = classLoader.getCachedJso(value.getJavaScriptObjectPointer()); + if (jso != null) { + return jso; + } + + // Instantiate the JSO class. + Class<?> jsoType = Class.forName(JSO_IMPL_CLASS, true, classLoader); + Constructor<?> ctor = jsoType.getDeclaredConstructor(); + ctor.setAccessible(true); + jso = ctor.newInstance(); + + // Set the reference field to this JsValue using reflection. + Field referenceField = jsoType.getField(HOSTED_MODE_REFERENCE); + referenceField.set(jso, value); + + classLoader.putCachedJso(value.getJavaScriptObjectPointer(), jso); + return jso; + } catch (InstantiationException e) { + caught = e; + } catch (IllegalAccessException e) { + caught = e; + } catch (SecurityException e) { + caught = e; + } catch (NoSuchMethodException e) { + caught = e; + } catch (IllegalArgumentException e) { + caught = e; + } catch (InvocationTargetException e) { + caught = e; + } catch (ClassNotFoundException e) { + caught = e; + } catch (NoSuchFieldException e) { + caught = e; + } + throw new RuntimeException("Error creating JavaScript object", caught); + } + private static int getIntRange(JsValue value, int low, int high, String typeName, String msgPrefix) { int intVal; @@ -347,19 +297,31 @@ } /** - * Verify that the supplied class is a subclass of - * com.google.gwt.core.client.JavaScriptObject, and return the - * JavaScriptObject class if it is. This is required since JavaScriptObject - * actually lives in a different classloader and can't be referenced directly. + * Returns the underlying JsValue from a JavaScriptObject instance. * - * @param type class to test - * @return the JavaScriptObject class object if it is a subclass, or null if - * not. + * The tricky part is that it is in a different ClassLoader so therefore can't + * be specified directly. The type is specified as Object, and reflection is + * used to retrieve the reference field. + * + * @param jso the instance of JavaScriptObject to retrieve the JsValue from. + * @return the JsValue representing the JavaScript object */ - private static Class<?> getJavaScriptObjectSuperclass(Class<?> type) { - while (type != null && !type.getName().equals(JSO_CLASS)) { - type = type.getSuperclass(); + private static JsValue getUnderlyingObject(Object jso) { + Throwable caught; + try { + Field referenceField = jso.getClass().getField(HOSTED_MODE_REFERENCE); + referenceField.setAccessible(true); + return (JsValue) referenceField.get(jso); + } catch (IllegalAccessException e) { + caught = e; + } catch (SecurityException e) { + caught = e; + } catch (NoSuchFieldException e) { + caught = e; } - return type; + throw new RuntimeException("Error reading " + HOSTED_MODE_REFERENCE, caught); + } + + private JsValueGlue() { } }
diff --git a/dev/core/src/com/google/gwt/dev/shell/JsniInjector.java b/dev/core/src/com/google/gwt/dev/shell/JsniInjector.java index 9ec1d9d..50805f5 100644 --- a/dev/core/src/com/google/gwt/dev/shell/JsniInjector.java +++ b/dev/core/src/com/google/gwt/dev/shell/JsniInjector.java
@@ -23,7 +23,6 @@ import com.google.gwt.core.ext.typeinfo.JParameter; import com.google.gwt.core.ext.typeinfo.JPrimitiveType; import com.google.gwt.core.ext.typeinfo.JType; -import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.jdt.CompilationUnitProviderWithAlternateSource; import com.google.gwt.dev.js.ast.JsBlock; @@ -45,37 +44,6 @@ public class JsniInjector { /** - * A consolidated way to get all expected types and succeed or fail - * atomically. - */ - private class CoreTypes { - static final String CLS_JSOBJECT = "JavaScriptObject"; - static final String CLS_STRING = "String"; - static final String PKG_JSOBJECT = "com.google.gwt.core.client"; - static final String PKG_STRING = "java.lang"; - - public final JClassType javaLangString; - - public final JClassType javaScriptObject; - - public CoreTypes(TreeLogger logger) throws UnableToCompleteException { - javaScriptObject = getCoreType(logger, PKG_JSOBJECT, CLS_JSOBJECT); - javaLangString = getCoreType(logger, PKG_STRING, CLS_STRING); - } - - private JClassType getCoreType(TreeLogger logger, String pkg, String cls) - throws UnableToCompleteException { - try { - return oracle.getType(pkg, cls); - } catch (NotFoundException e) { - String msg = "Unable to find core type '" + pkg + "." + cls + "'"; - logger.log(TreeLogger.ERROR, msg, e); - throw new UnableToCompleteException(); - } - } - } - - /** * A chunk of replacement text and where to put it. */ private static class Replacement implements Comparable<Replacement> { @@ -104,8 +72,6 @@ } } - private CoreTypes coreTypes; - private final TypeOracle oracle; private final Map<JMethod, JsBlock> parsedJsByMethod = new IdentityHashMap<JMethod, JsBlock>(); @@ -121,11 +87,6 @@ logger = logger.branch(TreeLogger.SPAM, "Checking for JavaScript native methods", null); - // Make sure the core types exist. - if (coreTypes == null) { - coreTypes = new CoreTypes(logger); - } - // Analyze the source and build a list of changes. char[] source = cup.getSource(); List<Replacement> changes = new ArrayList<Replacement>(); @@ -252,14 +213,8 @@ // Write the Java call to the property invoke method, adding // downcasts where necessary. JType returnType = method.getReturnType(); - boolean isJavaScriptObject = isJavaScriptObject(returnType); - JPrimitiveType primType; - if (isJavaScriptObject) { - // Add a downcast from Handle to the originally-declared type. - String returnTypeName = returnType.getParameterizedQualifiedSourceName(); - sb.append("return (" + returnTypeName + ")" + Jsni.JAVASCRIPTHOST_NAME - + ".invokeNativeHandle"); - } else if (null != (primType = returnType.isPrimitive())) { + JPrimitiveType primType = returnType.isPrimitive(); + if (primType != null) { // Primitives have special overloads. char[] primTypeSuffix = primType.getSimpleSourceName().toCharArray(); primTypeSuffix[0] = Character.toUpperCase(primTypeSuffix[0]); @@ -270,10 +225,6 @@ sb.append(Jsni.JAVASCRIPTHOST_NAME); sb.append("."); sb.append(invokeMethodName); - } else if (returnType == coreTypes.javaLangString) { - sb.append("return "); - sb.append(Jsni.JAVASCRIPTHOST_NAME); - sb.append(".invokeNativeString"); } else { // Some reference type. // We need to add a downcast to the originally-declared type. @@ -295,13 +246,6 @@ sb.append("\", this, "); } - if (isJavaScriptObject) { - // Handle-oriented calls also need the return type as an argument. - String returnTypeName = returnType.getErasedType().getQualifiedSourceName(); - sb.append(returnTypeName); - sb.append(".class, "); - } - // Build an array of classes that tells the invoker how to adapt the // incoming arguments for calling into JavaScript. sb.append(Jsni.buildTypeList(method)); @@ -316,6 +260,8 @@ sb.append("} catch (java.lang.Throwable __gwt_exception) {" + nl); sb.append("if (__gwt_exception instanceof java.lang.RuntimeException) throw (java.lang.RuntimeException) __gwt_exception;" + nl); + sb.append("if (__gwt_exception instanceof java.lang.Error) throw (java.lang.Error) __gwt_exception;" + + nl); JType[] throwTypes = method.getThrows(); for (int i = 0; i < throwTypes.length; ++i) { String typeName = throwTypes[i].getQualifiedSourceName(); @@ -355,19 +301,6 @@ return sb.toString(); } - private boolean isJavaScriptObject(JType type) { - JClassType classType = type.isClass(); - if (classType == null) { - return false; - } - - if (classType.isAssignableTo(coreTypes.javaScriptObject)) { - return true; - } else { - return false; - } - } - private void rewriteCompilationUnit(TreeLogger logger, char[] source, List<Replacement> changes, CompilationUnitProvider cup, boolean pretty) throws UnableToCompleteException { @@ -376,7 +309,9 @@ JClassType[] types = oracle.getTypesInCompilationUnit(cup); for (int i = 0; i < types.length; i++) { JClassType type = types[i]; - rewriteType(logger, source, changes, type, pretty); + if (!type.getQualifiedSourceName().startsWith("java.")) { + rewriteType(logger, source, changes, type, pretty); + } } }
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java index a65ab18..fcec6cf 100644 --- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java +++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
@@ -172,7 +172,8 @@ Class<?>[] types, Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeBoolean(" + name + ")"; - Boolean value = JsValueGlue.get(result, Boolean.class, msgPrefix); + Boolean value = JsValueGlue.get(result, getIsolatedClassLoader(), + boolean.class, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected a boolean"); @@ -184,7 +185,7 @@ Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeByte(" + name + ")"; - Byte value = JsValueGlue.get(result, Byte.class, msgPrefix); + Byte value = JsValueGlue.get(result, null, Byte.TYPE, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected a byte"); @@ -196,7 +197,7 @@ Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeCharacter(" + name + ")"; - Character value = JsValueGlue.get(result, Character.class, msgPrefix); + Character value = JsValueGlue.get(result, null, Character.TYPE, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected a char"); @@ -208,7 +209,7 @@ Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeDouble(" + name + ")"; - Double value = JsValueGlue.get(result, Double.class, msgPrefix); + Double value = JsValueGlue.get(result, null, Double.TYPE, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected a double"); @@ -220,7 +221,7 @@ Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeFloat(" + name + ")"; - Float value = JsValueGlue.get(result, Float.class, msgPrefix); + Float value = JsValueGlue.get(result, null, Float.TYPE, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected a float"); @@ -228,19 +229,11 @@ return value.floatValue(); } - public Object invokeNativeHandle(String name, Object jthis, - Class<?> returnType, Class<?>[] types, Object[] args) throws Throwable { - - JsValue result = invokeNative(name, jthis, types, args); - return JsValueGlue.get(result, returnType, "invokeNativeHandle(" + name - + ")"); - } - public int invokeNativeInt(String name, Object jthis, Class<?>[] types, Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeInteger(" + name + ")"; - Integer value = JsValueGlue.get(result, Integer.class, msgPrefix); + Integer value = JsValueGlue.get(result, null, Integer.TYPE, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected an int"); @@ -252,7 +245,7 @@ Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeLong(" + name + ")"; - Long value = JsValueGlue.get(result, Long.class, msgPrefix); + Long value = JsValueGlue.get(result, null, Long.TYPE, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected a long"); @@ -263,15 +256,15 @@ public Object invokeNativeObject(String name, Object jthis, Class<?>[] types, Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); - return JsValueGlue.get(result, Object.class, "invokeNativeObject(" + name - + ")"); + return JsValueGlue.get(result, getIsolatedClassLoader(), Object.class, + "invokeNativeObject(" + name + ")"); } public short invokeNativeShort(String name, Object jthis, Class<?>[] types, Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); String msgPrefix = "invokeNativeShort(" + name + ")"; - Short value = JsValueGlue.get(result, Short.class, msgPrefix); + Short value = JsValueGlue.get(result, null, Short.TYPE, msgPrefix); if (value == null) { throw new HostedModeException(msgPrefix + ": return value null received, expected a short"); @@ -279,13 +272,6 @@ return value.shortValue(); } - public String invokeNativeString(String name, Object jthis, Class<?>[] types, - Object[] args) throws Throwable { - JsValue result = invokeNative(name, jthis, types, args); - return JsValueGlue.get(result, String.class, "invokeNativeString(" + name - + ")"); - } - public void invokeNativeVoid(String name, Object jthis, Class<?>[] types, Object[] args) throws Throwable { JsValue result = invokeNative(name, jthis, types, args); @@ -390,7 +376,7 @@ } @SuppressWarnings("unchecked") - public Object rebindAndCreate(String requestedClassName) + public <T> T rebindAndCreate(String requestedClassName) throws UnableToCompleteException { Throwable caught = null; String msg = null; @@ -407,7 +393,7 @@ } else { Constructor<?> ctor = resolvedClass.getDeclaredConstructor(); ctor.setAccessible(true); - return ctor.newInstance(); + return (T) ctor.newInstance(); } } catch (ClassNotFoundException e) { msg = "Could not load deferred binding result type '" + resultName + "'";
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java index 940bf9e..a22c4f3 100644 --- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java +++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
@@ -92,7 +92,7 @@ try { // Invoke the property provider function in JavaScript. // - value = space.invokeNativeString("__gwt_getProperty", null, + value = (String) space.invokeNativeObject("__gwt_getProperty", null, new Class[] {String.class}, new Object[] {prop.getName()}); } catch (Throwable e) { // Treat as an unknown value.
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java b/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java index 95e9009..f4e4821 100644 --- a/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java +++ b/dev/core/src/com/google/gwt/dev/shell/ShellJavaScriptHost.java
@@ -75,12 +75,6 @@ Object[] args) throws Throwable; /** - * Invoke a native JavaScript function that returns a handle value. - */ - Object invokeNativeHandle(String name, Object jthis, Class<?> returnType, - Class<?>[] types, Object[] args) throws Throwable; - - /** * Invoke a native JavaScript function that returns an integer value. */ int invokeNativeInt(String name, Object jthis, Class<?>[] types, Object[] args) @@ -105,12 +99,6 @@ Object[] args) throws Throwable; /** - * Invoke a native JavaScript function that returns a string value. - */ - String invokeNativeString(String name, Object jthis, Class<?>[] types, - Object[] args) throws Throwable; - - /** * Invoke a native JavaScript function that returns no value. */ void invokeNativeVoid(String name, Object jthis, Class<?>[] types,
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java new file mode 100644 index 0000000..836d2ba --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/HostedModeClassRewriter.java
@@ -0,0 +1,168 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.shell.rewrite; + +import com.google.gwt.dev.shell.JsValueGlue; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * This class performs any and all byte code rewriting needed to make hosted + * mode work. Currently, it performs the following rewrites: + * <ol> + * <li>Rewrites all JSO types into an interface type (which retains the + * original name) and an implementation type (which has a $ appended).</li> + * <li>All JSO interface types are empty and mirror the original type + * hierarchy.</li> + * <li>All JSO impl types contain the guts of the original type, except that + * all instance methods are reimplemented as statics.</li> + * <li>Calls sites to JSO types rewritten to dispatch to impl types. Any + * virtual calls are also made static. Static field references to JSO types + * reference static fields in the the impl class.</li> + * <li>JavaScriptObject$ implements all the interface types and is the only + * instantiable type.</li> + * </ol> + * + * @see RewriteRefsToJsoClasses + * @see WriteJsoInterface + * @see WriteJsoImpl + */ +public class HostedModeClassRewriter { + + /** + * Maps instance methods to the class in which they are declared. + */ + public interface InstanceMethodMapper { + + /** + * For a given instance method and declared qualifying class, find the class + * in which that method was first declared. Methods declared on Object will + * return "java/lang/Object". Static methods will always return + * <code>declaredClass</code>. + * + * @param desc a descriptor of the static type of the qualifier + * @param signature the binary signature of the method + * @return the descriptor of the class in which that method was declared + * @throws IllegalArgumentException if the method could not be found + */ + String findDeclaringClass(String desc, String signature); + } + + static final String REFERENCE_FIELD = JsValueGlue.HOSTED_MODE_REFERENCE; + + static final String JAVASCRIPTOBJECT_DESC = JsValueGlue.JSO_CLASS.replace( + '.', '/'); + + static final String JAVASCRIPTOBJECT_IMPL_DESC = JsValueGlue.JSO_IMPL_CLASS.replace( + '.', '/');; + + static String addSyntheticThisParam(String owner, String methodDescriptor) { + return "(L" + owner + ";" + methodDescriptor.substring(1); + } + + private static String toDescriptor(String jsoSubtype) { + return jsoSubtype.replace('.', '/'); + } + + /** + * An unmodifiable set of descriptors containing the implementation form of + * <code>JavaScriptObject</code> and all subclasses. + */ + private final Set<String> jsoImplDescriptors; + + /** + * An unmodifiable set of descriptors containing the interface form of + * <code>JavaScriptObject</code> and all subclasses. + */ + private final Set<String> jsoIntfDescriptors; + + /** + * Maps methods to the class in which they are declared. + */ + private InstanceMethodMapper mapper; + + /** + * Creates a new {@link HostedModeClassRewriter} for a specified set of + * subclasses of JavaScriptObject. + * + * @param jsoSubtypes a set of binary type names representing JavaScriptObject + * and all of its subtypes of + * @param mapper maps methods to the class in which they are declared + */ + public HostedModeClassRewriter(Set<String> jsoSubtypes, + InstanceMethodMapper mapper) { + Set<String> buildJsoIntfDescriptors = new HashSet<String>(); + Set<String> buildJsoImplDescriptors = new HashSet<String>(); + for (String jsoSubtype : jsoSubtypes) { + String desc = toDescriptor(jsoSubtype); + buildJsoIntfDescriptors.add(desc); + buildJsoImplDescriptors.add(desc + "$"); + } + this.jsoIntfDescriptors = Collections.unmodifiableSet(buildJsoIntfDescriptors); + this.jsoImplDescriptors = Collections.unmodifiableSet(buildJsoImplDescriptors); + this.mapper = mapper; + } + + /** + * Returns <code>true</code> if the class is the implementation class for a + * JSO subtype. + */ + public boolean isJsoImpl(String className) { + return jsoImplDescriptors.contains(toDescriptor(className)); + } + + /** + * Returns <code>true</code> if the class is the interface class for a JSO + * subtype. + */ + public boolean isJsoIntf(String className) { + return jsoIntfDescriptors.contains(toDescriptor(className)); + } + + /** + * Performs rewriting transformations on a class. + * + * @param className the name of the class + * @param classBytes the bytes of the class + */ + public byte[] rewrite(String className, byte[] classBytes) { + String desc = toDescriptor(className); + + // The ASM model is to chain a bunch of visitors together. + ClassWriter writer = new ClassWriter(0); + ClassVisitor v = writer; + + // v = new CheckClassAdapter(v); + // v = new TraceClassVisitor(v, new PrintWriter(System.out)); + + v = new RewriteRefsToJsoClasses(v, jsoIntfDescriptors, mapper); + + if (jsoImplDescriptors.contains(desc)) { + v = new WriteJsoImpl(v, jsoIntfDescriptors, mapper); + } else if (jsoIntfDescriptors.contains(desc)) { + v = new WriteJsoInterface(v); + } + + new ClassReader(classBytes).accept(v, 0); + return writer.toByteArray(); + } +}
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteRefsToJsoClasses.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteRefsToJsoClasses.java new file mode 100644 index 0000000..83afe22 --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteRefsToJsoClasses.java
@@ -0,0 +1,151 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.shell.rewrite; + +import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodMapper; + +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.commons.Remapper; + +import java.util.Set; + +/** + * Rewrites references to modified JSO subtypes. + * + * <ol> + * <li>Changes the owner type for instructions that reference items in a JSO + * class to the implementation class.</li> + * <li>Rewrites instance calls to JSO classes into static calls.</li> + * <li>Updates the descriptor for such call sites to includes a synthetic + * <code>this</code> parameter. This modified method has same stack behavior + * as the original instance method.</li> + * </ol> + */ +class RewriteRefsToJsoClasses extends ClassAdapter { + + /** + * A method body rewriter to actually rewrite call sites. + */ + private class MyMethodAdapter extends MethodAdapter { + + private Remapper remapper = new Remapper() { + @Override + public String map(String typeName) { + if (jsoDescriptors.contains(typeName)) { + return HostedModeClassRewriter.JAVASCRIPTOBJECT_IMPL_DESC; + } + return typeName; + } + }; + + public MyMethodAdapter(MethodVisitor mv) { + super(mv); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, + String desc) { + if (jsoDescriptors.contains(owner)) { + // Change the owner to the rewritten class. + owner += "$"; + } + super.visitFieldInsn(opcode, owner, name, desc); + } + + @Override + public void visitLdcInsn(Object cst) { + cst = remapper.mapValue(cst); + super.visitLdcInsn(cst); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, + String desc) { + if (jsoDescriptors.contains(owner)) { + // Find the class that actually declared the method. + if (opcode == Opcodes.INVOKEVIRTUAL) { + owner = mapper.findDeclaringClass(owner, name + desc); + } + if (!owner.equals("java/lang/Object")) { + if (opcode == Opcodes.INVOKEVIRTUAL + || opcode == Opcodes.INVOKESPECIAL) { + // Instance/super call to JSO; rewrite as static. + opcode = Opcodes.INVOKESTATIC; + desc = HostedModeClassRewriter.addSyntheticThisParam(owner, desc); + name += "$"; + } + // Change the owner to implementation class. + owner += "$"; + } + } + super.visitMethodInsn(opcode, owner, name, desc); + } + + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + desc = remapper.mapType(desc); + super.visitMultiANewArrayInsn(desc, dims); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + if (opcode == Opcodes.ANEWARRAY) { + type = remapper.mapType(type); + } + super.visitTypeInsn(opcode, type); + } + } + + /** + * An unmodifiable set of descriptors containing <code>JavaScriptObject</code> + * and all subclasses. + */ + protected final Set<String> jsoDescriptors; + + /** + * Maps methods to the class in which they are declared. + */ + private InstanceMethodMapper mapper; + + /** + * Construct a new rewriter instance. + * + * @param cv the visitor to chain to + * @param jsoDescriptors an unmodifiable set of descriptors containing + * <code>JavaScriptObject</code> and all subclasses + * @param mapper maps methods to the class in which they are declared + */ + public RewriteRefsToJsoClasses(ClassVisitor cv, Set<String> jsoDescriptors, + InstanceMethodMapper mapper) { + super(cv); + this.jsoDescriptors = jsoDescriptors; + this.mapper = mapper; + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + // Wrap the returned method visitor in my own. + MethodVisitor mv = super.visitMethod(access, name, desc, signature, + exceptions); + return new MyMethodAdapter(mv); + } + +}
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoImpl.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoImpl.java new file mode 100644 index 0000000..82ae49b --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoImpl.java
@@ -0,0 +1,130 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.shell.rewrite; + +import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodMapper; + +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.ArrayList; +import java.util.Set; + +/** + * Writes the implementation class for a JSO type. + * + * <ol> + * <li>The new type has the same name as the old type with a '$' appended.</li> + * <li>The new type's superclass is Object.</li> + * <li>All instance methods in the original type become static methods taking + * an explicit <code>this</code> parameter. Such methods have the same stack + * behavior as the original.</li> + * <li>JavaScriptObject itself gets a new synthetic field to store the + * underlying hosted mode reference.</li> + * </ol> + */ +class WriteJsoImpl extends ClassAdapter { + + /** + * An unmodifiable set of descriptors containing <code>JavaScriptObject</code> + * and all subclasses. + */ + protected final Set<String> jsoDescriptors; + + /** + * Maps methods to the class in which they are declared. + */ + private InstanceMethodMapper mapper; + + /** + * The original name of the class being visited. + */ + private String originalName; + + /** + * Construct a new rewriter instance. + * + * @param cv the visitor to chain to + * @param jsoDescriptors an unmodifiable set of descriptors containing + * <code>JavaScriptObject</code> and all subclasses + * @param mapper maps methods to the class in which they are declared + */ + public WriteJsoImpl(ClassVisitor cv, Set<String> jsoDescriptors, + InstanceMethodMapper mapper) { + super(cv); + this.jsoDescriptors = jsoDescriptors; + this.mapper = mapper; + } + + @Override + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { + originalName = name; + + // JavaScriptObject$ must implement all JSO interface types. + if (isJavaScriptObject()) { + ArrayList<String> jsoDescList = new ArrayList<String>(); + jsoDescList.addAll(jsoDescriptors); + interfaces = jsoDescList.toArray(new String[jsoDescList.size()]); + } else { + interfaces = null; + } + + super.visit(version, access, name + '$', signature, "java/lang/Object", + interfaces); + + if (isJavaScriptObject()) { + FieldVisitor fv = visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, + HostedModeClassRewriter.REFERENCE_FIELD, "Ljava/lang/Object;", null, + null); + if (fv != null) { + fv.visitEnd(); + } + } + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + boolean isCtor = "<init>".equals(name); + if (!isJavaScriptObject() && isCtor) { + // Don't copy over constructors except for JavaScriptObject itself. + return null; + } + if (!isCtor && !isStatic(access) && !isObjectMethod(name + desc)) { + access |= Opcodes.ACC_STATIC; + desc = HostedModeClassRewriter.addSyntheticThisParam(originalName, desc); + name = name + "$"; + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + private boolean isJavaScriptObject() { + return originalName.equals(HostedModeClassRewriter.JAVASCRIPTOBJECT_DESC); + } + + private boolean isObjectMethod(String signature) { + return "java/lang/Object".equals(mapper.findDeclaringClass(originalName, + signature)); + } + + private boolean isStatic(int access) { + return (access & Opcodes.ACC_STATIC) != 0; + } +}
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoInterface.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoInterface.java new file mode 100644 index 0000000..de496fd --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/WriteJsoInterface.java
@@ -0,0 +1,89 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.shell.rewrite; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Writes an empty interface to stand in for a JSO type. + */ +class WriteJsoInterface extends ClassAdapter { + /** + * Construct a instance. + * + * @param cv the visitor to chain to + */ + public WriteJsoInterface(ClassVisitor cv) { + super(cv); + } + + @Override + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { + if ("java/lang/Object".equals(superName)) { + interfaces = null; + } else { + interfaces = new String[] {superName}; + } + super.visit(version, Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE, name, + signature, "java/lang/Object", interfaces); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return null; + } + + @Override + public void visitAttribute(Attribute attr) { + } + + @Override + public void visitEnd() { + super.visitEnd(); + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, + String signature, Object value) { + return null; + } + + @Override + public void visitInnerClass(String name, String outerName, String innerName, + int access) { + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + return null; + } + + @Override + public void visitOuterClass(String owner, String name, String desc) { + } + + @Override + public void visitSource(String source, String debug) { + } +}
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java index 096090f..7c6e2b5 100644 --- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java +++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -121,9 +121,13 @@ * Performs an array assignment, checking for valid index and type. */ public static Object setCheck(Array array, int index, Object value) { - if (value != null && array.queryId != 0 - && !Cast.instanceOf(value, array.queryId)) { - throw new ArrayStoreException(); + if (value != null) { + if (array.queryId > 0 && !Cast.canCastUnsafe(value.typeId, array.queryId)) { + throw new ArrayStoreException(); + } + if (array.queryId < 0 && Cast.isJavaObject(value)) { + throw new ArrayStoreException(); + } } return set(array, index, value); }
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java index f9c60d1..e0177fc 100644 --- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java +++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -1,5 +1,5 @@ /* - * Copyright 2006 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -15,8 +15,6 @@ */ package com.google.gwt.lang; -import com.google.gwt.core.client.JavaScriptObject; - // CHECKSTYLE_NAMING_OFF: Uses legacy conventions of underscore prefixes. /** @@ -28,27 +26,57 @@ // magic magic magic protected static Object typeIdArray; - protected static native boolean canCast(int srcId, int dstId) /*-{ - // Force to boolean. - return !!(srcId && @com.google.gwt.lang.Cast::typeIdArray[srcId][dstId]); + static native boolean canCast(int srcId, int dstId) /*-{ + return srcId && !!@com.google.gwt.lang.Cast::typeIdArray[srcId][dstId]; + }-*/; + + /** + * Danger: value not coerced to boolean; use the result only in a boolean + * context. + */ + static native boolean canCastUnsafe(int srcId, int dstId) /*-{ + return srcId && @com.google.gwt.lang.Cast::typeIdArray[srcId][dstId]; }-*/; static native String charToString(char x) /*-{ return String.fromCharCode(x); }-*/; - static native Object dynamicCast(Object src, int dstId) /*-{ - if (src != null) - @com.google.gwt.lang.Cast::canCast(II)(src.@java.lang.Object::typeId,dstId) - || @com.google.gwt.lang.Cast::throwClassCastException()(); - + static Object dynamicCast(Object src, int dstId) { + if (src != null && !canCastUnsafe(src.typeId, dstId)) { + throw new ClassCastException(); + } return src; - }-*/; + } - static native boolean instanceOf(Object src, int dstId) /*-{ - return (src != null) && - @com.google.gwt.lang.Cast::canCast(II)(src.@java.lang.Object::typeId,dstId); - }-*/; + /** + * Allow a cast to JSO only if there's no type ID. + */ + static Object dynamicCastJso(Object src) { + if (src != null && isJavaObject(src)) { + throw new ClassCastException(); + } + return src; + } + + static boolean instanceOf(Object src, int dstId) { + return (src != null) && canCast(src.typeId, dstId); + } + + /** + * Instance of JSO only if there's no type ID. + */ + static boolean instanceOfJso(Object src) { + return (src != null) && isJavaScriptObject(src); + } + + static boolean isJavaObject(Object src) { + return src.typeMarker == getNullMethod() || src.typeId == 2; + } + + static boolean isJavaScriptObject(Object src) { + return src.typeMarker != getNullMethod() && src.typeId != 2; + } /** * See JLS 5.1.3. @@ -120,14 +148,6 @@ } /** - * Unconditionally throw a {@link ClassCastException}. Called from {#link - * {@link #dynamicCast(Object, int)}. - */ - static Object throwClassCastException() throws ClassCastException { - throw new ClassCastException(); - } - - /** * Check a statically false cast, which can succeed if the argument is null. * Called by compiler-generated code based on static type information. */ @@ -139,26 +159,8 @@ return o; } - static native JavaScriptObject wrapJSO(JavaScriptObject jso, Object seed) /*-{ - _ = seed.prototype; - - // WEIRD: The inequality below represents the fact that superclasses always - // have typeId < any subclass typeId. This code lets us wrap the same JSO - // "tighter" but never "looser". This would break if the compiler did not - // ensure that superclass ids are less than subclass ids. - // - // Note also that the inequality is false (and thus allows wrapping) if - // jso's typeId is undefined, because (undefined < positive int). - - if (jso && !(jso.@java.lang.Object::typeId >= _.@java.lang.Object::typeId)) { - for (var i in _) { - // don't clobber toString - if (i != 'toString' ) { - jso[i] = _[i]; - } - } - } - return jso; + private static native Object getNullMethod() /*-{ + return @null::nullMethod(); }-*/; }
diff --git a/dev/core/test/com/google/gwt/dev/jdt/test/ByteCodeCompilerTest.java b/dev/core/test/com/google/gwt/dev/jdt/ByteCodeCompilerTest.java similarity index 99% rename from dev/core/test/com/google/gwt/dev/jdt/test/ByteCodeCompilerTest.java rename to dev/core/test/com/google/gwt/dev/jdt/ByteCodeCompilerTest.java index 4d51f30..0f24786 100644 --- a/dev/core/test/com/google/gwt/dev/jdt/test/ByteCodeCompilerTest.java +++ b/dev/core/test/com/google/gwt/dev/jdt/ByteCodeCompilerTest.java
@@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.google.gwt.dev.jdt.test; +package com.google.gwt.dev.jdt; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException;
diff --git a/dev/core/test/com/google/gwt/dev/jdt/JSORestrictionsTest.java b/dev/core/test/com/google/gwt/dev/jdt/JSORestrictionsTest.java new file mode 100644 index 0000000..24da3e1 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jdt/JSORestrictionsTest.java
@@ -0,0 +1,233 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.jdt; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.dev.jdt.StaticCompilationUnitProvider; +import com.google.gwt.dev.jdt.TypeOracleBuilder; + +import junit.framework.TestCase; + +public class JSORestrictionsTest extends TestCase { + + public void testInstanceField() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy extends JavaScriptObject {\n"); + buggyCode.append(" protected Buggy() { }\n"); + buggyCode.append(" int myStsate = 3;\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 4: " + + JSORestrictionsChecker.ERR_INSTANCE_FIELD); + } + + public void testMultiArgConstructor() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public final class Buggy extends JavaScriptObject {\n"); + buggyCode.append(" protected Buggy(int howBuggy) { }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 3: " + + JSORestrictionsChecker.ERR_CONSTRUCTOR_WITH_PARAMETERS); + } + + public void testNew() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy {\n"); + buggyCode.append(" public static class MyJSO extends JavaScriptObject { \n"); + buggyCode.append(" protected MyJSO() { }\n"); + buggyCode.append(" }\n"); + buggyCode.append(" MyJSO makeOne() { return new MyJSO(); }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 6: " + + JSORestrictionsChecker.ERR_NEW_JSO); + } + + public void testNoConstructor() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy extends JavaScriptObject {\n"); + buggyCode.append("}\n"); + + // The public constructor is implicit. + shouldGenerateError(buggyCode, "Line 2: " + + JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR); + } + + public void testNoInterfaces() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy {\n"); + buggyCode.append(" static interface Squeaks {\n"); + buggyCode.append(" public void squeak();\n"); + buggyCode.append(" }\n"); + buggyCode.append(" static class Squeaker extends JavaScriptObject implements Squeaks {\n"); + buggyCode.append(" public final void squeak() { }\n"); + buggyCode.append(" protected Squeaker() { }\n"); + buggyCode.append(" }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 6: " + + JSORestrictionsChecker.errInterfaceWithMethods("Buggy.Squeaks")); + } + + public void testNonEmptyConstructor() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy extends JavaScriptObject {\n"); + buggyCode.append(" protected Buggy() { while(true) { } }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 3: " + + JSORestrictionsChecker.ERR_NONEMPTY_CONSTRUCTOR); + } + + public void testNonFinalMethod() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy extends JavaScriptObject {\n"); + buggyCode.append(" int nonfinal() { return 10; }\n"); + buggyCode.append(" protected Buggy() { }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 3: " + + JSORestrictionsChecker.ERR_INSTANCE_METHOD_NONFINAL); + } + + public void testNonProtectedConstructor() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy extends JavaScriptObject {\n"); + buggyCode.append(" Buggy() { }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 3: " + + JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR); + } + + public void testNonStaticInner() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy {\n"); + buggyCode.append(" public class MyJSO extends JavaScriptObject {\n"); + buggyCode.append(" protected MyJSO() { }\n"); + buggyCode.append(" }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 3: " + + JSORestrictionsChecker.ERR_IS_NONSTATIC_NESTED); + } + + public void testNoOverride() throws UnableToCompleteException { + StringBuffer buggyCode = new StringBuffer(); + buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n"); + buggyCode.append("public class Buggy extends JavaScriptObject {\n"); + buggyCode.append(" protected Buggy() { }\n"); + buggyCode.append(" public final Object clone() { return this; }\n"); + buggyCode.append("}\n"); + + shouldGenerateError(buggyCode, "Line 4: " + + JSORestrictionsChecker.ERR_OVERRIDDEN_METHOD); + } + + private void addStandardCups(TypeOracleBuilder builder) + throws UnableToCompleteException { + StringBuffer code = new StringBuffer(); + code.append("package java.lang;\n"); + code.append("public class Object {\n"); + code.append(" public String toString() { return \"Object\"; }\n"); + code.append(" public Object clone() { return this; } "); + code.append("}\n"); + + StaticCompilationUnitProvider objectCup = new StaticCompilationUnitProvider( + "java.lang", "Object", code.toString().toCharArray()); + + code.setLength(0); + code.append("package java.lang;\n"); + code.append("public final class String {\n"); + code.append(" public int length() { return 0; }\n"); + code.append("}\n"); + + StaticCompilationUnitProvider stringCup = new StaticCompilationUnitProvider( + "java.lang", "String", code.toString().toCharArray()); + + code.setLength(0); + code.append("package java.lang;\n"); + code.append("public interface Serializable { }\n"); + + StaticCompilationUnitProvider serializableCup = new StaticCompilationUnitProvider( + "java.lang", "Serializable", code.toString().toCharArray()); + + code.setLength(0); + code.append("package com.google.gwt.core.client;\n"); + code.append("public class JavaScriptObject {\n"); + code.append(" protected JavaScriptObject() { }\n"); + code.append("}\n"); + + StaticCompilationUnitProvider jsoCup = new StaticCompilationUnitProvider( + "com.google.gwt.core.client", "JavaScriptObject", + code.toString().toCharArray()); + + builder.addCompilationUnit(objectCup); + builder.addCompilationUnit(stringCup); + builder.addCompilationUnit(serializableCup); + builder.addCompilationUnit(jsoCup); + } + + /** + * Test that when compiling buggyCode, the TypeOracleBuilder emits + * expectedError somewhere in its output. The code should define a class named + * Buggy. + */ + private void shouldGenerateError(CharSequence buggyCode, + final String expectedError) throws UnableToCompleteException { + TypeOracleBuilder builder = new TypeOracleBuilder(); + addStandardCups(builder); + + StaticCompilationUnitProvider buggyCup = new StaticCompilationUnitProvider( + "", "Buggy", buggyCode.toString().toCharArray()); + builder.addCompilationUnit(buggyCup); + + final boolean[] gotExpectedError = new boolean[1]; + + TreeLogger testLogger = new TreeLogger() { + public TreeLogger branch(Type type, String msg, Throwable caught) { + return this; + } + + public boolean isLoggable(Type type) { + return type == ERROR; + } + + public void log(Type type, String msg, Throwable caught) { + if (type == ERROR && msg.startsWith("Line ")) { + assertEquals(null, caught); + assertEquals(expectedError, msg); + gotExpectedError[0] = true; + } + } + }; + + builder.build(testLogger); + assertTrue("Failed to get expected error: '" + expectedError + "'", + gotExpectedError[0]); + } +}
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java b/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java index c312f2e..7c98a96 100644 --- a/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java +++ b/dev/linux/src/com/google/gwt/dev/shell/moz/GeckoDispatchAdapter.java
@@ -110,7 +110,8 @@ throw new RuntimeException("Cannot reassign method " + name); } Field field = javaDispatch.getField(dispId); - Object val = JsValueGlue.get(jsValue, field.getType(), "setField"); + Object val = JsValueGlue.get(jsValue, classLoader, field.getType(), + "setField"); javaDispatch.setFieldValue(dispId, val); } }
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java index a488495..36f0798 100644 --- a/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java +++ b/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -156,6 +156,8 @@ protected static native double _getNumber(int jsRootedValue); + protected static native int _getObjectPointer(int jsRootedValue); + protected static native String _getString(int jsRootedValue); protected static native String _getTypeString(int jsRootedValue); @@ -290,6 +292,11 @@ return _getInt(jsRootedValue); } + @Override + public int getJavaScriptObjectPointer() { + return _getObjectPointer(jsRootedValue); + } + /** * Returns the underlying JavaScript object pointer as an integer. */ @@ -433,8 +440,6 @@ * (non-Javadoc) * * @see com.google.gwt.dev.shell.JsValue#setByte(byte) - * - * TODO(jat): remove this method */ @Override public void setByte(byte val) { @@ -445,8 +450,6 @@ * (non-Javadoc) * * @see com.google.gwt.dev.shell.JsValue#setChar(char) - * - * TODO(jat): remove this method */ @Override public void setChar(char val) { @@ -487,8 +490,6 @@ * (non-Javadoc) * * @see com.google.gwt.dev.shell.JsValue#setShort(short) - * - * TODO(jat): remove this method */ @Override public void setShort(short val) { @@ -543,7 +544,7 @@ * java.lang.Object) */ @Override - public void setWrappedJavaObject(CompilingClassLoader cl, Object val) { + public <T> void setWrappedJavaObject(CompilingClassLoader cl, T val) { if (val == null) { setNull(); return;
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java index 24f0079..716a39f 100644 --- a/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java +++ b/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java
@@ -114,7 +114,7 @@ * @param methodName the method name on jsthis to call * @param jsthis A wrapped java object as a JsRootedValue pointer * @param jsargs the arguments to pass to the method as JsRootedValue pointers - * + * @param retval the jsvalue to write the result into * @throws RuntimeException if the invoke fails */ public static void invoke(int scriptObject, String methodName, int jsthis,
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/MethodDispatch.java b/dev/linux/src/com/google/gwt/dev/shell/moz/MethodDispatch.java index 165a34e..805e419 100644 --- a/dev/linux/src/com/google/gwt/dev/shell/moz/MethodDispatch.java +++ b/dev/linux/src/com/google/gwt/dev/shell/moz/MethodDispatch.java
@@ -67,10 +67,12 @@ } Object jthis = null; if (method.needsThis()) { - jthis = JsValueGlue.get(jsthis, method.getDeclaringClass(), "invoke this"); + jthis = JsValueGlue.get(jsthis, classLoader, method.getDeclaringClass(), + "invoke this"); } for (int i = 0; i < argc; ++i) { - args[i] = JsValueGlue.get(jsargs[i], paramTypes[i], "invoke arguments"); + args[i] = JsValueGlue.get(jsargs[i], classLoader, paramTypes[i], + "invoke arguments"); } try { Object result;
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/JsValueSaf.java b/dev/mac/src/com/google/gwt/dev/shell/mac/JsValueSaf.java index afedef1..6a0f4c1 100644 --- a/dev/mac/src/com/google/gwt/dev/shell/mac/JsValueSaf.java +++ b/dev/mac/src/com/google/gwt/dev/shell/mac/JsValueSaf.java
@@ -35,8 +35,8 @@ public class JsValueSaf extends JsValue { private static class JsCleanupSaf implements JsCleanup { - private final int jsval; private final Throwable creationStackTrace; + private final int jsval; /** * Create a cleanup object which takes care of cleaning up the underlying JS @@ -59,16 +59,16 @@ } } - /* - * Underlying JSValue* as an integer. - */ - private int jsval; - /* * Stores a stack trace of the creation site for debugging. */ private Throwable creationStackTrace; + /* + * Underlying JSValue* as an integer. + */ + private int jsval; + /** * Create a Java wrapper around an undefined JSValue. */ @@ -95,7 +95,16 @@ public int getInt() { int curExecState = LowLevelSaf.getExecState(); return LowLevelSaf.coerceToInt(curExecState, jsval); - } + } + + @Override + public int getJavaScriptObjectPointer() { + if (isJavaScriptObject()) { + return jsval; + } else { + return 0; + } + } public int getJsValue() { return jsval; @@ -195,8 +204,8 @@ } /** - * Set a new value. Unlock the previous value, but do *not* lock the new - * value (see class comment). + * Set a new value. Unlock the previous value, but do *not* lock the new value + * (see class comment). * * @param jsval the new value to set */ @@ -204,7 +213,7 @@ LowLevelSaf.gcUnlock(this.jsval, creationStackTrace); init(jsval); } - + @Override public void setNull() { setJsVal(LowLevelSaf.jsNull()); @@ -227,10 +236,10 @@ @Override public void setValue(JsValue other) { - int jsvalOther = ((JsValueSaf)other).jsval; + int jsvalOther = ((JsValueSaf) other).jsval; /* - * Add another lock to this jsval, since both the other object and this - * one will eventually release it. + * Add another lock to this jsval, since both the other object and this one + * will eventually release it. */ LowLevelSaf.gcLock(jsvalOther); setJsVal(jsvalOther); @@ -243,7 +252,7 @@ setNull(); return; } else if (val instanceof DispatchObject) { - dispObj = (DispatchObject)val; + dispObj = (DispatchObject) val; } else { dispObj = new WebKitDispatchAdapter(cl, val); } @@ -257,11 +266,12 @@ /** * Initialization helper method. + * * @param jsval underlying JSValue* */ private void init(int jsval) { this.jsval = jsval; - + // only create and fill in the stack trace if we are debugging if (LowLevelSaf.debugObjectCreation) { this.creationStackTrace = new Throwable();
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/MethodDispatch.java b/dev/mac/src/com/google/gwt/dev/shell/mac/MethodDispatch.java index 2d3152d..c6b5661 100644 --- a/dev/mac/src/com/google/gwt/dev/shell/mac/MethodDispatch.java +++ b/dev/mac/src/com/google/gwt/dev/shell/mac/MethodDispatch.java
@@ -59,11 +59,12 @@ } Object jthis = null; if (method.needsThis()) { - jthis = JsValueGlue.get(jsthis, method.getDeclaringClass(), - "invoke this"); + jthis = JsValueGlue.get(jsthis, classLoader, + method.getDeclaringClass(), "invoke this"); } for (int i = 0; i < argc; ++i) { - args[i] = JsValueGlue.get(jsargs[i], paramTypes[i], "invoke args"); + args[i] = JsValueGlue.get(jsargs[i], classLoader, paramTypes[i], + "invoke args"); } try { Object result;
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java b/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java index 767a4bf..d1cb4de 100644 --- a/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java +++ b/dev/mac/src/com/google/gwt/dev/shell/mac/WebKitDispatchAdapter.java
@@ -61,9 +61,6 @@ this.classLoader = cl; } - /* (non-Javadoc) - * @see com.google.gwt.dev.shell.mac.LowLevelSaf.DispatchObject#getField(java.lang.String) - */ public int getField(String name) { int dispId = classLoader.getDispId(name); if (dispId < 0) { @@ -87,16 +84,10 @@ } } - /* (non-Javadoc) - * @see com.google.gwt.dev.shell.mac.LowLevelSaf.DispatchObject#getTarget() - */ public Object getTarget() { return javaDispatch.getTarget(); } - /* (non-Javadoc) - * @see com.google.gwt.dev.shell.mac.LowLevelSaf.DispatchObject#setField(java.lang.String, int) - */ public void setField(String name, int value) { JsValue jsValue = new JsValueSaf(value); int dispId = classLoader.getDispId(name); @@ -108,7 +99,8 @@ throw new RuntimeException("Cannot reassign method " + name); } Field field = javaDispatch.getField(dispId); - Object val = JsValueGlue.get(jsValue, field.getType(), "setField"); + Object val = JsValueGlue.get(jsValue, classLoader, field.getType(), + "setField"); javaDispatch.setFieldValue(dispId, val); }
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchImpl.java b/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchImpl.java index 09103b1..9223168 100644 --- a/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchImpl.java +++ b/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchImpl.java
@@ -116,7 +116,7 @@ Variant[] params, MethodAdaptor method) throws InstantiationException, InvocationTargetException, HResultException { // TODO: make sure we have enough args! It's okay if there are too many. - Object[] javaParams = SwtOleGlue.convertVariantsToObjects( + Object[] javaParams = SwtOleGlue.convertVariantsToObjects(cl, method.getParameterTypes(), params, "Calling method '" + method.getName() + "'"); @@ -149,14 +149,7 @@ } } - // Convert it to a variant (if the return type is void, return - // a VT_EMPTY variant -- 'undefined' in JavaScript). - // - Class<?> returnType = method.getReturnType(); - if (returnType.equals(Void.TYPE)) { - return new Variant(); - } - return SwtOleGlue.convertObjectToVariant(cl, returnType, result); + return SwtOleGlue.convertObjectToVariant(cl, method.getReturnType(), result); } protected int refCount;
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchProxy.java b/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchProxy.java index 8c55c2a..05e83cc 100644 --- a/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchProxy.java +++ b/dev/windows/src/com/google/gwt/dev/shell/ie/IDispatchProxy.java
@@ -170,7 +170,7 @@ field.getType(), javaDispatch.getFieldValue(dispId)); } else if ((flags & (COM.DISPATCH_PROPERTYPUT | COM.DISPATCH_PROPERTYPUTREF)) != 0) { javaDispatch.setFieldValue(dispId, JsValueGlue.get(new JsValueIE6( - params[0]), field.getType(), "Setting field '" + params[0]), classLoader, field.getType(), "Setting field '" + field.getName() + "'")); return new Variant(); }
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/JsValueIE6.java b/dev/windows/src/com/google/gwt/dev/shell/ie/JsValueIE6.java index d4bad32..7682c8f 100644 --- a/dev/windows/src/com/google/gwt/dev/shell/ie/JsValueIE6.java +++ b/dev/windows/src/com/google/gwt/dev/shell/ie/JsValueIE6.java
@@ -26,7 +26,6 @@ import org.eclipse.swt.internal.ole.win32.IDispatch; import org.eclipse.swt.internal.ole.win32.IUnknown; import org.eclipse.swt.internal.win32.OS; -import org.eclipse.swt.ole.win32.OleAutomation; import org.eclipse.swt.ole.win32.Variant; /** @@ -42,7 +41,9 @@ } public void doCleanup() { - variant.dispose(); + if (variant != null) { + variant.dispose(); + } } } @@ -65,6 +66,52 @@ return variant; } + /** + * Copied with modification from OleAutomation.getIDsOfNames(). The reason we + * don't use that method directly is that querying for typeInfo that occurs in + * the OleAutomation(IDispatch) constructor will cause a VM crash on some + * kinds of JavaScript objects, such as the window.alert function. So we do it + * by hand. + */ + private static int[] oleAutomationGetIdsOfNames(IDispatch dispatch) { + String[] names = new String[] {"valueOf"}; + int[] ids = new int[names.length]; + int result = dispatch.GetIDsOfNames(new GUID(), names, names.length, + COM.LOCALE_USER_DEFAULT, ids); + if (result != COM.S_OK) { + return null; + } + return ids; + } + + /** + * Copied with modification from OleAutomation.invoke(). The reason we don't + * use that method directly is that querying for typeInfo that occurs in the + * OleAutomation(IDispatch) constructor will cause a VM crash on some kinds of + * JavaScript objects, such as the window.alert function. So we do it by hand. + */ + private static Variant oleAutomationInvoke(IDispatch dispatch, int dispId) { + int pVarResultAddress = 0; + try { + pVarResultAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, + Variant.sizeof); + int[] pArgErr = new int[1]; + int hr = dispatch.Invoke(dispId, new GUID(), COM.LOCALE_USER_DEFAULT, + COM.DISPATCH_METHOD, new DISPPARAMS(), pVarResultAddress, + new EXCEPINFO(), pArgErr); + + if (hr >= COM.S_OK) { + return Variant.win32_new(pVarResultAddress); + } + } finally { + if (pVarResultAddress != 0) { + COM.VariantClear(pVarResultAddress); + OS.GlobalFree(pVarResultAddress); + } + } + return null; + } + // a null variant means the JsValue is undefined (void) private Variant variant; @@ -104,6 +151,15 @@ return variant.getInt(); } + @Override + public int getJavaScriptObjectPointer() { + if (isJavaScriptObject()) { + return variant.getDispatch().getAddress(); + } else { + return 0; + } + } + /* * (non-Javadoc) * @@ -276,25 +332,22 @@ if (variant.getType() != COM.VT_DISPATCH) { return false; } - OleAutomation auto = null; + + // see if it has a valueOf method + IDispatch dispatch = variant.getDispatch(); + int[] ids = oleAutomationGetIdsOfNames(dispatch); + if (ids == null) { + return false; + } Variant result = null; try { - auto = new OleAutomation(variant.getDispatch()); - // see if it has a valueOf method - int[] ids = auto.getIDsOfNames(new String[] {"valueOf"}); - if (ids == null) { - return false; - } - result = auto.invoke(ids[0]); + result = oleAutomationInvoke(dispatch, ids[0]); /* * If the return type of the valueOf method is string, we assume it is a * String wrapper object. */ return result.getType() == COM.VT_BSTR; } finally { - if (auto != null) { - auto.dispose(); - } if (result != null) { result.dispose(); } @@ -466,44 +519,26 @@ variant = val; } - private <T> T tryToUnwrapWrappedJavaObject() { - /* - * This implementation copied from OleAutomation.invoke(). We used to have a - * varArg.getAutomation().invoke() implementation, but it turns out the - * querying for typeInfo that occurs in the OleAutomation(IDispatch) - * constructor will cause a VM crash on some kinds of JavaScript objects, - * such as the window.alert function. So we do it by hand. - */ - IDispatch dispatch = variant.getDispatch(); - Variant result = new Variant(); - int pVarResultAddress = 0; + private Object tryToUnwrapWrappedJavaObject() { int globalRef = 0; + Variant result = null; try { - pVarResultAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, - Variant.sizeof); - int[] pArgErr = new int[1]; - int hr = dispatch.Invoke(IDispatchProxy.DISPID_MAGIC_GETGLOBALREF, - new GUID(), COM.LOCALE_USER_DEFAULT, COM.DISPATCH_METHOD, - new DISPPARAMS(), pVarResultAddress, new EXCEPINFO(), pArgErr); - - if (hr >= COM.S_OK) { - result = Variant.win32_new(pVarResultAddress); + result = oleAutomationInvoke(variant.getDispatch(), + IDispatchProxy.DISPID_MAGIC_GETGLOBALREF); + if (result != null) { globalRef = result.getInt(); - } - if (globalRef != 0) { - // This is really a Java object being passed back via an IDispatchProxy. - IDispatchProxy proxy = (IDispatchProxy) LowLevel.objFromGlobalRefInt(globalRef); - return (T) proxy.getTarget(); + if (globalRef != 0) { + // This is really a Java object being passed back via an + // IDispatchProxy. + IDispatchProxy proxy = (IDispatchProxy) LowLevel.objFromGlobalRefInt(globalRef); + return proxy.getTarget(); + } } return null; } finally { if (result != null) { result.dispose(); } - if (pVarResultAddress != 0) { - COM.VariantClear(pVarResultAddress); - OS.GlobalFree(pVarResultAddress); - } } }
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/MethodDispatch.java b/dev/windows/src/com/google/gwt/dev/shell/ie/MethodDispatch.java index 10aaaed..2d642e9 100644 --- a/dev/windows/src/com/google/gwt/dev/shell/ie/MethodDispatch.java +++ b/dev/windows/src/com/google/gwt/dev/shell/ie/MethodDispatch.java
@@ -134,7 +134,7 @@ * methods). If method is static, it can be null. */ Object jthis = JsValueGlue.get(new JsValueIE6(params[0]), - method.getDeclaringClass(), "this"); + classLoader, method.getDeclaringClass(), "this"); Variant[] otherParams = new Variant[params.length - 1]; System.arraycopy(params, 1, otherParams, 0, otherParams.length); return callMethod(classLoader, jthis, otherParams, method);
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/SwtOleGlue.java b/dev/windows/src/com/google/gwt/dev/shell/ie/SwtOleGlue.java index 432f8cd..5f09e9a 100644 --- a/dev/windows/src/com/google/gwt/dev/shell/ie/SwtOleGlue.java +++ b/dev/windows/src/com/google/gwt/dev/shell/ie/SwtOleGlue.java
@@ -49,12 +49,12 @@ /** * Converts an array of variants to their equivalent java objects. */ - public static Object[] convertVariantsToObjects(Class<?>[] argTypes, - Variant[] varArgs, String msgPrefix) { + public static Object[] convertVariantsToObjects(CompilingClassLoader cl, + Class<?>[] argTypes, Variant[] varArgs, String msgPrefix) { Object[] javaArgs = new Object[Math.min(varArgs.length, argTypes.length)]; for (int i = 0; i < javaArgs.length; i++) { try { - Object javaArg = JsValueGlue.get(new JsValueIE6(varArgs[i]), + Object javaArg = JsValueGlue.get(new JsValueIE6(varArgs[i]), cl, argTypes[i], msgPrefix); javaArgs[i] = javaArg; } catch (IllegalArgumentException e) { @@ -169,11 +169,11 @@ /** * Convert a Java string to a COM BSTR. * - * Wrapper for the OS' SysAllocStringLen(), since SysAllocString() is not - * safe for embedded nulls. + * Wrapper for the OS' SysAllocStringLen(), since SysAllocString() is not safe + * for embedded nulls. */ public static int sysAllocString(String s) { return COM.SysAllocStringLen(s.toCharArray(), s.length()); } - + }
diff --git a/eclipse/dev/linux/.classpath b/eclipse/dev/linux/.classpath index 31ef93f..ab22cb4 100644 --- a/eclipse/dev/linux/.classpath +++ b/eclipse/dev/linux/.classpath
@@ -4,11 +4,13 @@ <classpathentry kind="src" path="core/test"/> <classpathentry kind="src" path="linux/src"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip" kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.gtk-linux-3.2.1.src.zip" kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.gtk-linux-3.2.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip" kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip" kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip" kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.gtk-linux-3.2.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.gtk-linux-3.2.1.src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/objectweb/asm-3.1.jar" sourcepath="/GWT_TOOLS/lib/objectweb/asm-3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/objectweb/asm-commons-3.1.jar" sourcepath="/GWT_TOOLS/lib/objectweb/asm-3.1-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-optional-1.0.jar"/>
diff --git a/eclipse/dev/mac/.classpath b/eclipse/dev/mac/.classpath index 59479a0..27a6e1e 100644 --- a/eclipse/dev/mac/.classpath +++ b/eclipse/dev/mac/.classpath
@@ -4,11 +4,13 @@ <classpathentry kind="src" path="core/test"/> <classpathentry kind="src" path="mac/src"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip" kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.src.zip" kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip" kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip" kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip" kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/objectweb/asm-3.1.jar" sourcepath="/GWT_TOOLS/lib/objectweb/asm-3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/objectweb/asm-commons-3.1.jar" sourcepath="/GWT_TOOLS/lib/objectweb/asm-3.1-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-optional-1.0.jar"/>
diff --git a/eclipse/dev/windows/.classpath b/eclipse/dev/windows/.classpath index 57f7f6f..35c95e8 100644 --- a/eclipse/dev/windows/.classpath +++ b/eclipse/dev/windows/.classpath
@@ -4,11 +4,13 @@ <classpathentry kind="src" path="core/test"/> <classpathentry kind="src" path="windows/src"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip" kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.win32-win32-3.2.1.src.zip" kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.win32-win32-3.2.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip" kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip" kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar"/> - <classpathentry sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip" kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.win32-win32-3.2.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.win32-win32-3.2.1.src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/jdt-3.3.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/jdt-3.3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/objectweb/asm-3.1.jar" sourcepath="/GWT_TOOLS/lib/objectweb/asm-3.1-src.zip"/> + <classpathentry kind="var" path="GWT_TOOLS/lib/objectweb/asm-commons-3.1.jar" sourcepath="/GWT_TOOLS/lib/objectweb/asm-3.1-src.zip"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/> <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-optional-1.0.jar"/>
diff --git a/eclipse/jni/linux/.cdtbuild b/eclipse/jni/linux/.cdtbuild deleted file mode 100644 index 95a1c73..0000000 --- a/eclipse/jni/linux/.cdtbuild +++ /dev/null
@@ -1,76 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<?fileVersion 3.1.0?> - -<ManagedProjectBuildInfo> -<project id="JNI.cdt.managedbuild.target.gnu.so.1993024758" name="Shared Library (Gnu)" projectType="cdt.managedbuild.target.gnu.so"> -<configuration artifactExtension="so" artifactName="gwt-ll" cleanCommand="rm -rf" description="" errorParsers="org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.GASErrorParser" id="cdt.managedbuild.config.gnu.so.debug.398050485" name="Debug" parent="cdt.managedbuild.config.gnu.so.debug"> -<toolChain id="cdt.managedbuild.toolchain.gnu.so.debug.1364127860" name="GCC Tool Chain" superClass="cdt.managedbuild.toolchain.gnu.so.debug"> -<tool command="gcc" id="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug.1760328332" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug"> -<option id="gnu.cpp.compiler.option.include.paths.1542704606" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath"> -<listOptionValue builtIn="false" value="/usr/lib/j2sdk1.5-sun/include"/> -<listOptionValue builtIn="false" value="/usr/lib/j2sdk1.5-sun/include/linux"/> -<listOptionValue builtIn="false" value=""${workspace_loc:/gwt-tools/sdk/mozilla-1.7.12/include}""/> -<listOptionValue builtIn="false" value=""${workspace_loc:/gwt-tools/sdk/mozilla-1.7.12/include/extra}""/> -<listOptionValue builtIn="false" value="/usr/local/google/home/jat/src/gwt-trunk/build/out/jni/linux"/> -</option> -<option id="gnu.cpp.compiler.option.preprocessor.def.1306763452" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols"> -<listOptionValue builtIn="false" value="_REENTRANT"/> -<listOptionValue builtIn="false" value="NO_NSPR_10_SUPPORT"/> -</option> -<option id="gnu.cpp.compiler.option.optimization.flags.1738733922" superClass="gnu.cpp.compiler.option.optimization.flags" value="-fno-omit-frame-pointer -fno-strict-aliasing" valueType="string"/> -<option id="gnu.cpp.compiler.option.other.other.284396253" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 -fPIC -MMD -MP -Wno-system-headers -Os" valueType="string"/> -<option id="gnu.cpp.compiler.so.debug.option.optimization.level.1987818635" superClass="gnu.cpp.compiler.so.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.optimize" valueType="enumerated"/> -<option id="gnu.cpp.compiler.option.warnings.allwarn.1524758494" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="false" valueType="boolean"/> -</tool> -<tool id="cdt.managedbuild.tool.gnu.c.compiler.so.debug.363855699" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.so.debug"/> -<tool id="cdt.managedbuild.tool.gnu.c.linker.so.debug.44069761" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.so.debug"/> -<tool id="cdt.managedbuild.tool.gnu.cpp.linker.so.debug.127620842" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.so.debug"> -<option id="gnu.cpp.link.option.strip.1852166367" superClass="gnu.cpp.link.option.strip" value="true" valueType="boolean"/> -<option id="gnu.cpp.link.option.libs.842521175" superClass="gnu.cpp.link.option.libs" valueType="libs"> -<listOptionValue builtIn="false" value="xpcomglue_s"/> -</option> -<option id="gnu.cpp.link.option.paths.1454970074" superClass="gnu.cpp.link.option.paths" valueType="stringList"> -<listOptionValue builtIn="false" value=""${workspace_loc:/gwt-tools/sdk/mozilla-1.7.12/lib}""/> -</option> -</tool> -<tool id="cdt.managedbuild.tool.gnu.assembler.so.debug.455913220" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.so.debug"/> -<macros/> -</toolChain> -</configuration> -<configuration artifactExtension="so" artifactName="libgwt-ll" cleanCommand="rm -rf" description="" errorParsers="org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.GASErrorParser" id="cdt.managedbuild.config.gnu.so.release.196519812" name="Release" parent="cdt.managedbuild.config.gnu.so.release"> -<toolChain id="cdt.managedbuild.toolchain.gnu.so.release.309670679" name="GCC Tool Chain" superClass="cdt.managedbuild.toolchain.gnu.so.release"> -<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.so.release.639871433" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.so.release"> -<option id="gnu.cpp.compiler.option.preprocessor.def.225251886" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols"> -<listOptionValue builtIn="false" value="_REENTRANT"/> -<listOptionValue builtIn="false" value="NO_NSPR_10_SUPPORT"/> -</option> -<option id="gnu.cpp.compiler.option.include.paths.2037074199" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath"> -<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/jdk-include}""/> -<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/jdk-include/linux}""/> -<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/headers-gen}""/> -<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/mozilla-sdk/include}""/> -<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/mozilla-sdk/include/extra}""/> -</option> -<option id="gnu.cpp.compiler.option.optimization.flags.324816514" superClass="gnu.cpp.compiler.option.optimization.flags" value="-Os -fPIC -fno-omit-frame-pointer -fno-strict-aliasing" valueType="string"/> -<option id="gnu.cpp.compiler.option.warnings.allwarn.98479430" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="false" valueType="boolean"/> -<option id="gnu.cpp.compiler.option.other.other.1762086408" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 -Wno-system-headers" valueType="string"/> -</tool> -<tool id="cdt.managedbuild.tool.gnu.c.compiler.so.release.861896716" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.so.release"/> -<tool id="cdt.managedbuild.tool.gnu.c.linker.so.release.1242435463" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.so.release"/> -<tool id="cdt.managedbuild.tool.gnu.cpp.linker.so.release.696243428" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.so.release"> -<option id="gnu.cpp.link.option.strip.1678101635" superClass="gnu.cpp.link.option.strip" value="true" valueType="boolean"/> -<option id="gnu.cpp.link.option.libs.1391450429" superClass="gnu.cpp.link.option.libs" valueType="libs"> -<listOptionValue builtIn="false" value="xpcomglue_s"/> -</option> -<option id="gnu.cpp.link.option.paths.1828386123" superClass="gnu.cpp.link.option.paths" valueType="stringList"> -<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/mozilla-sdk/lib}""/> -</option> -<option id="gnu.cpp.link.option.flags.1381564345" superClass="gnu.cpp.link.option.flags" value="-fPIC -Wl,shared-gcc" valueType="string"/> -</tool> -<tool id="cdt.managedbuild.tool.gnu.assembler.so.release.1277116837" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.so.release"/> -<macros/> -</toolChain> -</configuration> -<macros/> -</project> -</ManagedProjectBuildInfo>
diff --git a/eclipse/jni/linux/.cdtproject b/eclipse/jni/linux/.cdtproject deleted file mode 100644 index fcb39a2..0000000 --- a/eclipse/jni/linux/.cdtproject +++ /dev/null
@@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<?eclipse-cdt version="2.0"?> - -<cdtproject id="org.eclipse.cdt.managedbuilder.core.managedMake"> -<extension id="org.eclipse.cdt.managedbuilder.core.ManagedBuildManager" point="org.eclipse.cdt.core.ScannerInfoProvider"/> -<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> -<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"> -<attribute key="addr2line" value="addr2line"/> -<attribute key="c++filt" value="c++filt"/> -</extension> -<data> -<item id="org.eclipse.cdt.core.pathentry"> -<pathentry kind="src" path=""/> -<pathentry kind="out" path=""/> -<pathentry kind="con" path="org.eclipse.cdt.managedbuilder.MANAGED_CONTAINER"/> -</item> -</data> -</cdtproject>
diff --git a/eclipse/jni/linux/.cproject b/eclipse/jni/linux/.cproject new file mode 100644 index 0000000..22bf39c --- /dev/null +++ b/eclipse/jni/linux/.cproject
@@ -0,0 +1,326 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?fileVersion 4.0.0?> + +<cproject> +<storageModule moduleId="org.eclipse.cdt.core.settings"> +<cconfiguration id="cdt.managedbuild.config.gnu.so.debug.398050485"> +<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.so.debug.398050485" moduleId="org.eclipse.cdt.core.settings" name="Release"> +<extensions> +<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> +<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> +<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> +<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> +<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> +</extensions> +</storageModule> +<storageModule moduleId="cdtBuildSystem" version="4.0.0"> +<configuration artifactExtension="so" artifactName="gwt-ll" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" errorParsers="org.eclipse.cdt.core.MakeErrorParser" id="cdt.managedbuild.config.gnu.so.debug.398050485" name="Release" parent="cdt.managedbuild.config.gnu.so.debug" postannouncebuildStep="" postbuildStep="" preannouncebuildStep="" prebuildStep=""> +<folderInfo id="cdt.managedbuild.config.gnu.so.debug.398050485.561354823" name="/" resourcePath=""> +<toolChain errorParsers="" id="cdt.managedbuild.toolchain.gnu.so.debug.1364127860" name="GCC Tool Chain" nonInternalBuilderId="cdt.managedbuild.target.gnu.builder.so.debug" superClass="cdt.managedbuild.toolchain.gnu.so.debug"> +<targetPlatform binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.so.debug.761504216" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.so.debug"/> +<builder autoBuildTarget="all" buildPath="${workspace_loc:/jni-linux/Release}" cleanBuildTarget="clean" enableAutoBuild="true" enableCleanBuild="true" enabledIncrementalBuild="true" errorParsers="" id="org.eclipse.cdt.build.core.internal.builder.1220428271" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="CDT Internal Builder" parallelizationNumber="1" stopOnErr="false" superClass="org.eclipse.cdt.build.core.internal.builder"/> +<tool command="g++" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="org.eclipse.cdt.core.GCCErrorParser" id="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug.1760328332" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug"> +<option id="gnu.cpp.compiler.option.include.paths.1542704606" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath"> +<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/build}""/> +<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/jdk-include}""/> +<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/jdk-include/linux}""/> +<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/mozilla-sdk/include}""/> +<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/mozilla-sdk/include/extra}""/> +</option> +<option id="gnu.cpp.compiler.option.preprocessor.def.1306763452" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols"> +<listOptionValue builtIn="false" value="_REENTRANT"/> +<listOptionValue builtIn="false" value="NO_NSPR_10_SUPPORT"/> +</option> +<option id="gnu.cpp.compiler.option.optimization.flags.1738733922" name="Other optimization flags" superClass="gnu.cpp.compiler.option.optimization.flags" value="-fno-omit-frame-pointer -fno-strict-aliasing" valueType="string"/> +<option id="gnu.cpp.compiler.option.other.other.284396253" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -ggdb -m32 -fPIC -Wno-system-headers -Os" valueType="string"/> +<option id="gnu.cpp.compiler.so.debug.option.optimization.level.1987818635" name="Optimization Level" superClass="gnu.cpp.compiler.so.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/> +<option id="gnu.cpp.compiler.option.warnings.allwarn.1524758494" name="All warnings (-Wall)" superClass="gnu.cpp.compiler.option.warnings.allwarn" value="false" valueType="boolean"/> +<option id="gnu.cpp.compiler.so.debug.option.debugging.level.416622328" name="Debug Level" superClass="gnu.cpp.compiler.so.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/> +<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.44585156" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> +</tool> +<tool command="gcc" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="org.eclipse.cdt.core.GCCErrorParser" id="cdt.managedbuild.tool.gnu.c.compiler.so.debug.363855699" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.so.debug"> +<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.so.debug.option.optimization.level.1969495705" name="Optimization Level" superClass="gnu.c.compiler.so.debug.option.optimization.level" valueType="enumerated"/> +<option id="gnu.c.compiler.so.debug.option.debugging.level.1292178444" name="Debug Level" superClass="gnu.c.compiler.so.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/> +<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1996564179" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> +</tool> +<tool id="cdt.managedbuild.tool.gnu.c.linker.so.debug.44069761" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.so.debug"> +<option defaultValue="true" id="gnu.c.link.so.debug.option.shared.2039191396" name="Shared (-shared)" superClass="gnu.c.link.so.debug.option.shared" valueType="boolean"/> +</tool> +<tool command="g++" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="org.eclipse.cdt.core.GLDErrorParser" id="cdt.managedbuild.tool.gnu.cpp.linker.so.debug.127620842" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.so.debug"> +<option id="gnu.cpp.link.option.strip.1852166367" name="Omit all symbol information (-s)" superClass="gnu.cpp.link.option.strip" value="true" valueType="boolean"/> +<option id="gnu.cpp.link.option.libs.842521175" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs"> +<listOptionValue builtIn="false" value="xpcomglue_s"/> +</option> +<option id="gnu.cpp.link.option.paths.1454970074" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="stringList"> +<listOptionValue builtIn="false" value=""${workspace_loc:/jni-linux/mozilla-sdk/lib}""/> +</option> +<option defaultValue="true" id="gnu.cpp.link.so.debug.option.shared.1661107847" name="Shared (-shared)" superClass="gnu.cpp.link.so.debug.option.shared" valueType="boolean"/> +<option id="gnu.cpp.link.option.flags.502453637" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-fPIC -Wl,-shared-gcc" valueType="string"/> +</tool> +<tool command="as" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="org.eclipse.cdt.core.GASErrorParser" id="cdt.managedbuild.tool.gnu.assembler.so.debug.455913220" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.so.debug"> +<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1120557201" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> +</tool> +<tool id="cdt.managedbuild.tool.gnu.archiver.base.883660164" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> +</toolChain> +</folderInfo> +</configuration> +</storageModule> +<storageModule moduleId="scannerConfiguration"> +<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/> +<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="true"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="true"/> +</buildOutputProvider> +<scannerInfoProvider id="makefileGenerator"> +<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.debug.398050485;cdt.managedbuild.config.gnu.so.debug.398050485.561354823;cdt.managedbuild.tool.gnu.c.compiler.so.debug.363855699;cdt.managedbuild.tool.gnu.c.compiler.input.1996564179"> +<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> +<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="true"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="true"/> +</buildOutputProvider> +<scannerInfoProvider id="makefileGenerator"> +<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> +<buildOutputProvider> +<openAction enabled="false" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +</scannerConfigBuildInfo> +<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.debug.398050485;cdt.managedbuild.config.gnu.so.debug.398050485.561354823;cdt.managedbuild.tool.gnu.cpp.compiler.so.debug.1760328332;cdt.managedbuild.tool.gnu.cpp.compiler.input.44585156"> +<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/> +<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="true"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="true"/> +</buildOutputProvider> +<scannerInfoProvider id="makefileGenerator"> +<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> +<buildOutputProvider> +<openAction enabled="true" filePath=""/> +<parser enabled="false"/> +</buildOutputProvider> +<scannerInfoProvider id="specsFile"> +<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> +<parser enabled="true"/> +</scannerInfoProvider> +</profile> +</scannerConfigBuildInfo> +</storageModule> +<storageModule moduleId="org.eclipse.cdt.core.language.mapping"> +<project-mappings/> +</storageModule> +<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> +</cconfiguration> +</storageModule> +<storageModule moduleId="cdtBuildSystem" version="4.0.0"> +<project id="JNI.cdt.managedbuild.target.gnu.so.1993024758" name="Shared Library (Gnu)" projectType="cdt.managedbuild.target.gnu.so"/> +</storageModule> +</cproject>
diff --git a/eclipse/jni/linux/.project b/eclipse/jni/linux/.project index a5e1233..5acdfff 100644 --- a/eclipse/jni/linux/.project +++ b/eclipse/jni/linux/.project
@@ -9,13 +9,75 @@ <buildCommand> <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> <arguments> + <dictionary> + <key>org.eclipse.cdt.make.core.fullBuildTarget</key> + <value>all</value> + </dictionary> + <dictionary> + <key>?name?</key> + <value></value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.enableAutoBuild</key> + <value>true</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.buildLocation</key> + <value>${workspace_loc:/jni-linux/Release}</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.enableFullBuild</key> + <value>true</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.enableCleanBuild</key> + <value>true</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.cleanBuildTarget</key> + <value>clean</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.append_environment</key> + <value>true</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.contents</key> + <value>org.eclipse.cdt.make.core.activeConfigSettings</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key> + <value>true</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.buildArguments</key> + <value></value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.buildCommand</key> + <value>make</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.autoBuildTarget</key> + <value>all</value> + </dictionary> + <dictionary> + <key>org.eclipse.cdt.make.core.stopOnError</key> + <value>false</value> + </dictionary> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> + <arguments> </arguments> </buildCommand> </buildSpec> <natures> <nature>org.eclipse.cdt.core.cnature</nature> - <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> <nature>org.eclipse.cdt.core.ccnature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> </natures> <linkedResources> <link> @@ -29,6 +91,11 @@ <locationURI>JAVA_HOME/include</locationURI> </link> <link> + <name>build</name> + <type>2</type> + <locationURI>GWT_ROOT/build/out/jni/linux</locationURI> + </link> + <link> <name>mozilla-sdk</name> <type>2</type> <locationURI>GWT_TOOLS/sdk/mozilla-1.7.12</locationURI> @@ -38,10 +105,5 @@ <type>2</type> <locationURI>GWT_ROOT/jni/core</locationURI> </link> - <link> - <name>headers-gen</name> - <type>2</type> - <locationURI>GWT_ROOT/build/out/jni/linux</locationURI> - </link> </linkedResources> </projectDescription>
diff --git a/eclipse/jni/linux/.settings/org.eclipse.cdt.core.prefs b/eclipse/jni/linux/.settings/org.eclipse.cdt.core.prefs deleted file mode 100644 index cbbb52e..0000000 --- a/eclipse/jni/linux/.settings/org.eclipse.cdt.core.prefs +++ /dev/null
@@ -1,3 +0,0 @@ -#Thu Jan 25 19:11:27 GMT-05:00 2007 -eclipse.preferences.version=1 -indexerId=org.eclipse.cdt.core.fastIndexer
diff --git a/eclipse/jni/linux/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/eclipse/jni/linux/.settings/org.eclipse.cdt.managedbuilder.core.prefs deleted file mode 100644 index 7ee397d..0000000 --- a/eclipse/jni/linux/.settings/org.eclipse.cdt.managedbuilder.core.prefs +++ /dev/null
@@ -1,13 +0,0 @@ -#Thu Jan 25 19:30:13 GMT-05:00 2007 -cdt.managedbuild.config.gnu.so.debug.398050485/internalBuilder/enabled=false -cdt.managedbuild.config.gnu.so.debug.398050485/internalBuilder/ignoreErr=true -cdt.managedbuild.config.gnu.so.release.196519812/internalBuilder/enabled=false -cdt.managedbuild.config.gnu.so.release.196519812/internalBuilder/ignoreErr=true -eclipse.preferences.version=1 -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.so.debug.398050485=<?xml version\="1.0" encoding\="UTF-8"?>\n<environment>\n<variable name\="CPATH" operation\="remove"/>\n<variable name\="C_INCLUDE_PATH" operation\="remove"/>\n<variable name\="CPLUS_INCLUDE_PATH" operation\="remove"/>\n</environment>\n -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.so.release.196519812=<?xml version\="1.0" encoding\="UTF-8"?>\n<environment>\n<variable name\="CPATH" operation\="remove"/>\n<variable name\="C_INCLUDE_PATH" operation\="remove"/>\n<variable name\="CPLUS_INCLUDE_PATH" operation\="remove"/>\n</environment>\n -environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.so.debug.398050485=<?xml version\="1.0" encoding\="UTF-8"?>\n<environment>\n<variable name\="LIBRARY_PATH" operation\="remove"/>\n</environment>\n -environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.so.release.196519812=<?xml version\="1.0" encoding\="UTF-8"?>\n<environment>\n<variable name\="LIBRARY_PATH" operation\="remove"/>\n</environment>\n -environment/project=<?xml version\="1.0" encoding\="UTF-8"?>\n<environment/>\n -environment/project/cdt.managedbuild.config.gnu.so.debug.398050485=<?xml version\="1.0" encoding\="UTF-8"?>\n<environment/>\n -environment/project/cdt.managedbuild.config.gnu.so.release.196519812=<?xml version\="1.0" encoding\="UTF-8"?>\n<environment/>\n
diff --git a/eclipse/user/.classpath b/eclipse/user/.classpath index e7b1f4c..7002c3f 100644 --- a/eclipse/user/.classpath +++ b/eclipse/user/.classpath
@@ -1,12 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="core/src"/> + <classpathentry kind="src" path="gen"/> <classpathentry kind="src" path="core/javadoc"/> <classpathentry kind="src" path="core/test"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar" sourcepath="/GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2-src.zip"/> <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/junit/junit-3.8.1.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-3.8.1-src.zip"/> <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/servlet-api-2.4.jar" sourcepath="/GWT_TOOLS/lib/tomcat/jakarta-tomcat-5.0.28-src.zip"/> - <classpathentry combineaccessrules="false" kind="src" path="/gwt-dev-windows"/> + <classpathentry combineaccessrules="false" kind="src" path="/gwt-dev-linux"/> <classpathentry kind="output" path="bin"/> </classpath>
diff --git a/jni/linux/JsValueMoz.cpp b/jni/linux/JsValueMoz.cpp index be30ea4..1faa49f 100644 --- a/jni/linux/JsValueMoz.cpp +++ b/jni/linux/JsValueMoz.cpp
@@ -381,6 +381,24 @@ } /** + * Class: com_google_gwt_dev_shell_moz_JsValueMoz + * Method: _getObjectPointer() + * Signature: (I)I + */ +extern "C" JNIEXPORT jint JNICALL +Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getObjectPointer + (JNIEnv* jniEnv, jclass, jint jsRootedValueInt) +{ + JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*> + (jsRootedValueInt); + Tracer tracer("JsValueMoz._getObjectPointer", jsRootedValue); + JSObject* ptr = jsRootedValue->getObject(); + int val = reinterpret_cast<int>(ptr); + tracer.log("value=%d", val); + return val; +} + +/** * Return a Javascript string as a Java string. * * Class: com_google_gwt_dev_shell_moz_JsValueMoz @@ -454,12 +472,11 @@ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*> (jsRootedValueInt); Tracer tracer("JsValueMoz._getWrappedJavaObject", jsRootedValue); - jsval val = jsRootedValue->getValue(); - if(!JSVAL_IS_OBJECT(val)) { + JSObject* jsObject = jsRootedValue->getObject(); + if(!jsObject) { tracer.throwHostedModeException(jniEnv, "Javascript value not an object"); return 0; } - JSObject* jsObject = JSVAL_TO_OBJECT(val); JSContext* cx = JsRootedValue::currentContext(); if(!JS_InstanceOf(cx, jsObject, &gwt_nativewrapper_class, 0)) { tracer.throwHostedModeException(jniEnv,
diff --git a/jni/linux/prebuilt/libgwt-ll.so b/jni/linux/prebuilt/libgwt-ll.so index 48351ee..e941084 100755 --- a/jni/linux/prebuilt/libgwt-ll.so +++ b/jni/linux/prebuilt/libgwt-ll.so Binary files differ
diff --git a/user/src/com/google/gwt/core/client/Impl.java b/user/src/com/google/gwt/core/client/Impl.java index cb37219..8cb8903 100644 --- a/user/src/com/google/gwt/core/client/Impl.java +++ b/user/src/com/google/gwt/core/client/Impl.java
@@ -1,5 +1,5 @@ /* - * Copyright 2006 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -23,19 +23,8 @@ return ++sNextHashId; } - /* - * We need a separate overload for JavaScriptObject, so that the hosted mode - * JSNI invocation system will know to unwrap the Java object back to its - * underlying JavaScript object. - */ - static native int getHashCode(JavaScriptObject o) /*-{ - return (o == null) ? 0 : - (o.$H ? o.$H : (o.$H = @com.google.gwt.core.client.Impl::getNextHashId()())); - }-*/; - static native int getHashCode(Object o) /*-{ - return (o == null) ? 0 : - (o.$H ? o.$H : (o.$H = @com.google.gwt.core.client.Impl::getNextHashId()())); + return o.$H || (o.$H = @com.google.gwt.core.client.Impl::getNextHashId()()); }-*/; static native String getHostPageBaseURL() /*-{
diff --git a/user/src/com/google/gwt/core/client/JavaScriptObject.java b/user/src/com/google/gwt/core/client/JavaScriptObject.java index f9524c2..274d2da 100644 --- a/user/src/com/google/gwt/core/client/JavaScriptObject.java +++ b/user/src/com/google/gwt/core/client/JavaScriptObject.java
@@ -51,52 +51,54 @@ return {}; }-*/; - private static native boolean equalsImpl(JavaScriptObject o, - JavaScriptObject other) /*-{ - return o === other; - }-*/; - - private static native String toStringImpl(JavaScriptObject o) /*-{ - if (o.toString) - return o.toString(); - return "[object]"; - }-*/; - /** - * The underlying JavaScript object. This is used internally and should never - * be accessed by client code. - */ - protected Object hostedModeReference; - - /** - * Not directly instantiable. Subclasses should also define a protected - * no-arg constructor to prevent client code from directly instantiating - * the class. + * Not directly instantiable. All subclasses must also define a protected, + * empty, no-arg constructor. */ protected JavaScriptObject() { } - @Override - public boolean equals(Object other) { - if (!(other instanceof JavaScriptObject)) { - return false; - } - return equalsImpl(this, (JavaScriptObject) other); - } - - @Override - public int hashCode() { - return Impl.getHashCode(this); + /** + * A helper method to enable cross-casting from any {@link JavaScriptObject} + * type to any other {@link JavaScriptObject} type. + * + * @param <T> the target type + * @return this object as a different type + */ + @SuppressWarnings("unchecked") + public final <T extends JavaScriptObject> T cast() { + return (T) this; } + /** + * Returns <code>true</code> if the objects are JavaScript identical + * (triple-equals). + */ @Override - public String toString() { - /* - * Hosted mode will marshal an explicit argument from a JavaScriptObject - * back to its underlying object, but it won't currently do that for the - * implicit "this" arg. For now, can't implement instance methods on JSO - * directly as natives, so use a delegator. - */ - return toStringImpl(this); + public final boolean equals(Object other) { + return super.equals(other); } + + /** + * Uses a monotonically increasing counter to assign a hash code to the + * underlying JavaScript object. Do not call this method on non-modifiable + * JavaScript objects. + * + * TODO: if the underlying object defines a 'hashCode' method maybe use that? + * + * @return the hash code of the object + */ + @Override + public final int hashCode() { + return Impl.getHashCode(this); + } + + /** + * Returns the results of calling <code>toString</code> in JavaScript on the + * object, if the object implements toString; otherwise returns "[JavaScriptObject]". + */ + @Override + public final native String toString() /*-{ + return this.toString ? this.toString() : "[JavaScriptObject]"; + }-*/; }
diff --git a/user/src/com/google/gwt/json/client/JSONArray.java b/user/src/com/google/gwt/json/client/JSONArray.java index 5a47234..b9d24a2 100644 --- a/user/src/com/google/gwt/json/client/JSONArray.java +++ b/user/src/com/google/gwt/json/client/JSONArray.java
@@ -58,7 +58,12 @@ } JSONValue wrapped = null; if (rawTest(index)) { - wrapped = JSONParser.buildValue(rawGet(index)); + Object o = rawGet(index); + if (o instanceof String) { + wrapped = new JSONString((String) o); + } else { + wrapped = JSONParser.buildValue((JavaScriptObject) o); + } rawSet(index, null); } wrappedSet(index, wrapped); @@ -122,16 +127,16 @@ return []; }-*/; - private native JavaScriptObject rawGet(int index) /*-{ + private native Object rawGet(int index) /*-{ var x = this.@com.google.gwt.json.client.JSONArray::javascriptArray[index]; - if (typeof x == 'number' || typeof x == 'string' || typeof x == 'array' || typeof x == 'boolean') { + if (typeof x == 'number' || typeof x == 'array' || typeof x == 'boolean') { x = (Object(x)); } return x; }-*/; - private native void rawSet(int index, JavaScriptObject jsObject) /*-{ - this.@com.google.gwt.json.client.JSONArray::javascriptArray[index] = jsObject; + private native void rawSet(int index, Object value) /*-{ + this.@com.google.gwt.json.client.JSONArray::javascriptArray[index] = value; }-*/; private native boolean rawTest(int index) /*-{
diff --git a/user/src/com/google/gwt/json/client/JSONObject.java b/user/src/com/google/gwt/json/client/JSONObject.java index b6462a7..b1fe522 100644 --- a/user/src/com/google/gwt/json/client/JSONObject.java +++ b/user/src/com/google/gwt/json/client/JSONObject.java
@@ -48,7 +48,7 @@ frontStore[String(key)] = jsonValue; }-*/; - private static native JavaScriptObject removeBack(JavaScriptObject backStore, String key) /*-{ + private static native Object removeBack(JavaScriptObject backStore, String key) /*-{ key = String(key); var result = backStore[key]; delete backStore[key]; @@ -104,8 +104,12 @@ } JSONValue result = getFront(frontStore, key); if (result == null && containsBack(backStore, key)) { - JavaScriptObject jso = removeBack(backStore, key); - result = JSONParser.buildValue(jso); + Object o = removeBack(backStore, key); + if (o instanceof String) { + result = new JSONString((String) o); + } else { + result = JSONParser.buildValue((JavaScriptObject) o); + } putFront(frontStore, key, result); } return result;
diff --git a/user/src/com/google/gwt/json/client/JSONParser.java b/user/src/com/google/gwt/json/client/JSONParser.java index 597e379..ffda1c6 100644 --- a/user/src/com/google/gwt/json/client/JSONParser.java +++ b/user/src/com/google/gwt/json/client/JSONParser.java
@@ -46,8 +46,12 @@ throw new IllegalArgumentException("empty argument"); } try { - JavaScriptObject jsonObject = evaluate(jsonString); - return buildValue(jsonObject); + Object object = evaluate(jsonString); + if (object instanceof String) { + return new JSONString((String) object); + } else { + return buildValue((JavaScriptObject) object); + } } catch (JavaScriptException ex) { throw new JSONException(ex); } @@ -74,10 +78,6 @@ return JSONBoolean.getInstance(asBoolean(jsValue)); } - if (isString(jsValue)) { - return new JSONString(asString(jsValue)); - } - if (isDouble(jsValue)) { return new JSONNumber(asDouble(jsValue)); } @@ -117,23 +117,12 @@ }-*/; /** - * Returns the Javascript String as a Java String. This method assumes that - * {@link #isString(JavaScriptObject)} returned <code>true</code>. - * - * @param jsValue JavaScript object to convert - * @return the String represented by the jsValue + * This method converts the json string into either a String or a a by simply + * evaluating the string in JavaScript. */ - private static native String asString(JavaScriptObject jsValue) /*-{ - return jsValue; - }-*/; - - /* - * This method converts the json string into a JavaScriptObject inside of JSNI - * method by simply evaluating the string in JavaScript. - */ - private static native JavaScriptObject evaluate(String jsonString) /*-{ + private static native Object evaluate(String jsonString) /*-{ var x = eval('(' + jsonString + ')'); - if (typeof x == 'number' || typeof x == 'string' || typeof x == 'array' || typeof x == 'boolean') { + if (typeof x == 'number' || typeof x == 'array' || typeof x == 'boolean') { x = (Object(x)); } return x; @@ -196,17 +185,6 @@ }-*/; /** - * Returns <code>true</code> if the {@link JavaScriptObject} is a JavaScript - * String. - * - * @param jsValue JavaScript object to test - * @return <code>true</code> if jsValue is a JavaScript String - */ - private static native boolean isString(JavaScriptObject jsValue) /*-{ - return jsValue instanceof String; - }-*/; - - /** * Not instantiable. */ private JSONParser() {
diff --git a/user/src/com/google/gwt/user/client/Element.java b/user/src/com/google/gwt/user/client/Element.java index bfee634..b6c5be7 100644 --- a/user/src/com/google/gwt/user/client/Element.java +++ b/user/src/com/google/gwt/user/client/Element.java
@@ -35,38 +35,4 @@ */ protected Element() { } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object other) { - if (other instanceof Element) { - return DOM.compare(this, (Element) other); - } - - return super.equals(other); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return super.hashCode(); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return DOM.toString(this); - } }
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java index 08ad57b..09cf5af 100644 --- a/user/src/com/google/gwt/user/client/Event.java +++ b/user/src/com/google/gwt/user/client/Event.java
@@ -167,34 +167,4 @@ */ protected Event() { } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object other) { - return super.equals(other); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return super.hashCode(); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return DOM.eventToString(this); - } }
diff --git a/user/super/com/google/gwt/emul/java/lang/Object.java b/user/super/com/google/gwt/emul/java/lang/Object.java index 5f0a917..13bbca5 100644 --- a/user/super/com/google/gwt/emul/java/lang/Object.java +++ b/user/super/com/google/gwt/emul/java/lang/Object.java
@@ -1,5 +1,5 @@ /* - * Copyright 2006 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -27,11 +27,18 @@ * * @skip */ - protected transient int typeId; + public transient int typeId; - public native boolean equals(Object other) /*-{ - return this === other; - }-*/; + /** + * magic magic magic. + * + * @skip + */ + public transient Object typeMarker; + + public boolean equals(Object other) { + return this == other; + } /* * Magic; unlike the real JDT, we don't spec this method as final. The @@ -42,9 +49,9 @@ return Object.class; } - public int hashCode() { - return System.identityHashCode(this); - } + public native int hashCode() /*-{ + return @com.google.gwt.core.client.Impl::getHashCode(Ljava/lang/Object;)(this); + }-*/; public String toString() { return getClass().getName() + '@' + Integer.toHexString(hashCode());
diff --git a/user/super/com/google/gwt/emul/java/lang/System.java b/user/super/com/google/gwt/emul/java/lang/System.java index cc6a2e8..1811bee 100644 --- a/user/super/com/google/gwt/emul/java/lang/System.java +++ b/user/super/com/google/gwt/emul/java/lang/System.java
@@ -98,7 +98,7 @@ }-*/; public static native int identityHashCode(Object o) /*-{ - return @com.google.gwt.core.client.Impl::getHashCode(Ljava/lang/Object;)(o); + return (o == null) ? 0 : @com.google.gwt.core.client.Impl::getHashCode(Ljava/lang/Object;)(o); }-*/; public static native void setErr(PrintStream err) /*-{
diff --git a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java index acbeb46..b2a71ad 100644 --- a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java +++ b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
@@ -28,6 +28,7 @@ import com.google.gwt.dev.jjs.test.InnerClassTest; import com.google.gwt.dev.jjs.test.InnerOuterSuperTest; import com.google.gwt.dev.jjs.test.JsniConstructorTest; +import com.google.gwt.dev.jjs.test.JsoTest; import com.google.gwt.dev.jjs.test.MemberShadowingTest; import com.google.gwt.dev.jjs.test.MethodBindTest; import com.google.gwt.dev.jjs.test.MethodCallTest; @@ -61,6 +62,7 @@ suite.addTestSuite(InnerClassTest.class); suite.addTestSuite(InnerOuterSuperTest.class); suite.addTestSuite(JsniConstructorTest.class); + suite.addTestSuite(JsoTest.class); suite.addTestSuite(MemberShadowingTest.class); suite.addTestSuite(MethodBindTest.class); suite.addTestSuite(MethodCallTest.class);
diff --git a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java index bac67d4..9df5500 100644 --- a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
@@ -94,10 +94,6 @@ return new Number(v); }-*/; - private native static JavaScriptObject getBoxedStringAsObject(String v) /*-{ - return new String(v); - }-*/; - private native static String getBoxedStringAsString(String v) /*-{ return new String(v); }-*/; @@ -210,8 +206,6 @@ assertEquals(getJSOAsString(bvo), "true"); JavaScriptObject nvo = getBoxedNumberAsObject(42); assertEquals(getJSOAsString(nvo), "42"); - JavaScriptObject svo = getBoxedStringAsObject("test"); - assertEquals(getJSOAsString(svo), "test"); String sv = getBoxedStringAsString("test"); assertEquals(sv, "test"); }
diff --git a/user/test/com/google/gwt/dev/jjs/test/JsoTest.java b/user/test/com/google/gwt/dev/jjs/test/JsoTest.java new file mode 100644 index 0000000..21bd74d --- /dev/null +++ b/user/test/com/google/gwt/dev/jjs/test/JsoTest.java
@@ -0,0 +1,606 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.jjs.test; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.junit.client.GWTTestCase; + +/** + * Tests {@link JavaScriptObject} and subclasses. + */ +public class JsoTest extends GWTTestCase { + + private static class Bar extends JavaScriptObject { + public static int field; + + public static native String staticNative() /*-{ + return "nativeBar"; + }-*/; + + public static String staticValue() { + return "Bar" + field; + } + + protected Bar() { + } + + public final native String getBar() /*-{ + return this.bar; + }-*/; + + public final String value() { + return "Bar"; + } + } + + private static class Foo extends JavaScriptObject { + public static int field; + + public static native String staticNative() /*-{ + return "nativeFoo"; + }-*/; + + public static String staticValue() { + return "Foo" + field; + } + + protected Foo() { + } + + public final native String getFoo() /*-{ + return this.foo; + }-*/; + + public final String value() { + return "Foo"; + } + } + + private static class FooSub extends Foo { + protected FooSub() { + } + + public final String anotherValue() { + return "Still Foo"; + } + + public final String superCall() { + return super.value(); + } + } + + private static class JsArray<T> extends JavaScriptObject { + public static native <T> JsArray<T> create() /*-{ + return []; + }-*/; + + protected JsArray() { + } + + public final native T get(int index) /*-{ + return this[index]; + }-*/; + + public final native int length() /*-{ + return this.length; + }-*/; + + public final native void put(int index, T value) /*-{ + this[index] = value; + }-*/; + } + + private static class MethodMangleClash { + @SuppressWarnings("unused") + public static String func(JavaScriptObject this_) { + return "funcJavaScriptObject"; + } + + @SuppressWarnings("unused") + public static String func(MethodMangleClash this_) { + return "funcMethodMangleClash"; + } + + @SuppressWarnings("unused") + public String func() { + return "func"; + } + } + + private static class Overloads { + @SuppressWarnings("unused") + private static String sFunc(Bar b) { + return "sFunc Bar"; + } + + @SuppressWarnings("unused") + private static String sFunc(Bar[][] b) { + return "sFunc Bar[][]"; + } + + @SuppressWarnings("unused") + private static String sFunc(Foo f) { + return "sFunc Foo"; + } + + @SuppressWarnings("unused") + private static String sFunc(Foo[][] f) { + return "sFunc Foo[][]"; + } + + @SuppressWarnings("unused") + public Overloads(Bar b) { + } + + @SuppressWarnings("unused") + public Overloads(Bar[][] b) { + } + + @SuppressWarnings("unused") + public Overloads(Foo f) { + } + + @SuppressWarnings("unused") + public Overloads(Foo[][] f) { + } + + @SuppressWarnings("unused") + private String func(Bar b) { + return "func Bar"; + } + + @SuppressWarnings("unused") + private String func(Bar[][] b) { + return "func Bar[][]"; + } + + @SuppressWarnings("unused") + private String func(Foo f) { + return "func Foo"; + } + + @SuppressWarnings("unused") + private String func(Foo[][] f) { + return "func Foo[][]"; + } + } + + private static native Bar makeBar() /*-{ + return { + toString:function() { + return "bar"; + }, + bar: "this is bar", + }; + }-*/; + + private static native Foo makeFoo() /*-{ + return { + toString:function() { + return "foo"; + }, + foo: "this is foo", + }; + }-*/; + + private static native JavaScriptObject makeJSO() /*-{ + return { + toString:function() { + return "jso"; + }, + foo: "jso foo", + bar: "jso bar", + }; + }-*/; + + private static native JavaScriptObject makeMixedArray() /*-{ + return [ + @com.google.gwt.dev.jjs.test.JsoTest::makeJSO()(), + "foo", + @com.google.gwt.dev.jjs.test.JsoTest::makeObject()(), + null + ]; + }-*/; + + private static Object makeObject() { + return new Object() { + @Override + public String toString() { + return "myObject"; + } + }; + } + + private static native JavaScriptObject returnMe(JavaScriptObject jso) /*-{ + return jso; + }-*/; + + @Override + public String getModuleName() { + return "com.google.gwt.dev.jjs.CompilerSuite"; + } + + public void testArrayInit() { + Object[] array = {makeJSO(), new Object(), ""}; + assertTrue(array[0] instanceof JavaScriptObject); + assertFalse(array[1] instanceof JavaScriptObject); + assertFalse(array[2] instanceof JavaScriptObject); + } + + public void testArrayStore() { + JavaScriptObject[] jsoArray = new JavaScriptObject[1]; + jsoArray[0] = makeJSO(); + jsoArray[0] = makeFoo(); + jsoArray[0] = makeBar(); + + Foo[] fooArray = new Foo[1]; + fooArray[0] = (Foo) makeJSO(); + fooArray[0] = makeFoo(); + fooArray[0] = makeBar().cast(); + + Bar[] barArray = new Bar[1]; + barArray[0] = (Bar) makeJSO(); + barArray[0] = makeBar(); + barArray[0] = makeFoo().cast(); + + Object[] objArray = jsoArray; + try { + objArray[0] = new Object(); + fail("Expected ArrayStoreException"); + } catch (ArrayStoreException expected) { + } + } + + public void testBasic() { + JavaScriptObject jso = makeJSO(); + assertEquals("jso", jso.toString()); + + Foo foo = (Foo) jso; + assertEquals("jso", foo.toString()); + assertEquals("jso foo", foo.getFoo()); + assertEquals("Foo", foo.value()); + + Bar bar = (Bar) jso; + assertEquals("jso", bar.toString()); + assertEquals("jso bar", bar.getBar()); + assertEquals("Bar", bar.value()); + + foo = makeFoo(); + assertEquals("foo", foo.toString()); + assertEquals("this is foo", foo.getFoo()); + assertEquals("Foo", foo.value()); + + bar = makeBar(); + assertEquals("bar", bar.toString()); + assertEquals("this is bar", bar.getBar()); + assertEquals("Bar", bar.value()); + } + + @SuppressWarnings("cast") + public void testCasts() { + JavaScriptObject jso = makeJSO(); + assertTrue(jso instanceof JavaScriptObject); + assertTrue(jso instanceof Foo); + assertTrue(jso instanceof Bar); + + Foo foo = (Foo) jso; + foo = makeFoo(); + assertTrue((JavaScriptObject) foo instanceof Bar); + Bar bar = (Bar) (JavaScriptObject) makeFoo(); + bar = makeFoo().cast(); + + bar = (Bar) jso; + bar = makeBar(); + assertTrue((JavaScriptObject) bar instanceof Foo); + foo = (Foo) (JavaScriptObject) makeBar(); + foo = makeBar().cast(); + + // Implicit + jso = foo; + jso = bar; + + Object o = new Object(); + assertFalse(o instanceof JavaScriptObject); + assertFalse(o instanceof Foo); + assertFalse(o instanceof Bar); + try { + jso = (JavaScriptObject) o; + fail("Expected ClassCastException"); + } catch (ClassCastException expected) { + } + + o = "foo"; + assertFalse(o instanceof JavaScriptObject); + assertFalse(o instanceof Foo); + assertFalse(o instanceof Bar); + try { + jso = (JavaScriptObject) o; + fail("Expected ClassCastException"); + } catch (ClassCastException expected) { + } + + o = jso; + assertFalse(o instanceof String); + try { + String s = (String) o; + s.toString(); + fail("Expected ClassCastException"); + } catch (ClassCastException expected) { + } + } + + @SuppressWarnings("cast") + public void testCastsArray() { + JavaScriptObject[][] jso = new JavaScriptObject[0][0]; + assertTrue(jso instanceof JavaScriptObject[][]); + assertTrue(jso instanceof Foo[][]); + assertTrue(jso instanceof Bar[][]); + + Foo[][] foo = (Foo[][]) jso; + foo = new Foo[0][0]; + assertTrue((JavaScriptObject[][]) foo instanceof Bar[][]); + Bar[][] bar = (Bar[][]) (JavaScriptObject[][]) new Foo[0][0]; + + bar = (Bar[][]) jso; + bar = new Bar[0][0]; + assertTrue((JavaScriptObject[][]) bar instanceof Foo[][]); + foo = (Foo[][]) (JavaScriptObject[][]) new Bar[0][0]; + + Object[][] o = new Object[0][0]; + assertFalse(o instanceof JavaScriptObject[][]); + assertFalse(o instanceof Foo[][]); + assertFalse(o instanceof Bar[][]); + try { + jso = (JavaScriptObject[][]) o; + fail("Expected ClassCastException"); + } catch (ClassCastException expected) { + } + + o = jso; + assertFalse(o instanceof String[][]); + try { + String[][] s = (String[][]) o; + s.toString(); + fail("Expected ClassCastException"); + } catch (ClassCastException expected) { + } + } + + public void testClassLiterals() { + JavaScriptObject jso = makeJSO(); + Foo foo = makeFoo(); + Bar bar = makeBar(); + assertEquals(JavaScriptObject.class, jso.getClass()); + assertEquals(Foo.class, jso.getClass()); + assertEquals(Bar.class, jso.getClass()); + assertEquals(JavaScriptObject.class, foo.getClass()); + assertEquals(Foo.class, foo.getClass()); + assertEquals(Bar.class, foo.getClass()); + assertEquals(JavaScriptObject.class, bar.getClass()); + assertEquals(Foo.class, bar.getClass()); + assertEquals(Bar.class, bar.getClass()); + assertEquals(JavaScriptObject.class, Foo.class); + assertEquals(JavaScriptObject.class, Bar.class); + assertEquals(Foo.class, Bar.class); + + assertEquals("com.google.gwt.core.client.JavaScriptObject$", + JavaScriptObject.class.getName()); + } + + public void testClassLiteralsArray() { + JavaScriptObject[][] jso = new JavaScriptObject[0][0]; + Foo[][] foo = new Foo[0][0]; + Bar[][] bar = new Bar[0][0]; + assertEquals(JavaScriptObject[][].class, jso.getClass()); + assertEquals(Foo[][].class, jso.getClass()); + assertEquals(Bar[][].class, jso.getClass()); + assertEquals(JavaScriptObject[][].class, foo.getClass()); + assertEquals(Foo[][].class, foo.getClass()); + assertEquals(Bar[][].class, foo.getClass()); + assertEquals(JavaScriptObject[][].class, bar.getClass()); + assertEquals(Foo[][].class, bar.getClass()); + assertEquals(Bar[][].class, bar.getClass()); + assertEquals(JavaScriptObject[][].class, Foo[][].class); + assertEquals(JavaScriptObject[][].class, Bar[][].class); + assertEquals(Foo[][].class, Bar[][].class); + + assertEquals("[[Lcom.google.gwt.core.client.JavaScriptObject$;", + JavaScriptObject[][].class.getName()); + } + + public void testEquality() { + JavaScriptObject jso = makeJSO(); + assertEquals(jso, jso); + + JavaScriptObject jso2 = makeJSO(); + assertFalse(jso.equals(jso2)); + assertFalse(jso2.equals(jso)); + + jso2 = returnMe(jso); + assertEquals(jso, jso2); + } + + public void testGenericsJsos() { + JsArray<JavaScriptObject> a = JsArray.create(); + a.put(0, makeJSO()); + a.put(1, makeFoo()); + a.put(2, makeBar()); + a.put(3, null); + assertEquals(4, a.length()); + assertEquals("jso", a.get(0).toString()); + assertEquals("foo", a.get(1).toString()); + assertEquals("bar", a.get(2).toString()); + assertEquals(null, a.get(3)); + } + + public void testGenericsMixed() { + JsArray<Object> a = JsArray.create(); + a.put(0, makeJSO()); + a.put(1, "foo"); + a.put(2, makeObject()); + a.put(3, null); + assertEquals(4, a.length()); + assertEquals("jso", a.get(0).toString()); + assertEquals("foo", a.get(1)); + assertEquals("myObject", a.get(2).toString()); + assertEquals(null, a.get(3)); + } + + @SuppressWarnings("unchecked") + public void testGenericsRawJson() { + JsArray a = (JsArray) makeMixedArray(); + assertEquals(4, a.length()); + assertEquals("jso", a.get(0).toString()); + assertEquals("foo", a.get(1)); + assertEquals("myObject", a.get(2).toString()); + assertEquals(null, a.get(3)); + } + + public void testGenericsStrings() { + JsArray<String> a = JsArray.create(); + a.put(0, "foo"); + a.put(1, "bar"); + a.put(2, "baz"); + a.put(3, null); + assertEquals(4, a.length()); + assertEquals("foo", a.get(0)); + assertEquals("bar", a.get(1)); + assertEquals("baz", a.get(2)); + assertEquals(null, a.get(3)); + } + + public void testHashCode() { + // TODO: make this better. + JavaScriptObject jso = makeJSO(); + int jsoHashCode = jso.hashCode(); + Foo foo = makeFoo(); + Bar bar = makeBar(); + Object o = new Object() { + @Override + public int hashCode() { + // Return something unlikely so as not to collide with the JSOs. + return 0xDEADBEEF; + } + }; + + assertEquals(jsoHashCode, jso.hashCode()); + assertFalse(jsoHashCode == foo.hashCode()); + assertFalse(jsoHashCode == bar.hashCode()); + assertFalse(jsoHashCode == o.hashCode()); + assertFalse(foo.hashCode() == bar.hashCode()); + assertFalse(foo.hashCode() == o.hashCode()); + assertFalse(bar.hashCode() == o.hashCode()); + + o = jso; + assertEquals(jsoHashCode, o.hashCode()); + + String s = "foo"; + int stringHashCode = s.hashCode(); + o = s; + assertEquals(stringHashCode, o.hashCode()); + } + + public void testIdentity() { + JavaScriptObject jso = makeJSO(); + assertSame(jso, jso); + + JavaScriptObject jso2 = makeJSO(); + assertNotSame(jso, jso2); + + jso2 = returnMe(jso); + assertSame(jso, jso2); + } + + public void testInheritance() { + Foo foo = makeFoo(); + FooSub fooSub = (FooSub) foo; + assertEquals("Foo", fooSub.value()); + assertEquals("Still Foo", fooSub.anotherValue()); + assertEquals("Foo", fooSub.superCall()); + } + + public void testMethodMangleClash() { + assertEquals("funcJavaScriptObject", + MethodMangleClash.func((JavaScriptObject) null)); + assertEquals("funcMethodMangleClash", + MethodMangleClash.func((MethodMangleClash) null)); + assertEquals("func", new MethodMangleClash().func()); + } + + public void testOverloads() { + Foo foo = makeFoo(); + assertEquals("func Foo", new Overloads(foo).func(foo)); + assertEquals("sFunc Foo", Overloads.sFunc(foo)); + + Bar bar = makeBar(); + assertEquals("func Bar", new Overloads(bar).func(bar)); + assertEquals("sFunc Bar", Overloads.sFunc(bar)); + } + + public void testOverloadsArray() { + Foo[][] foo = new Foo[0][0]; + assertEquals("func Foo[][]", new Overloads(foo).func(foo)); + assertEquals("sFunc Foo[][]", Overloads.sFunc(foo)); + + Bar[][] bar = new Bar[0][0]; + assertEquals("func Bar[][]", new Overloads(bar).func(bar)); + assertEquals("sFunc Bar[][]", Overloads.sFunc(bar)); + } + + public native void testOverloadsArrayNative() /*-{ + var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new([[Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Foo[][]", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func([[Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Foo[][]", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc([[Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); + + var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new([[Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Bar[][]", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func([[Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Bar[][]", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc([[Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); + }-*/; + + public native void testOverloadsNative() /*-{ + var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new(Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Foo", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func(Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Foo", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc(Lcom/google/gwt/dev/jjs/test/JsoTest$Foo;)(null)); + + var o = @com.google.gwt.dev.jjs.test.JsoTest.Overloads::new(Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("func Bar", o.@com.google.gwt.dev.jjs.test.JsoTest.Overloads::func(Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("sFunc Bar", @com.google.gwt.dev.jjs.test.JsoTest.Overloads::sFunc(Lcom/google/gwt/dev/jjs/test/JsoTest$Bar;)(null)); + }-*/; + + public void testStaticAccess() { + Foo.field = 3; + assertEquals(3, Foo.field--); + assertEquals("Foo2", Foo.staticValue()); + assertEquals("nativeFoo", Foo.staticNative()); + + Bar.field = 10; + assertEquals(11, ++Bar.field); + assertEquals("Bar11", Bar.staticValue()); + assertEquals("nativeBar", Bar.staticNative()); + } + + public native void testStaticAccessNative() /*-{ + @com.google.gwt.dev.jjs.test.JsoTest.Foo::field = 3; + @junit.framework.Assert::assertEquals(II)(3, @com.google.gwt.dev.jjs.test.JsoTest.Foo::field--); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("Foo2", @com.google.gwt.dev.jjs.test.JsoTest.Foo::staticValue()()); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("nativeFoo", @com.google.gwt.dev.jjs.test.JsoTest.Foo::staticNative()()); + + @com.google.gwt.dev.jjs.test.JsoTest.Bar::field = 10; + @junit.framework.Assert::assertEquals(II)(11, ++@com.google.gwt.dev.jjs.test.JsoTest.Bar::field); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("Bar11", @com.google.gwt.dev.jjs.test.JsoTest.Bar::staticValue()()); + @junit.framework.Assert::assertEquals(Ljava/lang/Object;Ljava/lang/Object;)("nativeBar", @com.google.gwt.dev.jjs.test.JsoTest.Bar::staticNative()()); + }-*/; +}
diff --git a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java index d11c7fe..4949d47 100644 --- a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java +++ b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java
@@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -16,7 +16,6 @@ package com.google.gwt.dev.jjs.test; import com.google.gwt.core.client.JavaScriptException; -import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.junit.client.GWTTestCase; /** @@ -45,12 +44,6 @@ } } - private static class Foo extends JavaScriptObject { - public String toString() { - return "Foo"; - } - } - private static class HasClinit { public static int i = 1; @@ -93,14 +86,6 @@ @com.google.gwt.dev.jjs.test.MiscellaneousTest$HasClinit::i = 5; }-*/; - private static native Foo getFoo() /*-{ - return {}; - }-*/; - - private static native JavaScriptObject getJso() /*-{ - return {toString:function(){return 'jso';}}; - }-*/; - private static native void throwNativeException() /*-{ var a; a.asdf(); }-*/; @@ -214,6 +199,7 @@ b[2] = null; } + @SuppressWarnings("cast") public void testCasts() { Object o = noOptimizeFalse() ? (Object) new PolyA() : (Object) new PolyB(); assertTrue(o instanceof I); @@ -281,50 +267,6 @@ assertEquals(5, i); } - public void testJso() { - Foo foo = getFoo(); - assertEquals("Foo", foo.toString()); - JavaScriptObject jso = foo; - assertEquals("Foo", jso.toString()); - Object y = noOptimizeFalse() ? new Object() : foo; - assertEquals("Foo", y.toString()); - jso = getJso(); - assertEquals("jso", jso.toString()); - } - - public void testJsoArrayInit() { - Object[] jsos = {getJso(), ""}; - JavaScriptObject jso = (JavaScriptObject) jsos[0]; - } - - public void testJsoArrayStore() { - // Verify that a JSO stored into an array was correctly wrapped - String[] strings = {""}; - JavaScriptObject[] jsos = {getJso()}; - Object[] objArray = noOptimizeFalse() ? (Object[]) strings : jsos; - JavaScriptObject jso = (JavaScriptObject) objArray[0]; - - // Verify that ArrayStoreExceptions are generated in the correct cases - try { - JavaScriptObject[] typeTightenedFooArray = new Foo[3]; - typeTightenedFooArray[0] = getJso(); - fail(); - } catch (ArrayStoreException e) { - } - - try { - JavaScriptObject[] fooArray = noOptimizeFalse() ? new JavaScriptObject[3] - : new Foo[3]; - fooArray[0] = getJso(); - fail(); - } catch (ArrayStoreException e) { - } - - JavaScriptObject[] jsoArray = noOptimizeFalse() ? new Foo[3] - : new JavaScriptObject[3]; - jsoArray[0] = getJso(); - } - public void testString() { String x = "hi"; assertEquals("hi", x);