private void checkInvokeInterfaceSupported(final int opcode, CstMethodRef callee) {
    if (opcode == ByteOps.INVOKEINTERFACE) {
      // Invoked in the tranditional way, this is fine.
      return;
    }

    if (dexOptions.apiIsSupported(DexFormat.API_INVOKE_INTERFACE_METHODS)) {
      // Running at the officially support API level for default
      // and static interface methods.
      return;
    }

    //
    // One might expect a hard API level for invoking interface
    // methods. It's either okay to have code invoking static (and
    // default) interface methods or not. Reality asks to be
    // prepared for a little compromise here because the
    // traditional guidance to Android developers when producing a
    // multi-API level DEX file is to guard the use of the newer
    // feature with an API level check, e.g.
    //
    // int x = (android.os.Build.VERSION.SDK_INT >= 038) ?
    //         DoJava8Thing() : Do JavaOtherThing();
    //
    // This is fine advice if the bytecodes and VM semantics never
    // change. Unfortunately, changes like Java 8 support
    // introduce new bytecodes and also additional semantics to
    // existing bytecodes. Invoking static and default interface
    // methods is one of these awkward VM transitions.
    //
    // Experimentally invoke-static of static interface methods
    // breaks on VMs running below API level 21. Invocations of
    // default interface methods may soft-fail verification but so
    // long as they are not called that's okay.
    //
    boolean softFail = dexOptions.allowAllInterfaceMethodInvokes;
    if (opcode == ByteOps.INVOKESTATIC) {
      softFail &= dexOptions.apiIsSupported(DexFormat.API_INVOKE_STATIC_INTERFACE_METHODS);
    } else {
      assert (opcode == ByteOps.INVOKESPECIAL) || (opcode == ByteOps.INVOKEVIRTUAL);
    }

    // Running below the officially supported API level. Fail hard
    // unless the user has explicitly allowed this with
    // "--allow-all-interface-method-invokes".
    String invokeKind = (opcode == ByteOps.INVOKESTATIC) ? "static" : "default";
    if (softFail) {
      // The code we are warning about here should have an API check
      // that protects it being used on API version < API_INVOKE_INTERFACE_METHODS.
      String reason =
          String.format(
              "invoking a %s interface method %s.%s strictly requires "
                  + "--min-sdk-version >= %d (experimental at current API level %d)",
              invokeKind,
              callee.getDefiningClass().toHuman(),
              callee.getNat().toHuman(),
              DexFormat.API_INVOKE_INTERFACE_METHODS,
              dexOptions.minSdkVersion);
      warn(reason);
    } else {
      String reason =
          String.format(
              "invoking a %s interface method %s.%s strictly requires "
                  + "--min-sdk-version >= %d (blocked at current API level %d)",
              invokeKind,
              callee.getDefiningClass().toHuman(),
              callee.getNat().toHuman(),
              DexFormat.API_INVOKE_INTERFACE_METHODS,
              dexOptions.minSdkVersion);
      fail(reason);
    }
  }
Simulates the effect of the instruction at the given offset, by making appropriate calls on the
given frame.

@param offset {@code offset >= 0;} offset of the instruction to simulate
@param frame {@code non-null;} frame to operate on
@return the length of the instruction, in bytes
android/android_framework/dex-maker/src/main/java/com/android/dx/cf/code/Simulator.java