Merge pull request #2384 from mrcarlberg/even_faster_objj_msg_send

Speedup of the Cappuccino framework by more efficient objj_msgSend
This commit is contained in:
Martin Carlberg committed 2015-11-01 20:39:18 +01:00
commit 8c2f0bacf1
27 files changed
+380 -106

No files matched your search

+3 -2
View File
@@ -33,8 +33,9 @@ appKitTask = framework ("AppKit", function(appKitTask)
return "--include \"" + aFilename + "\"";
}).join(" ");
if ($CONFIGURATION === "Release")
appKitTask.setCompilerFlags("-O " + INCLUDES);
if ($CONFIGURATION === "Release") {
appKitTask.setCompilerFlags("-O2 " + INCLUDES);
}
else
appKitTask.setCompilerFlags("-DDEBUG -g " + INCLUDES);
});
+1 -1
View File
@@ -20,7 +20,7 @@ blendKitTask = framework ("BlendKit", function(blendKitTask)
blendKitTask.setFlattensSources(true); // FIXME: how do we non flatten?
if ($CONFIGURATION === "Release")
blendKitTask.setCompilerFlags("-O");
blendKitTask.setCompilerFlags("-O2");
else
blendKitTask.setCompilerFlags("-DDEBUG -g");
});
+1 -1
View File
@@ -51,7 +51,7 @@ foundationTask = framework ("Foundation", function(foundationTask)
INCLUDES = "--include \"../AppKit/Platform/Platform.h\" " + INCLUDES;
if ($CONFIGURATION === "Release")
foundationTask.setCompilerFlags("-O " + INCLUDES);
foundationTask.setCompilerFlags("-O2 " + INCLUDES);
else
foundationTask.setCompilerFlags("-DDEBUG -g " + INCLUDES);
});
+17
View File
@@ -45,6 +45,23 @@ if (DOMBaseElementsCount > 0)
pageURL = new CFURL(DOMBaseElementHref, pageURL);
}
// Set compiler flags
if (typeof OBJJ_COMPILER_FLAGS !== 'undefined')
{
var flags = 0;
for (var i = 0; i < OBJJ_COMPILER_FLAGS.length; i++)
{
var flag = ObjJAcornCompiler.Flags[OBJJ_COMPILER_FLAGS[i]];
if (flag != null)
{
flags |= flag;
}
}
exports.setCurrentCompilerFlags(flags);
}
// Turn the main file into a URL.
var mainFileURL = new CFURL(window.OBJJ_MAIN_FILE || "main.j"),
+1 -1
View File
@@ -351,7 +351,7 @@ function FileRequest(/*CFURL*/ aURL, onsuccess, onfailure, onprogress)
{
var aFilePath = aURL.toString().substring(5),
OS = require("os"),
gccFlags = require("objective-j").currentCompilerFlags(),
gccFlags = require("objective-j").currentGccCompilerFlags(),
chunk,
fileContents = "";
@@ -192,8 +192,12 @@ function resolveFlags(args)
else if (argument.indexOf("-g") === 0)
objjcFlags |= ObjectiveJ.ObjJAcornCompiler.Flags.IncludeDebugSymbols;
else if (argument.indexOf("-O") === 0)
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...'
if (argument.length > 2)
objjcFlags |= ObjectiveJ.ObjJAcornCompiler.Flags.InlineMsgSend;
}
else if (argument.indexOf("-G") === 0)
objjcFlags |= ObjectiveJ.ObjJAcornCompiler.Flags.Generate;
@@ -907,7 +907,7 @@ BundleTask.prototype.defineSourceTasks = function()
basePath = absolutePath.substring(0, absolutePath.length - theTranslatedFilename.length);
// Here we set the current compiler flags so the load system will know what compiler flags to use
ObjectiveJ.setCurrentCompilerFlags(environmentCompilerFlags);
ObjectiveJ.setCurrentGccCompilerFlags(environmentCompilerFlags);
// Here we tell the CFBundle to load frameworks for the current build enviroment and not the enviroment that is running
CFBundle.environments = function() {return [anEnvironment.name(), "ObjJ"]};
ObjectiveJ.make_narwhal_factory(absolutePath, basePath, translateFilenameToPath)(require, e, module, system, print);
+1 -1
View File
@@ -41,7 +41,7 @@ function FileExecutable(/*CFURL|String*/ aURL, /*Dictionary*/ aFilenameTranslate
if (fileContents.match(/^@STATIC;/))
executable = decompile(fileContents, aURL);
else if ((extension === "j" || !extension) && !fileContents.match(/^{/))
executable = exports.ObjJAcornCompiler.compileFileDependencies(fileContents, aURL, ObjJAcornCompiler.Flags.IncludeDebugSymbols);
executable = exports.ObjJAcornCompiler.compileFileDependencies(fileContents, aURL, exports.currentCompilerFlags());
else
executable = new Executable(fileContents, [], aURL);
+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("\"");
+81 -42
View File
@@ -49,9 +49,12 @@ GLOBAL(objj_ivar) = function(/*String*/ aName, /*String*/ aType)
GLOBAL(objj_method) = function(/*String*/ aName, /*IMP*/ anImplementation, /*Array<String>*/ types)
{
this.name = aName;
this.method_imp = anImplementation;
this.types = types;
var method = anImplementation || function(/*id*/ aReceiver, /*SEL*/ aSelector) {CPException.isa.objj_msgSend2(CPException, "raise:reason:", CPInternalInconsistencyException, aReceiver.isa.method_msgSend0(self, "className") + " does not have an implementation for selector '" + aSelector + "'")};
method.method_name = aName;
method.method_imp = anImplementation;
method.method_types = types;
return method;
}
GLOBAL(objj_class) = function(displayName)
@@ -197,7 +200,7 @@ GLOBAL(class_addMethod) = function(/*Class*/ aClass, /*SEL*/ aName, /*IMP*/ anIm
#if DEBUG
// Give this function a "pretty" name for the console.
method.method_imp.displayName = METHOD_DISPLAY_NAME(aClass, method);
method.displayName = METHOD_DISPLAY_NAME(aClass, method);
#endif
// FIXME: Should this be done here?
@@ -222,11 +225,11 @@ GLOBAL(class_addMethods) = function(/*Class*/ aClass, /*Array*/ methods)
// FIXME: Don't do it if it exists?
method_list.push(method);
method_dtable[method.name] = method;
method_dtable[method.method_name] = method;
#if DEBUG
// Give this function a "pretty" name for the console.
method.method_imp.displayName = METHOD_DISPLAY_NAME(aClass, method);
method.displayName = METHOD_DISPLAY_NAME(aClass, method);
#endif
}
@@ -292,12 +295,22 @@ GLOBAL(class_replaceMethod) = function(/*Class*/ aClass, /*SEL*/ aSelector, /*IM
return NULL;
var method = aClass.method_dtable[aSelector],
method_imp = NULL;
method_imp = method.method_imp,
new_method = new objj_method(method.method_name, aMethodImplementation, method.method_types);
if (method)
method_imp = method.method_imp;
new_method.displayName = method.displayName;
aClass.method_dtable[aSelector] = new_method;
method.method_imp = aMethodImplementation;
var index = aClass.method_list.indexOf(method);
if (index !== -1)
{
aClass.method_list[index] = new_method;
}
else
{
aClass.method_list.push(new_method);
}
return method_imp;
}
@@ -419,7 +432,7 @@ GLOBAL(protocol_addMethodDescriptions) = function(/*Protocol*/ proto, /*Array*/
{
var method = methods[index];
method_dtable[method.name] = method;
method_dtable[method.method_name] = method;
}
}
@@ -491,26 +504,43 @@ var _class_initialize = function(/*Class*/ aClass)
meta.objj_msgSend2 = objj_msgSendFast2;
meta.objj_msgSend3 = objj_msgSendFast3;
aClass.method_msgSend = aClass.method_dtable;
meta.method_msgSend = meta.method_dtable;
meta.objj_msgSend0(aClass, "initialize");
CHANGEINFO(meta, CLS_INITIALIZED, CLS_INITIALIZING);
}
}
var _objj_forward = function(self, _cmd)
GLOBAL(_objj_forward) = function(self, _cmd)
{
var isa = self.isa,
implementation = isa.method_dtable[SEL_forwardingTargetForSelector_];
meta = GETMETA(isa);
if (!GETINFO(meta, CLS_INITIALIZED) && !GETINFO(meta, CLS_INITIALIZING))
{
_class_initialize(isa);
}
var implementation = isa.method_msgSend[_cmd];
if (implementation)
{
var target = implementation.method_imp.call(this, self, SEL_forwardingTargetForSelector_, _cmd);
return implementation.apply(isa, arguments);
}
implementation = isa.method_dtable[SEL_forwardingTargetForSelector_];
if (implementation)
{
var target = implementation(self, SEL_forwardingTargetForSelector_, _cmd);
if (target && target !== self)
{
arguments[0] = target;
return objj_msgSend.apply(this, arguments);
return target.isa.objj_msgSend.apply(target.isa, arguments);
}
}
@@ -522,7 +552,7 @@ var _objj_forward = function(self, _cmd)
if (forwardInvocationImplementation)
{
var signature = implementation.method_imp.call(this, self, SEL_methodSignatureForSelector_, _cmd);
var signature = implementation(self, SEL_methodSignatureForSelector_, _cmd);
if (signature)
{
@@ -541,7 +571,7 @@ var _objj_forward = function(self, _cmd)
invocationIsa.objj_msgSend2(invocation, SEL_setArgument_atIndex_, arguments[index], index);
}
forwardInvocationImplementation.method_imp.call(this, self, SEL_forwardInvocation_, invocation);
forwardInvocationImplementation(self, SEL_forwardInvocation_, invocation);
return invocation == null ? null : invocationIsa.objj_msgSend0(invocation, SEL_returnValue);
}
@@ -552,7 +582,7 @@ var _objj_forward = function(self, _cmd)
implementation = isa.method_dtable[SEL_doesNotRecognizeSelector_];
if (implementation)
return implementation.method_imp.call(this, self, SEL_doesNotRecognizeSelector_, _cmd);
return implementation(self, SEL_doesNotRecognizeSelector_, _cmd);
throw class_getName(isa) + " does not implement doesNotRecognizeSelector:. Did you forget a superclass for " + class_getName(isa) + "?";
};
@@ -562,9 +592,7 @@ var _objj_forward = function(self, _cmd)
if (!ISINITIALIZED(aClass))\
_class_initialize(aClass);\
\
var method = aClass.method_dtable[aSelector];\
\
aMethodImplementation = method ? method.method_imp : _objj_forward;
aMethodImplementation = aClass.method_dtable[aSelector] || _objj_forward;
GLOBAL(class_getMethodImplementation) = function(/*Class*/ aClass, /*SEL*/ aSelector)
{
@@ -845,11 +873,28 @@ GLOBAL(objj_msgSendSuper) = function(/*id*/ aSuper, /*SEL*/ aSelector)
return implementation.apply(aSuper.receiver, arguments);
}
GLOBAL(objj_msgSendSuper0) = function(/*id*/ aSuper, /*SEL*/ aSelector)
{
return (aSuper.super_class.method_dtable[aSelector] || _objj_forward)(aSuper.receiver, aSelector);
}
GLOBAL(objj_msgSendSuper1) = function(/*id*/ aSuper, /*SEL*/ aSelector, arg0)
{
return (aSuper.super_class.method_dtable[aSelector] || _objj_forward)(aSuper.receiver, aSelector, arg0);
}
GLOBAL(objj_msgSendSuper2) = function(/*id*/ aSuper, /*SEL*/ aSelector, arg0, arg1)
{
return (aSuper.super_class.method_dtable[aSelector] || _objj_forward)(aSuper.receiver, aSelector, arg0, arg1);
}
GLOBAL(objj_msgSendSuper3) = function(/*id*/ aSuper, /*SEL*/ aSelector, arg0, arg1, arg2)
{
return (aSuper.super_class.method_dtable[aSelector] || _objj_forward)(aSuper.receiver, aSelector, arg0, arg1, arg2);
}
GLOBAL(objj_msgSendFast) = function(/*id*/ aReceiver, /*SEL*/ aSelector)
{
var method = this.method_dtable[aSelector],
implementation = method ? method.method_imp : _objj_forward;
#ifdef MAXIMUM_RECURSION_CHECKS
if (__objj_msgSend__StackDepth++ > MAXIMUM_RECURSION_DEPTH)
throw new Error("Maximum call stack depth exceeded.");
@@ -857,7 +902,7 @@ GLOBAL(objj_msgSendFast) = function(/*id*/ aReceiver, /*SEL*/ aSelector)
try {
#endif
return implementation.apply(aReceiver, arguments);
return (this.method_dtable[aSelector] || _objj_forward).apply(aReceiver, arguments);
#ifdef MAXIMUM_RECURSION_CHECKS
} finally {
@@ -874,9 +919,6 @@ var objj_msgSendFastInitialize = function(/*id*/ aReceiver, /*SEL*/ aSelector)
GLOBAL(objj_msgSendFast0) = function(/*id*/ aReceiver, /*SEL*/ aSelector)
{
var method = this.method_dtable[aSelector],
implementation = method ? method.method_imp : _objj_forward;
#ifdef MAXIMUM_RECURSION_CHECKS
if (__objj_msgSend__StackDepth++ > MAXIMUM_RECURSION_DEPTH)
throw new Error("Maximum call stack depth exceeded.");
@@ -884,7 +926,7 @@ GLOBAL(objj_msgSendFast0) = function(/*id*/ aReceiver, /*SEL*/ aSelector)
try {
#endif
return implementation(aReceiver, aSelector);
return (this.method_dtable[aSelector] || _objj_forward)(aReceiver, aSelector);
#ifdef MAXIMUM_RECURSION_CHECKS
} finally {
@@ -901,9 +943,6 @@ var objj_msgSendFast0Initialize = function(/*id*/ aReceiver, /*SEL*/ aSelector)
GLOBAL(objj_msgSendFast1) = function(/*id*/ aReceiver, /*SEL*/ aSelector, arg0)
{
var method = this.method_dtable[aSelector],
implementation = method ? method.method_imp : _objj_forward;
#ifdef MAXIMUM_RECURSION_CHECKS
if (__objj_msgSend__StackDepth++ > MAXIMUM_RECURSION_DEPTH)
throw new Error("Maximum call stack depth exceeded.");
@@ -911,7 +950,7 @@ GLOBAL(objj_msgSendFast1) = function(/*id*/ aReceiver, /*SEL*/ aSelector, arg0)
try {
#endif
return implementation(aReceiver, aSelector, arg0);
return (this.method_dtable[aSelector] || _objj_forward)(aReceiver, aSelector, arg0);
#ifdef MAXIMUM_RECURSION_CHECKS
} finally {
@@ -928,9 +967,6 @@ var objj_msgSendFast1Initialize = function(/*id*/ aReceiver, /*SEL*/ aSelector,
GLOBAL(objj_msgSendFast2) = function(/*id*/ aReceiver, /*SEL*/ aSelector, arg0, arg1)
{
var method = this.method_dtable[aSelector],
implementation = method ? method.method_imp : _objj_forward;
#ifdef MAXIMUM_RECURSION_CHECKS
if (__objj_msgSend__StackDepth++ > MAXIMUM_RECURSION_DEPTH)
throw new Error("Maximum call stack depth exceeded.");
@@ -938,7 +974,7 @@ GLOBAL(objj_msgSendFast2) = function(/*id*/ aReceiver, /*SEL*/ aSelector, arg0,
try {
#endif
return implementation(aReceiver, aSelector, arg0, arg1);
return (this.method_dtable[aSelector] || _objj_forward)(aReceiver, aSelector, arg0, arg1);
#ifdef MAXIMUM_RECURSION_CHECKS
} finally {
@@ -955,9 +991,6 @@ var objj_msgSendFast2Initialize = function(/*id*/ aReceiver, /*SEL*/ aSelector,
GLOBAL(objj_msgSendFast3) = function(/*id*/ aReceiver, /*SEL*/ aSelector, arg0, arg1, arg2)
{
var method = this.method_dtable[aSelector],
implementation = method ? method.method_imp : _objj_forward;
#ifdef MAXIMUM_RECURSION_CHECKS
if (__objj_msgSend__StackDepth++ > MAXIMUM_RECURSION_DEPTH)
throw new Error("Maximum call stack depth exceeded.");
@@ -965,7 +998,7 @@ GLOBAL(objj_msgSendFast3) = function(/*id*/ aReceiver, /*SEL*/ aSelector, arg0,
try {
#endif
return implementation(aReceiver, aSelector, arg0, arg1, arg2);
return (this.method_dtable[aSelector] || _objj_forward)(aReceiver, aSelector, arg0, arg1, arg2);
#ifdef MAXIMUM_RECURSION_CHECKS
} finally {
@@ -984,7 +1017,12 @@ var objj_msgSendFast3Initialize = function(/*id*/ aReceiver, /*SEL*/ aSelector,
GLOBAL(method_getName) = function(/*Method*/ aMethod)
{
return aMethod.name;
return aMethod.method_name;
}
GLOBAL(method_getTypes) = function(/*Method*/ aMethod)
{
return aMethod.method_types;
}
GLOBAL(method_getImplementation) = function(/*Method*/ aMethod)
@@ -1050,6 +1088,7 @@ objj_class.prototype.objj_msgSend0 = objj_msgSendFast0Initialize;
objj_class.prototype.objj_msgSend1 = objj_msgSendFast1Initialize;
objj_class.prototype.objj_msgSend2 = objj_msgSendFast2Initialize;
objj_class.prototype.objj_msgSend3 = objj_msgSendFast3Initialize;
objj_class.prototype.method_msgSend = Object.create(null);
var SEL_description = sel_getUid("description"),
SEL_forwardingTargetForSelector_ = sel_getUid("forwardingTargetForSelector:"),
@@ -0,0 +1,2 @@
(object==null?null:(object.isa.method_msgSend[":"]||_objj_forward)(object,":",argument));
@@ -0,0 +1,2 @@
var a=0;
((___r1=a++<2?small_target:big_target),___r1==null?null:(___r1.isa.method_msgSend["doStuff"]||_objj_forward)(___r1,"doStuff"));
@@ -0,0 +1 @@
(object==null?null:(object.isa.method_msgSend["for:in:nil:"]||_objj_forward)(object,"for:in:nil:",a,b,nil));
@@ -0,0 +1,2 @@
(object==null?null:(object.isa.method_msgSend["label:label2:label3:label4:"]||_objj_forward)(object,"label:label2:label3:label4:",argument,argument2,argument3,argument4));
@@ -0,0 +1,2 @@
(CPArray.isa.method_msgSend["new"]||_objj_forward)(CPArray,"new");
(object==null?null:(object.isa.method_msgSend["message"]||_objj_forward)(object,"message"));
@@ -0,0 +1,2 @@
(CPArray.isa.method_msgSend["arrayWithArray:"]||_objj_forward)(CPArray,"arrayWithArray:",[]);
(object==null?null:(object.isa.method_msgSend["label:"]||_objj_forward)(object,"label:",argument));
@@ -0,0 +1,11 @@
var the_class=objj_allocateClassPair(Nil,"MyClass"),meta_class=the_class.isa;
objj_registerClassPair(the_class);
class_addMethods(the_class,[new objj_method(sel_getUid("mySelector"),function $MyClass__mySelector(_1,_2){
(_1.isa.method_msgSend["init"]||_objj_forward)(_1,"init");
_1=nil;
(_1==null?null:(_1.isa.method_msgSend["init"]||_objj_forward)(_1,"init"));
},["id"]),new objj_method(sel_getUid("mySelector2"),function $MyClass__mySelector2(_3,_4){
(_3.isa.method_msgSend["init"]||_objj_forward)(_3,"init");
eval("self = null;");
(_3==null?null:(_3.isa.method_msgSend["init"]||_objj_forward)(_3,"init"));
},["id"])]);
@@ -0,0 +1,4 @@
(object==null?null:(object.isa.method_msgSend["label:"]||_objj_forward)(object,"label:",condition?true:false));
(object==null?null:(object.isa.method_msgSend["label:"]||_objj_forward)(object,"label:",condition?true:false));
(object==null?null:(object.isa.method_msgSend["label:"]||_objj_forward)(object,"label:",condition?true:false));
@@ -0,0 +1,3 @@
x=function(){
return (someIval==null?null:(someIval.isa.method_msgSend["someMethod"]||_objj_forward)(someIval,"someMethod"));
};
@@ -43,18 +43,28 @@ var FILENAMES = [
class_addMethod(self, testSelector, function(self, _cmd)
{
var filePath = FILE.join(FILE.dirname(module.path), filename + ".j"),
var d = FILE.dirname(module.path),
filePath = FILE.join(d, filename + ".j"),
unpreprocessed = FILE.read(filePath, { charset:"UTF-8" }),
preprocessed,
correct = FILE.read(FILE.join(FILE.dirname(module.path), filename + ".js"));
preprocessedInlined,
correct = FILE.read(FILE.join(d, filename + ".js")),
p = FILE.join(d, filename + "-inlined.js"),
correctInlined = FILE.exists(p) ? FILE.read(p) : correct; // Get inlined version if it exists. Otherwise use the regular one.
[self assertNoThrow:function() {
preprocessed = ObjectiveJ.ObjJAcornCompiler.compileToExecutable(unpreprocessed).code();
preprocessed = ObjectiveJ.ObjJAcornCompiler.compileToExecutable(unpreprocessed, nil, ObjectiveJ.ObjJAcornCompiler.Flags.IncludeDebugSymbols/* | ObjectiveJ.ObjJAcornCompiler.Flags.IncludeTypeSignatures*/).code();
preprocessed = compressor.compress(preprocessed, { charset : "UTF-8", useServer : true });
correct = compressor.compress(correct, { charset : "UTF-8", useServer : true });
// Get an Inlined version
preprocessedInlined = ObjectiveJ.ObjJAcornCompiler.compileToExecutable(unpreprocessed, nil, ObjectiveJ.ObjJAcornCompiler.Flags.IncludeDebugSymbols | ObjectiveJ.ObjJAcornCompiler.Flags.InlineMsgSend/* | ObjectiveJ.ObjJAcornCompiler.Flags.IncludeTypeSignatures*/).code();
preprocessedInlined = compressor.compress(preprocessedInlined, { charset : "UTF-8", useServer : true });
correctInlined = compressor.compress(correctInlined, { charset : "UTF-8", useServer : true });
}];
[self assert:correct equals:preprocessed];
[self assert:correctInlined equals:preprocessedInlined];
});
})();
}
@@ -40,7 +40,7 @@ app (projectName, function(task)
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g");
else
task.setCompilerFlags("-O");
task.setCompilerFlags("-O2");
});
task ("default", [projectName], function()
@@ -33,6 +33,8 @@
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks"];
// Uncomment below to generate debug symbols, type signatures and inline objj_msgSend functions
// OBJJ_COMPILER_FLAGS = ["IncludeDebugSymbols", "IncludeTypeSignatures", "InlineMsgSend"];
var progressBar = null;
@@ -112,7 +112,7 @@ var frameworkTask = framework (productName, function(frameworkTask)
if (configuration === "Debug")
frameworkTask.setCompilerFlags("-DDEBUG -g");
else
frameworkTask.setCompilerFlags("-O");
frameworkTask.setCompilerFlags("-O2");
});
task ("debug", function()
@@ -40,7 +40,7 @@ app (projectName, function(task)
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g");
else
task.setCompilerFlags("-O");
task.setCompilerFlags("-O2");
});
task ("default", [projectName], function()
@@ -33,6 +33,8 @@
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks"];
// Uncomment below to generate debug symbols, type signatures and inline objj_msgSend functions
// OBJJ_COMPILER_FLAGS = ["IncludeDebugSymbols", "IncludeTypeSignatures", "InlineMsgSend"];
var progressBar = null;
@@ -33,6 +33,8 @@
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks"];
// Uncomment below to generate debug symbols, type signatures and inline objj_msgSend functions
// OBJJ_COMPILER_FLAGS = ["IncludeDebugSymbols", "IncludeTypeSignatures", "InlineMsgSend"];
var progressBar = null;
+1
View File
@@ -148,6 +148,7 @@ global.filedir = JAKE.filedir;
global.FileList = JAKE.FileList;
global.$CONFIGURATION = SYSTEM.env['CONFIG'];
global.$INLINE_MSG_SEND = SYSTEM.env['INLINE_MSG_SEND'];
global.$BUILD_DIR = SYSTEM.env['BUILD_PATH'];
global.$BUILD_CONFIGURATION_DIR = FILE.join($BUILD_DIR, $CONFIGURATION);