interp: don't panic in the Store method

Instead return an error, which indicates where it goes wrong. That's
less user unfriendly than panicking.
Этот коммит содержится в:
Ayke van Laethem 2020-07-26 21:28:48 +02:00 коммит произвёл Ron Evans
родитель ccb803e35d
коммит 4fa1fc6e72
2 изменённых файлов: 22 добавлений и 15 удалений

Просмотреть файл

@ -111,7 +111,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
if inst.IsVolatile() { if inst.IsVolatile() {
fr.builder.CreateStore(value.Value(), ptr.Value()) fr.builder.CreateStore(value.Value(), ptr.Value())
} else { } else {
ptr.Store(value.Value()) err := ptr.Store(value.Value())
if err != nil {
return nil, nil, fr.errorAt(inst, err)
}
} }
case !inst.IsAGetElementPtrInst().IsNil(): case !inst.IsAGetElementPtrInst().IsNil():
value := fr.getLocal(inst.Operand(0)) value := fr.getLocal(inst.Operand(0))
@ -422,7 +425,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
if err != nil { if err != nil {
return nil, nil, fr.errorAt(inst, err) return nil, nil, fr.errorAt(inst, err)
} }
dstArray.Store(val) err = dstArray.Store(val)
if err != nil {
return nil, nil, fr.errorAt(inst, err)
}
// dst++ // dst++
dstArrayValue, err := dstArray.GetElementPtr([]uint32{1}) dstArrayValue, err := dstArray.GetElementPtr([]uint32{1})
if err != nil { if err != nil {

Просмотреть файл

@ -16,7 +16,7 @@ type Value interface {
Type() llvm.Type // equal to Value().Type() Type() llvm.Type // equal to Value().Type()
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, error) // dereference a pointer Load() (llvm.Value, error) // dereference a pointer
Store(llvm.Value) // store to a pointer Store(llvm.Value) error // store to a pointer
GetElementPtr([]uint32) (Value, error) // returns an interior pointer GetElementPtr([]uint32) (Value, error) // returns an interior pointer
String() string // string representation, for debugging String() string // string representation, for debugging
} }
@ -68,8 +68,8 @@ func (v *LocalValue) Load() (llvm.Value, error) {
} }
// Store stores to the underlying value if the value type is a pointer type, // Store stores to the underlying value if the value type is a pointer type,
// otherwise it panics. // otherwise it returns an error.
func (v *LocalValue) Store(value llvm.Value) { func (v *LocalValue) Store(value llvm.Value) error {
if !v.Underlying.IsAGlobalVariable().IsNil() { if !v.Underlying.IsAGlobalVariable().IsNil() {
if !value.IsConstant() { if !value.IsConstant() {
v.MarkDirty() v.MarkDirty()
@ -77,29 +77,28 @@ func (v *LocalValue) Store(value llvm.Value) {
} else { } else {
v.Underlying.SetInitializer(value) v.Underlying.SetInitializer(value)
} }
return return nil
} }
if !value.IsConstant() { if !value.IsConstant() {
v.MarkDirty() v.MarkDirty()
v.Eval.builder.CreateStore(value, v.Underlying) v.Eval.builder.CreateStore(value, v.Underlying)
return return nil
} }
switch v.Underlying.Opcode() { switch v.Underlying.Opcode() {
case llvm.GetElementPtr: case llvm.GetElementPtr:
indices := v.getConstGEPIndices() indices := v.getConstGEPIndices()
if indices[0] != 0 { if indices[0] != 0 {
panic("invalid GEP") return errors.New("invalid GEP")
} }
global := &LocalValue{v.Eval, v.Underlying.Operand(0)} global := &LocalValue{v.Eval, v.Underlying.Operand(0)}
agg, err := global.Load() agg, err := global.Load()
if err != nil { if err != nil {
panic(err) // TODO return err
} }
agg = llvm.ConstInsertValue(agg, value, indices[1:]) agg = llvm.ConstInsertValue(agg, value, indices[1:])
global.Store(agg) return global.Store(agg)
return
default: default:
panic("interp: store on a constant") return errors.New("interp: store on a constant")
} }
} }
@ -313,9 +312,11 @@ func (v *MapValue) Load() (llvm.Value, error) {
panic("interp: load from a map") panic("interp: load from a map")
} }
// Store panics: maps are of reference type so cannot be stored to. // Store returns an error: maps are of reference type so cannot be stored to.
func (v *MapValue) Store(value llvm.Value) { func (v *MapValue) Store(value llvm.Value) error {
panic("interp: store on a map") // This must be a bug, but it might be helpful to indicate the location
// anyway.
return errors.New("interp: store on a map")
} }
// GetElementPtr panics: maps are of reference type so their (interior) // GetElementPtr panics: maps are of reference type so their (interior)