1 16 package com.google.gwt.dev.jjs; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.UnableToCompleteException; 20 import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider; 21 import com.google.gwt.dev.jdt.ICompilationUnitAdapter; 22 import com.google.gwt.dev.jdt.RebindOracle; 23 import com.google.gwt.dev.jdt.RebindPermutationOracle; 24 import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd; 25 import com.google.gwt.dev.jjs.InternalCompilerException.NodeInfo; 26 import com.google.gwt.dev.jjs.ast.JClassType; 27 import com.google.gwt.dev.jjs.ast.JExpression; 28 import com.google.gwt.dev.jjs.ast.JMethod; 29 import com.google.gwt.dev.jjs.ast.JMethodCall; 30 import com.google.gwt.dev.jjs.ast.JNewInstance; 31 import com.google.gwt.dev.jjs.ast.JProgram; 32 import com.google.gwt.dev.jjs.ast.JReferenceType; 33 import com.google.gwt.dev.jjs.impl.ArrayNormalizer; 34 import com.google.gwt.dev.jjs.impl.AssertionRemover; 35 import com.google.gwt.dev.jjs.impl.BuildTypeMap; 36 import com.google.gwt.dev.jjs.impl.CastNormalizer; 37 import com.google.gwt.dev.jjs.impl.CatchBlockNormalizer; 38 import com.google.gwt.dev.jjs.impl.CompoundAssignmentNormalizer; 39 import com.google.gwt.dev.jjs.impl.DeadCodeElimination; 40 import com.google.gwt.dev.jjs.impl.GenerateJavaAST; 41 import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST; 42 import com.google.gwt.dev.jjs.impl.JavaScriptObjectCaster; 43 import com.google.gwt.dev.jjs.impl.MakeCallsStatic; 44 import com.google.gwt.dev.jjs.impl.MethodAndClassFinalizer; 45 import com.google.gwt.dev.jjs.impl.MethodCallTightener; 46 import com.google.gwt.dev.jjs.impl.MethodInliner; 47 import com.google.gwt.dev.jjs.impl.Pruner; 48 import com.google.gwt.dev.jjs.impl.ReplaceRebinds; 49 import com.google.gwt.dev.jjs.impl.TypeMap; 50 import com.google.gwt.dev.jjs.impl.TypeTightener; 51 import com.google.gwt.dev.js.JsNormalizer; 52 import com.google.gwt.dev.js.JsObfuscateNamer; 53 import com.google.gwt.dev.js.JsPrettyNamer; 54 import com.google.gwt.dev.js.JsSourceGenerationVisitor; 55 import com.google.gwt.dev.js.JsSymbolResolver; 56 import com.google.gwt.dev.js.JsVerboseNamer; 57 import com.google.gwt.dev.js.ast.JsProgram; 58 import com.google.gwt.dev.util.DefaultTextOutput; 59 import com.google.gwt.dev.util.Util; 60 61 import org.eclipse.jdt.core.compiler.IProblem; 62 import org.eclipse.jdt.internal.compiler.CompilationResult; 63 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; 64 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; 65 66 import java.util.HashSet ; 67 import java.util.Iterator ; 68 import java.util.List ; 69 import java.util.Set ; 70 71 75 public class JavaToJavaScriptCompiler { 76 77 private static void findEntryPoints(TreeLogger logger, 78 RebindOracle rebindOracle, String [] mainClassNames, JProgram program) 79 throws UnableToCompleteException { 80 JMethod bootStrapMethod = program.createMethod(null, "init".toCharArray(), 81 null, program.getTypeVoid(), false, true, true, false, false); 82 bootStrapMethod.freezeParamTypes(); 83 84 for (int i = 0; i < mainClassNames.length; ++i) { 85 String mainClassName = mainClassNames[i]; 86 JReferenceType referenceType = program.getFromTypeMap(mainClassName); 87 88 if (referenceType == null) { 89 logger.log(TreeLogger.ERROR, 90 "Could not find module entry point class '" + mainClassName + "'", 91 null); 92 throw new UnableToCompleteException(); 93 } 94 95 JExpression qualifier = null; 96 JMethod mainMethod = findMainMethod(referenceType); 97 if (mainMethod == null || !mainMethod.isStatic()) { 98 String originalClassName = mainClassName; 100 mainClassName = rebindOracle.rebind(logger, originalClassName); 101 referenceType = program.getFromTypeMap(mainClassName); 102 if (referenceType == null) { 103 logger.log(TreeLogger.ERROR, 104 "Could not find module entry point class '" + mainClassName 105 + "' after rebinding from '" + originalClassName + "'", null); 106 throw new UnableToCompleteException(); 107 } 108 109 if (!(referenceType instanceof JClassType)) { 110 logger.log(TreeLogger.ERROR, "Module entry point class '" 111 + mainClassName + "' must be a class", null); 112 throw new UnableToCompleteException(); 113 } 114 115 JClassType mainClass = (JClassType) referenceType; 116 if (mainClass.isAbstract()) { 117 logger.log(TreeLogger.ERROR, "Module entry point class '" 118 + mainClassName + "' must not be abstract", null); 119 throw new UnableToCompleteException(); 120 } 121 122 mainMethod = findMainMethodRecurse(referenceType); 123 if (mainMethod == null) { 124 logger.log(TreeLogger.ERROR, 125 "Could not find entry method 'onModuleLoad()' method in entry point class '" 126 + mainClassName + "'", null); 127 throw new UnableToCompleteException(); 128 } 129 130 if (mainMethod.isAbstract()) { 131 logger.log(TreeLogger.ERROR, 132 "Entry method 'onModuleLoad' in entry point class '" 133 + mainClassName + "' must not be abstract", null); 134 throw new UnableToCompleteException(); 135 } 136 137 if (!mainMethod.isStatic()) { 138 JMethod noArgCtor = null; 140 for (int j = 0; j < mainClass.methods.size(); ++j) { 141 JMethod ctor = (JMethod) mainClass.methods.get(j); 142 if (ctor.getName().equals(mainClass.getShortName())) { 143 if (ctor.params.size() == 0) { 144 noArgCtor = ctor; 145 } 146 } 147 } 148 if (noArgCtor == null) { 149 logger.log( 150 TreeLogger.ERROR, 151 "No default (zero argument) constructor could be found in entry point class '" 152 + mainClassName 153 + "' to qualify a call to non-static entry method 'onModuleLoad'", 154 null); 155 throw new UnableToCompleteException(); 156 } 157 158 JNewInstance newInstance = new JNewInstance(program, null, mainClass); 161 qualifier = new JMethodCall(program, null, newInstance, noArgCtor); 162 } 163 } 164 165 JMethodCall onModuleLoadCall = new JMethodCall(program, null, qualifier, 167 mainMethod); 168 bootStrapMethod.body.statements.add(onModuleLoadCall.makeStatement()); 169 } 170 program.addEntryMethod(bootStrapMethod); 171 } 172 173 private static JMethod findMainMethod(JReferenceType referenceType) { 174 for (int j = 0; j < referenceType.methods.size(); ++j) { 175 JMethod method = (JMethod) referenceType.methods.get(j); 176 if (method.getName().equals("onModuleLoad")) { 177 if (method.params.size() == 0) { 178 return method; 179 } 180 } 181 } 182 return null; 183 } 184 185 private static JMethod findMainMethodRecurse(JReferenceType referenceType) { 186 for (JReferenceType it = referenceType; it != null; it = it.extnds) { 187 JMethod result = findMainMethod(it); 188 if (result != null) { 189 return result; 190 } 191 } 192 return null; 193 } 194 195 private final String [] declEntryPoints; 196 private final CompilationUnitDeclaration[] goldenCuds; 197 private long lastModified; 198 private final boolean obfuscate; 199 private final boolean prettyNames; 200 private final Set problemSet = new HashSet (); 201 202 public JavaToJavaScriptCompiler(final TreeLogger logger, 203 final WebModeCompilerFrontEnd compiler, final String [] declEntryPts) 204 throws UnableToCompleteException { 205 this(logger, compiler, declEntryPts, true, false); 206 } 207 208 public JavaToJavaScriptCompiler(final TreeLogger logger, 209 final WebModeCompilerFrontEnd compiler, final String [] declEntryPts, 210 boolean obfuscate, boolean prettyNames) throws UnableToCompleteException { 211 212 if (declEntryPts.length == 0) { 213 throw new IllegalArgumentException ("entry point(s) required"); 214 } 215 216 this.declEntryPoints = declEntryPts; 219 220 this.obfuscate = obfuscate; 223 this.prettyNames = prettyNames; 224 225 RebindPermutationOracle rpo = compiler.getRebindPermutationOracle(); 228 Set allEntryPoints = new HashSet (); 229 for (int i = 0; i < declEntryPts.length; i++) { 230 String [] all = rpo.getAllPossibleRebindAnswers(logger, declEntryPts[i]); 231 Util.addAll(allEntryPoints, all); 232 } 233 String [] entryPts = Util.toStringArray(allEntryPoints); 234 235 int k = entryPts.length; 238 String [] seedTypeNames = new String [k + 3]; 239 System.arraycopy(entryPts, 0, seedTypeNames, 0, k); 240 seedTypeNames[k++] = "com.google.gwt.lang.Array"; 241 seedTypeNames[k++] = "com.google.gwt.lang.Cast"; 242 seedTypeNames[k++] = "com.google.gwt.lang.Exceptions"; 243 244 goldenCuds = compiler.getCompilationUnitDeclarations(logger, seedTypeNames); 247 248 checkForErrors(logger, false); 252 253 lastModified = 0; 256 CompilationUnitProvider newestCup = null; 257 for (int i = 0; i < goldenCuds.length; i++) { 258 CompilationUnitDeclaration cud = goldenCuds[i]; 259 ICompilationUnitAdapter icua = (ICompilationUnitAdapter) cud.compilationResult.compilationUnit; 260 CompilationUnitProvider cup = icua.getCompilationUnitProvider(); 261 long cupLastModified = cup.getLastModified(); 262 if (cupLastModified > lastModified) { 263 newestCup = cup; 264 lastModified = cupLastModified; 265 } 266 } 267 if (newestCup != null) { 268 String loc = newestCup.getLocation(); 269 String msg = "Newest compilation unit is '" + loc + "'"; 270 logger.log(TreeLogger.DEBUG, msg, null); 271 } 272 } 273 274 278 public String compile(TreeLogger logger, RebindOracle rebindOracle) 279 throws UnableToCompleteException { 280 281 try { 282 283 286 JProgram jprogram = new JProgram(logger, rebindOracle); 290 TypeMap typeMap = new TypeMap(jprogram); 291 JsProgram jsProgram = new JsProgram(); 292 TypeDeclaration[] allTypeDeclarations = BuildTypeMap.exec(typeMap, 293 goldenCuds, jsProgram); 294 295 checkForErrors(logger, true); 298 299 jprogram.typeOracle.computeBeforeAST(); 301 302 305 GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram); 307 308 checkForErrors(logger, true); 311 312 boolean isDebugEnabled = false; 314 if (!isDebugEnabled) { 315 AssertionRemover.exec(jprogram); 317 } 318 319 jprogram.typeOracle.computeAfterAST(); 321 322 ReplaceRebinds.exec(jprogram); 324 325 findEntryPoints(logger, rebindOracle, declEntryPoints, jprogram); 328 329 boolean didChange; 331 do { 332 didChange = false; 333 didChange = Pruner.exec(jprogram, true) || didChange; 335 didChange = MethodAndClassFinalizer.exec(jprogram) || didChange; 337 didChange = MakeCallsStatic.exec(jprogram) || didChange; 339 340 didChange = TypeTightener.exec(jprogram) || didChange; 347 348 didChange = MethodCallTightener.exec(jprogram) || didChange; 350 351 didChange = DeadCodeElimination.exec(jprogram) || didChange; 353 354 didChange = MethodInliner.exec(jprogram) || didChange; 356 357 if (didChange) { 358 jprogram.typeOracle.recomputeClinits(); 360 } 361 362 } while (didChange); 365 366 if (isDebugEnabled) { 370 } 372 CatchBlockNormalizer.exec(jprogram); 373 CompoundAssignmentNormalizer.exec(jprogram); 374 JavaScriptObjectCaster.exec(jprogram); 375 CastNormalizer.exec(jprogram); 376 ArrayNormalizer.exec(jprogram); 377 378 Pruner.exec(jprogram, false); 381 382 GenerateJavaScriptAST.exec(jprogram, jsProgram); 384 385 JsNormalizer.exec(jsProgram); 387 388 JsSymbolResolver.exec(jsProgram); 390 391 if (obfuscate) { 393 JsObfuscateNamer.exec(jsProgram); 394 } else if (prettyNames) { 395 JsPrettyNamer.exec(jsProgram); 396 } else { 397 JsVerboseNamer.exec(jsProgram); 398 } 399 400 DefaultTextOutput out = new DefaultTextOutput(obfuscate); 401 JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out); 402 v.accept(jsProgram); 403 return out.toString(); 404 } catch (UnableToCompleteException e) { 405 throw e; 407 } catch (InternalCompilerException e) { 408 TreeLogger topBranch = logger.branch(TreeLogger.ERROR, 409 "An internal compiler exception occurred", e); 410 List nodeTrace = e.getNodeTrace(); 411 for (Iterator it = nodeTrace.iterator(); it.hasNext();) { 412 NodeInfo nodeInfo = (NodeInfo) it.next(); 413 SourceInfo info = nodeInfo.getSourceInfo(); 414 String msg; 415 if (info != null) { 416 String fileName = info.getFileName(); 417 fileName = fileName.substring(fileName.lastIndexOf('/') + 1); 418 fileName = fileName.substring(fileName.lastIndexOf('\\') + 1); 419 msg = "at " + fileName + "(" + info.getStartLine() + "): "; 420 } else { 421 msg = "<no source info>: "; 422 } 423 424 String description = nodeInfo.getDescription(); 425 if (description != null) { 426 msg += description; 427 } else { 428 msg += "<no description available>"; 429 } 430 TreeLogger nodeBranch = topBranch.branch(TreeLogger.ERROR, msg, null); 431 String className = nodeInfo.getClassName(); 432 if (className != null) { 433 nodeBranch.log(TreeLogger.INFO, className, null); 434 } 435 } 436 throw new UnableToCompleteException(); 437 } catch (Throwable e) { 438 logger.log(TreeLogger.ERROR, "Unexpected internal compiler error", e); 439 throw new UnableToCompleteException(); 440 } 441 } 442 443 public long getLastModifiedTimeOfNewestCompilationUnit() { 444 return lastModified; 445 } 446 447 private void checkForErrors(final TreeLogger logger, boolean itemizeErrors) 448 throws UnableToCompleteException { 449 boolean compilationFailed = false; 450 if (goldenCuds.length == 0) { 451 compilationFailed = true; 452 } 453 for (int iCud = 0; iCud < goldenCuds.length; iCud++) { 454 CompilationUnitDeclaration cud = goldenCuds[iCud]; 455 CompilationResult result = cud.compilationResult(); 456 if (result.hasErrors()) { 457 compilationFailed = true; 458 if (!itemizeErrors) { 460 break; 461 } 462 TreeLogger branch = logger.branch(TreeLogger.ERROR, "Errors in " 463 + String.valueOf(result.getFileName()), null); 464 IProblem[] errors = result.getErrors(); 465 for (int i = 0; i < errors.length; i++) { 466 IProblem problem = errors[i]; 467 if (problemSet.contains(problem)) { 468 continue; 469 } 470 471 problemSet.add(problem); 472 473 String msg = problem.toString(); 476 msg = msg.substring(msg.indexOf(' ')); 477 478 int line = problem.getSourceLineNumber(); 481 StringBuffer msgBuf = new StringBuffer (); 482 msgBuf.append("Line "); 483 msgBuf.append(line); 484 msgBuf.append(": "); 485 msgBuf.append(msg); 486 branch.log(TreeLogger.ERROR, msgBuf.toString(), null); 487 } 488 } 489 } 490 if (compilationFailed) { 491 logger.log(TreeLogger.ERROR, "Cannot proceed due to previous errors", 492 null); 493 throw new UnableToCompleteException(); 494 } 495 } 496 } 497 | Popular Tags |