Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* Copyright (c) 2002-2011 by XMLVM.org
*
* Project Info: http://www.xmlvm.org
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package org.xmlvm.refcount;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jdom.Attribute;
import org.jdom.DataConversionException;
import org.jdom.Element;
import org.jdom.Namespace;
import org.xmlvm.refcount.optimizations.DeferredNullingOptimization;
import org.xmlvm.refcount.optimizations.RefCountOptimization;
import org.xmlvm.refcount.optimizations.RegisterSizeAndNullingOptimization;
/**
* Overview:
*
* This class uses reference counting to simulate the effects of a JVM garbage
* collector. It operates on the output of the DEX XMLVM process which is a XML
* based representation of a compiled java class that has been transformed from
* a stack machine to a register machine. This class manages object lifespan
* using a reference counting approach. For example, when an object is created
* it is given a reference count of 1. During the lifespan of the object the
* reference count is incremented as other objects store away pointers to the
* object in question. Eventually, the reference count is set to zero and the
* memory for the object is released.
*
* This class is interesting because manages these reference counts without any
* client programmer intervention to simulate the effects of a garbage. This is
* done by following a few simple rules: 1) Each pointer to an object always has
* a 'retain' associated with it. For example, if a register variable points
* toward an object then the following pattern would occur: Register r1 =
* object1; [r1 retain];
*
* When the pointer's end of life occurred, we would release the object
* reference [r1 release]; r1 = null;
*
* The same concept holds for other classes of pointer including, arrays, static
* references to objects, as well as instance references. In general the
* following invariant always holds true:
*
* If there is a pointer to an object, than that pointer has associated with it
* an increment for the objects reference count. If that pointer is overwritten
* for any reason, that reference is released.
*
* Based on this invariant, we know that when we can no longer point to an
* object all of its reference count increments will be gone and hence it will
* be freed by the runtime.
*
* Usage: For a represented as a jdom.Element, call Process.
*/
public class ReferenceCounting
{
Namespace dex= InstructionProcessor.dex;
Namespace vm= InstructionProcessor.vm;
String tmpRegNameSuffix= "tmp";
/**
* The entry point to this class. This function takes a method element and
* processes it, adding instructions to release and retain objects as
* needed. For the command set that it adds, see the InstructionProcessor
* class.
*/
@SuppressWarnings("unchecked")
public void process(Element method) throws DataConversionException, ReferenceCountingException
{
Attribute isAbstract= method.getAttribute("isAbstract");
Attribute isNative= method.getAttribute("isNative");
// abstract and native methods do not require processing
if (isAbstract != null && isAbstract.getBooleanValue())
{
return;
}
if (isNative != null && isNative.getBooleanValue())
{
return;
}
Element codeElement= method.getChild("code", dex);
int numReg= codeElement.getAttribute("register-size").getIntValue();
processRecStart(numReg, (List) codeElement.getChildren(), codeElement);
}
/**
* Set the expected frees that we must do before any optimizations have
* removed them.
*/
private void setWillFree(Map beenTo) throws ReferenceCountingException, DataConversionException
{
{
for (Map.Entry e : beenTo.entrySet())
{
RegisterSet objectRegs= e.getValue().getObjectRegs();
if (!e.getValue().getConflict().isEmpty())
{
throw new ReferenceCountingException("Ambigious register contents possible: Conflict: " + e.getValue().getConflict());
}
InstructionUseInfo useInfo= e.getValue().useInfo;
RegisterSet toFree;
if (e.getKey().getName().startsWith("return"))
{
// we want to free everything except what this instruction
// uses.
toFree= objectRegs.andNot(useInfo.usedReg());
}
else
{
// we free any register reference that is overwritten by
// this
// instruction
toFree= objectRegs.and(useInfo.allWrites());
}
useInfo.willFree= toFree;
useInfo.willNull= toFree.clone();
}
}
}
/**
* This is the last step in the release/retain markup process. It processes
* all of the DEX instructions that we have traversed in a method, looking
* at how they have been marked up. Based on how they have been marked up it
* adds required release/retains or other commands to the body of the method
* being processed.
*
* Returns whether this method needs to have a temp register defined.
*/
private boolean processReleaseRetain(Map beenTo) throws ReferenceCountingException, DataConversionException
{
boolean needsTmpReg= false;
for (Map.Entry e : beenTo.entrySet())
{
if (!e.getValue().getConflict().isEmpty())
{
throw new ReferenceCountingException("Ambigious register contents possible: Conflict: " + e.getValue().getConflict());
}
InstructionUseInfo useInfo= e.getValue().useInfo;
// if we are writing into an object, we may need to free.
// All objects in registers are held with a reference, so we will
// need to release.
List toAddBefore= new ArrayList();
List toAddAfter= new ArrayList();
// Release last -- because other wise we can get into odd situations
// where we don't to a required retain before the release.
List toReleaseLast= new ArrayList();
RegisterSet toFree;
toFree= useInfo.willFree;
// for the registers we want to free
for (int oneReg : toFree)
{
// If we use the object in the instruction as an argument and
// overwrite it, we must be careful to preserve it until after
// the call is done.
// Example of true case
// tmp = f1;
// f1 = func(f1);
// [release tmp];
// Example of false case:
// f1 = func(f1);
// [release f1]
if (!useInfo.usesAsObj().and(useInfo.allWrites()).isEmpty())
{
if (useInfo.freeTmpAfter)
{
throw new ReferenceCountingException("Conflict, tmp register used twice.");
}
Element tmpR= new Element(InstructionProcessor.cmd_tmp_equals_r, vm);
tmpR.setAttribute("reg", oneReg + "");
toAddBefore.add(tmpR);
needsTmpReg= true;
Element releaseTmp= new Element(InstructionProcessor.cmd_release, vm);
releaseTmp.setAttribute("reg", tmpRegNameSuffix);
toReleaseLast.add(releaseTmp);
Element nullTmp= new Element(InstructionProcessor.cmd_set_null, vm);
nullTmp.setAttribute("num", tmpRegNameSuffix);
toReleaseLast.add(nullTmp);
}
else
{
// No need to use tmp
Element release= new Element(InstructionProcessor.cmd_release, vm);
release.setAttribute("reg", oneReg + "");
toAddBefore.add(release);
if (useInfo.willNull.has(oneReg))
{
Element nullTmp= new Element(InstructionProcessor.cmd_set_null, vm);
nullTmp.setAttribute("num", oneReg + "");
toAddBefore.add(nullTmp);
}
}
}
if (useInfo.putRelease != null)
{
if (!useInfo.usesAsObj().and(useInfo.allWrites()).isEmpty())
{
needsTmpReg= true;
throw new ReferenceCountingException("We do not handle the case where a release is " + "made in a x = foo(x) situation because it " + " hasn't showed up so far");
}
else
{
toAddBefore.add(useInfo.putRelease);
}
}
// Add any necessary retains.
for (int oneReg : useInfo.requiresRetain)
{
Element retain= new Element(InstructionProcessor.cmd_retain, vm);
retain.setAttribute("reg", oneReg + "");
toAddAfter.add(retain);
}
// This handles the case where xmlvm2objc.xsl has set the temp reg
// to a value because a function call was made, but the result was
// not used by the program.
if (useInfo.freeTmpAfter)
{
Element releaseTmp= new Element(InstructionProcessor.cmd_release, vm);
releaseTmp.setAttribute("reg", tmpRegNameSuffix);
toAddAfter.add(releaseTmp);
needsTmpReg= true;
}
toAddAfter.addAll(toReleaseLast);
// At this point toAddBefore and toAddAfter have been filled with
// whatever instructions we need to add before and after this
// specific element. The helper function adds them.
addBeforeAndAfter(e.getKey(), toAddBefore, toAddAfter);
}
return needsTmpReg;
}
/**
* This is here because the jdom XML API is dumb enough that it cannot
* easily find the element before element X, or the element after element X.
*
* This function adds some elements before and after a particular element.
*
* TODO: if we believe prevElement map and nextElement map are correct, then
* we can use them instead to make this run faster.
*/
@SuppressWarnings("unchecked")
void addBeforeAndAfter(Element toAddTo, List toAddBefore, List toAddAfter) throws ReferenceCountingException
{
Element parent= toAddTo.getParentElement();
List