Package com.google.gwt.dev.jdt

Source Code of com.google.gwt.dev.jdt.ByteCodeCompiler

/*
* Copyright 2006 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 org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;

/**
* A facade around the JDT compiler to manage on-demand Java source to bytecode
* compilation, caching compiled bytecode where possible.
*/
public class ByteCodeCompiler extends AbstractCompiler {

  private final CacheManager cacheManager;

  /**
   * Creates a bytecode compiler for use not in hosted mode. All bytecode will
   * be thrown away after reload.
   *
   * @param sourceOracle used to find the source
   */
  public ByteCodeCompiler(SourceOracle sourceOracle) {
    super(sourceOracle, true);
    this.cacheManager = new CacheManager();
  }

  /**
   * Creates a byte code compiler given the supplied sourceOracle (to find the
   * source) and the supplied cacheManager (to keep the bytecode and other
   * info). If the cacheManager has a cacheDir, it will keep bytecode across
   * reload, and load them from the cacheDir on startup. Otherwise, each reload
   * will clear the cache. In hosted mode, the cacheManager used to create this
   * object should be the same one used to create the typeOracleBuilder.
   *
   * @param sourceOracle used to find the source
   * @param cacheManager used to keep the cached information
   */
  public ByteCodeCompiler(SourceOracle sourceOracle, CacheManager cacheManager) {
    super(sourceOracle, true);
    this.cacheManager = cacheManager;
  }

  /**
   * Get the bytecode for the specified type.
   *
   * @param binaryTypeName the binary type name to look up or compile
   */
  public byte[] getClassBytes(TreeLogger logger, String binaryTypeName)
      throws UnableToCompleteException {

    // We use a thread logger proxy because we can't wind the logger through
    // JDT directly.
    //
    String msg = "Getting bytecode for '" + binaryTypeName + "'";
    logger = logger.branch(TreeLogger.SPAM, msg, null);
    setLogger(logger);

    // Check the bytecode cache in case we've already compiled it.
    //
    ByteCode byteCode = doGetByteCodeFromCache(logger, binaryTypeName);
    if (byteCode != null) {
      // We have it already.
      //
      return byteCode.getBytes();
    }

    // Need to compile it. It could be the case that we have tried before and
    // failed, but on the off chance that it's been fixed since then, we adopt
    // a policy of always trying to recompile if we don't have it cached.
    //
    ICompilationUnit start = getCompilationUnitForType(logger, binaryTypeName);
    compile(logger, new ICompilationUnit[] {start});

    // Check the cache again. If it's there now, we succeeded.
    // If it isn't there now, we've already logged the error.
    //
    byteCode = doGetByteCodeFromCache(logger, binaryTypeName);
    if (byteCode != null) {
      return byteCode.getBytes();
    } else {
      throw new UnableToCompleteException();
    }
  }

  /**
   * Prevents the compile process from ever trying to compile these types from
   * source. This is used for special types that would not compile correctly
   * from source.
   *
   * @param binaryTypeName the binary name of the specified type
   */
  public void putClassBytes(TreeLogger logger, String binaryTypeName,
      byte[] bytes, String location) {

    // We must remember the package name independently in case this is a type
    // the host doesn't actually know about.
    //
    String pkgName = "";
    int lastDot = binaryTypeName.lastIndexOf('.');
    if (lastDot != -1) {
      pkgName = binaryTypeName.substring(0, lastDot);
    }
    rememberPackage(pkgName);

    // Cache the bytes.
    //
    ByteCode byteCode = new ByteCode(binaryTypeName, bytes, location, true);
    cacheManager.acceptIntoCache(logger, binaryTypeName, byteCode);
  }

  /**
   * This method removes the bytecode which is no longer current, or if the
   * cacheManager does not have a cacheDir, all the bytecode.
   *
   * @param logger used to describe the results to the user
   */
  public void removeStaleByteCode(TreeLogger logger) {
    cacheManager.removeStaleByteCode(logger, this);
  }

  protected void doAcceptResult(CompilationResult result) {
    // Take all compiled class files and put them in the byte cache.
    //
    TreeLogger logger = getLogger();
    ClassFile[] classFiles = result.getClassFiles();
    for (int i = 0; i < classFiles.length; i++) {
      ClassFile classFile = classFiles[i];
      char[][] compoundName = classFile.getCompoundName();
      char[] classNameChars = CharOperation.concatWith(compoundName, '.');
      String className = String.valueOf(classNameChars);
      byte bytes[] = classFile.getBytes();
      String loc = String.valueOf(result.compilationUnit.getFileName());
      boolean isTransient = true;
      if (result.compilationUnit instanceof ICompilationUnitAdapter) {
        ICompilationUnitAdapter unit = (ICompilationUnitAdapter) result.compilationUnit;
        isTransient = unit.getCompilationUnitProvider().isTransient();
      }
      ByteCode byteCode = new ByteCode(className, bytes, loc, isTransient);
      if (cacheManager.acceptIntoCache(logger, className, byteCode)) {
        logger.log(TreeLogger.SPAM, "Successfully compiled and cached '"
            + className + "'", null);
      }
    }
  }

  /**
   * Checks the cache for bytecode for the specified binary type name. Silently
   * removes and pretends it didn't see any bytecode that is out-of-date with
   * respect to the compilation unit that provides it.
   */
  protected ByteCode doGetByteCodeFromCache(TreeLogger logger,
      String binaryTypeName) {
    return cacheManager.getByteCode(logger, binaryTypeName);
  }
}
TOP

Related Classes of com.google.gwt.dev.jdt.ByteCodeCompiler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.