Skip to content

Commit

Permalink
Partially implement multiple inheritance on Emscripten target.
Browse files Browse the repository at this point in the history
  • Loading branch information
jjrv committed Oct 25, 2016
1 parent 40b9977 commit 3b1fdb4
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 269 deletions.
150 changes: 140 additions & 10 deletions src/em/BindClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {
import {_nbind as _globals} from './Globals';
import {_nbind as _type} from './BindingType';
import {_nbind as _value} from './ValueObj';
import {_nbind as _caller} from './Caller';
import {_nbind as _resource} from './Resource';
import {_nbind as _gc} from './GC';
import {SignatureType} from '../common';
import {StateFlags, TypeFlags, TypeSpecWithName, TypeSpecWithParam, PolicyTbl} from '../Type';

// Let decorators run eval in current scope to read function source code.
Expand All @@ -25,11 +27,17 @@ export namespace _nbind {

export namespace _nbind {

export var addMethod: typeof _globals.addMethod;
export var getType: typeof _globals.getType;

export var pushValue: typeof _value.pushValue;
export var popValue: typeof _value.popValue;

export var resources: typeof _resource.resources;

export var makeCaller: typeof _caller.makeCaller;
export var makeMethodCaller: typeof _caller.makeMethodCaller;

export var mark: typeof _gc.mark;

/** Base class for wrapped instances of bound C++ classes.
Expand Down Expand Up @@ -62,21 +70,17 @@ export namespace _nbind {

interface WrapperClass {
new(marker: {}, flags: number, ptr: number, shared?: number): Wrapper;

[key: string]: any;
}

const ptrMarker = {};

interface SuperClassType extends Wrapper {}

export function makeBound(
policyTbl: PolicyTbl,
bindClass: BindClass
) {
const SuperClass = bindClass.superList[0] ?
bindClass.superList[0].proto as { new(): Wrapper } :
Wrapper;

class Bound extends SuperClass {
class Bound extends Wrapper {
constructor(marker: {}, flags: number, ptr: number, shared?: number) {
// super() never gets called here but TypeScript 1.8 requires it.
if((false && super()) || !(this instanceof Bound)) {
Expand Down Expand Up @@ -155,6 +159,19 @@ export namespace _nbind {
return(Bound);
}

export interface MethodSpec {
name: string;
title: string;
signatureType?: SignatureType;
boundID?: number;
policyTbl?: PolicyTbl;
typeList?: (number | string)[];
ptr: number;
direct?: number;
num?: number;
flags?: TypeFlags;
}

// Base class for all bound C++ classes (not their instances),
// also inheriting from a generic type definition.

Expand All @@ -174,6 +191,116 @@ export namespace _nbind {
return(Bound);
}

addMethod(spec: MethodSpec) {
const overloadList = this.methodTbl[spec.name] || [];

overloadList.push(spec);

this.methodTbl[spec.name] = overloadList;
}

registerMethods(src: BindClass, staticOnly: boolean) {
let setter: ((arg: any) => void) | undefined;

for(let name of Object.keys(src.methodTbl)) {
const overloadList = src.methodTbl[name];

for(let spec of overloadList) {
let target: any;
let caller: any;

target = this.proto.prototype;

if(staticOnly && spec.signatureType != SignatureType.func) continue;

switch(spec.signatureType) {
case SignatureType.func:
target = this.proto;

// tslint:disable-next-line:no-switch-case-fall-through
case SignatureType.construct:
caller = makeCaller(spec);
addMethod(target, spec.name, caller, spec.typeList!.length - 1);
break;

case SignatureType.setter:
setter = makeMethodCaller(spec) as (arg: any) => void;
break;

case SignatureType.getter:
Object.defineProperty(target, spec.name, {
configurable: true,
enumerable: false,
get: makeMethodCaller(spec) as () => any,
set: setter
});
break;

case SignatureType.method:
caller = makeMethodCaller(spec);
addMethod(target, spec.name, caller, spec.typeList!.length - 1);
break;

default:
break;
}
}
}
}

registerSuperMethods(
src: BindClass,
firstSuper: number,
visitTbl: { [name: string]: boolean }
) {
if(visitTbl[src.name]) return;
visitTbl[src.name] = true;

this.registerMethods(src, firstSuper < 0);

let superNum = 0;
let nextFirst: number;

for(let superId of src.superIdList || []) {
const superClass = getType(superId) as BindClass;

if(superNum++ < firstSuper || firstSuper < 0) {
nextFirst = -1;
} else {
nextFirst = 0;
}

this.registerSuperMethods(superClass, nextFirst, visitTbl);
}
}

finish() {
if(this.ready) return;
this.ready = true;

let superClass: BindClass | undefined;
let firstSuper: BindClass | undefined;

for(let superId of this.superIdList || []) {
superClass = getType(superId) as BindClass;
superClass.finish();

firstSuper = firstSuper || superClass;
}

if(firstSuper) {
const Bound = this.proto;
const Proto = function(this: Wrapper) {
this.constructor = Bound;
} as any as { new(): Wrapper };

Proto.prototype = firstSuper.proto.prototype;
Bound.prototype = new Proto();
}

this.registerSuperMethods(this, 1, {});
}

wireRead = (arg: number) => popValue(arg, this.ptrType);
wireWrite = pushValue;

Expand All @@ -191,10 +318,13 @@ export namespace _nbind {
/** Number of super classes left to initialize. */
pendingSuperCount = 0;

superList: BindClass[] = [];
}
ready = false;

export const pendingChildTbl: { [id: number]: number[] } = {};
superIdList: number[];
methodTbl: { [name: string]: MethodSpec[] } = {};

static list: BindClass[] = [];
}

export function popPointer(ptr: number, type: BindClassPtr) {
return(ptr ? new type.proto(ptrMarker, type.flags, ptr) : null);
Expand Down
51 changes: 32 additions & 19 deletions src/em/Binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ using namespace nbind;

extern "C" {
extern void _nbind_register_pool(unsigned int pageSize, unsigned int *usedPtr, unsigned char *rootPtr, unsigned char **pagePtr);
extern void _nbind_register_primitive( TYPEID typeID, unsigned int size, unsigned char flag);
extern void _nbind_register_type( TYPEID typeID, const char *name);
extern void _nbind_register_class(const TYPEID *typeList, const char **policies, const TYPEID *superList, unsigned int superCount, const char *name, funcPtr destructor);
extern void _nbind_register_constructor(TYPEID classType, const char **policies, const TYPEID *types, unsigned int typeCount, funcPtr func, funcPtr ptrValue);
extern void _nbind_register_function( TYPEID classType, const char **policies, const TYPEID *types, unsigned int typeCount, funcPtr func, const char *name,
unsigned int num, unsigned int flags, funcPtr direct);
extern void _nbind_register_method( TYPEID classType, const char **policies, const TYPEID *types, unsigned int typeCount, funcPtr func, const char *name,
unsigned int num, unsigned int flags, unsigned int methodType
extern void _nbind_register_primitive(TYPEID typeID, unsigned int size, unsigned char flag);
extern void _nbind_register_type(TYPEID typeID, const char *name);
extern void _nbind_register_class(const TYPEID *typeList,
const char **policies, const TYPEID *superList, unsigned int superCount,
funcPtr destructor,
const char *name
);
extern void _nbind_register_function(TYPEID boundID,
const char **policies, const TYPEID *types, unsigned int typeCount,
funcPtr func, funcPtr direct, unsigned int signatureType,
const char *name, unsigned int num, unsigned int flags
);
extern void _nbind_finish();
}

unsigned int Pool::used = 0;
Expand Down Expand Up @@ -173,8 +177,8 @@ static void initModule() {
bindClass->getPolicies(),
superIdList,
bindClass->getSuperClassCount(),
bindClass->getName(),
bindClass->getDeleter()
bindClass->getDeleter(),
bindClass->getName()
);
}

Expand All @@ -189,10 +193,11 @@ static void initModule() {
signature->getTypeList(),
signature->getArity() + 1,
signature->getCaller(),
func.getPtr(),
static_cast<unsigned int>(signature->getType()),
func.getName(),
func.getNum(),
static_cast<unsigned int>(func.getFlags()),
func.getPtr()
static_cast<unsigned int>(func.getFlags())
);
}

Expand All @@ -216,16 +221,17 @@ static void initModule() {
case SignatureType :: getter:
case SignatureType :: setter:

_nbind_register_method(
_nbind_register_function(
id,
signature->getPolicies(),
signature->getTypeList(),
signature->getArity() + 1,
signature->getCaller(),
nullptr,
static_cast<unsigned int>(signature->getType()),
func.getName(),
func.getNum(),
static_cast<unsigned int>(func.getFlags()),
static_cast<unsigned int>(signature->getType())
static_cast<unsigned int>(func.getFlags())
);

break;
Expand All @@ -238,29 +244,36 @@ static void initModule() {
signature->getTypeList(),
signature->getArity() + 1,
signature->getCaller(),
func.getPtr(),
static_cast<unsigned int>(signature->getType()),
func.getName(),
func.getNum(),
static_cast<unsigned int>(func.getFlags()),
func.getPtr()
static_cast<unsigned int>(func.getFlags())
);

break;

case SignatureType :: construct:

_nbind_register_constructor(
_nbind_register_function(
id,
signature->getPolicies(),
signature->getTypeList(),
signature->getArity() + 1,
signature->getCaller(),
signature->getValueConstructor()
signature->getValueConstructor(),
static_cast<unsigned int>(signature->getType()),
nullptr, 0, 0
);

break;
}
}
}

// Set up inheritance.

_nbind_finish();
}

extern "C" {
Expand Down
Loading

0 comments on commit 3b1fdb4

Please sign in to comment.