From cffe42484955a864df8699629d96fe444e15cc8d Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 18 Mar 2021 22:56:59 +0100 Subject: [PATCH] interp: add support for runtime.interfaceMethod This is necessary so that when reflect.Type is converted from a concrete type to an interface type, the errors package can still be interpreted. Without this change, basically every program would grow in size by a few bytes. --- interp/interpreter.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/interp/interpreter.go b/interp/interpreter.go index 0c522ef5..5d1f024f 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -368,6 +368,39 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent } // If assertOk is still 1, the assertion succeeded. locals[inst.localIndex] = literalValue{assertOk} + case callFn.name == "runtime.interfaceMethod": + // This builtin returns the function (which may be a thunk) to + // invoke a method on an interface. It does not call the method. + if r.debug { + fmt.Fprintln(os.Stderr, indent+"interface method:", operands[1:]) + } + + // Load the first param, which is the type code (ptrtoint of the + // type code global). + typecodeID := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem).Operand(0).Initializer() + + // Load the method set, which is part of the typecodeID object. + methodSet := llvm.ConstExtractValue(typecodeID, []uint32{2}).Operand(0).Initializer() + + // We don't need to load the interface method set. + + // Load the signature of the to-be-called function. + signature := inst.llvmInst.Operand(2) + + // Iterate through all methods, looking for the one method that + // should be returned. + numMethods := methodSet.Type().ArrayLength() + var method llvm.Value + for i := 0; i < numMethods; i++ { + methodSignature := llvm.ConstExtractValue(methodSet, []uint32{uint32(i), 0}) + if methodSignature == signature { + method = llvm.ConstExtractValue(methodSet, []uint32{uint32(i), 1}).Operand(0) + } + } + if method.IsNil() { + return nil, mem, r.errorAt(inst, errors.New("could not find method: "+signature.Name())) + } + locals[inst.localIndex] = r.getValue(method) case callFn.name == "runtime.hashmapMake": // Create a new map. hashmapPointerType := inst.llvmInst.Type()