Author: [EMAIL PROTECTED]
Date: Thu Sep 4 15:38:41 2008
New Revision: 3622
Added:
trunk/dev/core/src/com/google/gwt/dev/shell/EmmaStrategy.java
(contents, props changed)
Modified:
trunk/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
trunk/dev/core/src/com/google/gwt/dev/util/Util.java
Log:
Adds Emma integration for client classes running in hosted mode. Here are
the key parts:
1) Bridge Emma's RT class. This is necessary to allow classes living in
the CCL to access the outside world, in this case the Emma coverage data
hook points.
2) Allow instrumented classes to load from disk. This is necessary to pick
up the modifications to pre-instrumented classes, which is the most common
use case with Emma. This is the only case we currently support, although
tobyr has some indication that Java class transformers might also work. We
only conditionally read class files off disk because it's slower; you have
to stat the class and java files to compare dates, and then actually read
the bytes, whereas normally the compiled bytes are already in RAM. Instant
hosted mode should level the playing field by always preferring disk.
Review by: bobv
Modified:
trunk/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
(original)
+++ trunk/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
Thu Sep 4 15:38:41 2008
@@ -354,10 +354,25 @@
*/
private static byte[] javaScriptHostBytes;
+ private static EmmaStrategy emmaStrategy;
+
static {
for (Class<?> c : BRIDGE_CLASSES) {
BRIDGE_CLASS_NAMES.put(c.getName(), c);
}
+ /*
+ * Specific support for bridging to Emma since the user classloader is
+ * generally completely isolated.
+ */
+ boolean emmaIsAvailable = false;
+ try {
+ Class<?> emmaBridge = Class.forName(EmmaStrategy.EMMA_RT_CLASSNAME,
+ false, Thread.currentThread().getContextClassLoader());
+ BRIDGE_CLASS_NAMES.put(EmmaStrategy.EMMA_RT_CLASSNAME, emmaBridge);
+ emmaIsAvailable = true;
+ } catch (ClassNotFoundException ignored) {
+ }
+ emmaStrategy = EmmaStrategy.get(emmaIsAvailable);
}
private static void classDump(String name, byte[] bytes) {
@@ -637,6 +652,8 @@
injectJsniFor(compiledClass);
byte[] classBytes = compiledClass.getBytes();
+ classBytes = emmaStrategy.getEmmaClassBytes(classBytes,
lookupClassName,
+ compiledClass.getUnit().getLastModified());
if (classRewriter != null) {
byte[] newBytes = classRewriter.rewrite(className, classBytes);
if (CLASS_DUMP) {
Added: trunk/dev/core/src/com/google/gwt/dev/shell/EmmaStrategy.java
==============================================================================
--- (empty file)
+++ trunk/dev/core/src/com/google/gwt/dev/shell/EmmaStrategy.java Thu Sep
4 15:38:41 2008
@@ -0,0 +1,88 @@
+/*
+ * 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;
+
+import com.google.gwt.dev.util.Util;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * Provides various strategies for emma integration based on runtime
detection.
+ */
+abstract class EmmaStrategy {
+
+ private static class NoEmmaStrategy extends EmmaStrategy {
+ public byte[] getEmmaClassBytes(byte[] classBytes, String slashedName,
+ long unitLastModified) {
+ return classBytes;
+ }
+ }
+
+ private static class PreinstrumentedEmmaStrategy extends EmmaStrategy {
+ public byte[] getEmmaClassBytes(byte[] classBytes, String slashedName,
+ long unitLastModified) {
+ // Check for an existing class on the classpath.
+ URL url = Thread.currentThread().getContextClassLoader().getResource(
+ slashedName + ".class");
+ if (url != null) {
+ // We found it on the class path.
+ try {
+ URLConnection conn = url.openConnection();
+ if (conn.getLastModified() >= unitLastModified) {
+ // It's as new as the source file, let's use it.
+ byte[] result = Util.readURLConnectionAsBytes(conn);
+ if (result != null) {
+ return result;
+ }
+ // Fall through.
+ }
+ // Fall through.
+ } catch (IOException ignored) {
+ // Fall through.
+ }
+ }
+
+ // Just return what we got.
+ return classBytes;
+ }
+ }
+
+ /**
+ * Classname for Emma's RT, to enable bridging.
+ */
+ public static final String EMMA_RT_CLASSNAME = "com.vladium.emma.rt.RT";
+
+ /**
+ * Gets the emma classloading strategy.
+ */
+ public static EmmaStrategy get(boolean emmaIsAvailable) {
+ /*
+ * Theoretically, emmarun could be using an instrumented ClassLoader,
but in
+ * practice we haven't been able to make GWT run at all in this case.
+ */
+ if (!emmaIsAvailable) {
+ return new NoEmmaStrategy();
+ } else {
+ return new PreinstrumentedEmmaStrategy();
+ }
+ }
+
+ public abstract byte[] getEmmaClassBytes(byte[] classBytes,
+ String slashedName, long unitLastModified);
+
+}
Modified: trunk/dev/core/src/com/google/gwt/dev/util/Util.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/util/Util.java (original)
+++ trunk/dev/core/src/com/google/gwt/dev/util/Util.java Thu Sep 4
15:38:41 2008
@@ -599,22 +599,12 @@
* @return null if the file could not be read
*/
public static byte[] readURLAsBytes(URL url) {
- // ENH: add a weak cache that has an additional check against the file
date
- InputStream input = null;
try {
- URLConnection connection = url.openConnection();
- connection.setUseCaches(false);
- input = connection.getInputStream();
- int contentLength = connection.getContentLength();
- if (contentLength < 0) {
- return null;
- }
-
- return readBytesFromInputStream(input, contentLength);
+ URLConnection conn = url.openConnection();
+ conn.setUseCaches(false);
+ return readURLConnectionAsBytes(conn);
} catch (IOException e) {
return null;
- } finally {
- Utility.close(input);
}
}
@@ -622,13 +612,30 @@
* @return null if the file could not be read
*/
public static char[] readURLAsChars(URL url) {
- // ENH: add a weak cache that has an additional check against the file
date
byte[] bytes = readURLAsBytes(url);
if (bytes != null) {
return toString(bytes, DEFAULT_ENCODING).toCharArray();
}
return null;
+ }
+
+ public static byte[] readURLConnectionAsBytes(URLConnection connection) {
+ // ENH: add a weak cache that has an additional check against the file
date
+ InputStream input = null;
+ try {
+ input = connection.getInputStream();
+ int contentLength = connection.getContentLength();
+ if (contentLength < 0) {
+ return null;
+ }
+
+ return readBytesFromInputStream(input, contentLength);
+ } catch (IOException e) {
+ return null;
+ } finally {
+ Utility.close(input);
+ }
}
/**
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---