Moves JsInterop metadata population behind jsinterop flag.

By doing that, we could unify all jsinterop flag checking in one
place and for example, we could directly ask an AST Node if it is
exported or not instead of going through JTypeOracle to check
the jsinterop flag.

The patch expected not to have any user visible changes.

Change-Id: Id4080a261ada47f71d210f699d72d5c39ed17bb5
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 30ab427..0f11fbe 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -338,9 +338,6 @@
         instrumentableLines = BaselineCoverageGatherer.exec(jprogram);
       }
 
-      // TypeOracle needs this to make decisions in several optimization passes
-      jprogram.typeOracle.setJsInteropMode(compilerContext.getOptions().getJsInteropMode());
-
       // Record initial set of type->type references.
       // type->type references need to be collected in two phases, 1) before any process to the
       // AST has happened (to record for example reference to types declaring compile-time
@@ -1149,7 +1146,6 @@
       // Synchronize JTypeOracle with compile optimization behavior.
       jprogram.typeOracle.setOptimize(
           options.getOptimizationLevel() > OptionOptimize.OPTIMIZE_LEVEL_DRAFT);
-      jprogram.typeOracle.setJsInteropMode(options.getJsInteropMode());
 
       jsProgram = new JsProgram();
 
@@ -1291,9 +1287,7 @@
       String[] additionalRootTypes, CompilationState compilationState) {
 
     Set<String> allRootTypes = Sets.newTreeSet();
-    if (jprogram.typeOracle.isJsInteropEnabled()) {
-      Iterables.addAll(allRootTypes, compilationState.getQualifiedJsInteropRootTypesNames());
-    }
+    Iterables.addAll(allRootTypes, compilationState.getQualifiedJsInteropRootTypesNames());
     Collections.addAll(allRootTypes, entryPointTypeNames);
     Collections.addAll(allRootTypes, additionalRootTypes);
     allRootTypes.addAll(JProgram.CODEGEN_TYPES_SET);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index 845d4e6..c023ee7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -153,23 +153,23 @@
   }
 
   public JsPropertyType getImmediateOrTransitiveJsPropertyType() {
-    if (isJsProperty()) {
+    if (isJsPropertyAccessor()) {
       return getJsPropertyType();
     }
     for (JMethod overriddenMethod : getOverriddenMethods()) {
-      if (overriddenMethod.isJsProperty()) {
+      if (overriddenMethod.isJsPropertyAccessor()) {
         return overriddenMethod.getJsPropertyType();
       }
     }
     return null;
   }
 
-  public boolean isJsProperty() {
+  public boolean isJsPropertyAccessor() {
     return jsPropertyType != null;
   }
 
   public boolean isOrOverridesJsProperty() {
-    if (isJsProperty()) {
+    if (isJsPropertyAccessor()) {
       return true;
     }
     for (JMethod overriddenMethod : getOverriddenMethods()) {
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 8f51dc2..7558c08 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
@@ -57,8 +57,7 @@
    * Returns whether a class is a synthetic Prototype class generated by APT or user.
    */
   public boolean isJsTypePrototype(JDeclaredType classType) {
-    return typeOracle.isJsInteropEnabled() && classType instanceof JClassType
-        && ((JClassType) classType).isJsPrototypeStub();
+    return classType instanceof JClassType && ((JClassType) classType).isJsPrototypeStub();
   }
 
   private static final class TreeStatistics extends JVisitor {
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 7e57e38..60f346f 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
@@ -17,7 +17,6 @@
 
 import com.google.gwt.dev.MinimalRebuildCache;
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
-import com.google.gwt.dev.util.arg.OptionJsInteropMode;
 import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting;
 import com.google.gwt.thirdparty.guava.common.base.Function;
 import com.google.gwt.thirdparty.guava.common.base.Objects;
@@ -135,7 +134,6 @@
   }
 
   private Set<JReferenceType> instantiatedJsoTypesViaCast = Sets.newHashSet();
-  private OptionJsInteropMode.Mode jsInteropMode;
 
   public void setInstantiatedJsoTypesViaCast(Set<JReferenceType> instantiatedJsoTypesViaCast) {
     this.instantiatedJsoTypesViaCast = instantiatedJsoTypesViaCast;
@@ -152,10 +150,6 @@
    * 3) the method returns or accepts JsAware/JsConvert types.
    */
   public boolean needsJsInteropBridgeMethod(JMethod x) {
-    if (!isJsInteropEnabled()) {
-      return false;
-    }
-
     /*
      * We need Javascript bridge methods for exports in this class
      * @JsType
@@ -196,12 +190,12 @@
      */
     // covariant methods need JS bridges
     List<JParameter> xParams = x.getParams();
-    if (isJsTypeMethod(x)) {
+    if (x.isOrOverridesJsTypeMethod()) {
       for (JMethod other : x.getEnclosingType().getMethods()) {
          if (other == x) {
            continue;
          }
-         if (isJsTypeMethod(other) && x.getName().equals(other.getName())) {
+        if (other.isOrOverridesJsTypeMethod() && x.getName().equals(other.getName())) {
            List<JParameter> otherParams = other.getParams();
            if (otherParams.size() == xParams.size()) {
              for (int i = 0; i < otherParams.size(); i++) {
@@ -218,16 +212,16 @@
       }
     }
 
-    if (x.needsVtable() && isJsTypeMethod(x)) {
+    if (x.needsVtable() && x.isOrOverridesJsTypeMethod()) {
       for (JMethod override : x.getOverriddenMethods()) {
-        if (!isJsTypeMethod(override)) {
+        if (!override.isOrOverridesJsTypeMethod()) {
           return true;
         }
       }
     }
 
     // implicit builtin @JsConvert, longs are converted
-    if (isJsTypeMethod(x) || isExportedMethod(x)) {
+    if (x.isOrOverridesJsTypeMethod() || x.isExported()) {
       if (x.getOriginalReturnType() == JPrimitiveType.LONG) {
         return true;
       }
@@ -241,14 +235,6 @@
     return false;
   }
 
-  public boolean isJsInteropEnabled() {
-    return jsInteropMode != OptionJsInteropMode.Mode.NONE;
-  }
-
-  public void setJsInteropMode(OptionJsInteropMode.Mode jsInteropMode) {
-    this.jsInteropMode = jsInteropMode;
-  }
-
   public void setOptimize(boolean optimize) {
     this.optimize = optimize;
   }
@@ -795,10 +781,6 @@
    * Get the nearest JS type.
    */
   public JDeclaredType getNearestJsType(JType type, boolean mustHavePrototype) {
-    if (!isJsInteropEnabled()) {
-      return null;
-    }
-
     type = type.getUnderlyingType();
 
     if (!(type instanceof JDeclaredType)) {
@@ -806,7 +788,7 @@
     }
 
     JDeclaredType dtype = (JDeclaredType) type;
-    if (isJsType(dtype) && (!mustHavePrototype || !Strings.isNullOrEmpty(dtype.getJsPrototype()))) {
+    if (dtype.isJsType() && (!mustHavePrototype || !Strings.isNullOrEmpty(dtype.getJsPrototype()))) {
       return dtype;
     }
 
@@ -825,7 +807,7 @@
    */
   public JMethod getJsFunctionMethod(JClassType type) {
     for (JMethod method : type.getMethods()) {
-      if (isJsFunctionMethod(method)) {
+      if (method.isOrOverridesJsFunctionMethod()) {
         return method;
       }
     }
@@ -1079,64 +1061,15 @@
     return classType.getSuperClass() == null;
   }
 
-
-  public boolean isExportedField(JField field) {
-    return isJsInteropEnabled() && field.isExported();
-  }
-
-  public boolean isExportedMethod(JMethod method) {
-    return isJsInteropEnabled() && method.isExported();
-  }
-
-  /**
-   * Returns whether the given method is exported by an @JsType annotation.
-   * <p>
-   * A method is a JsType method if it is a public instance method that has not been marked NoExport
-   * and is in a concrete class that has been annotated @JsType or overrides some other JsType
-   * method.
-   */
-  public boolean isJsTypeMethod(JMethod x) {
-    return isJsInteropEnabled() && x.isOrOverridesJsTypeMethod();
-  }
-
-  /**
-   * Returns whether the given method is directly marked with an @JsProperty annotation.
-   */
-  public boolean isJsPropertyMethod(JMethod x) {
-    return isJsInteropEnabled() && x.isJsProperty();
-  }
-
-  /**
-   * Returns whether the given field is exported by an @JsType annotation.
-   * <p>
-   * A field is a JsType field if it is a public instance field on a concrete class that has been
-   * annotated @JsType.
-   */
-  public boolean isJsTypeField(JField x) {
-    return isJsInteropEnabled() && x.isJsTypeMember();
-  }
-
   public boolean isSingleJsoImpl(JType type) {
     return type instanceof JReferenceType && getSingleJsoImpl((JReferenceType) type) != null;
   }
 
   /**
-   * Returns whether the given method may be implicitly called by a instance of a class that
-   * is exported by an @JsFunction annotation.
-   * <p>
-   * A method is a JsFunction method if it is or overrides a SAM function of a @JsFunction annotated
-   * functional interface.
-   */
-  public boolean isJsFunctionMethod(JMethod x) {
-    return isJsInteropEnabled() && x.isOrOverridesJsFunctionMethod();
-  }
-
-  /**
    * Whether the type is a JS interface (does not check supertypes).
    */
   public boolean isJsType(JType type) {
-    return isJsInteropEnabled()
-        && (type instanceof JDeclaredType && ((JDeclaredType) type).isJsType());
+    return type instanceof JDeclaredType && ((JDeclaredType) type).isJsType();
   }
 
   /**
@@ -1144,27 +1077,14 @@
    * one of the types has a js prototype.
    */
   public boolean isOrExtendsJsType(JType type, boolean mustHavePrototype) {
-    if (isJsInteropEnabled()) {
-      JDeclaredType dtype = getNearestJsType(type, mustHavePrototype);
-      return dtype != null;
-    } else {
-      return false;
-    }
+    return getNearestJsType(type, mustHavePrototype) != null;
   }
 
   /**
    * Whether the type is a JsFunction interface.
    */
   public boolean isJsFunction(JType type) {
-    return isJsInteropEnabled()
-        && (type instanceof JInterfaceType && ((JInterfaceType) type).isJsFunction());
-  }
-
-  /**
-   * Whether the type or any supertypes is a JsFunction type.
-   */
-  public boolean isOrExtendsJsFunction(JDeclaredType type) {
-    return isJsInteropEnabled() && !getImplementedJsFunctions(type).isEmpty();
+    return type instanceof JInterfaceType && ((JInterfaceType) type).isJsFunction();
   }
 
   /**
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
index e18da72..4582834 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -607,17 +607,17 @@
         if (dependencyRecorder != null) {
           curMethodStack.remove(curMethodStack.size() - 1);
         }
-        if (method.isNative() || program.typeOracle.isJsTypeMethod(method)
-            || program.typeOracle.isJsFunctionMethod(method)) {
+        if (method.isNative() || method.isOrOverridesJsTypeMethod()
+            || method.isOrOverridesJsFunctionMethod()) {
             /*
              * SPECIAL: returning from this method passes a value from
              * JavaScript into Java.
              */
           maybeRescueJavaScriptObjectPassingIntoJava(method.getType());
         }
-        if (program.typeOracle.isExportedMethod(method)
-            || program.typeOracle.isJsTypeMethod(method)
-            || program.typeOracle.isJsFunctionMethod(method)) {
+        if (method.isExported()
+            || method.isOrOverridesJsTypeMethod()
+            || method.isOrOverridesJsFunctionMethod()) {
           for (JParameter param : method.getParams()) {
             /**
              * TODO (cromwellian): JS visible methods (virtual or static) may be supplied
@@ -708,13 +708,13 @@
         // already safely rescued by other ControlFlow logic.
         if (dtype.isJsType() || dtype.isJsFunction()) {
           for (JMethod method : dtype.getMethods()) {
-            if (program.typeOracle.isJsTypeMethod(method)
-                || program.typeOracle.isJsFunctionMethod(method)) {
+            if (method.isOrOverridesJsTypeMethod()
+                || method.isOrOverridesJsFunctionMethod()) {
               rescue(method);
             }
           }
           for (JField field : dtype.getFields()) {
-            if (program.typeOracle.isJsTypeField(field)) {
+            if (field.isJsTypeMember()) {
               rescue(field);
             }
           }
@@ -800,8 +800,8 @@
         JParameter param = params.get(i);
         if (arg.hasSideEffects() || liveFieldsAndMethods.contains(param)
             // rescue any args of JsInterface Prototype methods or JsInterface
-            || program.typeOracle.isJsTypeMethod(method)
-            || program.typeOracle.isJsFunctionMethod(method)
+            || method.isOrOverridesJsTypeMethod()
+            || method.isOrOverridesJsFunctionMethod()
             || program.isJsTypePrototype(method.getEnclosingType())) {
           this.accept(arg);
           continue;
@@ -864,8 +864,8 @@
       for (JMethod method : type.getMethods()) {
         if (!method.isStatic() && (membersToRescueIfTypeIsInstantiated.contains(method)
             // method may be called from JS as well
-           || program.typeOracle.isJsTypeMethod(method)
-           || program.typeOracle.isJsFunctionMethod(method))) {
+           || method.isOrOverridesJsTypeMethod()
+           || method.isOrOverridesJsFunctionMethod())) {
           rescue(method);
         }
       }
@@ -1056,14 +1056,14 @@
     for (JDeclaredType type : declaredTypes) {
       // first time through, record all exported methods
       for (JMethod method : type.getMethods()) {
-        if (program.typeOracle.isExportedMethod(method)) {
+        if (method.isExported()) {
           // treat class as instantiated, since a ctor may be called from JS export
           rescuer.rescue(method.getEnclosingType(), true, true);
           traverseFrom(method);
         }
       }
       for (JField field : type.getFields()) {
-        if (program.typeOracle.isExportedField(field)) {
+        if (field.isExported()) {
           rescuer.rescue(field.getEnclosingType(), true, true);
           rescuer.rescue(field);
         }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java
index 3e70eb4..c8ef394 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java
@@ -112,7 +112,7 @@
   public boolean visit(JField x, Context ctx) {
     String typeName = x.getEnclosingType().getName();
 
-    if (program.typeOracle.isExportedField(x) && x.isStatic()) {
+    if (x.isExported() && x.isStatic()) {
       stringAnalyzableTypeEnvironment.recordExportedStaticReferenceInType(typeName);
     }
 
@@ -136,7 +136,7 @@
           overriddenMethodName);
     }
 
-    if (program.typeOracle.isExportedMethod(x) || program.typeOracle.isJsTypeMethod(x)) {
+    if (x.isExported() || x.isOrOverridesJsTypeMethod()) {
       if (x.isStatic() || x.isConstructor()) {
         stringAnalyzableTypeEnvironment.recordExportedStaticReferenceInType(typeName);
       }
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 85b2c61..c645462 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
@@ -437,7 +437,7 @@
         if (specialObfuscatedFields.containsKey(x)) {
           jsName = scopeStack.peek().declareName(mangleNameSpecialObfuscate(x));
           jsName.setObfuscatable(false);
-        } else if (typeOracle.isJsTypeField(x)) {
+        } else if (x.isJsTypeMember()) {
           jsName = scopeStack.peek().declareName(name, name);
           jsName.setObfuscatable(false);
         } else {
@@ -569,7 +569,7 @@
             polyName = interfaceScope.declareName(mangleNameSpecialObfuscate(x));
             polyName.setObfuscatable(false);
             // if a JsType and we can set set the interface method to non-obfuscatable
-          } else if (typeOracle.isJsTypeMethod(x) && !typeOracle.needsJsInteropBridgeMethod(x)) {
+          } else if (x.isOrOverridesJsTypeMethod() && !typeOracle.needsJsInteropBridgeMethod(x)) {
             if (x.isOrOverridesJsProperty()) {
               // Prevent JsProperty functions like x() from colliding with intended JS native
               // properties like .x;
@@ -944,10 +944,7 @@
         globalStmts.add(vars);
       }
 
-      if (typeOracle.isJsInteropEnabled() && typeOracle.isInstantiatedType(x) && !x.isJsoType() &&
-        x !=  program.getTypeJavaLangString()) {
-        collectExports(x);
-      }
+      collectExports(x);
 
       // TODO(zundel): Check that each unique method has a unique
       // name / poly name.
@@ -1194,19 +1191,17 @@
         globalStmts.add(vars);
       }
 
-      if (typeOracle.isJsInteropEnabled()) {
-        /*
-         * If a @JsType is exported, but no constructors are, @JsDoc type declarations added by the
-         * linker will fail in uncompiled mode, as they will try to access the 'Foo.prototype' which
-         * is undefined even though the goog.provide('Foo') statement exists. Here we synthesize a
-         * simple constructor to aid the linker.
-         */
-        if (closureCompilerFormatEnabled && x.isJsType()) {
-          declareSynthesizedClosureConstructor(x, globalStmts);
-        }
-
-        collectExports(x);
+      /*
+       * If a @JsType is exported, but no constructors are, @JsDoc type declarations added by the
+       * linker will fail in uncompiled mode, as they will try to access the 'Foo.prototype' which
+       * is undefined even though the goog.provide('Foo') statement exists. Here we synthesize a
+       * simple constructor to aid the linker.
+       */
+      if (closureCompilerFormatEnabled && x.isJsType()) {
+        declareSynthesizedClosureConstructor(x, globalStmts);
       }
+
+      collectExports(x);
     }
 
     @Override
@@ -1560,7 +1555,7 @@
 
       // in JsType case, super.foo() call requires SuperCtor.prototype.foo.call(this, args)
       // the method target should be on a class that ends with $Prototype and implements a JsType
-      if (!(method instanceof JConstructor) && typeOracle.isJsTypeMethod(method)) {
+      if (!(method instanceof JConstructor) && method.isOrOverridesJsTypeMethod()) {
         JsNameRef protoRef = prototype.makeRef(x.getSourceInfo());
         methodRef = new JsNameRef(methodRef.getSourceInfo(), method.getName());
         // add qualifier so we have jsPrototype.prototype.methodName.call(this, args)
@@ -2855,13 +2850,13 @@
       }
 
       for (JMethod m : x.getMethods()) {
-        if (typeOracle.isExportedMethod(m)) {
+        if (m.isExported()) {
           exportedMembersByExportName.put(m.getQualifiedExportName(), m);
         }
       }
 
       for (JField f : x.getFields()) {
-        if (typeOracle.isExportedField(f)) {
+        if (f.isExported()) {
           if (!f.isFinal()) {
             logger.log(TreeLogger.Type.WARN, "Exporting effectively non-final field "
                 + f.getQualifiedName() + ". Due to the way exporting works, the value of the"
@@ -2955,7 +2950,7 @@
     private boolean isMethodPotentiallyCalledAcrossClasses(JMethod method) {
       assert incremental || crossClassTargets != null;
       return crossClassTargets == null || crossClassTargets.contains(method)
-          || typeOracle.isExportedMethod(method) || typeOracle.isJsTypeMethod(method);
+          || method.isExported() || method.isOrOverridesJsTypeMethod();
     }
 
     private Iterable<JMethod> getPotentiallyAliveConstructors(JClassType x) {
@@ -3193,7 +3188,7 @@
     @Override
     public void endVisit(JMethod x, Context ctx) {
       // methods which are exported or static indexed methods may be called externally
-      if (typeOracle.isExportedMethod(x) || x.isStatic() && program.getIndexedMethods()
+      if (x.isExported() || x.isStatic() && program.getIndexedMethods()
           .contains(x)) {
         if (x instanceof JConstructor) {
           // exported ctors always considered live
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 1fa9e52..0b578d4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -109,6 +109,7 @@
 import com.google.gwt.dev.js.ast.JsNode;
 import com.google.gwt.dev.js.ast.JsParameter;
 import com.google.gwt.dev.util.StringInterner;
+import com.google.gwt.dev.util.arg.OptionJsInteropMode.Mode;
 import com.google.gwt.dev.util.collect.Stack;
 import com.google.gwt.thirdparty.guava.common.base.Function;
 import com.google.gwt.thirdparty.guava.common.base.Preconditions;
@@ -3781,6 +3782,8 @@
 
   private CompilerContext compilerContext;
 
+  private boolean isJsInteropEnabled;
+
   /**
    * Externalized class and method form for Exceptions.safeClose() to provide support
    * for try-with-resources.
@@ -3828,8 +3831,9 @@
     this.jsniRefs = jsniRefs;
     this.jsniMethods = jsniMethods;
     this.compilerContext = compilerContext;
-    newTypes = Lists.newArrayList();
-    curCud = new CudInfo(cud);
+    this.isJsInteropEnabled = compilerContext.getOptions().getJsInteropMode() == Mode.JS;
+    this.newTypes = Lists.newArrayList();
+    this.curCud = new CudInfo(cud);
   }
 
   /**
@@ -3900,7 +3904,9 @@
               getFieldDisposition(binding), AccessModifier.fromFieldBinding(binding));
     }
     enclosingType.addField(field);
-    JsInteropUtil.maybeSetJsInteropProperties(field, x.annotations);
+    if (isJsInteropEnabled) {
+      JsInteropUtil.maybeSetJsInteropProperties(field, x.annotations);
+    }
     typeMap.setField(binding, field);
   }
 
@@ -4070,7 +4076,9 @@
     maybeAddMethodSpecialization(x, method);
     maybeSetDoNotInline(x, method);
     maybeSetHasNoSideEffects(x, method);
-    JsInteropUtil.maybeSetJsInteropProperties(method, x.annotations);
+    if (isJsInteropEnabled) {
+      JsInteropUtil.maybeSetJsInteropProperties(method, x.annotations);
+    }
   }
 
   private void maybeSetDoNotInline(AbstractMethodDeclaration x,
@@ -4158,7 +4166,9 @@
     JMethod method = typeMap.createMethod(info, binding, paramNames);
     assert !method.isExternal();
     method.setBody(new JMethodBody(info));
-    JsInteropUtil.maybeSetJsInteropProperties(method);
+    if (isJsInteropEnabled) {
+      JsInteropUtil.maybeSetJsInteropProperties(method);
+    }
     typeMap.setMethod(binding, method);
     return method;
   }
@@ -4179,7 +4189,9 @@
       JDeclaredType type;
       if (binding.isClass()) {
         type = new JClassType(info, name, binding.isAbstract(), binding.isFinal());
-        ((JClassType) type).setJsPrototypeStub(JsInteropUtil.isJsPrototypeFlag(x));
+        if (isJsInteropEnabled) {
+          ((JClassType) type).setJsPrototypeStub(JsInteropUtil.isJsPrototypeFlag(x));
+        }
       } else if (binding.isInterface() || binding.isAnnotationType()) {
         type = new JInterfaceType(info, name);
       } else if (binding.isEnum()) {
@@ -4192,7 +4204,9 @@
       } else {
         throw new InternalCompilerException("ReferenceBinding is not a class, interface, or enum.");
       }
-      JsInteropUtil.maybeSetJsInteropProperties(type, x.annotations);
+      if (isJsInteropEnabled) {
+        JsInteropUtil.maybeSetJsInteropProperties(type, x.annotations);
+      }
       JdtUtil.setClassDispositionFromBinding(binding, type);
       typeMap.setSourceType(binding, type);
       newTypes.add(type);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
index 4511989..56ec06b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
@@ -165,9 +165,9 @@
 
   @Override
   public boolean visit(JField x, Context ctx) {
-    if (currentType == x.getEnclosingType() && jprogram.typeOracle.isExportedField(x)) {
+    if (currentType == x.getEnclosingType() && x.isExported()) {
       checkExportName(x);
-    } else if (jprogram.typeOracle.isJsTypeField(x)) {
+    } else if (x.isJsTypeMember()) {
       checkJsTypeFieldName(x, x.getJsMemberName());
     }
 
@@ -181,14 +181,14 @@
     }
     currentJsTypeProcessedMethods.addAll(x.getOverriddenMethods());
 
-    if (currentType == x.getEnclosingType() && jprogram.typeOracle.isExportedMethod(x)) {
+    if (currentType == x.getEnclosingType() && x.isExported()) {
       checkExportName(x);
-    } else if (jprogram.typeOracle.isJsTypeMethod(x)) {
+    } else if (x.isOrOverridesJsTypeMethod()) {
       checkJsTypeMethod(x);
     }
 
     if (currentType == x.getEnclosingType()) {
-      if (jprogram.typeOracle.isJsPropertyMethod(x) && !jprogram.typeOracle.isJsType(currentType)) {
+      if (x.isJsPropertyAccessor() && !currentType.isJsType()) {
         if (currentType instanceof JInterfaceType) {
           logError("Method '%s' can't be a JsProperty since interface '%s' is not a JsType.",
               x.getName(), x.getEnclosingType().getName());
@@ -221,9 +221,9 @@
   }
 
   private void checkJsTypeHierarchy(JInterfaceType interfaceType) {
-    if (jprogram.typeOracle.isJsType(currentType)) {
+    if (currentType.isJsType()) {
       for (JDeclaredType superInterface : interfaceType.getImplements()) {
-        if (!jprogram.typeOracle.isJsType(superInterface)) {
+        if (!superInterface.isJsType()) {
           logWarning(
               "JsType interface '%s' extends non-JsType interface '%s'. This is not recommended.",
               interfaceType.getName(), superInterface.getName());
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 1a9ca7e..d31e670 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
@@ -317,7 +317,7 @@
         return false;
       }
 
-      if (program.typeOracle.isJsTypeMethod(method)) {
+      if (method.isOrOverridesJsTypeMethod()) {
         return false;
       }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizer.java
index 7b79eee..2434147 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizer.java
@@ -71,9 +71,9 @@
            * parameter values they'll supply.
            */
           || program.isJsTypePrototype(method.getEnclosingType())
-          || program.typeOracle.isJsTypeMethod(method)
-          || program.typeOracle.isJsFunctionMethod(method)
-          || program.typeOracle.isExportedMethod(method)) {
+          || method.isOrOverridesJsTypeMethod()
+          || method.isOrOverridesJsFunctionMethod()
+          || method.isExported()) {
         return;
       }
 
@@ -135,9 +135,9 @@
     @Override
     public boolean visit(JMethod x, Context ctx) {
       Set<JMethod> overriddenMethods = x.getOverriddenMethods();
-      if (!overriddenMethods.isEmpty() || program.typeOracle.isJsTypeMethod(x)
-          || program.typeOracle.isJsFunctionMethod(x)
-          || program.typeOracle.isExportedMethod(x)) {
+      if (!overriddenMethods.isEmpty() || x.isOrOverridesJsTypeMethod()
+          || x.isOrOverridesJsFunctionMethod()
+          || x.isExported()) {
         for (JMethod m : overriddenMethods) {
           rescuedMethods.add(m);
         }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index 1493065..dd5a834 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -459,7 +459,7 @@
     public void exit(JField x, Context ctx) {
       // TODO: we should also skip @JsType fields when we implement them.
       if (program.codeGenTypes.contains(x.getEnclosingType())
-          || program.typeOracle.isExportedField(x)) {
+          || x.isExported()) {
         // We cannot tighten this field as we don't know all callers.
         return;
       }
@@ -523,8 +523,8 @@
        * The only information that we can infer about native methods is if they
        * are declared to return a leaf type.
        */
-      if (x.isNative() || program.typeOracle.isJsTypeMethod(x)
-          || program.typeOracle.isJsFunctionMethod(x)) {
+      if (x.isNative() || x.isOrOverridesJsTypeMethod()
+          || x.isOrOverridesJsFunctionMethod()) {
         return;
       }
 
@@ -564,9 +564,9 @@
     public void endVisit(JParameter x, Context ctx) {
       JMethod currentMethod = getCurrentMethod();
       if (program.codeGenTypes.contains(currentMethod.getEnclosingType())
-          || program.typeOracle.isExportedMethod(currentMethod)
-          || program.typeOracle.isJsFunctionMethod(currentMethod)
-          || program.typeOracle.isJsTypeMethod(currentMethod)) {
+          || currentMethod.isExported()
+          || currentMethod.isOrOverridesJsFunctionMethod()
+          || currentMethod.isOrOverridesJsTypeMethod()) {
         // We cannot tighten this parameter as we don't know all callers.
         return;
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
index b34812f..3a939d9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -726,7 +726,6 @@
 
   private MinimalRebuildCache minimalRebuildCache;
   private boolean incrementalCompile;
-  private boolean jsInteropEnabled;
   private final List<String> rootTypeSourceNames = Lists.newArrayList();
   private final Permutation[] permutations;
 
@@ -734,7 +733,6 @@
       JsProgram jsProgram, PrecompilationContext precompilationContext) {
 
     this.incrementalCompile = compilerContext.getOptions().isIncrementalCompileEnabled();
-    this.jsInteropEnabled = program.typeOracle.isJsInteropEnabled();
 
     this.logger = logger;
     this.compilerContext = compilerContext;
@@ -805,8 +803,8 @@
       }
 
       rootTypeBinaryNames.add(rootType.getName());
-      if (jsInteropEnabled && (rootType.hasAnyExports() || rootType.isOrExtendsJsType()
-          || rootType.isOrExtendsJsFunction())) {
+      if (rootType.hasAnyExports() || rootType.isOrExtendsJsType()
+          || rootType.isOrExtendsJsFunction()) {
         fullFlowIntoType(rootType);
       }
     }
@@ -1021,8 +1019,7 @@
       if (t instanceof JClassType && requiresDevirtualization(t)) {
         instantiate(t);
       }
-      if (jsInteropEnabled
-          && (t.hasAnyExports() || t.isOrExtendsJsType() || t.isOrExtendsJsFunction())) {
+      if (t.hasAnyExports() || t.isOrExtendsJsType() || t.isOrExtendsJsFunction()) {
         instantiate(t);
       }
     }
@@ -1323,13 +1320,12 @@
       instantiate(translate(intf));
     }
     staticInitialize(type);
-    boolean isJsType = jsInteropEnabled && type.isOrExtendsJsType();
-    boolean isJsFunction = jsInteropEnabled && type.isOrExtendsJsFunction();
+    boolean isJsTypeOrFunction = type.isOrExtendsJsType() || type.isOrExtendsJsFunction();
 
     // Flow into any reachable virtual methods.
     for (JMethod method : type.getMethods()) {
-      if ((isJsType || isJsFunction) && method.canBePolymorphic() ||
-          program.typeOracle.isExportedMethod(method)) {
+      if (isJsTypeOrFunction && method.canBePolymorphic()
+          || method.isExported()) {
         // Fake a call into the method to keep it around. For JsType, JsFunction and exported
         // methods.
         flowInto(method);
@@ -1349,7 +1345,7 @@
     }
 
     for (JField field : type.getFields()) {
-      if (program.typeOracle.isExportedField(field)) {
+      if (field.isExported()) {
         flowInto(field);
       }
     }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
index c8832cc..a36ee47 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
@@ -40,6 +40,7 @@
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JVisitor;
 import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.util.arg.OptionJsInteropMode;
 import com.google.gwt.dev.util.arg.SourceLevel;
 import com.google.gwt.dev.util.log.AbstractTreeLogger;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
@@ -310,6 +311,7 @@
         }).build();
     compilerContext.getOptions().setSourceLevel(sourceLevel);
     compilerContext.getOptions().setStrict(true);
+    compilerContext.getOptions().setJsInteropMode(OptionJsInteropMode.Mode.JS);
     CompilationState state =
         CompilationStateBuilder.buildFrom(logger, compilerContext,
             sourceOracle.getResources(), getAdditionalTypeProviderDelegate());