diff options
author | Ayke van Laethem <[email protected]> | 2021-03-18 22:56:59 +0100 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-03-23 14:32:33 +0100 |
commit | cffe42484955a864df8699629d96fe444e15cc8d (patch) | |
tree | cb37442a0b11db5081e5d3f5d068eef4998136dd | |
parent | 51938e9d1c989edd24595b38023148e166abe2bd (diff) | |
download | tinygo-cffe42484955a864df8699629d96fe444e15cc8d.tar.gz tinygo-cffe42484955a864df8699629d96fe444e15cc8d.zip |
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.
-rw-r--r-- | interp/interpreter.go | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/interp/interpreter.go b/interp/interpreter.go index 0c522ef5d..5d1f024fc 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() |