Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 1 | //===- interfaces.go - IR generation for interfaces -----------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file implements IR generation for dealing with interface values. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | package irgen |
| 15 | |
| 16 | import ( |
Peter Collingbourne | 56109b7 | 2015-01-13 20:45:08 +0000 | [diff] [blame] | 17 | "llvm.org/llgo/third_party/gotools/go/types" |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 18 | "llvm.org/llvm/bindings/go/llvm" |
| 19 | ) |
| 20 | |
| 21 | // interfaceMethod returns a function and receiver pointer for the specified |
| 22 | // interface and method pair. |
| 23 | func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) { |
| 24 | llitab := fr.builder.CreateExtractValue(lliface, 0, "") |
| 25 | recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer]) |
| 26 | methodset := fr.types.MethodSet(ifacety) |
| 27 | // TODO(axw) cache ordered method index |
| 28 | index := -1 |
| 29 | for i, m := range orderedMethodSet(methodset) { |
| 30 | if m.Obj() == method { |
| 31 | index = i |
| 32 | break |
| 33 | } |
| 34 | } |
| 35 | if index == -1 { |
| 36 | panic("could not find method index") |
| 37 | } |
| 38 | llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "") |
| 39 | // Skip runtime type pointer. |
| 40 | llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{ |
| 41 | llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false), |
| 42 | }, "") |
| 43 | |
| 44 | llifn := fr.builder.CreateLoad(llifnptr, "") |
| 45 | // Replace receiver type with unsafe.Pointer. |
| 46 | recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer]) |
| 47 | sig := method.Type().(*types.Signature) |
| 48 | sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic()) |
| 49 | fn = newValue(llifn, sig) |
| 50 | return |
| 51 | } |
| 52 | |
| 53 | // compareInterfaces emits code to compare two interfaces for |
| 54 | // equality. |
| 55 | func (fr *frame) compareInterfaces(a, b *govalue) *govalue { |
| 56 | aNull := a.value.IsNull() |
| 57 | bNull := b.value.IsNull() |
| 58 | if aNull && bNull { |
| 59 | return newValue(boolLLVMValue(true), types.Typ[types.Bool]) |
| 60 | } |
| 61 | |
| 62 | compare := fr.runtime.emptyInterfaceCompare |
| 63 | aI := a.Type().Underlying().(*types.Interface).NumMethods() > 0 |
| 64 | bI := b.Type().Underlying().(*types.Interface).NumMethods() > 0 |
| 65 | switch { |
| 66 | case aI && bI: |
| 67 | compare = fr.runtime.interfaceCompare |
| 68 | case aI: |
| 69 | a = fr.convertI2E(a) |
| 70 | case bI: |
| 71 | b = fr.convertI2E(b) |
| 72 | } |
| 73 | |
| 74 | result := compare.call(fr, a.value, b.value)[0] |
| 75 | result = fr.builder.CreateIsNull(result, "") |
| 76 | result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") |
| 77 | return newValue(result, types.Typ[types.Bool]) |
| 78 | } |
| 79 | |
| 80 | func (fr *frame) makeInterface(llv llvm.Value, vty types.Type, iface types.Type) *govalue { |
| 81 | if _, ok := vty.Underlying().(*types.Pointer); !ok { |
| 82 | ptr := fr.createTypeMalloc(vty) |
| 83 | fr.builder.CreateStore(llv, ptr) |
| 84 | llv = ptr |
| 85 | } |
| 86 | return fr.makeInterfaceFromPointer(llv, vty, iface) |
| 87 | } |
| 88 | |
| 89 | func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue { |
| 90 | i8ptr := llvm.PointerType(llvm.Int8Type(), 0) |
| 91 | llv := fr.builder.CreateBitCast(vptr, i8ptr, "") |
| 92 | value := llvm.Undef(fr.types.ToLLVM(iface)) |
| 93 | itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface)) |
| 94 | value = fr.builder.CreateInsertValue(value, itab, 0, "") |
| 95 | value = fr.builder.CreateInsertValue(value, llv, 1, "") |
| 96 | return newValue(value, iface) |
| 97 | } |
| 98 | |
| 99 | // Reads the type descriptor from the given interface type. |
| 100 | func (fr *frame) getInterfaceTypeDescriptor(v *govalue) llvm.Value { |
| 101 | isempty := v.Type().Underlying().(*types.Interface).NumMethods() == 0 |
| 102 | itab := fr.builder.CreateExtractValue(v.value, 0, "") |
| 103 | if isempty { |
| 104 | return itab |
| 105 | } else { |
| 106 | itabnonnull := fr.builder.CreateIsNotNull(itab, "") |
| 107 | return fr.loadOrNull(itabnonnull, itab, types.Typ[types.UnsafePointer]).value |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // Reads the value from the given interface type, assuming that the |
| 112 | // interface holds a value of the correct type. |
| 113 | func (fr *frame) getInterfaceValue(v *govalue, ty types.Type) *govalue { |
| 114 | val := fr.builder.CreateExtractValue(v.value, 1, "") |
| 115 | if _, ok := ty.Underlying().(*types.Pointer); !ok { |
| 116 | typedval := fr.builder.CreateBitCast(val, llvm.PointerType(fr.types.ToLLVM(ty), 0), "") |
| 117 | val = fr.builder.CreateLoad(typedval, "") |
| 118 | } |
| 119 | return newValue(val, ty) |
| 120 | } |
| 121 | |
| 122 | // If cond is true, reads the value from the given interface type, otherwise |
| 123 | // returns a nil value. |
| 124 | func (fr *frame) getInterfaceValueOrNull(cond llvm.Value, v *govalue, ty types.Type) *govalue { |
| 125 | val := fr.builder.CreateExtractValue(v.value, 1, "") |
| 126 | if _, ok := ty.Underlying().(*types.Pointer); ok { |
| 127 | val = fr.builder.CreateSelect(cond, val, llvm.ConstNull(val.Type()), "") |
| 128 | } else { |
| 129 | val = fr.loadOrNull(cond, val, ty).value |
| 130 | } |
| 131 | return newValue(val, ty) |
| 132 | } |
| 133 | |
| 134 | func (fr *frame) interfaceTypeCheck(val *govalue, ty types.Type) (v *govalue, okval *govalue) { |
| 135 | tytd := fr.types.ToRuntime(ty) |
| 136 | if _, ok := ty.Underlying().(*types.Interface); ok { |
| 137 | var result []llvm.Value |
| 138 | if val.Type().Underlying().(*types.Interface).NumMethods() > 0 { |
| 139 | result = fr.runtime.ifaceI2I2.call(fr, tytd, val.value) |
| 140 | } else { |
| 141 | result = fr.runtime.ifaceE2I2.call(fr, tytd, val.value) |
| 142 | } |
| 143 | v = newValue(result[0], ty) |
| 144 | okval = newValue(result[1], types.Typ[types.Bool]) |
| 145 | } else { |
| 146 | valtd := fr.getInterfaceTypeDescriptor(val) |
| 147 | tyequal := fr.runtime.typeDescriptorsEqual.call(fr, valtd, tytd)[0] |
| 148 | okval = newValue(tyequal, types.Typ[types.Bool]) |
| 149 | tyequal = fr.builder.CreateTrunc(tyequal, llvm.Int1Type(), "") |
| 150 | |
| 151 | v = fr.getInterfaceValueOrNull(tyequal, val, ty) |
| 152 | } |
| 153 | return |
| 154 | } |
| 155 | |
| 156 | func (fr *frame) interfaceTypeAssert(val *govalue, ty types.Type) *govalue { |
| 157 | if _, ok := ty.Underlying().(*types.Interface); ok { |
| 158 | return fr.changeInterface(val, ty, true) |
| 159 | } else { |
| 160 | valtytd := fr.types.ToRuntime(val.Type()) |
| 161 | valtd := fr.getInterfaceTypeDescriptor(val) |
| 162 | tytd := fr.types.ToRuntime(ty) |
| 163 | fr.runtime.checkInterfaceType.call(fr, valtd, tytd, valtytd) |
| 164 | |
| 165 | return fr.getInterfaceValue(val, ty) |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | // convertI2E converts a non-empty interface value to an empty interface. |
| 170 | func (fr *frame) convertI2E(v *govalue) *govalue { |
| 171 | td := fr.getInterfaceTypeDescriptor(v) |
| 172 | val := fr.builder.CreateExtractValue(v.value, 1, "") |
| 173 | |
| 174 | typ := types.NewInterface(nil, nil) |
| 175 | intf := llvm.Undef(fr.types.ToLLVM(typ)) |
| 176 | intf = fr.builder.CreateInsertValue(intf, td, 0, "") |
| 177 | intf = fr.builder.CreateInsertValue(intf, val, 1, "") |
| 178 | return newValue(intf, typ) |
| 179 | } |
| 180 | |
| 181 | func (fr *frame) changeInterface(v *govalue, ty types.Type, assert bool) *govalue { |
| 182 | td := fr.getInterfaceTypeDescriptor(v) |
| 183 | tytd := fr.types.ToRuntime(ty) |
| 184 | var itab llvm.Value |
| 185 | if assert { |
| 186 | itab = fr.runtime.assertInterface.call(fr, tytd, td)[0] |
| 187 | } else { |
| 188 | itab = fr.runtime.convertInterface.call(fr, tytd, td)[0] |
| 189 | } |
| 190 | val := fr.builder.CreateExtractValue(v.value, 1, "") |
| 191 | |
| 192 | intf := llvm.Undef(fr.types.ToLLVM(ty)) |
| 193 | intf = fr.builder.CreateInsertValue(intf, itab, 0, "") |
| 194 | intf = fr.builder.CreateInsertValue(intf, val, 1, "") |
| 195 | return newValue(intf, ty) |
| 196 | } |