all: complete the implementation of interface asserts

Because a few things were left unimplemented it only happened to kind-of
work before in my test cases.
This commit should complete interface-to-interface type asserts.
Этот коммит содержится в:
Ayke van Laethem 2018-09-11 19:39:25 +02:00
родитель 61e6f7cf5b
коммит 4ad6df3227
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
2 изменённых файлов: 29 добавлений и 6 удалений

Просмотреть файл

@ -446,12 +446,14 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
} }
interfaceTypes := c.ir.AllInterfaces() interfaceTypes := c.ir.AllInterfaces()
interfaceIndex := make([]llvm.Value, len(interfaceTypes))
interfaceLengths := make([]llvm.Value, len(interfaceTypes)) interfaceLengths := make([]llvm.Value, len(interfaceTypes))
interfaceMethods := make([]llvm.Value, 0) interfaceMethods := make([]llvm.Value, 0)
for i, itfType := range interfaceTypes { for i, itfType := range interfaceTypes {
if itfType.Type.NumMethods() > 0xff { if itfType.Type.NumMethods() > 0xff {
return errors.New("too many methods for interface " + itfType.Type.String()) return errors.New("too many methods for interface " + itfType.Type.String())
} }
interfaceIndex[i] = llvm.ConstInt(llvm.Int16Type(), uint64(i), false)
interfaceLengths[i] = llvm.ConstInt(llvm.Int8Type(), uint64(itfType.Type.NumMethods()), false) interfaceLengths[i] = llvm.ConstInt(llvm.Int8Type(), uint64(itfType.Type.NumMethods()), false)
funcs := make([]*types.Func, itfType.Type.NumMethods()) funcs := make([]*types.Func, itfType.Type.NumMethods())
for i := range funcs { for i := range funcs {
@ -493,6 +495,14 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
signatureArrayOldGlobal.ReplaceAllUsesWith(llvm.ConstBitCast(signatureArrayNewGlobal, signatureArrayOldGlobal.Type())) signatureArrayOldGlobal.ReplaceAllUsesWith(llvm.ConstBitCast(signatureArrayNewGlobal, signatureArrayOldGlobal.Type()))
signatureArrayOldGlobal.EraseFromParentAsGlobal() signatureArrayOldGlobal.EraseFromParentAsGlobal()
signatureArrayNewGlobal.SetName("runtime.methodSetSignatures") signatureArrayNewGlobal.SetName("runtime.methodSetSignatures")
interfaceIndexArray := llvm.ConstArray(llvm.Int16Type(), interfaceIndex)
interfaceIndexArrayNewGlobal := llvm.AddGlobal(c.mod, interfaceIndexArray.Type(), "runtime.interfaceIndex.tmp")
interfaceIndexArrayNewGlobal.SetInitializer(interfaceIndexArray)
interfaceIndexArrayNewGlobal.SetLinkage(llvm.InternalLinkage)
interfaceIndexArrayOldGlobal := c.mod.NamedGlobal("runtime.interfaceIndex")
interfaceIndexArrayOldGlobal.ReplaceAllUsesWith(llvm.ConstBitCast(interfaceIndexArrayNewGlobal, interfaceIndexArrayOldGlobal.Type()))
interfaceIndexArrayOldGlobal.EraseFromParentAsGlobal()
interfaceIndexArrayNewGlobal.SetName("runtime.interfaceIndex")
interfaceLengthsArray := llvm.ConstArray(llvm.Int8Type(), interfaceLengths) interfaceLengthsArray := llvm.ConstArray(llvm.Int8Type(), interfaceLengths)
interfaceLengthsArrayNewGlobal := llvm.AddGlobal(c.mod, interfaceLengthsArray.Type(), "runtime.interfaceLengths.tmp") interfaceLengthsArrayNewGlobal := llvm.AddGlobal(c.mod, interfaceLengthsArray.Type(), "runtime.interfaceLengths.tmp")
interfaceLengthsArrayNewGlobal.SetInitializer(interfaceLengthsArray) interfaceLengthsArrayNewGlobal.SetInitializer(interfaceLengthsArray)

Просмотреть файл

@ -37,7 +37,7 @@ type methodSetRange struct {
// in. // in.
var ( var (
firstTypeWithMethods uint16 // the lowest typecode that has at least one method firstTypeWithMethods uint16 // the lowest typecode that has at least one method
methodSetRanges [0]methodSetRange // indexes into methodSetSignatures and methodSetFunctions methodSetRanges [0]methodSetRange // indices into methodSetSignatures and methodSetFunctions
methodSetSignatures [0]uint16 // uniqued method ID methodSetSignatures [0]uint16 // uniqued method ID
methodSetFunctions [0]*uint8 // function pointer of method methodSetFunctions [0]*uint8 // function pointer of method
interfaceIndex [0]uint16 // mapping from interface ID to an index in interfaceMethods interfaceIndex [0]uint16 // mapping from interface ID to an index in interfaceMethods
@ -81,15 +81,28 @@ func interfaceEqual(x, y _interface) bool {
// This is a compiler intrinsic. // This is a compiler intrinsic.
//go:nobounds //go:nobounds
func interfaceImplements(typecode, interfaceNum uint16) bool { func interfaceImplements(typecode, interfaceNum uint16) bool {
// method set indexes of the concrete type // method set indices of the interface
itfIndex := interfaceIndex[interfaceNum]
itfIndexEnd := itfIndex + uint16(interfaceLengths[interfaceNum])
if itfIndex == itfIndexEnd {
// This interface has no methods, so it satisfies all types.
// TODO: this should be figured out at compile time (as it is known at
// compile time), so that this check is unnecessary at runtime.
return true
}
if typecode < firstTypeWithMethods {
// Type has no methods while the interface has (checked above), so this
// type does not satisfy this interface.
return false
}
// method set indices of the concrete type
methodSet := methodSetRanges[typecode-firstTypeWithMethods] methodSet := methodSetRanges[typecode-firstTypeWithMethods]
methodIndex := methodSet.index methodIndex := methodSet.index
methodIndexEnd := methodSet.index + methodSet.length methodIndexEnd := methodSet.index + methodSet.length
// method set indexes of the interface
itfIndex := interfaceIndex[interfaceNum]
itfIndexEnd := itfIndex + uint16(interfaceLengths[interfaceNum])
// Iterate over all methods of the interface: // Iterate over all methods of the interface:
for itfIndex < itfIndexEnd { for itfIndex < itfIndexEnd {
methodId := interfaceMethods[itfIndex] methodId := interfaceMethods[itfIndex]