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);