HomeForumSourceResearchGuide
Sign in to contribute to source. how it works
Component util.compiler.EnvelopeWriter by barry
expand copy to clipboardexpand
uses HWI

const byte OBJ_VERSION = 7
const byte OS_TYPE = 1

const byte TYPE_NULL = 0
const byte TYPE_LITERAL = 1
const byte TYPE_PATTERN = 2
const byte TYPE_FUNCTION = 3
const byte TYPE_UNUSED_D = 4
const byte TYPE_OBJECT = 5
const byte TYPE_DATA = 6
const byte TYPE_ARRAY = 7
const byte TYPE_VAR = 8
const byte TYPE_UNUSED_C = 9
const byte TYPE_EVENTSOURCE = 10
const byte TYPE_UNUSED_A = 11
const byte TYPE_UNUSED_B = 12
const byte TYPE_PTRH = 13
const byte TYPE_DECIMAL = 14

const byte F_RECURSE_POINT = 128 //TODO: this is a shared flag with OpParser, we need to surface this in a public type

data DanaCommonHeader {
	const byte OBJECT_MAGIC[] = new byte[](0x44, 0x41, 0x4E, 0x41, 0x0, 0x1)
	byte magic[6]
	byte checksum[4] //optional (if it's 0 then it's not configured for this object)
	byte objectType[2] //byte 1 is OBJECT_TYPE_X; byte 2 is unused
	byte hostType[2] //byte 1 is address-size; byte 2 is endianness?
	byte vpuType[2] //VM architecture code indicating which architecture this object was compiled for; this must match the VM's own vpuType code (basically it indicates that all of the instructions are in the expected places and the instruction set itself is compatible)
	}

data DanaMachineHeader64 {
	//machine code
	int8 textOffset
	int8 textSize
	//local relocations; a list of addresses to add the start address of this object to
	int8 lrTableOffset
	int8 lrTableSize
	int8 lrTableCount
	//infoSections: offset to the first extended infoSection, if any (0 is none)
	int8 infoSectionsOffset
	int8 infoSectionsSize
	int8 infoSectionsCount
	}

data DanaMachineHeader32 {
	//machine code
	int4 textOffset
	int4 textSize
	//local relocations; a list of addresses to add the start address of this object to
	int4 lrTableOffset
	int4 lrTableSize
	int4 lrTableCount
	//infoSections: offset to the first extended infoSection, if any (0 is none)
	int4 infoSectionsOffset
	int4 infoSectionsSize
	int4 infoSectionsCount
	}

data SourceHeader {
	int componentSize
	int objectDefinitions
	int bindportDefinitions
	int objectsCount
	int bindportsCount
	int classInitFunction //void f() to initialise class/static globals
	int classStateSpec //points to a DanaType
	int typeMappings //points to an array of integers, each of which points at a typelink
	int typeMappingsCount
	int sourceNameOffset
	int2 capabilities //if this component has any special capabilities (unused)
	}

data RelocationRecord {
	int addr
	}

data TypeOffset {
	char name[]
	int offset
	int fieldsOffset
}

data DanaTypeRecord {
	int1 typeClass
	const byte F_BOOL = 1
	const byte F_CHAR = 2
	const byte F_GC_NOCYCLE = 128
	int1 flags
	int esize
	int fieldsOffset
	int fieldCount
	}

//an info section header
data DanaInfoSection64{
	byte sectionType[4] //type code identifying the section's purpose (0.x.x.x, D.N.x.x, F.R.x.x are reserved)
	byte contentType[4] //type code identifying the kind of content (json, xml, jpeg, etc.)
	int8 size //size of the section's content, excluding this header
	}

data DanaInfoSection32{
	byte sectionType[4] //type code identifying the section's purpose (0.x.x.x, D.N.x.x, F.R.x.x are reserved)
	byte contentType[4] //type code identifying the kind of content (json, xml, jpeg, etc.)
	int4 size //size of the section's content, excluding this header
	}

data ConInt64 {
	int8 value
}

data ConInt32 {
	int4 value
}

data StringTable {
	int offset
	char str[]
}

data Relocation {
	int offset
}

