Skip to content

Commit

Permalink
Porting go-qml to Go 1.6
Browse files Browse the repository at this point in the history
Go 1.6 cannot have Go pointer stored into the cgo space. So instead we
need to store all Go values in a map and pass a key to the cgo
space. When needed the key can be used to retrieve the go value from the
map.
  • Loading branch information
SjB committed Apr 5, 2016
1 parent 2ee7e5f commit 826359a
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 75 deletions.
65 changes: 41 additions & 24 deletions bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func init() {
guiMainRef = cdata.Ref()
}

// foldRefs holds all fold values that are created. Since Go Pointer
// are not allowed to be held by cgo. We need a lookup table to
// interface the two space.
var foldRefs = make(map[uintptr]*valueFold)

// Run runs the main QML event loop, runs f, and then terminates the
// event loop once f returns.
//
Expand Down Expand Up @@ -210,6 +215,16 @@ const (
jsOwner
)

func storeFold(fold *valueFold) C.GoRef {
foldRef := uintptr(unsafe.Pointer(fold))
foldRefs[foldRef] = fold
return C.GoRef(foldRef)
}

func restoreFold(ref uintptr) *valueFold {
return foldRefs[ref]
}

// wrapGoValue creates a new GoValue object in C++ land wrapping
// the Go value contained in the given interface.
//
Expand Down Expand Up @@ -251,7 +266,7 @@ func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue u
gvalue: gvalue,
owner: owner,
}
fold.cvalue = C.newGoValue(unsafe.Pointer(fold), typeInfo(gvalue), parent)
fold.cvalue = C.newGoValue(storeFold(fold), typeInfo(gvalue), parent)
if prev != nil {
// Put new fold first so the single cppOwner, if any, is always the first entry.
fold.next = prev
Expand Down Expand Up @@ -289,7 +304,7 @@ func addrOf(gvalue interface{}) uintptr {
var typeNew = make(map[*valueFold]bool)

//export hookGoValueTypeNew
func hookGoValueTypeNew(cvalue unsafe.Pointer, specp unsafe.Pointer) (foldp unsafe.Pointer) {
func hookGoValueTypeNew(cvalue unsafe.Pointer, specp unsafe.Pointer) (foldr C.GoRef) {
// Initialization is postponed until the engine is available, so that
// we can hand Init the qml.Object that represents the object.
init := reflect.ValueOf((*TypeSpec)(specp).Init)
Expand All @@ -299,15 +314,17 @@ func hookGoValueTypeNew(cvalue unsafe.Pointer, specp unsafe.Pointer) (foldp unsa
cvalue: cvalue,
owner: jsOwner,
}

typeNew[fold] = true
//fmt.Printf("[DEBUG] value alive (type-created): cvalue=%x gvalue=%x/%#v\n", fold.cvalue, addrOf(fold.gvalue), fold.gvalue)
stats.valuesAlive(+1)
return unsafe.Pointer(fold)
return storeFold(fold)
}

//export hookGoValueDestroyed
func hookGoValueDestroyed(enginep unsafe.Pointer, foldp unsafe.Pointer) {
fold := (*valueFold)(foldp)
func hookGoValueDestroyed(enginep unsafe.Pointer, foldr uintptr) {
fold := restoreFold(foldr)

engine := fold.engine
if engine == nil {
before := len(typeNew)
Expand Down Expand Up @@ -360,8 +377,8 @@ func deref(value reflect.Value) reflect.Value {
}

//export hookGoValueReadField
func hookGoValueReadField(enginep, foldp unsafe.Pointer, reflectIndex, getIndex, setIndex C.int, resultdv *C.DataValue) {
fold := ensureEngine(enginep, foldp)
func hookGoValueReadField(enginep unsafe.Pointer, foldr uintptr, reflectIndex, getIndex, setIndex C.int, resultdv *C.DataValue) {
fold := ensureEngine(enginep, foldr)

var field reflect.Value
if getIndex >= 0 {
Expand All @@ -376,7 +393,7 @@ func hookGoValueReadField(enginep, foldp unsafe.Pointer, reflectIndex, getIndex,
// TODO Handle getters that return []qml.Object.
// TODO Handle other GoValue slices (!= []qml.Object).
resultdv.dataType = C.DTListProperty
*(*unsafe.Pointer)(unsafe.Pointer(&resultdv.data)) = C.newListProperty(foldp, C.intptr_t(reflectIndex), C.intptr_t(setIndex))
*(*unsafe.Pointer)(unsafe.Pointer(&resultdv.data)) = C.newListProperty(C.GoRef(foldr), C.intptr_t(reflectIndex), C.intptr_t(setIndex))
return
}

Expand Down Expand Up @@ -406,8 +423,8 @@ func hookGoValueReadField(enginep, foldp unsafe.Pointer, reflectIndex, getIndex,
}

//export hookGoValueWriteField
func hookGoValueWriteField(enginep, foldp unsafe.Pointer, reflectIndex, setIndex C.int, assigndv *C.DataValue) {
fold := ensureEngine(enginep, foldp)
func hookGoValueWriteField(enginep unsafe.Pointer, foldr uintptr, reflectIndex, setIndex C.int, assigndv *C.DataValue) {
fold := ensureEngine(enginep, foldr)
v := reflect.ValueOf(fold.gvalue)
ve := v
for ve.Type().Kind() == reflect.Ptr {
Expand Down Expand Up @@ -483,8 +500,8 @@ var (
)

//export hookGoValueCallMethod
func hookGoValueCallMethod(enginep, foldp unsafe.Pointer, reflectIndex C.int, args *C.DataValue) {
fold := ensureEngine(enginep, foldp)
func hookGoValueCallMethod(enginep unsafe.Pointer, foldr uintptr, reflectIndex C.int, args *C.DataValue) {
fold := ensureEngine(enginep, foldr)
v := reflect.ValueOf(fold.gvalue)

// TODO Must assert that v is necessarily a pointer here, but we shouldn't have to manipulate
Expand Down Expand Up @@ -548,7 +565,7 @@ func printPaintPanic() {
}

//export hookGoValuePaint
func hookGoValuePaint(enginep, foldp unsafe.Pointer, reflectIndex C.intptr_t) {
func hookGoValuePaint(enginep unsafe.Pointer, foldr uintptr, reflectIndex C.intptr_t) {
// Besides a convenience this is a workaround for http://golang.org/issue/8588
defer printPaintPanic()
defer atomic.StoreUintptr(&guiPaintRef, 0)
Expand All @@ -557,7 +574,7 @@ func hookGoValuePaint(enginep, foldp unsafe.Pointer, reflectIndex C.intptr_t) {
// so no two paintings should be happening at the same time.
atomic.StoreUintptr(&guiPaintRef, cdata.Ref())

fold := ensureEngine(enginep, foldp)
fold := ensureEngine(enginep, foldr)
if fold.init.IsValid() {
return
}
Expand All @@ -568,8 +585,8 @@ func hookGoValuePaint(enginep, foldp unsafe.Pointer, reflectIndex C.intptr_t) {
method.Call([]reflect.Value{reflect.ValueOf(painter)})
}

func ensureEngine(enginep, foldp unsafe.Pointer) *valueFold {
fold := (*valueFold)(foldp)
func ensureEngine(enginep unsafe.Pointer, foldr uintptr) *valueFold {
fold := restoreFold(foldr)
if fold.engine != nil {
if fold.init.IsValid() {
initGoType(fold)
Expand Down Expand Up @@ -637,22 +654,22 @@ func listSlice(fold *valueFold, reflectIndex C.intptr_t) *[]Object {
}

//export hookListPropertyAt
func hookListPropertyAt(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t, index C.int) (objp unsafe.Pointer) {
fold := (*valueFold)(foldp)
func hookListPropertyAt(foldr uintptr, reflectIndex, setIndex C.intptr_t, index C.int) (objp unsafe.Pointer) {
fold := restoreFold(foldr)
slice := listSlice(fold, reflectIndex)
return (*slice)[int(index)].Common().addr
}

//export hookListPropertyCount
func hookListPropertyCount(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t) C.int {
fold := (*valueFold)(foldp)
func hookListPropertyCount(foldr uintptr, reflectIndex, setIndex C.intptr_t) C.int {
fold := restoreFold(foldr)
slice := listSlice(fold, reflectIndex)
return C.int(len(*slice))
}

//export hookListPropertyAppend
func hookListPropertyAppend(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t, objp unsafe.Pointer) {
fold := (*valueFold)(foldp)
func hookListPropertyAppend(foldr uintptr, reflectIndex, setIndex C.intptr_t, objp unsafe.Pointer) {
fold := restoreFold(foldr)
slice := listSlice(fold, reflectIndex)
var objdv C.DataValue
objdv.dataType = C.DTObject
Expand All @@ -666,8 +683,8 @@ func hookListPropertyAppend(foldp unsafe.Pointer, reflectIndex, setIndex C.intpt
}

//export hookListPropertyClear
func hookListPropertyClear(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t) {
fold := (*valueFold)(foldp)
func hookListPropertyClear(foldr uintptr, reflectIndex, setIndex C.intptr_t) {
fold := restoreFold(foldr)
slice := listSlice(fold, reflectIndex)
newslice := (*slice)[0:0]
if setIndex >= 0 {
Expand Down
28 changes: 14 additions & 14 deletions cpp/capi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,17 +543,17 @@ int objectIsView(QObject_ *object)
return dynamic_cast<QQuickView *>(qobject) ? 1 : 0;
}

error *objectGoAddr(QObject_ *object, GoAddr **addr)
error *objectGoRef(QObject_ *object, GoRef *ref)
{
QObject *qobject = static_cast<QObject *>(object);
GoValue *goValue = dynamic_cast<GoValue *>(qobject);
if (goValue) {
*addr = goValue->addr;
*ref = goValue->ref;
return 0;
}
GoPaintedValue *goPaintedValue = dynamic_cast<GoPaintedValue *>(qobject);
if (goPaintedValue) {
*addr = goPaintedValue->addr;
*ref= goPaintedValue->ref;
return 0;
}
return errorf("QML object is not backed by a Go value");
Expand All @@ -571,13 +571,13 @@ void delString(QString_ *s)
delete reinterpret_cast<QString *>(s);
}

GoValue_ *newGoValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject_ *parent)
GoValue_ *newGoValue(GoRef ref, GoTypeInfo *typeInfo, QObject_ *parent)
{
QObject *qparent = reinterpret_cast<QObject *>(parent);
if (typeInfo->paint) {
return new GoPaintedValue(addr, typeInfo, qparent);
return new GoPaintedValue(ref, typeInfo, qparent);
}
return new GoValue(addr, typeInfo, qparent);
return new GoValue(ref, typeInfo, qparent);
}

void goValueActivate(GoValue_ *value, GoTypeInfo *typeInfo, int addrOffset)
Expand Down Expand Up @@ -749,13 +749,13 @@ void packDataValue(QVariant_ *var, DataValue *value)
GoValue *goValue = dynamic_cast<GoValue *>(qobject);
if (goValue) {
value->dataType = DTGoAddr;
*(void **)(value->data) = goValue->addr;
*(uintptr_t*)(value->data) = goValue->ref;
break;
}
GoPaintedValue *goPaintedValue = dynamic_cast<GoPaintedValue *>(qobject);
if (goPaintedValue) {
value->dataType = DTGoAddr;
*(void **)(value->data) = goPaintedValue->addr;
*(uintptr_t*)(value->data) = goPaintedValue->ref;
break;
}
value->dataType = DTObject;
Expand Down Expand Up @@ -813,28 +813,28 @@ QVariantList_ *newVariantList(DataValue *list, int len)

QObject *listPropertyAt(QQmlListProperty<QObject> *list, int i)
{
return reinterpret_cast<QObject *>(hookListPropertyAt(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, i));
return reinterpret_cast<QObject *>(hookListPropertyAt((uintptr_t)list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, i));
}

int listPropertyCount(QQmlListProperty<QObject> *list)
{
return hookListPropertyCount(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2);
return hookListPropertyCount((uintptr_t)list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2);
}

void listPropertyAppend(QQmlListProperty<QObject> *list, QObject *obj)
{
hookListPropertyAppend(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, obj);
hookListPropertyAppend((uintptr_t)list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, obj);
}

void listPropertyClear(QQmlListProperty<QObject> *list)
{
hookListPropertyClear(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2);
hookListPropertyClear((uintptr_t)list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2);
}

QQmlListProperty_ *newListProperty(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex)
QQmlListProperty_ *newListProperty(GoRef ref, intptr_t reflectIndex, intptr_t setIndex)
{
QQmlListProperty<QObject> *list = new QQmlListProperty<QObject>();
list->data = addr;
list->data = (void*)ref;
list->dummy1 = (void*)reflectIndex;
list->dummy2 = (void*)setIndex;
list->at = listPropertyAt;
Expand Down
27 changes: 14 additions & 13 deletions cpp/capi.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ typedef void QMessageLogContext_;
typedef void QImage_;
typedef void GoValue_;
typedef void GoAddr;
typedef uintptr_t GoRef;
typedef void GoTypeSpec_;

typedef char error;
Expand Down Expand Up @@ -141,7 +142,7 @@ int objectIsComponent(QObject_ *object);
int objectIsWindow(QObject_ *object);
int objectIsView(QObject_ *object);
error *objectConnect(QObject_ *object, const char *signal, int signalLen, QQmlEngine_ *engine, void *func, int argsLen);
error *objectGoAddr(QObject_ *object, GoAddr **addr);
error *objectGoRef(QObject_ *object, GoRef *ref);

QQmlComponent_ *newComponent(QQmlEngine_ *engine, QObject_ *parent);
void componentLoadURL(QQmlComponent_ *component, const char *url, int urlLen);
Expand All @@ -166,15 +167,15 @@ const unsigned char *imageConstBits(QImage_ *image);
QString_ *newString(const char *data, int len);
void delString(QString_ *s);

GoValue_ *newGoValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject_ *parent);
GoValue_ *newGoValue(GoRef ref, GoTypeInfo *typeInfo, QObject_ *parent);
void goValueActivate(GoValue_ *value, GoTypeInfo *typeInfo, int addrOffset);

void packDataValue(QVariant_ *var, DataValue *result);
void unpackDataValue(DataValue *value, QVariant_ *result);

QVariantList_ *newVariantList(DataValue *list, int len);

QQmlListProperty_ *newListProperty(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex);
QQmlListProperty_ *newListProperty(GoRef ref, intptr_t reflectIndex, intptr_t setIndex);

int registerType(char *location, int major, int minor, char *name, GoTypeInfo *typeInfo, GoTypeSpec_ *spec);
int registerSingleton(char *location, int major, int minor, char *name, GoTypeInfo *typeInfo, GoTypeSpec_ *spec);
Expand All @@ -183,21 +184,21 @@ void installLogHandler();

void hookIdleTimer();
void hookLogHandler(LogMessage *message);
void hookGoValueReadField(QQmlEngine_ *engine, GoAddr *addr, int memberIndex, int getIndex, int setIndex, DataValue *result);
void hookGoValueWriteField(QQmlEngine_ *engine, GoAddr *addr, int memberIndex, int setIndex, DataValue *assign);
void hookGoValueCallMethod(QQmlEngine_ *engine, GoAddr *addr, int memberIndex, DataValue *result);
void hookGoValueDestroyed(QQmlEngine_ *engine, GoAddr *addr);
void hookGoValuePaint(QQmlEngine_ *engine, GoAddr *addr, intptr_t reflextIndex);
void hookGoValueReadField(QQmlEngine_ *engine, GoRef ref, int memberIndex, int getIndex, int setIndex, DataValue *result);
void hookGoValueWriteField(QQmlEngine_ *engine, GoRef ref, int memberIndex, int setIndex, DataValue *assign);
void hookGoValueCallMethod(QQmlEngine_ *engine, GoRef ref, int memberIndex, DataValue *result);
void hookGoValueDestroyed(QQmlEngine_ *engine, GoRef ref);
void hookGoValuePaint(QQmlEngine_ *engine, GoRef ref, intptr_t reflextIndex);
QImage_ *hookRequestImage(void *imageFunc, char *id, int idLen, int width, int height);
GoAddr *hookGoValueTypeNew(GoValue_ *value, GoTypeSpec_ *spec);
uintptr_t hookGoValueTypeNew(GoValue_ *value, GoTypeSpec_ *spec);
void hookWindowHidden(QObject_ *addr);
void hookSignalCall(QQmlEngine_ *engine, void *func, DataValue *params);
void hookSignalDisconnect(void *func);
void hookPanic(char *message);
int hookListPropertyCount(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex);
QObject_ *hookListPropertyAt(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex, int i);
void hookListPropertyAppend(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex, QObject_ *obj);
void hookListPropertyClear(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex);
int hookListPropertyCount(GoRef ref, intptr_t reflectIndex, intptr_t setIndex);
QObject_ *hookListPropertyAt(GoRef ref, intptr_t reflectIndex, intptr_t setIndex, int i);
void hookListPropertyAppend(GoRef ref, intptr_t reflectIndex, intptr_t setIndex, QObject_ *obj);
void hookListPropertyClear(GoRef ref, intptr_t reflectIndex, intptr_t setIndex);

void registerResourceData(int version, char *tree, char *name, char *data);
void unregisterResourceData(int version, char *tree, char *name, char *data);
Expand Down
Loading

0 comments on commit 826359a

Please sign in to comment.