All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.java.com.debughelper.tools.r8.graph.ObjectToOffsetMapping Maven / Gradle / Ivy

The newest version!
// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.debughelper.tools.r8.graph;

import com.debughelper.tools.r8.dex.Constants;
import com.debughelper.tools.r8.graph.DexProto;
import com.debughelper.tools.r8.errors.CompilationError;

import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap.Entry;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class ObjectToOffsetMapping {

  private final static int NOT_FOUND = -1;
  private final static int NOT_SET = -2;

  private final DexProgramClass[] classes;
  private final Reference2IntMap protos;
  private final Reference2IntMap types;
  private final Reference2IntMap methods;
  private final Reference2IntMap fields;
  private final Reference2IntMap strings;
  private final Reference2IntMap callSites;
  private final Reference2IntMap methodHandles;
  private DexString firstJumboString;

  public ObjectToOffsetMapping(
      DexApplication application,
      Collection classes,
      Collection protos,
      Collection types,
      Collection methods,
      Collection fields,
      Collection strings,
      Collection callSites,
      Collection methodHandles) {
    assert application != null;
    assert classes != null;
    assert protos != null;
    assert types != null;
    assert methods != null;
    assert fields != null;
    assert strings != null;
    assert callSites != null;
    assert methodHandles != null;

    this.classes = sortClasses(application, classes);
    this.protos = createMap(protos, this::failOnOverflow);
    this.types = createMap(types, this::failOnOverflow);
    this.methods = createMap(methods, this::failOnOverflow);
    this.fields = createMap(fields, this::failOnOverflow);
    this.strings = createMap(strings, this::setFirstJumboString);
    this.callSites = createMap(callSites, this::failOnOverflow);
    this.methodHandles = createMap(methodHandles, this::failOnOverflow);
  }

  private void setFirstJumboString(DexString string) {
    assert firstJumboString == null;
    firstJumboString = string;
  }

  private void failOnOverflow(DexItem item) {
    throw new CompilationError("Index overflow for " + item.getClass());
  }

  private  Reference2IntMap createMap(Collection items,
      Consumer onUInt16Overflow) {
    if (items.isEmpty()) {
      return null;
    }
    Reference2IntMap map = new Reference2IntLinkedOpenHashMap<>(items.size());
    map.defaultReturnValue(NOT_FOUND);
    Collection sorted = items.stream().sorted().collect(Collectors.toList());
    int index = 0;
    for (T item : sorted) {
      if (index == Constants.U16BIT_MAX + 1) {
        onUInt16Overflow.accept(item);
      }
      map.put(item, index++);
    }
    return map;
  }

  /**
   * Here, 'depth' of a program class is an integer one bigger then the maximum depth of its
   * superclass and implemented interfaces. The depth of classes without any or without known
   * superclasses and interfaces is 1.
   */
  private static class ProgramClassDepthsMemoized {

    private final static int UNKNOWN_DEPTH = -1;

    private final DexApplication application;
    private final Reference2IntMap depthOfClasses = new Reference2IntOpenHashMap<>();

    ProgramClassDepthsMemoized(DexApplication application) {
      this.application = application;
      depthOfClasses.defaultReturnValue(UNKNOWN_DEPTH);
    }

    int getDepth(DexProgramClass programClass) {
      int depth = depthOfClasses.getInt(programClass);

      // TODO(b/65536002): use "computeIntIfAbsent" after upgrading to fastutils 8.x.
      if (depth == UNKNOWN_DEPTH) {
        // Emulating the algorithm of com.debughelper.dx.merge.SortableType.tryAssignDepth().
        DexType superType = programClass.superType;
        int maxDepth;
        if (superType == null) {
          maxDepth = 0;
        } else {
          maxDepth = 1;
          DexProgramClass superClass = application.programDefinitionFor(superType);
          if (superClass != null) {
            maxDepth = getDepth(superClass);
          }
        }
        for (DexType inf : programClass.interfaces.values) {
          DexProgramClass infClass = application.programDefinitionFor(inf);
          maxDepth = Math.max(maxDepth, infClass == null ? 1 : getDepth(infClass));
        }
        depth = maxDepth + 1;
        depthOfClasses.put(programClass, depth);
      }

      return depth;
    }
  }

  private static DexProgramClass[] sortClasses(DexApplication application,
      Collection classes) {
    // Collect classes in subtyping order, based on a sorted list of classes to start with.
    ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(application);
    List sortedClasses =
        classes
            .stream()
            .sorted(
                (x, y) -> {
                  int dx = classDepths.getDepth(x);
                  int dy = classDepths.getDepth(y);
                  return dx != dy ? dx - dy : x.type.compareTo(y.type);
                })
            .collect(Collectors.toList());
    return sortedClasses.toArray(new DexProgramClass[sortedClasses.size()]);
  }

  private static  Collection keysOrEmpty(Map map) {
    return map == null ? Collections.emptyList() : map.keySet();
  }

  public Collection getMethods() {
    return keysOrEmpty(methods);
  }

  public DexProgramClass[] getClasses() {
    return classes;
  }

  public Collection getTypes() {
    return keysOrEmpty(types);
  }

  public Collection getProtos() {
    return keysOrEmpty(protos);
  }

  public Collection getFields() {
    return keysOrEmpty(fields);
  }

  public Collection getStrings() {
    return keysOrEmpty(strings);
  }

  public Collection getCallSites() {
    return keysOrEmpty(callSites);
  }

  public Collection getMethodHandles() {
    return keysOrEmpty(methodHandles);
  }

  public boolean hasJumboStrings() {
    return firstJumboString != null;
  }

  public DexString getFirstJumboString() {
    return firstJumboString;
  }

  public DexString getFirstString() {
    for (Entry dexStringEntry : strings.reference2IntEntrySet()) {
      if (dexStringEntry.getIntValue() == 0) {
        return dexStringEntry.getKey();
      }
    }
    return null;
  }

  private  int getOffsetFor(T item, Reference2IntMap map) {
    int index = map.getInt(item);
    assert index != NOT_SET : "Index was not set: " + item;
    assert index != NOT_FOUND : "Missing dependency: " + item;
    return index;
  }

  public int getOffsetFor(DexProto proto) {
    return getOffsetFor(proto, protos);
  }

  public int getOffsetFor(DexField field) {
    return getOffsetFor(field, fields);
  }

  public int getOffsetFor(DexMethod method) {
    return getOffsetFor(method, methods);
  }

  public int getOffsetFor(DexString string) {
    return getOffsetFor(string, strings);
  }

  public int getOffsetFor(DexType type) {
    return getOffsetFor(type, types);
  }

  public int getOffsetFor(DexCallSite callSite) {
    return getOffsetFor(callSite, callSites);
  }

  public int getOffsetFor(DexMethodHandle methodHandle) {
    return getOffsetFor(methodHandle, methodHandles);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy