@Override public Iterable<BuildDependency> getDependencies(Map<Element, LayoutDecisionMap> decisions) { HashSet<BuildDependency> deps = ObjectFile.minimalDependencies(decisions, this); // our content (but not our size) depends on the offset and size // of the corresponding element LayoutDecision ourContent = decisions.get(this).getDecision(LayoutDecision.Kind.CONTENT); LayoutDecision elOffset = decisions.get(el).getDecision(LayoutDecision.Kind.OFFSET); LayoutDecision elSize = decisions.get(el).getDecision(LayoutDecision.Kind.SIZE); deps.add(BuildDependency.createOrGet(ourContent, elOffset)); deps.add(BuildDependency.createOrGet(ourContent, elSize)); return deps; }
public static LayoutDecisionMap defaultDecisions(Element e, LayoutDecisionMap copyingIn) { LayoutDecisionMap decisions = new LayoutDecisionMap(e); decisions.putUndecided(LayoutDecision.Kind.CONTENT); assert !decisions.getDecision(LayoutDecision.Kind.CONTENT).isTaken(); decisions.putUndecided(LayoutDecision.Kind.SIZE); decisions.putUndecided(LayoutDecision.Kind.OFFSET); if (e.isReferenceable()) { decisions.putUndecided(LayoutDecision.Kind.VADDR); } // any decisions present in copyingIn will be already "taken" // i.e. they're LayoutProperties decisions.putDecidedValues(copyingIn); return decisions; }
@SuppressWarnings("unchecked") public static <T> T defaultGetOrDecide(Map<Element, LayoutDecisionMap> alreadyDecided, Element el, LayoutDecision.Kind k, T hint) { /* By default, we return what's already been decided or else take the hint. */ LayoutDecisionMap m = alreadyDecided.get(el); if (m != null && m.getDecision(k) != null && m.getDecision(k).isTaken()) { return (T) m.getDecidedValue(k); } else { return hint; } }
LayoutDecisionMap m = e.getDecisions(new LayoutDecisionMap(e)); allDecisions.addAll(m.getDecisions()); assert decisionsByElement.get(e).containsKey(LayoutDecision.Kind.CONTENT); assert decisionsByElement.get(e).containsKey(LayoutDecision.Kind.SIZE); assert decisionsByElement.get(e).containsKey(LayoutDecision.Kind.OFFSET); LayoutDecision offsetBootstrapDecision = decisionsByElement.get(offsetBootstrapElement).getDecision(LayoutDecision.Kind.OFFSET); boolean added = false; boolean sawBootstrapOffsetDecision = false; decisionsTaken.put(e, new LayoutDecisionMap(e)); if (decisionsTaken.get(e).getDecision(LayoutDecision.Kind.CONTENT) != null) { decidedContent = (byte[]) decisionsTaken.get(e).getDecision(LayoutDecision.Kind.CONTENT).getValue(); totalSize = Math.max(totalSize, (int) decisionsTaken.get(e).getDecision(LayoutDecision.Kind.OFFSET).getValue() + (int) decisionsTaken.get(e).getDecidedValue(LayoutDecision.Kind.SIZE));
@Override public int getOrDecideSize(Map<Element, LayoutDecisionMap> alreadyDecided, int sizeHint) { return ((byte[]) alreadyDecided.get(this).getDecidedValue(LayoutDecision.Kind.CONTENT)).length; } }
protected static Iterable<LayoutDecision> decisionsByKind(final LayoutDecision.Kind kind, final Map<Element, LayoutDecisionMap> decisions) { return () -> StreamSupport.stream(decisions.values().spliterator(), false) .flatMap(layoutDecisionMap -> StreamSupport.stream(layoutDecisionMap.spliterator(), false)) .filter(decision -> decision.getKind() == kind).iterator(); }
public LayoutDecisionMap getOrCreate(ObjectFile.Element key) { LayoutDecisionMap m = map.get(key); if (m == null) { m = new LayoutDecisionMap(key); this.put(key, m); } return m; }
public void putDecidedValues(LayoutDecisionMap copyingIn) { assert !copyingIn.getDecisions().stream().filter(d -> d.getValue() == null).findAny().isPresent(); decisions.putAll(copyingIn.decisions); }
@Override public int getOrDecideSize(java.util.Map<Element, LayoutDecisionMap> alreadyDecided, int sizeHint) { Object decidedContent = alreadyDecided.get(this).getDecidedValue(LayoutDecision.Kind.CONTENT); assert decidedContent != null; return ((byte[]) decidedContent).length; } //@formatter:on
protected static Iterable<LayoutDecision> allDecisions(final Map<Element, LayoutDecisionMap> decisions) { return () -> StreamSupport.stream(decisions.values().spliterator(), false) .flatMap(layoutDecisionMap -> StreamSupport.stream(layoutDecisionMap.spliterator(), false)).iterator(); }
protected static List<LayoutDecision> maximalDecisionValues(Map<Element, LayoutDecisionMap> alreadyDecided, LayoutDecision.Kind k, Comparator<LayoutDecision> cmp) { ArrayList<LayoutDecision> currentMax = null; for (Map.Entry<Element, LayoutDecisionMap> eOuter : alreadyDecided.entrySet()) { LayoutDecision decisionToCompare = eOuter.getValue().getDecision(k); Integer compareResult = currentMax == null ? null : cmp.compare(decisionToCompare, currentMax.get(0)); if (currentMax == null || compareResult > 0) { // replace the current max with a new equivalence class currentMax = new ArrayList<>(1); currentMax.add(decisionToCompare); } else if (compareResult == 0) { // extend current max equivalence class currentMax.add(decisionToCompare); } // else it's less than the current max, so do nothing } return currentMax; }
public void writeBuffer(List<Element> sortedObjectFileElements, ByteBuffer out) { /* Emit each one! */ for (Element e : sortedObjectFileElements) { int off = (int) decisionsTaken.get(e).getDecision(LayoutDecision.Kind.OFFSET).getValue(); assert off != Integer.MAX_VALUE; // not allowed any more -- this was a broken approach out.position(off); int expectedSize = (int) decisionsTaken.get(e).getDecidedValue(LayoutDecision.Kind.SIZE); byte[] content = (byte[]) decisionsTaken.get(e).getDecidedValue(LayoutDecision.Kind.CONTENT); out.put(content); int emittedSize = out.position() - off; assert emittedSize >= 0; if (emittedSize != expectedSize) { throw new IllegalStateException("For element " + e + ", expected size " + expectedSize + " but emitted size " + emittedSize); } } }
@Override public int getMemSize(Map<Element, LayoutDecisionMap> alreadyDecided) { return (int) alreadyDecided.get(this).getDecidedValue(LayoutDecision.Kind.SIZE); }
public Object getDecidedValue(LayoutDecision.Kind key) { return getDecision(key).getValue(); }
protected static int nextAvailableVaddr(final Map<Element, LayoutDecisionMap> alreadyDecided, int base, int defaultValue) { int nextAvailable = -1; List<LayoutDecision> maxVaddrDecisions = maximalDecisionValues(alreadyDecided, LayoutDecision.Kind.VADDR, new IntegerDecisionComparator(false)); // break ties using size (nulls to head) Collections.sort(maxVaddrDecisions, new SizeTiebreakComparator(alreadyDecided, false)); // we sorted into ascending size order, so get the biggest LayoutDecision maxVaddrDecision = maxVaddrDecisions.get(maxVaddrDecisions.size() - 1); if (maxVaddrDecision == null || !maxVaddrDecision.isTaken()) { /* * This means we have not decided any vaddr yet. We use the caller-supplied default * value. */ nextAvailable = defaultValue; } else { assert alreadyDecided.get(maxVaddrDecision.getElement()).getDecision(LayoutDecision.Kind.SIZE).isTaken(); int vaddr = (int) alreadyDecided.get(maxVaddrDecision.getElement()).getDecidedValue(LayoutDecision.Kind.VADDR); int size = maxVaddrDecision.getElement().getMemSize(alreadyDecided); nextAvailable = vaddr + size; } if (nextAvailable < base) { return base; } else { return nextAvailable; } }
@Override public int getMemSize(Map<Element, LayoutDecisionMap> alreadyDecided) { return (int) alreadyDecided.get(element).getDecidedValue(LayoutDecision.Kind.SIZE); }
public static HashSet<BuildDependency> basicDependencies(Map<Element, LayoutDecisionMap> decisions, Element el, boolean sizeOnContent, boolean vaddrOnOffset) { HashSet<BuildDependency> deps = new HashSet<>(); /* * As a minimum, we specify that the offset and vaddr of an element depend on its size. This * is so that once we assign an offset or vaddr, the "next available" offset/vaddr can * always be computed -- using the size which we require to have already been decided. */ deps.add(BuildDependency.createOrGet(decisions.get(el).getDecision(LayoutDecision.Kind.OFFSET), decisions.get(el).getDecision(LayoutDecision.Kind.SIZE))); if (decisions.get(el).getDecision(LayoutDecision.Kind.VADDR) != null) { deps.add(BuildDependency.createOrGet(decisions.get(el).getDecision(LayoutDecision.Kind.VADDR), decisions.get(el).getDecision(LayoutDecision.Kind.SIZE))); } if (sizeOnContent) { deps.add(BuildDependency.createOrGet(decisions.get(el).getDecision(LayoutDecision.Kind.SIZE), decisions.get(el).getDecision(LayoutDecision.Kind.CONTENT))); } // if we have a vaddr, by default it depends on our offset if (vaddrOnOffset && decisions.get(el).getDecision(LayoutDecision.Kind.VADDR) != null) { deps.add(BuildDependency.createOrGet(decisions.get(el).getDecision(LayoutDecision.Kind.VADDR), decisions.get(el).getDecision(LayoutDecision.Kind.OFFSET))); } return deps; }
@Override public byte[] getOrDecideContent(Map<Element, LayoutDecisionMap> alreadyDecided, byte[] contentHint) { OutputAssembler out = AssemblyBuffer.createOutputAssembler(getOwner().getByteOrder()); ArrayList<LayoutDecision> decisionsOfInterest = new ArrayList<>(); for (Section s : getSections()) { MachOSection ms = (MachOSection) s; if (ms.flags.contains(SectionFlag.SOME_INSTRUCTIONS)) { decisionsOfInterest.add(alreadyDecided.get(s).getDecision(LayoutDecision.Kind.OFFSET)); } } // sort these sections by their decided offset Collections.sort(decisionsOfInterest, new IntegerDecisionComparator(false)); // we should not have any undecideds! assert decisionsOfInterest.size() == 0 || decisionsOfInterest.get(0).isTaken(); EntryStruct ent = new EntryStruct(); for (int i = 0; i < decisionsOfInterest.size(); ++i) { LayoutDecision decision = decisionsOfInterest.get(i); ent.fileOffset = (int) decision.getValue(); int fileSize = (int) alreadyDecided.get(decision.getElement()).getDecidedValue(LayoutDecision.Kind.SIZE); int sectionEndInFile = ent.fileOffset + fileSize; Integer nextOffset = (i + 1 < decisionsOfInterest.size()) ? (int) decisionsOfInterest.get(i + 1).getValue() : null; int nextPageBoundary = (sectionEndInFile % getPageSize()) == 0 ? sectionEndInFile : (((sectionEndInFile >> getPageSizeShift()) + 1) << getPageSizeShift()); ent.length = (short) (nextOffset == null ? nextPageBoundary : Math.min(nextPageBoundary, nextOffset)); ent.entryKind = (short) 0; // FIXME ent.write(out); } return out.getBlob(); } }
@Override protected void writePayload(OutputAssembler out, Map<Element, LayoutDecisionMap> alreadyDecided) { int symtabOffset = (int) alreadyDecided.get(symtab).getDecidedValue(LayoutDecision.Kind.OFFSET); int symtabEntriesCount = symtab.getEntryCount(); int strtabOffset = (int) alreadyDecided.get(symtab.strtab).getDecidedValue(LayoutDecision.Kind.OFFSET); int strtabSize = (int) alreadyDecided.get(symtab.strtab).getDecidedValue(LayoutDecision.Kind.SIZE); writePayloadFields(out, symtabOffset, symtabEntriesCount, strtabOffset, strtabSize); }
@Override public Iterable<BuildDependency> getDependencies(Map<Element, LayoutDecisionMap> decisions) { HashSet<BuildDependency> deps = ObjectFile.minimalDependencies(decisions, this); // our content depends on the offset and size of strtab, and offset of symtab LayoutDecision ourContent = decisions.get(this).getDecision(LayoutDecision.Kind.CONTENT); LayoutDecision strtabSize = decisions.get(symtab.strtab).getDecision(LayoutDecision.Kind.SIZE); LayoutDecision strtabOffset = decisions.get(symtab.strtab).getDecision(LayoutDecision.Kind.OFFSET); LayoutDecision symtabOffset = decisions.get(symtab).getDecision(LayoutDecision.Kind.OFFSET); deps.add(BuildDependency.createOrGet(ourContent, strtabSize)); deps.add(BuildDependency.createOrGet(ourContent, strtabOffset)); deps.add(BuildDependency.createOrGet(ourContent, symtabOffset)); return deps; } }