Generate proper C++ for capture by-reference.

This commit is contained in:
Jonathan Protzenko 2015-11-02 13:43:15 -08:00
Родитель 2a575e029c
Коммит 75c3f42594
5 изменённых файлов: 46 добавлений и 9 удалений

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

@ -250,6 +250,8 @@ module TDev.AST.Json
locals?:JLocalDef[]; // this contains the reference in short mode; it never contains anything else locals?:JLocalDef[]; // this contains the reference in short mode; it never contains anything else
isImplicit:boolean; isImplicit:boolean;
isOptional:boolean; isOptional:boolean;
allLocals: JLocalDef[];
capturedLocals: JLocalDef[];
} }
export interface JOptionalParameter extends JNode export interface JOptionalParameter extends JNode
@ -377,6 +379,7 @@ module TDev.AST.Json
{ {
name:string; name:string;
type:JTypeRef; type:JTypeRef;
isByRef: boolean;
} }
// Response to: // Response to:

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

@ -88,8 +88,11 @@ module TDev {
public visitExprHolder(env: H.Env, locals: J.JLocalDef[], expr: J.JExprHolder) { public visitExprHolder(env: H.Env, locals: J.JLocalDef[], expr: J.JExprHolder) {
var decls = locals.map(d => { var decls = locals.map(d => {
var x = H.defaultValueForType(this.libraryMap, d.type); // Side-effect: marks [d] as promoted, if needed.
return this.visit(env, d) + (x ? " = " + x : "") + ";"; var decl = this.visit(env, d);
var defaultValue = H.defaultValueForType(this.libraryMap, d.type);
var initialValue = !H.isPromoted(env, d.id) && defaultValue ? " = " + defaultValue : "";
return decl + initialValue + ";";
}); });
return decls.join("\n"+env.indent) + return decls.join("\n"+env.indent) +
(decls.length ? "\n" + env.indent : "") + (decls.length ? "\n" + env.indent : "") +
@ -104,11 +107,23 @@ module TDev {
// which C and C++ accept both "f" and "&f" (we hence use the former) // which C and C++ accept both "f" and "&f" (we hence use the former)
// - arrays, strings, user-defined objects, which are in fact of type // - arrays, strings, user-defined objects, which are in fact of type
// "ManagedType<T>", no "&" operator here. // "ManagedType<T>", no "&" operator here.
return H.resolveLocal(env, name, id); // However, we now support capture-by-reference. This means that the
// data is ref-counted (so as to be shared), but assignment and
// reference operate on the ref-counted data (not on the pointer), so we
// must add a dereference there.
var prefix = H.isPromoted(env, id) ? "*" : "";
return prefix+H.resolveLocal(env, name, id);
} }
public visitLocalDef(env: H.Env, name: string, id: string, type: J.JTypeRef) { public visitLocalDef(env: H.Env, name: string, id: string, type: J.JTypeRef, isByRef: boolean) {
return H.mkType(env, this.libraryMap, type)+" "+H.resolveLocal(env, name, id); var t = H.mkType(env, this.libraryMap, type);
var l = H.resolveLocal(env, name, id);
if (H.shouldPromoteToRef(env, type, isByRef)) {
H.markPromoted(env, id);
return "ManagedType<"+ t + "> " + l + "(new "+t+")";
} else {
return t + " " + l;
}
} }
// Allows the target to redefine their own string type. // Allows the target to redefine their own string type.

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

@ -140,6 +140,10 @@ module TDev {
libName: string; libName: string;
indent: string; indent: string;
// A table of id's that have been promoted to ref-counted types (because
// they were captured by a closure). Modified in an imperative manner.
promotedIds: StringMap<boolean>;
} }
export function indent(e: Env): Env { export function indent(e: Env): Env {
@ -149,9 +153,18 @@ module TDev {
globalNameMap: e.globalNameMap, globalNameMap: e.globalNameMap,
libName: e.libName, libName: e.libName,
indent: e.indent + " ", indent: e.indent + " ",
promotedIds: e.promotedIds,
}; };
} }
export function markPromoted(e: Env, id: string) {
e.promotedIds[id] = true;
}
export function isPromoted(e: Env, id: string) {
return e.promotedIds[id];
}
export function emptyEnv(g: GlobalNameMap, libName: string): Env { export function emptyEnv(g: GlobalNameMap, libName: string): Env {
var usedNames: StringMap<boolean> = {}; var usedNames: StringMap<boolean> = {};
var m = libName ? g.libraries[libName] : g.program; var m = libName ? g.libraries[libName] : g.program;
@ -165,6 +178,7 @@ module TDev {
globalNameMap: g, globalNameMap: g,
libName: libName, libName: libName,
indent: "", indent: "",
promotedIds: {},
}; };
} }
@ -240,6 +254,10 @@ module TDev {
return n; return n;
} }
export function shouldPromoteToRef(e: Env, t: J.JTypeRef, isByRef: boolean) {
return typeof t == "string" && isByRef;
}
// --- Helper functions. // --- Helper functions.
// For constructing / modifying AST nodes. // For constructing / modifying AST nodes.
@ -325,7 +343,7 @@ module TDev {
var retType = outParams.length ? mkType(env, libMap, outParams[0].type) : "void"; var retType = outParams.length ? mkType(env, libMap, outParams[0].type) : "void";
var args = "(" + inParams.map(p => mkParam(env, libMap, p)).join(", ") + ")"; var args = "(" + inParams.map(p => mkParam(env, libMap, p)).join(", ") + ")";
if (isLambda) if (isLambda)
return "[=] "+args+" -> "+retType; return "[=] "+args+" mutable -> "+retType;
else else
return retType + " " + name + args; return retType + " " + name + args;
} }

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

@ -30,7 +30,7 @@ module TDev {
return this.visitGlobalDef(env, n13.name, n13.type, n13.comment); return this.visitGlobalDef(env, n13.name, n13.type, n13.comment);
case "localDef": case "localDef":
var n1 = <J.JLocalDef> n; var n1 = <J.JLocalDef> n;
return this.visitLocalDef(env, n1.name, n1.id, n1.type); return this.visitLocalDef(env, n1.name, n1.id, n1.type, n1.isByRef);
case "localRef": case "localRef":
var n11 = <J.JLocalRef> n; var n11 = <J.JLocalRef> n;
return this.visitLocalRef(env, n11.name, <any> n11.localId); return this.visitLocalRef(env, n11.name, <any> n11.localId);
@ -115,7 +115,8 @@ module TDev {
env: T, env: T,
name: string, name: string,
id: string, id: string,
type: J.JTypeRef): U { throw new Error("Not implemented"); } type: J.JTypeRef,
isByRef: boolean): U { throw new Error("Not implemented"); }
public visitLocalRef(env: T, name: string, id: string): U { throw new Error("Not implemented"); } public visitLocalRef(env: T, name: string, id: string): U { throw new Error("Not implemented"); }
public visitExprHolder( public visitExprHolder(
env: T, env: T,

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

@ -4,7 +4,7 @@ module TDev.Cloud {
export var lite = false; export var lite = false;
export var fullTD = true; export var fullTD = true;
export var litePermissions:StringMap<boolean> = {}; export var litePermissions:StringMap<boolean> = {};
var microbitGitTag = "v12"; var microbitGitTag = "v13";
export var useEmbeddedGcc = true; export var useEmbeddedGcc = true;
export var useNativeCompilation = false; export var useNativeCompilation = false;