Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

unsafe: Removes most of the unsafe casts. #58

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion runtime/baseexception.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type BaseException struct {
}

func toBaseExceptionUnsafe(o *Object) *BaseException {
return (*BaseException)(o.toPointer())
return o.self.(*BaseException)
}

// ToObject upcasts e to an Object.
Expand Down
5 changes: 5 additions & 0 deletions runtime/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,8 @@ var (
trueStr = NewStr("True").ToObject()
falseStr = NewStr("False").ToObject()
)

func init() {
False.self = False
True.self = True
}
3 changes: 2 additions & 1 deletion runtime/builtin_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package grumpy
import (
"fmt"
"math/big"
"reflect"
"unicode"
)

Expand Down Expand Up @@ -325,7 +326,7 @@ func builtinID(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
if raised := checkFunctionArgs(f, "id", args, ObjectType); raised != nil {
return nil, raised
}
return NewInt(int(uintptr(args[0].toPointer()))).ToObject(), nil
return NewInt(int(reflect.ValueOf(args[0]).Pointer())).ToObject(), nil
}

func builtinIsInstance(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
Expand Down
3 changes: 2 additions & 1 deletion runtime/builtin_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package grumpy
import (
"fmt"
"math/big"
"reflect"
"testing"
)

Expand Down Expand Up @@ -102,7 +103,7 @@ func TestBuiltinFuncs(t *testing.T) {
{f: "hex", args: wrapArgs(0.1), wantExc: mustCreateException(TypeErrorType, "hex() argument can't be converted to hex")},
{f: "hex", args: wrapArgs(1, 2, 3), wantExc: mustCreateException(TypeErrorType, "'hex' requires 1 arguments")},
{f: "hex", args: wrapArgs(newObject(hexOctType)), want: NewStr("0xhexadecimal").ToObject()},
{f: "id", args: wrapArgs(foo), want: NewInt(int(uintptr(foo.toPointer()))).ToObject()},
{f: "id", args: wrapArgs(foo), want: NewInt(int(reflect.ValueOf(foo).Pointer())).ToObject()},
{f: "id", args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, "'id' requires 1 arguments")},
{f: "isinstance", args: wrapArgs(NewInt(42).ToObject(), IntType.ToObject()), want: True.ToObject()},
{f: "isinstance", args: wrapArgs(NewStr("foo").ToObject(), TupleType.ToObject()), want: False.ToObject()},
Expand Down
8 changes: 6 additions & 2 deletions runtime/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type Code struct {
fn func(*Frame, []*Object) (*Object, *BaseException)
}

func (c *Code) ToObject() *Object { return &c.Object }

// NewCode creates a new Code object that executes the given fn.
func NewCode(name, filename string, args []FunctionArg, flags CodeFlag, fn func(*Frame, []*Object) (*Object, *BaseException)) *Code {
argc := len(args)
Expand All @@ -62,11 +64,13 @@ func NewCode(name, filename string, args []FunctionArg, flags CodeFlag, fn func(
logFatal(fmt.Sprintf(format, name, arg.Name))
}
}
return &Code{Object{typ: CodeType}, name, filename, argc, minArgc, flags, args, fn}
c := &Code{Object{typ: CodeType}, name, filename, argc, minArgc, flags, args, fn}
c.self = c
return c
}

func toCodeUnsafe(o *Object) *Code {
return (*Code)(o.toPointer())
return o.self.(*Code)
}

// Eval runs the code object c in the context of the given globals.
Expand Down
4 changes: 2 additions & 2 deletions runtime/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ func compareRich(f *Frame, op compareOp, v, w *Object) (*Object, *BaseException)
// closely resembles the behavior of CPython's default_3way_compare in object.c.
func compareDefault(f *Frame, v, w *Object) int {
if v.typ == w.typ {
pv, pw := uintptr(v.toPointer()), uintptr(w.toPointer())
pv, pw := reflect.ValueOf(v).Pointer(), reflect.ValueOf(w).Pointer()
if pv < pw {
return -1
}
Expand All @@ -938,7 +938,7 @@ func compareDefault(f *Frame, v, w *Object) int {
if v.typ.Name() != w.typ.Name() {
return 1
}
if uintptr(v.typ.toPointer()) < uintptr(w.typ.toPointer()) {
if reflect.ValueOf(v.typ).Pointer() < reflect.ValueOf(w.typ).Pointer() {
return -1
}
return 1
Expand Down
6 changes: 3 additions & 3 deletions runtime/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,14 @@ func TestBinaryOps(t *testing.T) {
func TestCompareDefault(t *testing.T) {
o1, o2 := newObject(ObjectType), newObject(ObjectType)
// Make sure uintptr(o1) < uintptr(o2).
if uintptr(o1.toPointer()) > uintptr(o2.toPointer()) {
if reflect.ValueOf(o1).Pointer() > reflect.ValueOf(o2).Pointer() {
o1, o2 = o2, o1
}
// When type names are equal, comparison should fall back to comparing
// the pointer values of the types of the objects.
fakeObjectType := newTestClass("object", []*Type{ObjectType}, NewDict())
o3, o4 := newObject(fakeObjectType), newObject(ObjectType)
if uintptr(o3.typ.toPointer()) > uintptr(o4.typ.toPointer()) {
if reflect.ValueOf(o3.typ).Pointer() > reflect.ValueOf(o4.typ).Pointer() {
o3, o4 = o4, o3
}
// An int subtype that equals anything, but doesn't override other
Expand Down Expand Up @@ -331,7 +331,7 @@ func TestHash(t *testing.T) {
cases := []invokeTestCase{
{args: wrapArgs("foo"), want: hashFoo},
{args: wrapArgs(123), want: NewInt(123).ToObject()},
{args: wrapArgs(o), want: NewInt(int(uintptr(o.toPointer()))).ToObject()},
{args: wrapArgs(o), want: NewInt(int(reflect.ValueOf(o).Pointer())).ToObject()},
{args: wrapArgs(NewList()), wantExc: mustCreateException(TypeErrorType, "unhashable type: 'list'")},
{args: wrapArgs(NewDict()), wantExc: mustCreateException(TypeErrorType, "unhashable type: 'dict'")},
{args: wrapArgs(newObject(badHash)), wantExc: mustCreateException(TypeErrorType, "an integer is required")},
Expand Down
6 changes: 4 additions & 2 deletions runtime/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ type Property struct {
}

func newProperty(get, set, del *Object) *Property {
return &Property{Object{typ: PropertyType}, get, set, del}
p := &Property{Object{typ: PropertyType}, get, set, del}
p.self = p
return p
}

func toPropertyUnsafe(o *Object) *Property {
return (*Property)(o.toPointer())
return o.self.(*Property)
}

// ToObject upcasts p to an Object.
Expand Down
22 changes: 15 additions & 7 deletions runtime/dict.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ type Dict struct {

// NewDict returns an empty Dict.
func NewDict() *Dict {
return &Dict{Object: Object{typ: DictType}, table: newDictTable(0)}
d := &Dict{Object: Object{typ: DictType}, table: newDictTable(0)}
d.self = d
return d
}

func newStringDict(items map[string]*Object) *Dict {
Expand All @@ -278,11 +280,13 @@ func newStringDict(items map[string]*Object) *Dict {
for key, value := range items {
table.insertAbsentEntry(&dictEntry{hashString(key), NewStr(key).ToObject(), value})
}
return &Dict{Object: Object{typ: DictType}, table: table}
d := &Dict{Object: Object{typ: DictType}, table: table}
d.self = d
return d
}

func toDictUnsafe(o *Object) *Dict {
return (*Dict)(o.toPointer())
return o.self.(*Dict)
}

// loadTable atomically loads and returns d's underlying dictTable.
Expand Down Expand Up @@ -741,15 +745,17 @@ type dictItemIterator struct {
// newDictItemIterator creates a dictItemIterator object for d. It assumes that
// d.mutex is held by the caller.
func newDictItemIterator(d *Dict) *dictItemIterator {
return &dictItemIterator{
i := &dictItemIterator{
Object: Object{typ: dictItemIteratorType},
iter: newDictEntryIterator(d),
guard: newDictVersionGuard(d),
}
i.self = i
return i
}

func toDictItemIteratorUnsafe(o *Object) *dictItemIterator {
return (*dictItemIterator)(o.toPointer())
return o.self.(*dictItemIterator)
}

func (iter *dictItemIterator) ToObject() *Object {
Expand Down Expand Up @@ -784,15 +790,17 @@ type dictKeyIterator struct {
// newDictKeyIterator creates a dictKeyIterator object for d. It assumes that
// d.mutex is held by the caller.
func newDictKeyIterator(d *Dict) *dictKeyIterator {
return &dictKeyIterator{
i := &dictKeyIterator{
Object: Object{typ: dictKeyIteratorType},
iter: newDictEntryIterator(d),
guard: newDictVersionGuard(d),
}
i.self = i
return i
}

func toDictKeyIteratorUnsafe(o *Object) *dictKeyIterator {
return (*dictKeyIterator)(o.toPointer())
return o.self.(*dictKeyIterator)
}

func (iter *dictKeyIterator) ToObject() *Object {
Expand Down
3 changes: 2 additions & 1 deletion runtime/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ type File struct {
func NewFileFromFD(fd uintptr) *File {
// TODO: Use fcntl or something to get the mode of the descriptor.
file := &File{Object: Object{typ: FileType}, mode: "?", open: true, file: os.NewFile(fd, "<fdopen>")}
file.self = file
file.reader = bufio.NewReader(file.file)
return file
}

func toFileUnsafe(o *Object) *File {
return (*File)(o.toPointer())
return o.self.(*File)
}

// ToObject upcasts f to an Object.
Expand Down
6 changes: 4 additions & 2 deletions runtime/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ type Float struct {

// NewFloat returns a new Float holding the given floating point value.
func NewFloat(value float64) *Float {
return &Float{Object{typ: FloatType}, value}
f := &Float{Object{typ: FloatType}, value}
f.self = f
return f
}

func toFloatUnsafe(o *Object) *Float {
return (*Float)(o.toPointer())
return o.self.(*Float)
}

// ToObject upcasts f to an Object.
Expand Down
10 changes: 7 additions & 3 deletions runtime/float_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,14 @@ func TestFloatIsTrue(t *testing.T) {
}

func TestFloatNew(t *testing.T) {
setFloatSelf := func(f *Float) *Float {
f.self = f
return f
}
floatNew := mustNotRaise(GetAttr(NewRootFrame(), FloatType.ToObject(), NewStr("__new__"), nil))
strictEqType := newTestClassStrictEq("StrictEq", FloatType)
subType := newTestClass("SubType", []*Type{FloatType}, newStringDict(map[string]*Object{}))
subTypeObject := (&Float{Object: Object{typ: subType}, value: 3.14}).ToObject()
subTypeObject := setFloatSelf(&Float{Object: Object{typ: subType}, value: 3.14}).ToObject()
goodSlotType := newTestClass("GoodSlot", []*Type{ObjectType}, newStringDict(map[string]*Object{
"__float__": newBuiltinFunction("__float__", func(_ *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
return NewFloat(3.14).ToObject(), nil
Expand Down Expand Up @@ -199,8 +203,8 @@ func TestFloatNew(t *testing.T) {
{args: wrapArgs(FloatType, newObject(goodSlotType)), want: NewFloat(3.14).ToObject()},
{args: wrapArgs(FloatType, newObject(badSlotType)), wantExc: mustCreateException(TypeErrorType, "__float__ returned non-float (type object)")},
{args: wrapArgs(FloatType, newObject(slotSubTypeType)), want: subTypeObject},
{args: wrapArgs(strictEqType, 3.14), want: (&Float{Object{typ: strictEqType}, 3.14}).ToObject()},
{args: wrapArgs(strictEqType, newObject(goodSlotType)), want: (&Float{Object{typ: strictEqType}, 3.14}).ToObject()},
{args: wrapArgs(strictEqType, 3.14), want: setFloatSelf(&Float{Object{typ: strictEqType}, 3.14}).ToObject()},
{args: wrapArgs(strictEqType, newObject(goodSlotType)), want: setFloatSelf(&Float{Object{typ: strictEqType}, 3.14}).ToObject()},
{args: wrapArgs(strictEqType, newObject(badSlotType)), wantExc: mustCreateException(TypeErrorType, "__float__ returned non-float (type object)")},
{args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, "'__new__' requires 1 arguments")},
{args: wrapArgs(IntType), wantExc: mustCreateException(TypeErrorType, "float.__new__(int): int is not a subtype of float")},
Expand Down
3 changes: 2 additions & 1 deletion runtime/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func NewRootFrame() *Frame {
// newFrame creates a new Frame whose parent frame is back.
func newFrame(back *Frame) *Frame {
f := &Frame{Object: Object{typ: FrameType}}
f.self = f
f.pushFrame(back)
return f
}
Expand All @@ -64,7 +65,7 @@ func (f *Frame) pushFrame(back *Frame) {
}

func toFrameUnsafe(o *Object) *Frame {
return (*Frame)(o.toPointer())
return o.self.(*Frame)
}

// Globals returns the globals dict for this frame.
Expand Down
16 changes: 11 additions & 5 deletions runtime/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,21 @@ type FunctionArg struct {
// number of arguments are provided, populating *args and **kwargs if
// necessary, etc.
func NewFunction(c *Code, globals *Dict) *Function {
return &Function{Object{typ: FunctionType, dict: NewDict()}, nil, c.name, c, globals}
f := &Function{Object{typ: FunctionType, dict: NewDict()}, nil, c.name, c, globals}
f.self = f
return f
}

// newBuiltinFunction returns a function object with the given name that
// invokes fn when called.
func newBuiltinFunction(name string, fn Func) *Function {
return &Function{Object: Object{typ: FunctionType, dict: NewDict()}, fn: fn, name: name}
f := &Function{Object: Object{typ: FunctionType, dict: NewDict()}, fn: fn, name: name}
f.self = f
return f
}

func toFunctionUnsafe(o *Object) *Function {
return (*Function)(o.toPointer())
return o.self.(*Function)
}

// ToObject upcasts f to an Object.
Expand Down Expand Up @@ -150,11 +154,13 @@ type staticMethod struct {
}

func newStaticMethod(callable *Object) *staticMethod {
return &staticMethod{Object{typ: StaticMethodType}, callable}
s := &staticMethod{Object{typ: StaticMethodType}, callable}
s.self = s
return s
}

func toStaticMethodUnsafe(o *Object) *staticMethod {
return (*staticMethod)(o.toPointer())
return o.self.(*staticMethod)
}

// ToObject upcasts f to an Object.
Expand Down
6 changes: 4 additions & 2 deletions runtime/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ type Generator struct {

// NewGenerator returns a new Generator object that runs the given Block b.
func NewGenerator(f *Frame, fn func(*Object) (*Object, *BaseException)) *Generator {
return &Generator{Object: Object{typ: GeneratorType}, frame: f, fn: fn}
g := &Generator{Object: Object{typ: GeneratorType}, frame: f, fn: fn}
g.self = g
return g
}

func toGeneratorUnsafe(o *Object) *Generator {
return (*Generator)(o.toPointer())
return o.self.(*Generator)
}

func (g *Generator) resume(f *Frame, sendValue *Object) (*Object, *BaseException) {
Expand Down
24 changes: 11 additions & 13 deletions runtime/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ const (
internedIntMax = 300
)

var (
internedInts = makeInternedInts()
)
var internedInts [internedIntMax - internedIntMin + 1]Int

func init() {
for i := internedIntMin; i <= internedIntMax; i++ {
internedInts[i-internedIntMin] = Int{Object{typ: IntType, self: &internedInts[i-internedIntMin]}, i}
}
}

// Int represents Python 'int' objects.
type Int struct {
Expand All @@ -41,11 +45,13 @@ func NewInt(value int) *Int {
if value >= internedIntMin && value <= internedIntMax {
return &internedInts[value-internedIntMin]
}
return &Int{Object{typ: IntType}, value}
i := &Int{Object{typ: IntType}, value}
i.self = i
return i
}

func toIntUnsafe(o *Object) *Int {
return (*Int)(o.toPointer())
return o.self.(*Int)
}

// ToObject upcasts i to an Object.
Expand Down Expand Up @@ -504,11 +510,3 @@ func intFromObject(f *Frame, o *Object) (*Object, *BaseException) {
func intToLong(o *Int) *Long {
return NewLong(big.NewInt(int64(o.Value())))
}

func makeInternedInts() [internedIntMax - internedIntMin + 1]Int {
var ints [internedIntMax - internedIntMin + 1]Int
for i := internedIntMin; i <= internedIntMax; i++ {
ints[i-internedIntMin] = Int{Object{typ: IntType}, i}
}
return ints
}
Loading