uses HWI
data StoreVarEx {
StoreVarEx links[]
int index
char name[]
char intfName[]
}
data StoreFunctionEx {
StoreVarEx locals[]
OpToken instructions[]
char name[]
char intfName[]
}
const bool DEBUG = false
const bool RETURN_AUTO_STORE = true
component provides StoreAnalyser requires io.Output out, data.IntUtil iu, DNCUtil dncUtil, data.adt.List {
bool isAutoStoreType(DanaType t, DanaType types[])
{
if (t == null)
{
return false
}
if (t.class == DanaType.INTEGER || t.class == DanaType.DECIMAL)
{
return true
}
if (t.class == DanaType.ARRAY)
{
DanaType fieldType = dncUtil.findType(types, t.fields[0].type)
return isAutoStoreType(fieldType, types)
}
return false
}
DanaType getConstuctor(DanaType object, DanaType types[])
{
for (int i = 0; i < object.fields.arrayLength; i ++)
{
DanaType fieldType = dncUtil.findType(types, object.fields[i].type)
if (fieldType.class == DanaType.FUNCTION && object.fields[i].name == object.name)
{
return fieldType
}
}
return null
}
StoreFunction getStoreFunction(StoreObject object, char name[], char intfName[])
{
for (int i = 0; i < object.functions.arrayLength; i++)
{
if (object.functions[i].name == name)
return object.functions[i]
}
return null
}
StoreFunctionEx getStoreFunctionEx(StoreFunctionEx exfs[], char name[], char intfName[])
{
for (int i = 0; i < exfs.arrayLength; i++)
{
if (exfs[i].name == name)
return exfs[i]
}
return null
}
bool isLocalVariableAccess(OpToken t)
{
if (t.type == HWI.OP_ID_GET_REF && (t.parameters[1].type == HWI.OP_ID_LOCALS))
{
return true
}
else if (t.type == HWI.OP_ID_GET_PTR_HND && (t.parameters[1].type == HWI.OP_ID_LOCALS))
{
return true
}
return false
}
bool isGlobalVariableAccess(OpToken t)
{
if (t.type == HWI.OP_ID_GET_REF && (t.parameters[1].type == HWI.OP_ID_GLOBALS || t.parameters[1].type == HWI.OP_ID_PRIVATE_IVS || t.parameters[1].type == HWI.OP_ID_PRIVATE_INTER_IVS))
{
return true
}
else if (t.type == HWI.OP_ID_GET_PTR_HND && (t.parameters[1].type == HWI.OP_ID_GLOBALS || t.parameters[1].type == HWI.OP_ID_PRIVATE_IVS || t.parameters[1].type == HWI.OP_ID_PRIVATE_INTER_IVS))
{
return true
}
return false
}
OpToken StoreAnalyser:getOriginLocal(OpToken t, DanaType types[])
{
//recurse down through "t" to the single instruction
while (t != null && !isLocalVariableAccess(t))
{
if (t.parameters.arrayLength == 0)
{
return null
}
//filter out anything that's nested within something which returns an auto-store type
if (isAutoStoreType(t.returnType, types))
{
return null
}
if (t.type == HWI.OP_ID_MEMBER_ACCESS
|| t.type == HWI.OP_ID_GET_INDEX_TO_ASSIGN
|| t.type == HWI.OP_ID_GET_FIELD_TO_ASSIGN
|| t.type == HWI.OP_ID_GET_PTR_HND
|| t.type == HWI.OP_ID_GET_INDEX_R
|| t.type == HWI.OP_ID_GET_INDEX_P
|| t.type == HWI.OP_ID_GET_REF)
{
t = t.parameters[1]
}
else
{
t = t.parameters[0]
}
}
return t
}
OpToken getOriginGlobal(OpToken t, DanaType types[])
{
//recurse down through "t" to the single instruction
while (t != null && !isGlobalVariableAccess(t))
{
if (t.parameters.arrayLength == 0)
{
return null
}
//filter out anything that's nested within something which returns an auto-store type
if (isAutoStoreType(t.returnType, types))
{
return null
}
if (t.type == HWI.OP_ID_MEMBER_ACCESS
|| t.type == HWI.OP_ID_GET_INDEX_TO_ASSIGN
|| t.type == HWI.OP_ID_GET_FIELD_TO_ASSIGN
|| t.type == HWI.OP_ID_GET_PTR_HND
|| t.type == HWI.OP_ID_GET_INDEX_R
|| t.type == HWI.OP_ID_GET_INDEX_P
|| t.type == HWI.OP_ID_GET_REF)
{
t = t.parameters[1]
}
else
{
t = t.parameters[0]
}
}
return t
}
int getParamAssignIndex(OpToken call, int index)
{
OpToken pq = call.parameters[index]
OpToken fp = pq.parameters[0]
if (pq.type == HWI.OP_ID_ASSIGN_POINTER)
fp = pq.parameters[1]
return fp.variableIndex
}
OpToken[] getVariableAccesses(OpToken t, DanaType types[])
{
//recursive down through "t", collecting every variable access
// - we only count those which are not primitive arrays
OpToken result[] = null
if (t != null)
{
if (t.parameters.arrayLength == 0)
{
return result
}
//filter out anything that's nested within something which returns an auto-store type
if (isAutoStoreType(t.returnType, types))
{
return null
}
//filter out anything that's nested within a function call, which in v272 are treated as having always store-able result values
// - this is a messy approach prone to mistakes, but the correction requires a more sophisticated algorithm and additional language features
if (RETURN_AUTO_STORE)
{
if (t.type == HWI.OP_ID_STACK_FRAME_LAUNCH_P || t.type == HWI.OP_ID_STACK_FRAME_LAUNCH_R)
{
return null
}
}
//filter instructions which return unrelated things
if (t.type == HWI.OP_ID_TYPEOF_VAR || t.type == HWI.OP_ID_NEW_DYN_OBJECT_CONSTRUCT || t.type == HWI.OP_ID_NEW_DYN_OBJECT)
{
return null
}
if (isLocalVariableAccess(t))
{
result = new OpToken[](result, t)
}
//in object constructors, ignore anything related to a parameter that isn't qualified as "store"
if (t.type == HWI.OP_ID_NEW_OBJECT_CONSTRUCT_CHK)
{
DanaType objectType = t.parameters[0].returnType
DanaType cfunction = getConstuctor(objectType, types)
for (int i = 1; i < t.parameters.arrayLength; i++)
{
//the the actual parameter index being assigned in to, which isn't necessarily the in-order index
int fpIndex = getParamAssignIndex(t, i)
if (cfunction.fields[fpIndex].qualifier == "store" || cfunction.fields[fpIndex].qualifier == "opt.store")
{
result = new OpToken[](result, getVariableAccesses(t.parameters[i], types))
}
}
}
//otherwise consider everything
else
{
for (int i = 0; i < t.parameters.arrayLength; i++)
{
result = new OpToken[](result, getVariableAccesses(t.parameters[i], types))
}
}
}
return result
}
bool hasLocalAC(StoreFunction f, OpToken varsRHS[])
{
for (int j = 0; j < varsRHS.arrayLength; j++)
{
if (f.locals[varsRHS[j].variableIndex-1].class == StoreVar.AC_LOCAL)
return true
}
return false
}
//TODO: the "stack depth" checks here should not really be required, we should be able to avoid creating cycles in the first place during link graph construction
char[] makeCausePath(StoreObject object, StoreFunction f, int index, StoreFunctionEx exfs[], StoreVarEx exl[], int depth)
{
StoreVar sv = f.locals[index]
StoreVarEx svx = exl[index]
if (sv.regraded)
{
for (int i = 0; i < svx.links.arrayLength; i++)
{
if (svx.links[i].name == f.name)
{
if (f.locals[svx.links[i].index].class == StoreVar.AC_LOCAL)
{
if (depth < 50)
{
return "variable '$(sv.name)' is potentially assigned from '$(f.locals[svx.links[i].index].name)'; $(makeCausePath(object, f, svx.links[i].index, exfs, exl, depth+1))"
}
else
{
return "variable '$(sv.name)' is potentially assigned from '$(f.locals[svx.links[i].index].name)'; further cause chain not followed due to potentially recursive stack"
}
}
}
else
{
StoreFunction nextf = getStoreFunction(object, svx.links[i].name, svx.links[i].intfName)
StoreFunctionEx exf = getStoreFunctionEx(exfs, svx.links[i].name, svx.links[i].intfName)
if (nextf.locals[svx.links[i].index].class == StoreVar.AC_LOCAL)
{
if (depth < 50)
{
return "variable '$(sv.name)' is potentially assigned from '$(svx.links[i].name)():$(nextf.locals[svx.links[i].index].name)'; $(makeCausePath(object, nextf, svx.links[i].index, exfs, exf.locals, depth+1))"
}
else
{
return "variable '$(sv.name)' is potentially assigned from '$(svx.links[i].name)():$(nextf.locals[svx.links[i].index].name)'; further cause chain not followed due to potentially recursive stack"
}
}
}
}
if (svx.links.arrayLength != 0)
{
return "no additional information from $(svx.links.arrayLength) links, link0 was $(svx.links[0].name) of $(f.locals[svx.links[0].index].name) ($(svx.links[0].index))"
}
else
{
return "no additional information from $(svx.links.arrayLength) links"
}
}
else
{
return "variable '$(sv.name)' is defined as local-only"
}
return null
}
char[] getLocalCauses(StoreObject object, StoreFunction f, OpToken varsRHS[], StoreFunctionEx exfs[], StoreVarEx exl[])
{
for (int j = 0; j < varsRHS.arrayLength; j++)
{
if (f.locals[varsRHS[j].variableIndex-1].class == StoreVar.AC_LOCAL)
{
return makeCausePath(object, f, varsRHS[j].variableIndex-1, exfs, exl, 0)
}
}
return null
}
void printLocalCauses(StoreObject object, StoreFunction f, OpToken varsRHS[], StoreFunctionEx exfs[], StoreVarEx exl[])
{
for (int j = 0; j < varsRHS.arrayLength; j++)
{
if (f.locals[varsRHS[j].variableIndex-1].class == StoreVar.AC_LOCAL)
{
char p[] = makeCausePath(object, f, varsRHS[j].variableIndex-1, exfs, exl, 0)
out.println(p)
}
}
}
void addError(StoreAnalysis result, char file[], int lineNumber, char string[])
{
for (int i = 0; i < result.warnings.arrayLength; i++)
{
if (result.warnings[i].line == lineNumber && result.warnings[i].message == string)
return
}
result.warnings = new OpParseError[](result.warnings, new OpParseError(file, lineNumber, string))
}
char[] getFunctionName(DanaType t, int functionIndex, DanaType types[])
{
int j = 0
for (int i = 0; i < t.fields.arrayLength; i++)
{
DanaType fieldType = dncUtil.findType(types, t.fields[i].type)
if (fieldType.class == DanaType.FUNCTION)
{
if (j == functionIndex)
{
return t.fields[i].name
}
j ++
}
}
return null
}
DanaType getFunctionType(DanaType t, int functionIndex, DanaType types[])
{
int j = 0
for (int i = 0; i < t.fields.arrayLength; i++)
{
DanaType fieldType = dncUtil.findType(types, t.fields[i].type)
if (fieldType.class == DanaType.FUNCTION)
{
if (j == functionIndex)
{
return fieldType
}
j ++
}
}
return null
}
bool linkExists(StoreVarEx svx, StoreVarEx link)
{
if (svx === link) return true
for (int i = 0; i < svx.links.arrayLength; i++)
{
if (svx.links[i] === link) return true
for (int j = 0; j < link.links.arrayLength; j++)
{
if (svx === link.links[j] || svx.links[i] === link.links[j]) return true
}
}
return false
}
bool addLinks(OpToken originLHS, StoreVarEx svx, StoreFunction f, OpToken varsRHS[], StoreVarEx exl[])
{
for (int j = 0; j < varsRHS.arrayLength; j++)
{
if (DEBUG) out.println(" -- RHS involves $(varsRHS[j].variableIndex)")
if (!linkExists(svx, exl[varsRHS[j].variableIndex-1])) svx.links = new StoreVarEx[](svx.links, exl[varsRHS[j].variableIndex-1])
if (f.locals[originLHS.variableIndex-1].class == StoreVar.AC_STORE && f.locals[varsRHS[j].variableIndex-1].class == StoreVar.AC_LOCAL)
{
if (DEBUG) out.println(" -- LHS forced to AC-LOCAL")
f.locals[originLHS.variableIndex-1].class = StoreVar.AC_LOCAL
f.locals[originLHS.variableIndex-1].regraded = true
return true
}
else if (f.locals[originLHS.variableIndex-1].class == StoreVar.AC_LOCAL)
{
if (DEBUG) out.println(" -- LHS already AC-LOCAL")
}
}
return false
}
bool isStoreParam(DanaType object, int functionIndex, OpToken paramToken, DanaType types[])
{
//get the param index from the param access instruction
OpToken fp = paramToken.parameters[0]
if (paramToken.type == HWI.OP_ID_ASSIGN_POINTER)
fp = paramToken.parameters[1]
int paramIndex = fp.variableIndex
DanaType type = getFunctionType(object, functionIndex, types)
DanaTypeField tf = type.fields[paramIndex]
return tf.qualifier == "store" || tf.qualifier == "opt,store"
}
//this function broadly acts on three things: assignments to variables, parameters passed to local function calls, and parameters passed to object function calls
bool build(char file[], StoreObject object, StoreFunction f, StoreFunctionEx exfs[], StoreVarEx exl[], OpToken instructions[], OpToken parent, DanaType types[], StoreAnalysis result)
{
bool change = false
for (int i = 0; i < instructions.arrayLength; i++)
{
if (build(file, object, f, exfs, exl, instructions[i].parameters, instructions[i], types, result)) change = true
if (instructions[i].type == HWI.OP_ID_ASSIGN_POINTER || instructions[i].type == HWI.OP_ID_VASSIGN)
{
//get the origin of the LHS
//get the origin(s) of the RHS (for which there may be multiple)
//do the association, considering transitivity, and consider switch to local-only for LHS if necessary
// - we need a way to list associations on variables; maybe we pass StoreFunctionEx in and it has an array of StoreVarEx's which we can place copies
OpToken originLHS = getOriginLocal(instructions[i].parameters[1], types)
OpToken varsRHS[] = getVariableAccesses(instructions[i].parameters[2], types)
if (originLHS != null)
{
StoreVarEx lhs = exl[originLHS.variableIndex-1]
if (DEBUG) out.println("line $(originLHS.lineNumber):: LHS assign variable index $(originLHS.variableIndex)")
//now perform the association of variables in the StoreVarEx, and modify the StoreVar to local if necessary (reporting change if so)
for (int j = 0; j < varsRHS.arrayLength; j++)
{
if (DEBUG) out.println(" -- RHS involves $(varsRHS[j].variableIndex)")
if (!linkExists(lhs, exl[varsRHS[j].variableIndex-1])) lhs.links = new StoreVarEx[](lhs.links, exl[varsRHS[j].variableIndex-1])
if (f.locals[originLHS.variableIndex-1].class == StoreVar.AC_STORE && f.locals[varsRHS[j].variableIndex-1].class == StoreVar.AC_LOCAL)
{
if (DEBUG) out.println(" -- LHS forced to AC-LOCAL")
f.locals[originLHS.variableIndex-1].class = StoreVar.AC_LOCAL
f.locals[originLHS.variableIndex-1].regraded = true
change = true
}
else if (f.locals[originLHS.variableIndex-1].class == StoreVar.AC_LOCAL)
{
if (DEBUG) out.println(" -- LHS already AC-LOCAL")
}
}
}
else if (parent != null && (parent.type == HWI.OP_ID_STACK_FRAME_LAUNCH_P || parent.type == HWI.OP_ID_STACK_FRAME_LAUNCH_R))
{
//param1 is always the stack frame variable
originLHS = instructions[i].parameters[1]
if (DEBUG) out.println("line $(originLHS.lineNumber):: CALL assign parameter index $(originLHS.variableIndex), parent1 is $(parent.parameters[1].type)")
if (parent.parameters[1].type == HWI.OP_ID_STACK_FRAME_INIT_LOCAL)
{
//this doesn't allow us to directly track cause and effect, so here we need to grab the Ex of the other object, via its StoreFunctionEx ...
StoreVar lhs = null
StoreVarEx lhsEx = null
// - local function parameters can be forced to local (they all start as store)
StoreFunction sfq = getStoreFunction(object, parent.parameters[1].functionRef.name, parent.parameters[1].functionRef.intfName)
StoreFunctionEx sfqx = null//getStoreFunctionEx(exfs, parent.parameters[1].functionRef.name, parent.parameters[1].functionRef.intfName)
for (int m = 0; m < exfs.arrayLength; m++)
{
if (exfs[m].name == parent.parameters[1].functionRef.name)
{
sfqx = exfs[m]
break
}
}
lhs = sfq.locals[originLHS.variableIndex-1]
lhsEx = sfqx.locals[originLHS.variableIndex-1]
for (int j = 0; j < varsRHS.arrayLength; j++)
{
if (DEBUG) out.println(" -- RHS involves $(varsRHS[j].variableIndex)")
if (!linkExists(lhsEx, exl[varsRHS[j].variableIndex-1])) lhsEx.links = new StoreVarEx[](lhsEx.links, exl[varsRHS[j].variableIndex-1])
if (lhs.class == StoreVar.AC_STORE && f.locals[varsRHS[j].variableIndex-1].class == StoreVar.AC_LOCAL)
{
if (DEBUG) out.println(" -- LHS forced to AC-LOCAL")
lhs.class = StoreVar.AC_LOCAL
lhs.regraded = true
change = true
}
else if (lhs.class == StoreVar.AC_LOCAL)
{
if (DEBUG) out.println(" -- LHS already AC-LOCAL")
}
}
}
else if (parent.parameters[1].type == HWI.OP_ID_STACK_FRAME_INIT_OBJECT)
{
//it's a function call on an object
// - if it's a local going into a store, that's an error, UNLESS the object ref is ALSO local, in which case it's a LOAD-time register flag adjustment
// - there IS a second constraint, which is that you can't pass things into store parameters of an object you don't own (this is the implementation of read-only for non-owners, for object state), but this constraint is checked at runtime (though it would be useful to add warnings when we're sure it's an issue here)
originLHS = getOriginLocal(parent.parameters[1].parameters[0], types)
if (originLHS != null)
{
if (DEBUG) out.println("OBJ-CALL-L, type $(originLHS.returnType.name), index $(parent.parameters[1].functionIndex)")
if (f.locals[originLHS.variableIndex-1].class == StoreVar.AC_LOCAL)
{
//this is the case where we're allowed to send otherwise local-only values into store parameters
if (DEBUG) out.println(" -- object origin already AC-LOCAL")
}
else
{
//this is an error, if the parameter has a store qualifier, and the varRHS list has AC_LOCAL values
StoreVarEx lhs = exl[originLHS.variableIndex-1]
addLinks(originLHS, lhs, f, varsRHS, exl)
if (isStoreParam(parent.parameters[1].parameters[0].returnType, parent.parameters[1].functionIndex, instructions[i], types) && hasLocalAC(f, varsRHS))
{
//here we force the originLHS to AC_LOCAL, and later pick up any residual errors resulting from assignment of that originLHS into store locations
if (DEBUG) out.println(" -- object origin forced to AC-LOCAL")
f.locals[originLHS.variableIndex-1].class = StoreVar.AC_LOCAL
f.locals[originLHS.variableIndex-1].regraded = true
change = true
}
}
}
else if ((originLHS = getOriginGlobal(parent.parameters[1].parameters[0], types)) != null)
{
if (DEBUG) out.println("OBJ-CALL-G, type $(originLHS.returnType.name), index $(parent.parameters[1].functionIndex)")
//this is an error, if the parameter has a store qualifier, and the varRHS list has AC_LOCAL values
if (isStoreParam(parent.parameters[1].parameters[0].returnType, parent.parameters[1].functionIndex, instructions[i], types) && hasLocalAC(f, varsRHS))
{
if (DEBUG) out.println(" -- ERROR: assignment into store parameter of function $(originLHS.returnType.name):$(getFunctionName(originLHS.returnType, parent.parameters[1].functionIndex, types)) from a local-only variable")
if (DEBUG) printLocalCauses(object, f, varsRHS, exfs, exl)
addError(result, file, instructions[i].lineNumber, "assignment into store parameter of function $(originLHS.returnType.name):$(getFunctionName(originLHS.returnType, parent.parameters[1].functionIndex, types)) from a local-only variable: $(getLocalCauses(object, f, varsRHS, exfs, exl))")
}
}
else
{
//derivation of the object reference via a function call (?) -- TBD on whether or not we should act on this in some way
}
}
}
else if ((originLHS = getOriginGlobal(instructions[i].parameters[1], types)) != null)
{
//this is only for error generation, reporting cause and effect...
if (hasLocalAC(f, varsRHS))
{
if (DEBUG) out.println(" -- ERROR: assignment into global state from a local-only variable on line $(instructions[i].lineNumber)")
if (DEBUG) printLocalCauses(object, f, varsRHS, exfs, exl)
addError(result, file, instructions[i].lineNumber, "assignment into global state from a local-only variable: $(getLocalCauses(object, f, varsRHS, exfs, exl))")
}
}
}
}
return change
}
bool storeBuild(char file[], StoreObject object, StoreFunction f, StoreFunctionEx exfs[], StoreFunctionEx exf, DanaType types[], StoreAnalysis result)
{
//keep looping until there are no more store --> local changes
// - we only care about origin variables in assignments, not fields or array indices
// - we're just tracking interactions between origin variables
// - on right-hand-sides we need to be aware of constructor operations which collect multiple origin variables together (array, data, and objects)
bool change = true
bool changed = false
while (change)
{
change = build(file, object, f, exfs, exf.locals, exf.instructions, null, types, result)
if (change) changed = true
}
return changed
}
//this procedure analyses all functions to determine the local/store status of each of their local variables
// - including their parameters, in the case of local functions
StoreAnalysis StoreAnalyser:analyse(char file[], ProvidedObject objects[], DanaType types[])
{
//start with the interface functions on each object, since the local/store status of their parameters is fixed
// - local variables that aren't parameters start as "store" and are downgraded to "local" if they are assigned to from any local variable throughout the function
// - we record every assignment, so we have a reason for the downgrade
// - we should ALSO look at assignments into globals, so we can error if it's from a local, and report why that thing is a local if it's indirect
// - with this figured out, we can move onto local functions, whose parameters will already have started as "store" and been forced-to-local if needed by the above process
//we first create a structure which mirrors objects[]: with objects, functions, and variables
StoreAnalysis result = new StoreAnalysis()
StoreFunctionEx streams[]
result.objects = new StoreObject[objects.arrayLength]
for (int i = 0; i < objects.arrayLength; i++)
{
result.objects[i] = new StoreObject()
for (int j = 0; j < objects[i].interfaces.arrayLength; j++)
{
for (int k = 0; k < objects[i].interfaces[j].functions.arrayLength; k++)
{
StoreFunction nsf = new StoreFunction(objects[i].interfaces[j].functions[k].name, objects[i].mainInterface, objects[i].interfaces[j].type)
//nsf.instructions = objects[i].interfaces[j].functions[k].instructions //TODO: fails to make "result" into a local-only variable, which is ironic...
result.objects[i].functions = new StoreFunction[](result.objects[i].functions, nsf)
//the compiler includes the return value as a "variable", so we need one less than that...
nsf.locals = new StoreVar[objects[i].interfaces[j].functions[k].variables.fields.arrayLength-1]
StoreFunctionEx exsf = new StoreFunctionEx(new StoreVarEx[nsf.locals.arrayLength], objects[i].interfaces[j].functions[k].instructions, objects[i].interfaces[j].functions[k].name, objects[i].interfaces[j].type)
streams = new StoreFunctionEx[](streams, exsf)
int vn = 0
for (int m = 1; m < objects[i].interfaces[j].functions[k].variables.fields.arrayLength; m++)
{
byte class = StoreVar.AC_STORE
OpFunction opf = objects[i].interfaces[j].functions[k]
if (vn < opf.parameters.arrayLength && (opf.parameters[vn].qualifier & Parameter.Q_STORE) != Parameter.Q_STORE)
{
class = StoreVar.AC_LOCAL
}
if (DEBUG) out.println("var $m class is $(class) ($(opf.parameters.arrayLength) params) for $(nsf.name)")
nsf.locals[vn] = new StoreVar(opf.variables.fields[m].name, opf.variables.fields[m].type, m, class)
exsf.locals[vn] = new StoreVarEx(null, vn, objects[i].interfaces[j].functions[k].name, objects[i].interfaces[j].type)
vn ++
}
}
}
for (int j = 0; j < objects[i].localFunctions.arrayLength; j++)
{
StoreFunction nsf = new StoreFunction(objects[i].localFunctions[j].name)
//nsf.instructions = objects[i].localFunctions[j].instructions
result.objects[i].functions = new StoreFunction[](result.objects[i].functions, nsf)
nsf.locals = new StoreVar[objects[i].localFunctions[j].variables.fields.arrayLength-1]
StoreFunctionEx exsf = new StoreFunctionEx(new StoreVarEx[nsf.locals.arrayLength], objects[i].localFunctions[j].instructions, objects[i].localFunctions[j].name)
streams = new StoreFunctionEx[](streams, exsf)
int vn = 0
for (int m = 1; m < objects[i].localFunctions[j].variables.fields.arrayLength; m++)
{
byte class = StoreVar.AC_STORE
OpFunction opf = objects[i].localFunctions[j]
//if (vn < opf.parameters.arrayLength && (opf.parameters[vn].qualifier & Parameter.Q_STORE) != Parameter.Q_STORE)
// {
// class = StoreVar.AC_LOCAL
// }
if (DEBUG) out.println("var $m class is $(class) ($(opf.parameters.arrayLength) params) for $(nsf.name)")
nsf.locals[vn] = new StoreVar(opf.variables.fields[m].name, opf.variables.fields[m].type, m, class)
exsf.locals[vn] = new StoreVarEx(null, vn, objects[i].localFunctions[j].name)
vn ++
}
}
}
int si = 0
for (int i = 0; i < result.objects.arrayLength; i++)
{
//interface-functions first: we only need to do these once at this outer level as their parameter qualifiers are fixed (though we may run multiple passes for internal changes)
int ssi = si
for (int j = 0; j < result.objects[i].functions.arrayLength; j++)
{
if (result.objects[i].functions[j].implName != null)
{
if (DEBUG) out.println("== store build for $(result.objects[i].functions[j].implName):$(result.objects[i].functions[j].intfName):$(result.objects[i].functions[j].name) ==")
storeBuild(file, result.objects[i], result.objects[i].functions[j], streams, streams[si], types, result)
}
si ++
}
//local-functions next: we may need to do these multiple times once at this outer level, since their parameter qualifiers may change
bool change = true
while (change)
{
change = false
si = ssi
for (int j = 0; j < result.objects[i].functions.arrayLength; j++)
{
if (result.objects[i].functions[j].implName == null)
{
if (DEBUG) out.println("== store build for _local:$(result.objects[i].functions[j].name) ==")
bool c = storeBuild(file, result.objects[i], result.objects[i].functions[j], streams, streams[si], types, result)
if (c) change = true
}
si ++
}
}
}
return result
}
}