component provides EnvelopeWriter requires data.adt.List, data.StringBuilder, data.query.Search search, data.StringUtil stringUtil, data.IntUtil iu, io.Output out, DNCUtil dncUtil {
	
	int addressWidth
	bool evenAddressLock = true
	byte targetEndianMode = EnvelopeWriter.EM_BIG
	byte myEndianMode = EnvelopeWriter.EM_BIG //Dana is always EM_BIG, so this is redundant, but here as a potential future config option
	byte osType = OS_TYPE

	int LIVE_TYPE_FIELD_COUNT = 4
	int LIVE_POINTER_FIELD_COUNT = 2
	int LIVE_BINDPOINT_FIELD_COUNT = 6
	int LIVE_INTERFACE_FIELD_COUNT = LIVE_BINDPOINT_FIELD_COUNT + 1
	int LIVE_OBJECT_SPEC_FIELD_COUNT = 8
	int LIVE_BINDPORT_FIELD_COUNT = LIVE_BINDPOINT_FIELD_COUNT + 8
	int LIVE_COMPONENT_FIELD_COUNT = LIVE_POINTER_FIELD_COUNT + 14
	int LIVE_VFRAME_FIELD_COUNT = 18
	int VFRAME_HEADER_FIELD_COUNT = 11

	bool EAL_PATTERNS = true

	List relocations

	SourceHeader sourceHdr = new SourceHeader()
	char sourceName[]

	bool firstWrite = true

	int fileTextOffset
	int fileTextSize
	int fileNNITableOffset
	int fileLiteralsOffset
	int fileRelocationsOffset
	int fileRelocationsSize
	int fileRelocationsCount
	int fileInfoSectionsOffset
	int fileInfoSectionsCount
	int fileInfoSectionsSize
	int fileTypeMappingsOffset
	int fileInfoStaticStateOffset
	TypeOffset typeOffsetList[]

	TypeMapping typeMappings[]

	EnvelopeWriter:EnvelopeWriter(char name[], int aw, opt byte emode, byte ost)
		{
		relocations = new List()

		sourceName = name
		addressWidth = aw
		if (isset emode) targetEndianMode = emode
		if (isset ost) osType = ost
		}
	
	int getLiveTypeSize()
		{
		return addressWidth * LIVE_TYPE_FIELD_COUNT
		}
	
	int getLivePointerSize()
		{
		return addressWidth * LIVE_POINTER_FIELD_COUNT
		}
	
	int getLiveComponentSize()
		{
		return addressWidth * LIVE_COMPONENT_FIELD_COUNT
		}
	
	int getLiveObjectSpecSize()
		{
		return addressWidth * LIVE_OBJECT_SPEC_FIELD_COUNT
		}
	
	int getLiveInterfaceSize()
		{
		return addressWidth * LIVE_INTERFACE_FIELD_COUNT
		}
	
	int getLiveBindportSize()
		{
		return addressWidth * LIVE_BINDPORT_FIELD_COUNT
		}
	
	int getVFrameSize()
		{
		return addressWidth * LIVE_VFRAME_FIELD_COUNT
		}
	
	int getVFrameHeaderSize()
		{
		return addressWidth * VFRAME_HEADER_FIELD_COUNT
		}
	
	bool isByteAlignedType(DanaType t)
		{
		return t.class == DanaType.INTERFACE || t.class == DanaType.DATA || (t.class == DanaType.ARRAY && t.storageSize == 0)
		}
	
	int translateTypeClass(int class)
		{
		if (class == DanaType.INTEGER)
			{
			return TYPE_LITERAL
			}
			else if (class == DanaType.DECIMAL)
			{
			return TYPE_DECIMAL
			}
			else if (class == DanaType.DATA)
			{
			return TYPE_DATA
			}
			else if (class == DanaType.INTERFACE)
			{
			return TYPE_OBJECT
			}
			else if (class == DanaType.ARRAY)
			{
			return TYPE_ARRAY
			}
			else if (class == DanaType.VAR)
			{
			return TYPE_VAR
			}

		return TYPE_NULL
		}
	
	int getTypeSize(DanaType t, DanaType types[])
		{
		if (t.class == DanaType.INTERFACE || t.class == DanaType.DATA || (t.class == DanaType.ARRAY && t.storageSize == 0))
			{
			return getLivePointerSize()
			}
			else if (t.class == DanaType.ARRAY)
			{
			//TODO: fixed-length multi-dimensional arrays, where we need to multiply-up the storage size...?
			DanaType arType = types.findFirst(DanaType.[name], new DanaType(name = t.fields[0].type))
			return (arType.storageSize * t.storageSize)
			}
			else
			{
			return t.storageSize
			}
		}
	
	int addressAlign(File fd)
		{
		if (evenAddressLock)
			{
			int pos = fd.getPos()
			int rm = 0
			if (pos % addressWidth != 0)
				rm = addressWidth - (pos % addressWidth)
			
			int tot = rm

			byte pb = 0
			while (rm > 0)
				{
				fd.write(pb)
				rm --
				}
			
			return tot
			}
		
		return 0
		}
	
	byte[] endianSwap(byte bytes[])
		{
		if (myEndianMode != targetEndianMode)
			{
			byte result[] = new byte[bytes.arrayLength]
			int rindex = result.arrayLength - 1
			for (int i = 0; i < result.arrayLength; i++)
				{
				result[rindex - i] = bytes[i]
				}

			return result
			}
			else
			{
			return bytes
			}
		}
	
	void setConValue(ConInt32 v32, ConInt64 v64, int8 value)
		{
		if (addressWidth == 8)
			v64.value = value
			else if (addressWidth == 4)
			v32.value = value
		}
	
	char[] getStringNT(char str[])
		{
		char res[] = new char[str.arrayLength + 1]
		res =[] str
		return res
		}
	
	int getPatternStorageSize(DanaType t, DanaType types[])
		{
		int total = 0

		for (int i = 0; i < t.fields.arrayLength; i ++)
			{
			if (t.fields[i].qualifier != "constant")
				{
				//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = t.fields[i].type))
				DanaType fieldType = dncUtil.findType(types, t.fields[i].type)

				if (fieldType == null)
					{
					throw new Exception("unknown/null field type of $(t.fields[i].type) in type '$(t.name)'")
					}

				if (fieldType.class == DanaType.DATA
					|| (fieldType.class == DanaType.ARRAY && fieldType.storageSize == 0)
					|| fieldType.class == DanaType.INTERFACE)
					{
					total += getLivePointerSize()
					}
					else if (fieldType.class == DanaType.ARRAY)
					{
					//TODO: fixed-length multi-dimensional arrays, where we need to multiply-up the storage size...?
					//DanaType arType = types.findFirst(DanaType.[name], new DanaType(name = fieldType.fields[0].type))
					DanaType arType = dncUtil.findType(types, fieldType.fields[0].type)
					total += (arType.storageSize * fieldType.storageSize)
					}
					else
					{
					total += fieldType.storageSize
					}
				
				if (evenAddressLock && isByteAlignedType(fieldType))
					{
					if (total % addressWidth != 0)
						{
						total += (addressWidth - (total % addressWidth))
						}
					}
				}
			}
		
		return total
		}
	
	int getFieldCount(DanaType t)
		{
		int result = 0
		for (int i = 0; i < t.fields.arrayLength; i++)
			{
			if (t.fields[i].qualifier != "constant")
				result ++
			}
		
		return result
		}
	
	void writeCommonHeader(File fd)
		{
		//DanaCommonHeader hdr = new DanaCommonHeader(DanaCommonHeader.OBJECT_MAGIC, null, null, new byte[](8, 1), new byte[](OS_TYPE, OBJ_VERSION)) //TODO: this line causes a runtime segfault!

		DanaCommonHeader hdr = new DanaCommonHeader()
		hdr.magic = DanaCommonHeader.OBJECT_MAGIC
		hdr.hostType[0] = addressWidth
		hdr.hostType[1] = 1
		hdr.vpuType[0] = osType
		hdr.vpuType[1] = OBJ_VERSION
		fd.write(dana.serial(hdr))
		}
	
	void writeMachineHeader(File fd)
		{
		if (addressWidth == 8)
			{
			DanaMachineHeader64 hdr = new DanaMachineHeader64()
			//machine code
			hdr.textOffset = fileTextOffset
			hdr.textSize = fileTextSize
			//local relocations; a list of addresses to add the start address of this object to
			hdr.lrTableOffset = fileRelocationsOffset
			hdr.lrTableSize = fileRelocationsSize
			hdr.lrTableCount = fileRelocationsCount
			//infoSections: offset to the first extended infoSection, if any (0 is none)
			hdr.infoSectionsOffset = fileInfoSectionsOffset //TODO: we need DNIL for load to work properly...(see how util.ObjectFile does this?)
			hdr.infoSectionsSize = fileInfoSectionsSize
			hdr.infoSectionsCount = fileInfoSectionsCount
			fd.write(dana.serial(hdr))
			}
			else if (addressWidth == 4)
			{
			DanaMachineHeader32 hdr = new DanaMachineHeader32()
			//machine code
			hdr.textOffset = fileTextOffset
			hdr.textSize = fileTextSize
			//local relocations; a list of addresses to add the start address of this object to
			hdr.lrTableOffset = fileRelocationsOffset
			hdr.lrTableSize = fileRelocationsSize
			hdr.lrTableCount = fileRelocationsCount
			//infoSections: offset to the first extended infoSection, if any (0 is none)
			hdr.infoSectionsOffset = fileInfoSectionsOffset //TODO: we need DNIL for load to work properly...(see how util.ObjectFile does this?)
			hdr.infoSectionsSize = fileInfoSectionsSize
			hdr.infoSectionsCount = fileInfoSectionsCount
			fd.write(dana.serial(hdr))
			}

		}
	
	int getTotalComponentSize(OpParseResult parseResult, DanaType types[])
		{
		int objectsSize = 0

		for (int i = 0; i < parseResult.providedObjects.arrayLength; i++)
			{
			objectsSize += getLiveObjectSpecSize()
			objectsSize += getLiveInterfaceSize() * parseResult.providedObjects[i].interfaces.arrayLength
			}
		
		return getLiveComponentSize() + objectsSize + (getLiveBindportSize() * parseResult.requiredInterfaces.arrayLength) + getPatternStorageSize(parseResult.staticGlobals, types)
		}

	void writeComponentSourceHeader(File fd, char name[], OpParseResult parseResult, DanaType types[], LiteralsTable literals, int textOffset, int classInitOffset, List reloc)
		{
		//SourceHeader hdr = new SourceHeader()
		//hdr.componentSize = getTotalComponentSize(parseResult, types)
		//hdr.objectDefinitions = sourceHdr.objectDefinitions
		//hdr.bindportDefinitions = sourceHdr.bindportDefinitions
		//hdr.objectsCount = parseResult.providedObjects.arrayLength
		//hdr.bindportsCount = parseResult.requiredInterfaces.arrayLength
		//hdr.classInitFunction = 0 //TODO
		//hdr.classStateSpec = 0 //TODO
		//hdr.typeMappings = 0 //TODO
		//hdr.typeMappingsCount = 0 //TODO
		//hdr.sourceNameOffset = fileLiteralsOffset + getLiteralOffset(literals, getStringNT(name))
		//hdr.capabilities = 0
		//fd.write(dana.serial(hdr))

		//this header is written host-endian
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		setConValue(con32, con64, getTotalComponentSize(parseResult, types))
		fd.write(endianSwap(conBytes))

		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, sourceHdr.objectDefinitions)
		fd.write(endianSwap(conBytes))

		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, sourceHdr.bindportDefinitions)
		fd.write(endianSwap(conBytes))

		setConValue(con32, con64, parseResult.providedObjects.arrayLength)
		fd.write(endianSwap(conBytes))

		setConValue(con32, con64, parseResult.requiredInterfaces.arrayLength)
		fd.write(endianSwap(conBytes))

		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, classInitOffset)
		fd.write(endianSwap(conBytes))

		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, fileInfoStaticStateOffset)
		fd.write(endianSwap(conBytes))

		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, fileTypeMappingsOffset)
		fd.write(endianSwap(conBytes))

		setConValue(con32, con64, typeMappings.arrayLength)
		fd.write(endianSwap(conBytes))

		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, literals.getOffsetOf(getStringNT(name)))
		fd.write(endianSwap(conBytes))

		setConValue(con32, con64, 0)
		fd.write(endianSwap(conBytes))
		}
	
	void writeNNITable(File fd, int textOffset)
		{
		if (addressWidth == 8)
			{
			int8 table[] = new int8[256]
			fd.write(dana.serial(table))
			}
			else if (addressWidth == 4)
			{
			int4 table[] = new int4[256]
			fd.write(dana.serial(table))
			}
		}
	
	void writeDanaType(File fd, int textOffset, byte class, byte flags, int size, int fieldsOffset, int fieldsCount, List reloc)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)
		
		fd.write(class)
		fd.write(flags)

		addressAlign(fd)

		setConValue(con32, con64, size)
		fd.write(endianSwap(conBytes))

		//relocation entry
		if (fieldsCount != 0 && reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, fieldsOffset)
		fd.write(endianSwap(conBytes))

		setConValue(con32, con64, fieldsCount)
		fd.write(endianSwap(conBytes))
		}
	
	void writeDanaTypeField(File fd, StringTable strTable, char name[], int textOffset, int typeOffset, List reloc)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		byte b = 0

		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		//DanaTypeField.type
		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, typeOffset)
		fd.write(endianSwap(conBytes))
		
		if (strTable != null && name != null)
			{
			//DanaTypeField.fieldName
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			//setConValue(con32, con64, strTable.offset + strTable.str.find(name))
			setConValue(con32, con64, strTable.offset + dncUtil.findString(strTable.str, name))
			fd.write(endianSwap(conBytes))
			
			//DanaTypeField.fieldNameLength
			setConValue(con32, con64, name.arrayLength)
			fd.write(endianSwap(conBytes))
			}
			else
			{
			//DanaTypeField.fieldName
			setConValue(con32, con64, 0)
			fd.write(conBytes)
			
			//DanaTypeField.fieldNameLength
			setConValue(con32, con64, 0)
			fd.write(conBytes)
			}
		
		//DanaTypeField.flags
		fd.write(b)
		
		addressAlign(fd)
		
		//DanaTypeField.offset
		setConValue(con32, con64, 0)
		fd.write(conBytes)
		}
	
	VariableRef[] writeDanaTypeFields(File fd, StringTable strTable, int textOffset, DanaType type, DanaType types[], TypeOffset offsets[], List reloc)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)
		int offset = 0

		//out.println("writing fields of type $(type.name)")

		VariableRef result[] = new VariableRef[type.fields.arrayLength]

		for (int i = 0; i < type.fields.arrayLength; i++)
			{
			if (type.fields[i].qualifier != "constant")
				{
				int fieldTypeAddr = 0
				//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = type.fields[i].type))
				DanaType fieldType = dncUtil.findType(types, type.fields[i].type)
				TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(fieldType.name))

				//in the first pass, offset may not exist for the field (as it hasn't been written out yet)
				if (fieldTypeOffset != null)
					fieldTypeAddr = fieldTypeOffset.offset
				
				//out.println("  - write field type $(fieldType.name), offset $(fieldTypeAddr) ($(fieldTypeAddr-textOffset)), offset-in $(offset), storage-size $(fieldType.storageSize)")

				if (EAL_PATTERNS)
					{
					if (evenAddressLock && isByteAlignedType(fieldType))
						{
						//out.println(" - considering offset adjustment for $(offset % addressWidth)")
						if ((offset % addressWidth) != 0)
							{
							offset += (addressWidth - (offset % addressWidth))
							//out.println(" - offset adjustment made, to $(offset)")
							}
						}
					}
				
				int vsize = getTypeSize(fieldType, types)
				
				//DanaTypeField.type
				if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
				setConValue(con32, con64, fieldTypeAddr)
				fd.write(endianSwap(conBytes))
				
				if (strTable != null && (type.class == TYPE_DATA || type.class == TYPE_FUNCTION || type.class == TYPE_EVENTSOURCE))
					{
					//printf("NAME: %s\n", fields -> name);
					
					//DanaTypeField.fieldName
					if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
					//setConValue(con32, con64, strTable.offset + strTable.str.find(type.fields[i].name))
					setConValue(con32, con64, strTable.offset + dncUtil.findString(strTable.str, type.fields[i].name))
					fd.write(endianSwap(conBytes))
					
					//DanaTypeField.fieldNameLength
					setConValue(con32, con64, type.fields[i].name.arrayLength)
					fd.write(endianSwap(conBytes))
					}
					else
					{
					//DanaTypeField.fieldName
					setConValue(con32, con64, 0)
					fd.write(conBytes)
					
					//DanaTypeField.fieldNameLength
					setConValue(con32, con64, 0)
					fd.write(conBytes)
					}
				
				//DanaTypeField.flags
				byte b = 0
				
				if ((type.fields[i].flags & F_RECURSE_POINT) == F_RECURSE_POINT)
					b |= 0x1
				
				if (type.fields[i].qualifier.find("store") != StringUtil.NOT_FOUND)
					b |= 0x2
				
				if (type.fields[i].qualifier.find("opt") != StringUtil.NOT_FOUND)
					b |= 0x4

				fd.write(b)
				
				addressAlign(fd)
				
				//DanaTypeField.offset
				setConValue(con32, con64, offset)
				fd.write(endianSwap(conBytes))

				result[i] = new VariableRef(fieldTypeAddr, offset, translateTypeClass(fieldType.class))
				
				offset += vsize
				}
			}
		
		return result
		}
	
	int writeDanaObjectType(File fd, StringTable strTable, int textOffset, DanaType type, DanaType types[], TypeOffset offsets[], List reloc)
		{
		int fieldsOffset
		int fieldCount

		//out.println("write object type $(type.name)")

		//write all functions

		int functionOffsets[]

		for (int i = 0; i < type.fields.arrayLength; i++)
			{
			//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = type.fields[i].type))
			DanaType fieldType = dncUtil.findType(types, type.fields[i].type)
			TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(fieldType.name))

			if (fieldType.class == DanaType.FUNCTION)
				{
				functionOffsets = new int[](functionOffsets, fd.getPos() - textOffset)

				fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
				fieldCount = fieldType.fields.arrayLength

				//out.println(" - write function type $(fieldType.name)")
				
				byte flags = 0
				//if (fieldType.isConstructor) flags = 2 //TODO (isn't this just a naming equivalence check??)
				writeDanaType(fd, textOffset, TYPE_FUNCTION, flags, getPatternStorageSize(fieldType, types), fieldsOffset, fieldCount, reloc)
				writeDanaTypeFields(fd, strTable, textOffset, fieldType, types, offsets, reloc)
				}
			}
		
		fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
		fieldCount = functionOffsets.arrayLength// + t -> object -> eventSourcesCount;
		
		int functionListTypeOffset = (fd.getPos() - textOffset)
		writeDanaType(fd, textOffset, TYPE_DATA, 0, type.storageSize, fieldsOffset, fieldCount, reloc)
		
		// (fields)
		int j = 0
		for (int i = 0; i < type.fields.arrayLength; i++)
			{
			//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = type.fields[i].type))
			DanaType fieldType = dncUtil.findType(types, type.fields[i].type)
			TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(fieldType.name))

			if (fieldType.class == DanaType.FUNCTION)
				{
				writeDanaTypeField(fd, strTable, type.fields[i].name, textOffset, functionOffsets[j], reloc)
				j ++
				}
			}
		
		//write all events

		int eventOffsets[]

		for (int i = 0; i < type.fields.arrayLength; i++)
			{
			//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = type.fields[i].type))
			DanaType fieldType = dncUtil.findType(types, type.fields[i].type)
			TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(fieldType.name))

			if (fieldType.class == DanaType.EVENT)
				{
				eventOffsets = new int[](eventOffsets, fd.getPos() - textOffset)

				fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
				fieldCount = fieldType.fields.arrayLength
				
				byte flags = 0
				writeDanaType(fd, textOffset, TYPE_EVENTSOURCE, flags, getPatternStorageSize(fieldType, types), fieldsOffset, fieldCount, reloc)
				writeDanaTypeFields(fd, strTable, textOffset, fieldType, types, offsets, reloc)
				}
			}
		
		fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
		fieldCount = eventOffsets.arrayLength
		
		int eventListTypeOffset = (fd.getPos() - textOffset)
		writeDanaType(fd, textOffset, TYPE_DATA, 0, type.storageSize, fieldsOffset, fieldCount, reloc)
		
		// (fields)
		int qi = 0
		for (int i = 0; i < type.fields.arrayLength; i++)
			{
			//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = type.fields[i].type))
			DanaType fieldType = dncUtil.findType(types, type.fields[i].type)
			TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(fieldType.name))

			if (fieldType.class == DanaType.EVENT)
				{
				writeDanaTypeField(fd, strTable, type.fields[i].name, textOffset, eventOffsets[qi], reloc)
				qi ++
				}
			}
		
		//write all transfer fields

		int transferListTypeOffset = (fd.getPos() - textOffset)

		fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
		fieldCount = 0

		for (int i = 0; i < type.fields.arrayLength; i++)
			{
			DanaType fieldType = dncUtil.findType(types, type.fields[i].type)
			//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = type.fields[i].type))
			TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(fieldType.name))

			if (fieldType.class != DanaType.FUNCTION && fieldType.class != DanaType.EVENT && type.fields[i].qualifier == "transfer")
				{
				fieldCount ++
				}
			}

		writeDanaType(fd, textOffset, TYPE_DATA, 0, type.storageSize, fieldsOffset, fieldCount, reloc)

		// (fields)
		for (int i = 0; i < type.fields.arrayLength; i++)
			{
			//DanaType fieldType = types.findFirst(DanaType.[name], new DanaType(name = type.fields[i].type))
			DanaType fieldType = dncUtil.findType(types, type.fields[i].type)
			TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(fieldType.name))

			if (fieldType.class != DanaType.FUNCTION && fieldType.class != DanaType.EVENT && type.fields[i].qualifier == "transfer")
				{
				writeDanaTypeField(fd, strTable, type.fields[i].name, textOffset, fieldTypeOffset.offset, reloc)
				}
			}

		//and finally the object itself, with its fields pointing to the lists of functions / events / transfers

		fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
		fieldCount = 3
		
		byte flags = 0
		if (type.name == "lang.Proxy") flags = 0x1
		if (type.name == "lang.Morph") flags = 0x2
		
		int typeOffset = (fd.getPos() - textOffset)
		writeDanaType(fd, textOffset, TYPE_OBJECT, flags, type.storageSize, fieldsOffset, fieldCount, reloc)
		
		writeDanaTypeField(fd, strTable, ".functions", textOffset, functionListTypeOffset, reloc)
		writeDanaTypeField(fd, strTable, ".events", textOffset, eventListTypeOffset, reloc)
		writeDanaTypeField(fd, strTable, ".state", textOffset, transferListTypeOffset, reloc)

		return typeOffset
		}
	
	TypeOffset[] writeTypes(File fd, DanaType types[], int textOffset, List reloc)
		{
		//write all field names to a string table
		StringBuilder build = new StringBuilder()

		for (int i = 0; i < types.arrayLength; i++)
			{
			if (types[i].class == DanaType.DATA)
				{
				for (int j = 0; j < types[i].fields.arrayLength; j++)
					{
					build.add(types[i].fields[j].name)
					}
				}
				else if (types[i].class == DanaType.INTERFACE)
				{
				for (int j = 0; j < types[i].fields.arrayLength; j++)
					{
					build.add(types[i].fields[j].name)
					}
				}
			}

		build.add(".functions")
		build.add(".events")
		build.add(".state")

		StringTable strTable = new StringTable(fd.getPos() - textOffset, build.get())
		fd.write(strTable.str)

		addressAlign(fd)

		//write all types, populating the offset list first so it doesn't matter if types and the types of their fields appear out of order
		TypeOffset offsets[] = typeOffsetList
		if (firstWrite)
			{
			offsets = new TypeOffset[types.arrayLength]

			for (int i = 0; i < types.arrayLength; i++)
				{
				offsets[i] = new TypeOffset(types[i].name)
				}
			}
		
		for (int i = 0; i < types.arrayLength; i++)
			{
			if (firstWrite)
				{
				TypeOffset tOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(types[i].name))
				tOffset.offset = fd.getPos() - textOffset
				}

			if (types[i].class == DanaType.INTEGER)
				{
				byte flags = 0
				if (types[i].name == "bool")
					flags = DanaTypeRecord.F_BOOL
					else if (types[i].name == "char")
					flags = DanaTypeRecord.F_CHAR
			
				writeDanaType(fd, textOffset, TYPE_LITERAL, flags, types[i].storageSize, 0, 0, reloc)
				}
				else if (types[i].class == DanaType.DECIMAL)
				{
				writeDanaType(fd, textOffset, TYPE_DECIMAL, 0, types[i].storageSize, 0, 0, reloc)
				}
				else if (types[i].class == DanaType.DATA)
				{
				byte flags = 0
				if (types[i].flags == DanaType.F_NO_CYCLE) flags = DanaTypeRecord.F_GC_NOCYCLE
				
				if (firstWrite) offsets[i].fieldsOffset = offsets[i].offset + getLiveTypeSize()
				
				int size = getPatternStorageSize(types[i], types)

				writeDanaType(fd, textOffset, TYPE_DATA, flags, size, offsets[i].fieldsOffset, getFieldCount(types[i]), reloc)
				writeDanaTypeFields(fd, strTable, textOffset, types[i], types, offsets, reloc)
				}
				else if (types[i].class == DanaType.ARRAY)
				{
				byte flags = 0
				if (types[i].flags == DanaType.F_NO_CYCLE) flags = DanaTypeRecord.F_GC_NOCYCLE
				
				TypeOffset fieldTypeOffset = offsets.findFirst(TypeOffset.[name], new TypeOffset(types[i].fields[0].type))

				if (fieldTypeOffset == null) throw new Exception("array type $(types[i].fields[0].type) not found in offsets table")

				//out.println(" - found array type $(types[i].fields[0].type) for $(types[i].name), offset $(fieldTypeOffset.offset)")

				if (firstWrite) offsets[i].fieldsOffset = offsets[i].offset + getLiveTypeSize()
				writeDanaType(fd, textOffset, TYPE_ARRAY, flags, types[i].storageSize, offsets[i].fieldsOffset, 1, reloc)
				writeDanaTypeField(fd, null, null, textOffset, fieldTypeOffset.offset, reloc)
				}
				else if (types[i].class == DanaType.INTERFACE)
				{
				int offset = writeDanaObjectType(fd, strTable, textOffset, types[i], types, offsets, reloc)
				if (firstWrite) offsets[i].offset = offset
				}
			}
		
		return offsets
		}
	
	void writeInterfaceRecords(File fd)
		{
		//build a local string table

		//write the interface details

		//return their offsets

		//TODO: re-use writeInterfaceDetails() for this
		}
	
	int writeGlobalStateDefinitions(File fd, OpParseResult opr, DanaType types[], TypeOffset typeOffsets[], int textOffset, List reloc)
		{
		StringBuilder build = new StringBuilder()

		for (int i = 0; i < types.arrayLength; i++)
			{
			if (types[i].class == DanaType.DATA)
				{
				for (int j = 0; j < types[i].fields.arrayLength; j++)
					{
					build.add(types[i].fields[j].name)
					}
				}
				else if (types[i].class == DanaType.INTERFACE)
				{
				for (int j = 0; j < types[i].fields.arrayLength; j++)
					{
					build.add(types[i].fields[j].name)
					}
				}
			}

		StringTable strTable = new StringTable(fd.getPos() - textOffset, build.get())
		fd.write(strTable.str)

		addressAlign(fd)

		int pos = fd.getPos() - textOffset

		int fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
		
		int size = getPatternStorageSize(opr.staticGlobals, types)
		writeDanaType(fd, textOffset, TYPE_DATA, 0, size, fieldsOffset, opr.staticGlobals.fields.arrayLength, reloc)
		writeDanaTypeFields(fd, strTable, textOffset, opr.staticGlobals, types, typeOffsets, reloc)

		return pos
		}
	
	void writeFunctionLinks(File fd, ImplementedInterface impIntf, int textOffset, List reloc)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		//just write the function-implementation offset for every function in this interface, in the correct order
		for (int i = 0; i < impIntf.functions.arrayLength; i++)
			{
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			//out.println("flink @ $(impIntf.functions[i].offset)")
			setConValue(con32, con64, impIntf.functions[i].offset)
			fd.write(endianSwap(conBytes))
			}
		}
	
	void writeInterfaceDetails(File fd, StringTable strTable, char name[], char semantic[], int typeOffset, int functionLinksAddr, int flags, int textOffset, List reloc)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		// InterfaceDetails.name
		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, strTable.offset + strTable.str.find(name))
		fd.write(endianSwap(conBytes))
		
		// InterfaceDetails.nameLen
		setConValue(con32, con64, name.arrayLength)
		fd.write(endianSwap(conBytes))
		
		// InterfaceDetails.type
		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, typeOffset)
		fd.write(endianSwap(conBytes))
		
		// InterfaceDetails.variantNameLen
		setConValue(con32, con64, semantic.arrayLength)
		fd.write(endianSwap(conBytes))
		
		// InterfaceDetails.variantName
		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, strTable.offset + strTable.str.find(semantic))
		fd.write(endianSwap(conBytes))
		
		// InterfaceDetails.functionBindings
		if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, functionLinksAddr)
		fd.write(endianSwap(conBytes))

		// InterfaceDetails.flags
		setConValue(con32, con64, flags)
		fd.write(endianSwap(conBytes))
		}
	
	bool hasEventFields(char typeName[], DanaType types[])
		{
		DanaType t = types.findFirst(DanaType.[name], new DanaType(name = typeName))

		for (int i = 0; i < t.fields.arrayLength; i++)
			{
			DanaType f = types.findFirst(DanaType.[name], new DanaType(name = t.fields[i].type))
			if (f.class == DanaType.EVENT) return true
			}

		return false
		}
	
	int writeProvidedObjectDefinitions(File fd, ProvidedObject objects[], ImplementedObject iObjects[], DanaType types[], TypeOffset typeOffsets[], int textOffset, List reloc)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		//build a local string table
		StringBuilder build = new StringBuilder()

		for (int i = 0; i < objects.arrayLength; i++)
			{
			build.add(objects[i].mainInterface)
			build.add(objects[i].semantic)
			build.add("$(objects[i].mainInterface):$(objects[i].semantic)")

			for (int j = 0; j < objects[i].subInterfaces.arrayLength; j ++)
				{
				build.add(objects[i].subInterfaces[j].string)
				}

			//TODO: transfer fields?
			}

		StringTable strTable = new StringTable(fd.getPos() - textOffset, build.get())
		fd.write(strTable.str)

		addressAlign(fd)

		int detailsLinks[] = new int[objects.arrayLength]

		//write function links, interface details, and provided object specs
		for (int i = 0; i < objects.arrayLength; i ++)
			{
			int functionLinkBlocks[] = new int[objects[i].subInterfaces.arrayLength + 1]

			ImplementedObject iObject = iObjects[i]

			for (int j = 0; j < objects[i].interfaces.arrayLength; j++)
				{
				functionLinkBlocks[j] = fd.getPos() - textOffset
				writeFunctionLinks(fd, iObject.interfaces[j], textOffset, reloc)
				}
			
			detailsLinks[i] = fd.getPos() - textOffset

			TypeOffset typeOffset = typeOffsets.findFirst(TypeOffset.[name], new TypeOffset(objects[i].mainInterface))
			if (typeOffset == null) out.println("[error: provided type '$(objects[i].mainInterface)' has no offset]")
			//out.println("$(objects[i].mainInterface) intf type offset is $(typeOffset.offset) of $(typeOffset.name)")
			char fullName[] = objects[i].mainInterface
			if (objects[i].semantic != null)
				{
				fullName = "$fullName:$(objects[i].semantic)"
				}
			writeInterfaceDetails(fd, strTable, fullName, objects[i].semantic, typeOffset.offset, functionLinkBlocks[0], 0, textOffset, reloc)

			for (int j = 0; j < objects[i].subInterfaces.arrayLength; j++)
				{
				typeOffset = typeOffsets.findFirst(TypeOffset.[name], new TypeOffset(objects[i].subInterfaces[j].string))
				writeInterfaceDetails(fd, strTable, objects[i].subInterfaces[j].string, null, typeOffset.offset, functionLinkBlocks[j+1], 0, textOffset, reloc)
				}
			}
		
		//write the state specs
		int stateLinks[] = new int[objects.arrayLength]
		int transferStateLinks[] = new int[objects.arrayLength]
		int eventSinkFunctionLinks[] = new int[objects.arrayLength]

		for (int i = 0; i < objects.arrayLength; i ++)
			{
			stateLinks[i] = fd.getPos() - textOffset

			int fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
			
			int size = getPatternStorageSize(objects[i].instanceGlobals, types)
			writeDanaType(fd, textOffset, TYPE_DATA, 0, size, fieldsOffset, objects[i].instanceGlobals.fields.arrayLength, reloc)
			writeDanaTypeFields(fd, strTable, textOffset, objects[i].instanceGlobals, types, typeOffsets, reloc)
			}
		
		for (int i = 0; i < objects.arrayLength; i ++)
			{
			transferStateLinks[i] = fd.getPos() - textOffset

			int fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
			
			int size = getPatternStorageSize(objects[i].transferState, types)
			writeDanaType(fd, textOffset, TYPE_DATA, 0, size, fieldsOffset, objects[i].transferState.fields.arrayLength, reloc)
			writeDanaTypeFields(fd, strTable, textOffset, objects[i].transferState, types, typeOffsets, reloc)
			}
		
		for (int i = 0; i < objects.arrayLength; i ++)
			{
			eventSinkFunctionLinks[i] = fd.getPos() - textOffset

			//write all the function links, relocated
			for (int j = 0; j < objects[i].localFunctions.arrayLength; j++)
				{
				if (objects[i].localFunctions[j].ftype == OpFunction.EVENTSINK)
					{
					if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
					setConValue(con32, con64, iObjects[i].localFunctions[j].offset)
					fd.write(endianSwap(conBytes))
					}
				}
			}

		//write the object spec records
		int providedObjectsAddr = fd.getPos() - textOffset

		for (int i = 0; i < objects.arrayLength; i ++)
			{
			//StaticObjectSpec.interfaces
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			setConValue(con32, con64, detailsLinks[i])
			fd.write(endianSwap(conBytes))
			
			//StaticObjectSpec.interfacesCount
			setConValue(con32, con64, objects[i].subInterfaces.arrayLength + 1)
			fd.write(endianSwap(conBytes))
			
			//StaticObjectSpec.objectInitFunction
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			setConValue(con32, con64, iObjects[i].initFunction.offset) // ?? TODO. (we need to build a separate, internal, list of function offsets, per-prov-object)
			fd.write(endianSwap(conBytes))
			
			//StaticObjectSpec.eventDispatchCount
			if (hasEventFields(objects[i].mainInterface, types))
				setConValue(con32, con64, 1)
				else
				setConValue(con32, con64, 0)
			fd.write(endianSwap(conBytes))
			
			//StaticObjectSpec.eventQueueCount
			setConValue(con32, con64, objects[i].eventSinkCount)
			fd.write(endianSwap(conBytes))
			
			//StaticObjectSpec.transferStateSpec
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			setConValue(con32, con64, transferStateLinks[i])
			fd.write(endianSwap(conBytes))
			
			//StaticObjectSpec.stateSpec
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			setConValue(con32, con64, stateLinks[i])
			fd.write(endianSwap(conBytes))
			
			//StaticObjectSpec.eventQueueFunctionBindings
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			setConValue(con32, con64, eventSinkFunctionLinks[i])
			fd.write(endianSwap(conBytes))
			}

		return providedObjectsAddr
		}
	
	int writeRequiredInterfaceDefinitions(File fd, RequiredInterface requiredInterfaces[], TypeOffset typeOffsets[], int textOffset, List reloc)
		{
		//build a local string table
		StringBuilder build = new StringBuilder()

		for (int i = 0; i < requiredInterfaces.arrayLength; i++)
			{
			build.add(requiredInterfaces[i].name)
			build.add(requiredInterfaces[i].semantic)
			build.add("$(requiredInterfaces[i].name):$(requiredInterfaces[i].semantic)")
			}

		StringTable strTable = new StringTable(fd.getPos() - textOffset, build.get())
		fd.write(strTable.str)

		addressAlign(fd)

		//interface details (re-use the above util function)
		int publicBindportsAddr = fd.getPos() - textOffset

		for (int i = 0; i < requiredInterfaces.arrayLength; i++)
			{
			char fullName[] = requiredInterfaces[i].name

			if (requiredInterfaces[i].semantic.arrayLength != 0)
				{
				fullName = "$fullName:$(requiredInterfaces[i].semantic)"
				}
			
			TypeOffset typeOffset = typeOffsets.findFirst(TypeOffset.[name], new TypeOffset(requiredInterfaces[i].name))
			if (typeOffset == null) out.println("[error: type '$(requiredInterfaces[i].name)' has no offset]")
			writeInterfaceDetails(fd, strTable, fullName, requiredInterfaces[i].semantic, typeOffset.offset, 0, requiredInterfaces[i].isNative, textOffset, reloc)
			}
		
		return publicBindportsAddr
		}
	
	int writeLiteralsTable(File fd, LiteralsTable litTable, int textOffset)
		{
		int offset = fd.getPos() - textOffset

		fd.write(litTable.getBytes())

		addressAlign(fd)

		return offset
		}
	
	void writeTypeMappings(File fd, TypeOffset typeOffsets[], int textOffset, List reloc)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null

		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		fileTypeMappingsOffset = fd.getPos() - textOffset

		for (int i = 0; i < typeMappings.arrayLength; i++)
			{
			//out.println("write index $i type mapping for $(typeMappings[i].name)")
			TypeOffset typeOffset = typeOffsets.findFirst(TypeOffset.[name], new TypeOffset(typeMappings[i].name))
			int offset = typeOffset.offset
			if (reloc != null) reloc.add(new Relocation(fd.getPos() - textOffset))
			setConValue(con32, con64, offset)
			fd.write(endianSwap(conBytes))
			}
		}
	
	ImplementedObject[] buildImplementedInterfaces(ProvidedObject objects[], DanaType types[])
		{
		//build a list of function offset records, for all interface and local functions

		ImplementedObject iObjects[] = null

		for (int i = 0; i < objects.arrayLength; i++)
			{
			ImplementedObject iObject = new ImplementedObject(objects[i].mainInterface, objects[i].semantic)

			iObject.initFunction = new ImplementedFunction(null, objects[i].initFunction)

			iObjects = new ImplementedObject[](iObjects, iObject)

			//add interface functions
			for (int j = 0; j < objects[i].interfaces.arrayLength; j++)
				{
				ImplementedInterface newIntf = new ImplementedInterface(objects[i].interfaces[j].type)
				iObject.interfaces = new ImplementedInterface[](iObject.interfaces, newIntf)

				//add the functions
				for (int k = 0; k < objects[i].interfaces[j].functions.arrayLength; k++)
					{
					ImplementedFunction newFunc = new ImplementedFunction(objects[i].interfaces[j].functions[k].name, objects[i].interfaces[j].functions[k])
					newIntf.functions = new ImplementedFunction[](newIntf.functions, newFunc)
					}
				}
			
			//add local functions
			for (int j = 0; j < objects[i].localFunctions.arrayLength; j++)
				{
				ImplementedFunction newFunc = new ImplementedFunction(objects[i].localFunctions[j].name, objects[i].localFunctions[j])
				iObject.localFunctions = new ImplementedFunction[](iObject.localFunctions, newFunc)
				}
			}
		
		return iObjects
		}
	
	void collectLiterals(OpToken instructions[], LiteralsTable litTable)
		{
		for (int i = 0; i < instructions.arrayLength; i++)
			{
			if (instructions[i].type == HWI.OP_ID_GET_LITERAL_PTR)
				{
				litTable.add(instructions[i].refValue)
				}
			
			collectLiterals(instructions[i].parameters, litTable)
			}
		}
	
	void buildLiteralTable(OpParseResult result, LiteralsTable litTable)
		{
		//find all the literal values, from OpTypes.LITERAL token values
		for (int i = 0; i < result.providedObjects.arrayLength; i++)
			{
			for (int j = 0; j < result.providedObjects[i].interfaces.arrayLength; j++)
				{
				for (int k = 0; k < result.providedObjects[i].interfaces[j].functions.arrayLength; k++)
					{
					collectLiterals(result.providedObjects[i].interfaces[j].functions[k].instructions, litTable)
					litTable.add(getStringNT(result.providedObjects[i].interfaces[j].functions[k].name))
					}
				}
			
			for (int j = 0; j < result.providedObjects[i].localFunctions.arrayLength; j++)
				{
				collectLiterals(result.providedObjects[i].localFunctions[j].instructions, litTable)
				litTable.add(getStringNT(result.providedObjects[i].localFunctions[j].name))
				}
			
			collectLiterals(result.providedObjects[i].initFunction.instructions, litTable)
			litTable.add(getStringNT(result.providedObjects[i].initFunction.name))
			}
		
		collectLiterals(result.classInitFunction.instructions, litTable)
		litTable.add(getStringNT(result.classInitFunction.name))
		}
	
	void addTypeMapping(DanaType t)
		{
		for (int i = 0; i < typeMappings.arrayLength; i++)
			{
			if (typeMappings[i].name == t.name)
				{
				return
				}
			}
		
		typeMappings = new TypeMapping[](typeMappings, new TypeMapping(t.name, typeMappings.arrayLength))
		}
	
	void collectTypeMappings(OpToken instructions[])
		{
		for (int i = 0; i < instructions.arrayLength; i++)
			{
			if (instructions[i].refType != null)
				{
				addTypeMapping(instructions[i].refType)
				}
			
			collectTypeMappings(instructions[i].parameters)
			}
		}
	
	void buildTypeMappingTable(OpParseResult result)
		{
		//find all the literal values, from OpTypes.LITERAL token values
		for (int i = 0; i < result.providedObjects.arrayLength; i++)
			{
			for (int j = 0; j < result.providedObjects[i].interfaces.arrayLength; j++)
				{
				for (int k = 0; k < result.providedObjects[i].interfaces[j].functions.arrayLength; k++)
					{
					collectTypeMappings(result.providedObjects[i].interfaces[j].functions[k].instructions)
					}
				}
			
			for (int j = 0; j < result.providedObjects[i].localFunctions.arrayLength; j++)
				{
				collectTypeMappings(result.providedObjects[i].localFunctions[j].instructions)
				}
			
			collectTypeMappings(result.providedObjects[i].initFunction.instructions)
			}
		
		collectTypeMappings(result.classInitFunction.instructions)
		}
	
	ImplementedObject[] EnvelopeWriter:prepareEnvelope(OpParseResult parseResult, DanaType types[], LiteralsTable literals)
		{
		//TODO: build a list of implemented-interfaces, with function names in the right order (expanded/flattened for inherentence), for each ProvidedObject (used by writeProvidedObjectDefinitions())

		buildLiteralTable(parseResult, literals)

		literals.add(getStringNT(parseResult.classInitFunction.name))

		literals.add(getStringNT(sourceName))

		buildTypeMappingTable(parseResult)

		return buildImplementedInterfaces(parseResult.providedObjects, types)
		}
	
	TypeMapping[] EnvelopeWriter:getTypeMappings()
		{
		return typeMappings
		}
	
	bool EnvelopeWriter:writeEnvelope(File ofd, OpParseResult parseResult, ImplementedObject iObjects[], DanaType types[], LiteralsTable literals, TypeTable typeTable, int classInitOffset, bool reloc)
		{
		//note: passing in a non-null relocations List, to any function, implies "reloc = true"
		List buildReloc = relocations
		if (!reloc) buildReloc = null
		
		writeCommonHeader(ofd)
		writeMachineHeader(ofd)
		fileTextOffset = ofd.getPos()
		int cshPosition = ofd.getPos()
		writeComponentSourceHeader(ofd, sourceName, parseResult, types, literals, fileTextOffset, classInitOffset, buildReloc)
		fileNNITableOffset = ofd.getPos() - fileTextOffset
		writeNNITable(ofd, fileTextOffset)
		TypeOffset typeOffsets[] = writeTypes(ofd, types, fileTextOffset, buildReloc)
		writeInterfaceRecords(ofd)
		fileInfoStaticStateOffset = writeGlobalStateDefinitions(ofd, parseResult, types, typeOffsets, fileTextOffset, buildReloc)
		sourceHdr.objectDefinitions = writeProvidedObjectDefinitions(ofd, parseResult.providedObjects, iObjects, types, typeOffsets, fileTextOffset, buildReloc)
		sourceHdr.bindportDefinitions = writeRequiredInterfaceDefinitions(ofd, parseResult.requiredInterfaces, typeOffsets, fileTextOffset, buildReloc)
		
		fileLiteralsOffset = writeLiteralsTable(ofd, literals, fileTextOffset)
		writeTypeMappings(ofd, typeOffsets, fileTextOffset, buildReloc)

		if (firstWrite)
			{
			typeOffsetList = typeOffsets
			for (int i = 0; i < types.arrayLength; i++)
				{
				typeTable.add(types[i].name, typeOffsets[i].offset)
				}
			}

		firstWrite = false

		literals.setOffset(fileLiteralsOffset)

		return true
		}
	
	int EnvelopeWriter:getTextOffset()
		{
		return fileTextOffset
		}
	
	int EnvelopeWriter:getNNITableOffset()
		{
		return fileNNITableOffset
		}
	
	int getCoreParamCount(Parameter params[])
		{
		int result = 0
		for (int i = 0; i < params.arrayLength; i++)
			{
			if ((params[i].qualifier & Parameter.Q_OPT) != Parameter.Q_OPT)
				{
				result ++
				}
			}
		
		return result
		}
	
	//this function is roughly writeFunctionNNI() from compiler.c
	FunctionInfo EnvelopeWriter:writeFrameHeader(File fd, ImplementedFunction function, DanaType types[], LiteralsTable literals, int textOffset)
		{
		List reloc = relocations
		
		FunctionInfo result = new FunctionInfo()

		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		addressAlign(fd)
		
		//optimiseInstructionStream(f); //TODO??
		
		result.localsReferenceOffset = fd.getPos() - textOffset
		//out.println("write frame header for $(function.function.name)")
		result.dataContentSize = getPatternStorageSize(function.function.variables, types)
		
		int fieldsOffset = (fd.getPos() - textOffset) + getLiveTypeSize()
		int fieldCount = function.function.variables.fields.arrayLength

		//out.println("fields-offset $(fieldsOffset)")
		
		writeDanaType(fd, textOffset, TYPE_PATTERN, 0, result.dataContentSize, fieldsOffset, fieldCount, reloc)
		
		result.variables = writeDanaTypeFields(fd, null, textOffset, function.function.variables, types, typeOffsetList, reloc)
		
		//registers
		if (result.registerCount == 0) result.registerCount = 1 //bit of a hack to guarantee at least one register for function call returns...
		
		//thread header
		result.textOffset = fd.getPos() - textOffset
		
		//patch references to this function, now that its offset is known
		int cp = fd.getPos()
		for (int j = 0; j < function.references.arrayLength; j++)
			{
			fd.setPos(function.references[j] + textOffset)
			 
			setConValue(con32, con64, result.textOffset)
			fd.write(endianSwap(conBytes))
			}
		fd.setPos(cp)
		
		//f -> scopeCount += 1;
		
		int frameSize = getVFrameSize() + result.dataContentSize
		result.codeStart = getVFrameHeaderSize()

		// - VFrameHeader -
		
		// VFrameHeader.frameSize
		setConValue(con32, con64, frameSize)
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.proxyHeader
		setConValue(con32, con64, 0)
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.formalParamsCount
		setConValue(con32, con64, function.function.parameters.arrayLength)
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.formalParamsCore
		setConValue(con32, con64, getCoreParamCount(function.function.parameters))
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.pcLoc
		reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, result.textOffset + result.codeStart)
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.eiiLoc (not used)
		result.exPos = fd.getPos()
		reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, 8)
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.localsDef
		reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, result.localsReferenceOffset)
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.functionName
		reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, literals.getOffsetOf(getStringNT(function.name)))
		fd.write(endianSwap(conBytes))
		
		// VFrameHeader.xRegisterCount (configured by nni)
		reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, 0)
		fd.write(endianSwap(conBytes))
		
		reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, 0)
		fd.write(endianSwap(conBytes))
		
		reloc.add(new Relocation(fd.getPos() - textOffset))
		setConValue(con32, con64, 0)
		fd.write(endianSwap(conBytes))

		return result
		}
	
	void EnvelopeWriter:addRelocations(int list[])
		{
		for (int i = 0; i < list.arrayLength; i++)
			{
			relocations.add(new Relocation(list[i]))
			}
		}
	
	void EnvelopeWriter:writeTextEnd(File fd)
		{
		addressAlign(fd)

		fileTextSize = fd.getPos() - fileTextOffset
		}
	
	void EnvelopeWriter:writeRelocations(File fd)
		{
		ConInt64 con64 = new ConInt64()
		ConInt32 con32 = new ConInt32()
		byte conBytes[] = null
		
		if (addressWidth == 8)
			conBytes = dana.serial(con64)
			else if (addressWidth == 4)
			conBytes = dana.serial(con32)

		fileRelocationsOffset = fd.getPos()
		fileRelocationsCount = relocations.getLength()

		for (Relocation r = relocations.getFirst(); r != null; r = relocations.getNext())
			{
			setConValue(con32, con64, r.offset)
			fd.write(conBytes)
			}

		fileRelocationsSize = fd.getPos() - fileRelocationsOffset
		}
	
	void EnvelopeWriter:writeInfoSection(File fd, char id[], char contentType[], byte content[])
		{
		if (fileInfoSectionsOffset == 0) fileInfoSectionsOffset = fd.getPos()
		fileInfoSectionsCount ++

		if (addressWidth == 8)
			{
			DanaInfoSection64 dis = new DanaInfoSection64()
			dis.sectionType =[] id
			dis.contentType =[] contentType
			dis.size = content.arrayLength
			
			fd.write(dana.serial(dis))
			fd.write(content)
			}
			else
			{
			DanaInfoSection32 dis = new DanaInfoSection32()
			dis.sectionType =[] id
			dis.contentType =[] contentType
			dis.size = content.arrayLength
			
			fd.write(dana.serial(dis))
			fd.write(content)
			}

		fileInfoSectionsSize = fd.getPos() - fileInfoSectionsOffset
		}
	
	}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n util.compiler.EnvelopeWriter -m "reason for update" -u yourUsername
Version 4 by barry
Version 3 by barry
Version 2 by barry
Version 1 (this version) by barry
Notes for this version: New compiler components