Switch to 16-bit typecodes and method IDs

It took Android some time to even hit the 64K limit for regular method
calls, so switching to 16-bit IDs should be fine for method IDs of
interfaces. At least for the time being. When this limit is ever hit,
I'll think of another way, probably involving some platform-dependent
interface code (e.g. microcontrollers won't need 64K of methods) or
detecting the limit at build time.

https://android-developers.googleblog.com/2014/12/google-play-services-and-dex-method.html

Code size isn't changed, probably because the compiler optimizes away
all method calls.
This commit is contained in:
Ayke van Laethem
2018-08-26 23:56:35 +02:00
parent 539de9db9e
commit 64e478ef36
2 changed files with 32 additions and 16 deletions
+26 -10
View File
@@ -381,8 +381,8 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
rangeType := c.mod.GetTypeByName("runtime.methodSetRange")
for _, meta := range dynamicTypes {
rangeValues := []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), uint64(startIndex), false),
llvm.ConstInt(llvm.Int32Type(), uint64(len(meta.Methods)), false),
llvm.ConstInt(llvm.Int16Type(), uint64(startIndex), false),
llvm.ConstInt(llvm.Int16Type(), uint64(len(meta.Methods)), false),
}
rangeValue := llvm.ConstNamedStruct(rangeType, rangeValues)
ranges = append(ranges, rangeValue)
@@ -394,12 +394,16 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
fn := llvm.ConstBitCast(f.llvmFn, c.i8ptrType)
funcPointers = append(funcPointers, fn)
signatureNum := c.ir.MethodNum(method.Obj().(*types.Func))
signature := llvm.ConstInt(llvm.Int32Type(), uint64(signatureNum), false)
signature := llvm.ConstInt(llvm.Int16Type(), uint64(signatureNum), false)
signatures = append(signatures, signature)
}
startIndex += len(meta.Methods)
}
if len(ranges) >= 1<<16 {
return errors.New("method call numbers do not fit in a 16-bit integer")
}
// Replace the pre-created arrays with the generated arrays.
rangeArray := llvm.ConstArray(rangeType, ranges)
rangeArrayNewGlobal := llvm.AddGlobal(c.mod, rangeArray.Type(), "runtime.methodSetRanges.tmp")
@@ -417,7 +421,7 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
funcArrayOldGlobal.ReplaceAllUsesWith(llvm.ConstBitCast(funcArrayNewGlobal, funcArrayOldGlobal.Type()))
funcArrayOldGlobal.EraseFromParentAsGlobal()
funcArrayNewGlobal.SetName("runtime.methodSetFunctions")
signatureArray := llvm.ConstArray(llvm.Int32Type(), signatures)
signatureArray := llvm.ConstArray(llvm.Int16Type(), signatures)
signatureArrayNewGlobal := llvm.AddGlobal(c.mod, signatureArray.Type(), "runtime.methodSetSignatures.tmp")
signatureArrayNewGlobal.SetInitializer(signatureArray)
signatureArrayNewGlobal.SetLinkage(llvm.PrivateLinkage)
@@ -426,7 +430,7 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
signatureArrayOldGlobal.EraseFromParentAsGlobal()
signatureArrayNewGlobal.SetName("runtime.methodSetSignatures")
c.mod.NamedGlobal("runtime.firstInterfaceNum").SetInitializer(llvm.ConstInt(llvm.Int32Type(), uint64(c.ir.FirstDynamicType()), false))
c.mod.NamedGlobal("runtime.firstInterfaceNum").SetInitializer(llvm.ConstInt(llvm.Int16Type(), uint64(c.ir.FirstDynamicType()), false))
return nil
}
@@ -746,8 +750,11 @@ func (c *Compiler) getInterpretedValue(value Value) (llvm.Value, error) {
if !ok {
panic("interface number is unknown")
}
if itfTypeNum >= 1<<16 {
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
}
fields := []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), uint64(itfTypeNum), false),
llvm.ConstInt(llvm.Int16Type(), uint64(itfTypeNum), false),
llvm.Undef(c.i8ptrType),
}
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields)
@@ -1334,7 +1341,7 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon, parentHandle l
}
values := []llvm.Value{
itf,
llvm.ConstInt(llvm.Int32Type(), uint64(c.ir.MethodNum(instr.Method)), false),
llvm.ConstInt(llvm.Int16Type(), uint64(c.ir.MethodNum(instr.Method)), false),
}
fn := c.builder.CreateCall(c.mod.NamedFunction("runtime.itfmethod"), values, "invoke.func")
fnCast := c.builder.CreateBitCast(fn, llvmFnType, "invoke.func.cast")
@@ -1609,7 +1616,10 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
}
}
itfTypeNum, _ := c.ir.TypeNum(expr.X.Type())
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), []llvm.Value{llvm.ConstInt(llvm.Int32Type(), uint64(itfTypeNum), false), llvm.Undef(c.i8ptrType)})
if itfTypeNum >= 1<<16 {
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
}
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), []llvm.Value{llvm.ConstInt(llvm.Int16Type(), uint64(itfTypeNum), false), llvm.Undef(c.i8ptrType)})
itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
return itf, nil
case *ssa.MakeMap:
@@ -1730,6 +1740,9 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Static analysis has determined this type assert will never apply.
return llvm.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.ConstInt(llvm.Int1Type(), 0, false)}, false), nil
}
if assertedTypeNum >= 1<<16 {
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
}
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
valuePtr := c.builder.CreateExtractValue(itf, 1, "interface.value")
var value llvm.Value
@@ -1758,7 +1771,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
}
// TODO: for interfaces, check whether the type implements the
// interface.
commaOk := c.builder.CreateICmp(llvm.IntEQ, llvm.ConstInt(llvm.Int32Type(), uint64(assertedTypeNum), false), actualTypeNum, "")
commaOk := c.builder.CreateICmp(llvm.IntEQ, llvm.ConstInt(llvm.Int16Type(), uint64(assertedTypeNum), false), actualTypeNum, "")
tuple := llvm.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(llvm.Int1Type())}, false) // create empty tuple
tuple = c.builder.CreateInsertValue(tuple, value, 0, "") // insert value
tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean
@@ -1933,11 +1946,14 @@ func (c *Compiler) parseConst(expr *ssa.Const) (llvm.Value, error) {
return llvm.Value{}, errors.New("non-nil interface constant")
}
itfTypeNum, ok := c.ir.TypeNum(expr.Type())
if itfTypeNum >= 1<<16 {
return llvm.Value{}, errors.New("interface typecodes do not fit in a 16-bit integer")
}
if !ok {
panic("interface number is unknown")
}
fields := []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), uint64(itfTypeNum), false),
llvm.ConstInt(llvm.Int16Type(), uint64(itfTypeNum), false),
llvm.Undef(c.i8ptrType),
}
itf := llvm.ConstNamedStruct(c.mod.GetTypeByName("runtime._interface"), fields)