interp: error location for "unknown GEP" error
This commit removes a panic and replaces it with a proper source location. The message still isn't very helpful, but at least it points to a location in the source code. I'm not very happy with all the `err.Error()` calls, but that's the way to fit this in a `scanner.Error`. Eventually we should make a replacement for `scanner.Error` that does proper wrapping of the original error message.
Этот коммит содержится в:
родитель
ec467da83c
коммит
25cff20117
3 изменённых файлов: 49 добавлений и 20 удалений
|
@ -125,7 +125,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||||
}
|
}
|
||||||
indices[i] = uint32(operand.Value().ZExtValue())
|
indices[i] = uint32(operand.Value().ZExtValue())
|
||||||
}
|
}
|
||||||
result := value.GetElementPtr(indices)
|
result, err := value.GetElementPtr(indices)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fr.errorAt(inst, err.Error())
|
||||||
|
}
|
||||||
if result.Type() != inst.Type() {
|
if result.Type() != inst.Type() {
|
||||||
return nil, nil, fr.errorAt(inst, "interp: gep: type does not match")
|
return nil, nil, fr.errorAt(inst, "interp: gep: type does not match")
|
||||||
}
|
}
|
||||||
|
@ -264,7 +267,11 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||||
if elementCount == 1 {
|
if elementCount == 1 {
|
||||||
fr.locals[resultInst] = result
|
fr.locals[resultInst] = result
|
||||||
} else {
|
} else {
|
||||||
fr.locals[resultInst] = result.GetElementPtr([]uint32{0, 0})
|
result, err := result.GetElementPtr([]uint32{0, 0})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errorAt(inst, err.Error())
|
||||||
|
}
|
||||||
|
fr.locals[resultInst] = result
|
||||||
}
|
}
|
||||||
case callee.Name() == "runtime.hashmapMake":
|
case callee.Name() == "runtime.hashmapMake":
|
||||||
// create a map
|
// create a map
|
||||||
|
@ -365,8 +372,16 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||||
// a bitcast of the original array instead of the GEP,
|
// a bitcast of the original array instead of the GEP,
|
||||||
// which breaks our assumptions.
|
// which breaks our assumptions.
|
||||||
// Re-add this GEP, in the hope that it it is then of the correct type...
|
// Re-add this GEP, in the hope that it it is then of the correct type...
|
||||||
dstArray = dstArray.GetElementPtr([]uint32{0, 0}).(*LocalValue)
|
dstArrayValue, err := dstArray.GetElementPtr([]uint32{0, 0})
|
||||||
srcArray = srcArray.GetElementPtr([]uint32{0, 0}).(*LocalValue)
|
if err != nil {
|
||||||
|
return nil, nil, errorAt(inst, err.Error())
|
||||||
|
}
|
||||||
|
dstArray = dstArrayValue.(*LocalValue)
|
||||||
|
srcArrayValue, err := srcArray.GetElementPtr([]uint32{0, 0})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errorAt(inst, err.Error())
|
||||||
|
}
|
||||||
|
srcArray = srcArrayValue.(*LocalValue)
|
||||||
}
|
}
|
||||||
if fr.Eval.TargetData.TypeAllocSize(dstArray.Type().ElementType()) != elementSize {
|
if fr.Eval.TargetData.TypeAllocSize(dstArray.Type().ElementType()) != elementSize {
|
||||||
return nil, nil, fr.errorAt(inst, "interp: slice dst element size does not match pointer type")
|
return nil, nil, fr.errorAt(inst, "interp: slice dst element size does not match pointer type")
|
||||||
|
@ -385,12 +400,21 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||||
return nil, nil, fr.errorAt(inst, "interp: trying to copy a slice with negative length?")
|
return nil, nil, fr.errorAt(inst, "interp: trying to copy a slice with negative length?")
|
||||||
}
|
}
|
||||||
for i := int64(0); i < length; i++ {
|
for i := int64(0); i < length; i++ {
|
||||||
|
var err error
|
||||||
// *dst = *src
|
// *dst = *src
|
||||||
dstArray.Store(srcArray.Load())
|
dstArray.Store(srcArray.Load())
|
||||||
// dst++
|
// dst++
|
||||||
dstArray = dstArray.GetElementPtr([]uint32{1}).(*LocalValue)
|
dstArrayValue, err := dstArray.GetElementPtr([]uint32{1})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errorAt(inst, err.Error())
|
||||||
|
}
|
||||||
|
dstArray = dstArrayValue.(*LocalValue)
|
||||||
// src++
|
// src++
|
||||||
srcArray = srcArray.GetElementPtr([]uint32{1}).(*LocalValue)
|
srcArrayValue, err := srcArray.GetElementPtr([]uint32{1})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errorAt(inst, err.Error())
|
||||||
|
}
|
||||||
|
srcArray = srcArrayValue.(*LocalValue)
|
||||||
}
|
}
|
||||||
case callee.Name() == "runtime.stringToBytes":
|
case callee.Name() == "runtime.stringToBytes":
|
||||||
// convert a string to a []byte
|
// convert a string to a []byte
|
||||||
|
|
|
@ -24,7 +24,11 @@ func getStringBytes(strPtr Value, strLen llvm.Value) []byte {
|
||||||
}
|
}
|
||||||
buf := make([]byte, strLen.ZExtValue())
|
buf := make([]byte, strLen.ZExtValue())
|
||||||
for i := range buf {
|
for i := range buf {
|
||||||
c := strPtr.GetElementPtr([]uint32{uint32(i)}).Load()
|
gep, err := strPtr.GetElementPtr([]uint32{uint32(i)})
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // TODO
|
||||||
|
}
|
||||||
|
c := gep.Load()
|
||||||
buf[i] = byte(c.ZExtValue())
|
buf[i] = byte(c.ZExtValue())
|
||||||
}
|
}
|
||||||
return buf
|
return buf
|
||||||
|
|
|
@ -3,6 +3,7 @@ package interp
|
||||||
// This file provides a litte bit of abstraction around LLVM values.
|
// This file provides a litte bit of abstraction around LLVM values.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
|
@ -16,7 +17,7 @@ type Value interface {
|
||||||
IsConstant() bool // returns true if this value is a constant value
|
IsConstant() bool // returns true if this value is a constant value
|
||||||
Load() llvm.Value // dereference a pointer
|
Load() llvm.Value // dereference a pointer
|
||||||
Store(llvm.Value) // store to a pointer
|
Store(llvm.Value) // store to a pointer
|
||||||
GetElementPtr([]uint32) Value // returns an interior pointer
|
GetElementPtr([]uint32) (Value, error) // returns an interior pointer
|
||||||
String() string // string representation, for debugging
|
String() string // string representation, for debugging
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,21 +98,21 @@ func (v *LocalValue) Store(value llvm.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetElementPtr returns a GEP when the underlying value is of pointer type.
|
// GetElementPtr returns a GEP when the underlying value is of pointer type.
|
||||||
func (v *LocalValue) GetElementPtr(indices []uint32) Value {
|
func (v *LocalValue) GetElementPtr(indices []uint32) (Value, error) {
|
||||||
if !v.Underlying.IsAGlobalVariable().IsNil() {
|
if !v.Underlying.IsAGlobalVariable().IsNil() {
|
||||||
int32Type := v.Underlying.Type().Context().Int32Type()
|
int32Type := v.Underlying.Type().Context().Int32Type()
|
||||||
gep := llvm.ConstGEP(v.Underlying, getLLVMIndices(int32Type, indices))
|
gep := llvm.ConstGEP(v.Underlying, getLLVMIndices(int32Type, indices))
|
||||||
return &LocalValue{v.Eval, gep}
|
return &LocalValue{v.Eval, gep}, nil
|
||||||
}
|
}
|
||||||
if !v.Underlying.IsAConstantExpr().IsNil() {
|
if !v.Underlying.IsAConstantExpr().IsNil() {
|
||||||
switch v.Underlying.Opcode() {
|
switch v.Underlying.Opcode() {
|
||||||
case llvm.GetElementPtr, llvm.IntToPtr, llvm.BitCast:
|
case llvm.GetElementPtr, llvm.IntToPtr, llvm.BitCast:
|
||||||
int32Type := v.Underlying.Type().Context().Int32Type()
|
int32Type := v.Underlying.Type().Context().Int32Type()
|
||||||
llvmIndices := getLLVMIndices(int32Type, indices)
|
llvmIndices := getLLVMIndices(int32Type, indices)
|
||||||
return &LocalValue{v.Eval, llvm.ConstGEP(v.Underlying, llvmIndices)}
|
return &LocalValue{v.Eval, llvm.ConstGEP(v.Underlying, llvmIndices)}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("interp: unknown GEP")
|
return nil, errors.New("interp: unknown GEP")
|
||||||
}
|
}
|
||||||
|
|
||||||
// stripPointerCasts removes all const bitcasts from pointer values, if there
|
// stripPointerCasts removes all const bitcasts from pointer values, if there
|
||||||
|
@ -309,8 +310,8 @@ func (v *MapValue) Store(value llvm.Value) {
|
||||||
|
|
||||||
// GetElementPtr panics: maps are of reference type so their (interior)
|
// GetElementPtr panics: maps are of reference type so their (interior)
|
||||||
// addresses cannot be calculated.
|
// addresses cannot be calculated.
|
||||||
func (v *MapValue) GetElementPtr(indices []uint32) Value {
|
func (v *MapValue) GetElementPtr(indices []uint32) (Value, error) {
|
||||||
panic("interp: GEP on a map")
|
return nil, errors.New("interp: GEP on a map")
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutString does a map assign operation, assuming that the map is of type
|
// PutString does a map assign operation, assuming that the map is of type
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче