/* * Copyright 2014 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.JConstructor; import com.google.gwt.dev.jjs.ast.JDeclaredType; 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.JNewInstance; import com.google.gwt.dev.jjs.ast.JProgram; import com.google.gwt.dev.jjs.ast.JType; import com.google.gwt.dev.jjs.ast.js.JsniMethodRef; import com.google.gwt.dev.util.log.speedtracer.CompilerEventType; import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; import com.google.gwt.thirdparty.guava.common.base.Function; import com.google.gwt.thirdparty.guava.common.base.Joiner; import com.google.gwt.thirdparty.guava.common.collect.Iterables; import java.util.HashMap; import java.util.Map; /** * Rewrite instantiations of Boolean, Double, and String to use static helper methods which return * unboxed versions. * */ public class RewriteConstructorCallsForUnboxedTypes extends JModVisitor { public static final String NATIVE_TYPE_CREATEMETHOD_PREFIX = "$create"; private JProgram program; private Map<JDeclaredType, Map<String, JMethod>> createMethodsByType = new HashMap<>(); public RewriteConstructorCallsForUnboxedTypes(JProgram program) { this.program = program; for (JDeclaredType unboxedType : program.getRepresentedAsNativeTypes()) { HashMap<String, JMethod> createMethods = new HashMap<>(); createMethodsByType.put(unboxedType, createMethods); for (JMethod method : unboxedType.getMethods()) { if (method.getName().startsWith(NATIVE_TYPE_CREATEMETHOD_PREFIX)) { createMethods.put(getParametersAsString(method), method); } } } } @Override public void endVisit(JNewInstance x, Context ctx) { JConstructor ctor = x.getTarget(); if (!program.isRepresentedAsNativeJsPrimitive(ctor.getEnclosingType())) { return; } // map BoxedType(args) -> BoxedType.$create(args) JMethod createMethod = createMethodsByType .get(ctor.getEnclosingType()) .get(getParametersAsString(ctor)); assert createMethod != null; JMethodCall createCall = new JMethodCall(x.getSourceInfo(), null, createMethod); createCall.addArgs(x.getArgs()); ctx.replaceMe(createCall); } @Override public void endVisit(JsniMethodRef x, Context ctx) { if (x.getTarget().isConstructor() && program.isRepresentedAsNativeJsPrimitive(x.getTarget().getEnclosingType())) { JConstructor ctor = (JConstructor) x.getTarget(); // map BoxedType(args) -> BoxedType.$createType(args) JMethod createMethod = createMethodsByType .get(ctor.getEnclosingType()) .get(getParametersAsString(ctor)); assert createMethod != null; JsniMethodRef newJsniMethodRef = new JsniMethodRef(x.getSourceInfo(), x.getIdent(), createMethod, program.getJavaScriptObject()); ctx.replaceMe(newJsniMethodRef); } } private static String getParametersAsString(JMethod method) { return Joiner.on(",").join(Iterables.transform(method.getOriginalParamTypes(), new Function<JType, String>() { @Override public String apply(JType type) { return type.getJsniSignatureName(); } })); } private static final String NAME = RewriteConstructorCallsForUnboxedTypes.class .getSimpleName(); private OptimizerStats execImpl() { OptimizerStats stats = new OptimizerStats(NAME); accept(program); return stats; } public static OptimizerStats exec(JProgram program) { Event optimizeEvent = SpeedTracerLogger .start(CompilerEventType.OPTIMIZE, "optimizer", NAME); OptimizerStats stats = new RewriteConstructorCallsForUnboxedTypes(program).execImpl(); optimizeEvent.end("didChange", "" + stats.didChange()); return stats; } }