Fixed: Optionally inline objj_msgSend function. Generate faster code for Array and Dictionary Literals.

This commit is contained in:
Martin Carlberg
2015-10-06 13:30:09 +02:00
parent 4ba9a19b5c
commit 101261ca63
+217 -50
View File
@@ -365,7 +365,8 @@ var MethodDef = function(name, types)
this.types = types;
}
var currentCompilerFlags = "";
var currentCompilerFlags = 0;
var currentGccCompilerFlags = "";
var reservedIdentifiers = exports.acorn.makePredicate("self _cmd undefined localStorage arguments");
@@ -414,14 +415,12 @@ var ObjJAcornCompiler = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*
}
this.dependencies = [];
this.flags = flags | ObjJAcornCompiler.Flags.IncludeDebugSymbols;
this.flags = flags & (ObjJAcornCompiler.Flags.IncludeDebugSymbols | ObjJAcornCompiler.Flags.InlineMsgSend | ObjJAcornCompiler.Flags.IncludeTypeSignatures);
this.classDefs = classDefs ? classDefs : Object.create(null);
this.protocolDefs = protocolDefs ? protocolDefs : Object.create(null);
this.typeDefs = typeDefs ? typeDefs : Object.create(null);
this.lastPos = 0;
if (currentCompilerFlags & ObjJAcornCompiler.Flags.Generate)
this.generate = true;
this.generate = true;
this.generate = true; // Before there was an option to generate the code or copy & paste it from the source. Today we always generate the code.
compile(this.tokens, new Scope(null ,{ compiler: this }), pass === 2 ? pass2 : pass1);
}
@@ -487,7 +486,42 @@ ObjJAcornCompiler.prototype.compilePass2 = function()
return this.jsBuffer.toString();
}
var currentCompilerFlags = "";
exports.setCurrentGccCompilerFlags = function(/*String*/ compilerFlags)
{
if (currentGccCompilerFlags === compilerFlags) return;
currentGccCompilerFlags = compilerFlags;
var args = compilerFlags.split(" "),
count = args.length,
objjcFlags = 0;
for (var index = 0; index < count; ++index)
{
var argument = args[index];
if (argument.indexOf("-g") === 0)
objjcFlags |= ObjectiveJ.ObjJAcornCompiler.Flags.IncludeDebugSymbols;
else if (argument.indexOf("-O") === 0) {
objjcFlags |= ObjectiveJ.ObjJAcornCompiler.Flags.Compress;
// FIXME: currently we are sending in '-O2' when we want InlineMsgSend. Here we only check if we it is '-O...'.
// Maybe we should have some other option for this
if (argument.length > 2)
objjcFlags |= ObjectiveJ.ObjJAcornCompiler.Flags.InlineMsgSend;
}
else if (argument.indexOf("-G") === 0)
objjcFlags |= ObjectiveJ.ObjJAcornCompiler.Flags.Generate;
}
currentCompilerFlags = objjcFlags;
}
exports.currentGccCompilerFlags = function(/*String*/ compilerFlags)
{
return currentGccCompilerFlags;
}
exports.setCurrentCompilerFlags = function(/*String*/ compilerFlags)
{
@@ -504,6 +538,7 @@ ObjJAcornCompiler.Flags = { };
ObjJAcornCompiler.Flags.IncludeDebugSymbols = 1 << 0;
ObjJAcornCompiler.Flags.IncludeTypeSignatures = 1 << 1;
ObjJAcornCompiler.Flags.Generate = 1 << 2;
ObjJAcornCompiler.Flags.InlineMsgSend = 1 << 3;
ObjJAcornCompiler.prototype.addWarning = function(/* Warning */ aWarning)
{
@@ -1626,64 +1661,170 @@ Literal: function(node, st, c) {
},
ArrayLiteral: function(node, st, c) {
var compiler = st.compiler,
generate = compiler.generate;
generate = compiler.generate,
buffer = compiler.jsBuffer;
if (!generate) {
compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, node.start));
buffer.concat(compiler.source.substring(compiler.lastPos, node.start));
compiler.lastPos = node.start;
}
if (!generate) buffer.concat(" "); // Add an extra space if it looks something like this: "return(<expression>)". No space between return and expression.
if (!st.receiverLevel) st.receiverLevel = 0;
if (!node.elements.length) {
compiler.jsBuffer.concat("objj_msgSend(objj_msgSend(CPArray, \"alloc\"), \"init\")");
if (compiler.flags & ObjJAcornCompiler.Flags.InlineMsgSend) {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = (CPArray.isa.method_msgSend[\"alloc\"] || _objj_forward)(CPArray, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : (___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.method_msgSend[\"init\"] || _objj_forward)(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"init\"))");
} else {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = CPArray.isa.objj_msgSend0(CPArray, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.objj_msgSend0(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"init\"))");
}
if (!(st.maxReceiverLevel >= st.receiverLevel))
st.maxReceiverLevel = st.receiverLevel;
} else {
compiler.jsBuffer.concat("objj_msgSend(objj_msgSend(CPArray, \"alloc\"), \"initWithObjects:count:\", [");
if (compiler.flags & ObjJAcornCompiler.Flags.InlineMsgSend) {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = (CPArray.isa.method_msgSend[\"alloc\"] || _objj_forward)(CPArray, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : (___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.method_msgSend[\"initWithObjects:count:\"] || _objj_forward)(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"initWithObjects:count:\", [");
} else {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = CPArray.isa.objj_msgSend0(CPArray, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.objj_msgSend2(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"initWithObjects:count:\", [");
}
if (!(st.maxReceiverLevel >= st.receiverLevel))
st.maxReceiverLevel = st.receiverLevel;
for (var i = 0; i < node.elements.length; i++) {
var elt = node.elements[i];
if (i)
compiler.jsBuffer.concat(", ");
buffer.concat(", ");
if (!generate) compiler.lastPos = elt.start;
c(elt, st, "Expression");
if (!generate) compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, elt.end));
if (!generate) buffer.concat(compiler.source.substring(compiler.lastPos, elt.end));
}
compiler.jsBuffer.concat("], " + node.elements.length + ")");
buffer.concat("], " + node.elements.length + "))");
}
st.receiverLevel--;
if (!generate) compiler.lastPos = node.end;
},
DictionaryLiteral: function(node, st, c) {
var compiler = st.compiler,
generate = compiler.generate;
generate = compiler.generate,
buffer = compiler.jsBuffer,
noOfKeys = node.keys.length;
if (!generate) {
compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, node.start));
buffer.concat(compiler.source.substring(compiler.lastPos, node.start));
compiler.lastPos = node.start;
}
if (!generate) buffer.concat(" "); // Add an extra space if it looks something like this: "return(<expression>)". No space between return and expression.
if (!node.keys.length) {
compiler.jsBuffer.concat("objj_msgSend(objj_msgSend(CPDictionary, \"alloc\"), \"init\")");
if (!st.receiverLevel) st.receiverLevel = 0;
if (!noOfKeys) {
if (compiler.flags & ObjJAcornCompiler.Flags.InlineMsgSend) {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = (CPDictionary.isa.method_msgSend[\"alloc\"] || _objj_forward)(CPDictionary, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : (___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.method_msgSend[\"init\"] || _objj_forward)(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"init\"))");
} else {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = CPDictionary.isa.objj_msgSend0(CPDictionary, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.objj_msgSend0(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"init\"))");
}
if (!(st.maxReceiverLevel >= st.receiverLevel))
st.maxReceiverLevel = st.receiverLevel;
} else {
compiler.jsBuffer.concat("objj_msgSend(objj_msgSend(CPDictionary, \"alloc\"), \"initWithObjectsAndKeys:\"");
for (var i = 0; i < node.keys.length; i++) {
var key = node.keys[i],
value = node.values[i];
if (compiler.flags & ObjJAcornCompiler.Flags.InlineMsgSend) {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = (CPDictionary.isa.method_msgSend[\"alloc\"] || _objj_forward)(CPDictionary, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : (___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.method_msgSend[\"initWithObjects:forKeys:\"] || _objj_forward)(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"initWithObjects:forKeys:\", [");
} else {
buffer.concat("(___r");
buffer.concat(++st.receiverLevel + "");
buffer.concat(" = CPDictionary.isa.objj_msgSend0(CPDictionary, \"alloc\"), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(".isa.objj_msgSend2(___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(", \"initWithObjects:forKeys:\", [");
}
compiler.jsBuffer.concat(", ");
if (!(st.maxReceiverLevel >= st.receiverLevel))
st.maxReceiverLevel = st.receiverLevel;
for (var i = 0; i < noOfKeys; i++) {
var value = node.values[i];
if (i) buffer.concat(", ");
if (!generate) compiler.lastPos = value.start;
c(value, st, "Expression");
if (!generate) compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, value.end));
if (!generate) buffer.concat(compiler.source.substring(compiler.lastPos, value.end));
}
compiler.jsBuffer.concat(", ");
buffer.concat("], [");
for (var i = 0; i < noOfKeys; i++) {
var key = node.keys[i];
if (i) buffer.concat(", ");
if (!generate) compiler.lastPos = key.start;
c(key, st, "Expression");
if (!generate) compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, key.end));
if (!generate) buffer.concat(compiler.source.substring(compiler.lastPos, key.end));
}
compiler.jsBuffer.concat(")");
buffer.concat("]))");
}
st.receiverLevel--;
if (!generate) compiler.lastPos = node.end;
},
ImportStatement: function(node, st, c) {
@@ -2257,17 +2398,48 @@ MethodDeclarationStatement: function(node, st, c) {
MessageSendExpression: function(node, st, c) {
var compiler = st.compiler,
generate = compiler.generate,
inlineMsgSend = compiler.flags & ObjJAcornCompiler.Flags.InlineMsgSend,
buffer = compiler.jsBuffer,
nodeObject = node.object;
nodeObject = node.object,
selectors = node.selectors,
arguments = node.arguments,
argumentsLength = arguments.length,
firstSelector = selectors[0],
selector = firstSelector ? firstSelector.name : ""; // There is always at least one selector
// Put together the selector. Maybe this should be done in the parser...
for (var i = 0; i < argumentsLength; i++)
if (i === 0)
selector += ":";
else
selector += (selectors[i] ? selectors[i].name : "") + ":";
if (!generate) {
buffer.concat(compiler.source.substring(compiler.lastPos, node.start));
compiler.lastPos = nodeObject ? nodeObject.start : node.arguments.length ? node.arguments[0].start : node.end;
} else if (!inlineMsgSend) {
// Find out the total number of arguments so we can choose appropriate msgSend function. Only needed if call the function and not inline it
var totalNoOfParameters = argumentsLength;
if (node.parameters)
totalNoOfParameters += node.parameters.length;
}
if (node.superObject)
{
if (!generate) buffer.concat(" "); // Add an extra space if it looks something like this: "return(<expression>)". No space between return and expression.
buffer.concat("objj_msgSendSuper(");
buffer.concat("{ receiver:self, super_class:" + (st.currentMethodType() === "+" ? compiler.currentSuperMetaClass : compiler.currentSuperClass ) + " }");
if (inlineMsgSend) {
buffer.concat("(");
buffer.concat(st.currentMethodType() === "+" ? compiler.currentSuperMetaClass : compiler.currentSuperClass);
buffer.concat(".method_dtable[\"");
buffer.concat(selector);
buffer.concat("\"] || _objj_forward)(self");
} else {
buffer.concat("objj_msgSendSuper");
if (totalNoOfParameters < 4) {
buffer.concat("" + totalNoOfParameters);
}
buffer.concat("({ receiver:self, super_class:" + (st.currentMethodType() === "+" ? compiler.currentSuperMetaClass : compiler.currentSuperClass ) + " }");
}
}
else
{
@@ -2293,6 +2465,8 @@ MessageSendExpression: function(node, st, c) {
c(nodeObject, st, "Expression");
buffer.concat(" == null ? null : ");
}
if (inlineMsgSend)
buffer.concat("(");
c(nodeObject, st, "Expression");
} else {
receiverIsNotSelf = true;
@@ -2303,12 +2477,20 @@ MessageSendExpression: function(node, st, c) {
c(nodeObject, st, "Expression");
buffer.concat("), ___r");
buffer.concat(st.receiverLevel + "");
buffer.concat(" == null ? null : ___r");
buffer.concat(" == null ? null : ");
if (inlineMsgSend)
buffer.concat("(");
buffer.concat("___r");
buffer.concat(st.receiverLevel + "");
if (!(st.maxReceiverLevel >= st.receiverLevel))
st.maxReceiverLevel = st.receiverLevel;
}
buffer.concat(".isa.objj_msgSend");
if (inlineMsgSend) {
buffer.concat(".isa.method_msgSend[\"");
buffer.concat(selector);
buffer.concat("\"] || _objj_forward)");
} else
buffer.concat(".isa.objj_msgSend");
} else {
buffer.concat(" "); // Add an extra space if it looks something like this: "return(<expression>)". No space between return and expression.
buffer.concat("objj_msgSend(");
@@ -2316,19 +2498,11 @@ MessageSendExpression: function(node, st, c) {
}
}
var selectors = node.selectors,
arguments = node.arguments,
argumentsLength = arguments.length,
firstSelector = selectors[0],
selector = firstSelector ? firstSelector.name : ""; // There is always at least one selector
if (generate && !node.superObject) {
var totalNoOfParameters = argumentsLength;
if (node.parameters)
totalNoOfParameters += node.parameters.length;
if (totalNoOfParameters < 4) {
buffer.concat("" + totalNoOfParameters);
if (!inlineMsgSend) {
if (totalNoOfParameters < 4) {
buffer.concat("" + totalNoOfParameters);
}
}
if (receiverIsIdentifier) {
@@ -2340,13 +2514,6 @@ MessageSendExpression: function(node, st, c) {
}
}
// Put together the selector. Maybe this should be done in the parser...
for (var i = 0; i < argumentsLength; i++)
if (i === 0)
selector += ":";
else
selector += (selectors[i] ? selectors[i].name : "") + ":";
buffer.concat(", \"");
buffer.concat(selector); // FIXME: sel_getUid(selector + "") ? This FIXME is from the old preprocessor compiler
buffer.concat("\"");