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.
Этот коммит содержится в:
родитель
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)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче