From 4ba9a19b5c3b246ed04e5f929322f9372c517a58 Mon Sep 17 00:00:00 2001 From: Martin Carlberg Date: Tue, 6 Oct 2015 13:27:10 +0200 Subject: [PATCH 01/25] Fixed: Speed improvements in objj_msgSend and objj_msgSendSuper functions. More efficient implementation of objj_method. --- Objective-J/Runtime.js | 123 +++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 42 deletions(-) diff --git a/Objective-J/Runtime.js b/Objective-J/Runtime.js index e352cf3e1..2c07e2154 100644 --- a/Objective-J/Runtime.js +++ b/Objective-J/Runtime.js @@ -49,9 +49,12 @@ GLOBAL(objj_ivar) = function(/*String*/ aName, /*String*/ aType) GLOBAL(objj_method) = function(/*String*/ aName, /*IMP*/ anImplementation, /*Array*/ 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:"), From 101261ca63d858913535f2225d2abaec037941b1 Mon Sep 17 00:00:00 2001 From: Martin Carlberg Date: Tue, 6 Oct 2015 13:30:09 +0200 Subject: [PATCH 02/25] Fixed: Optionally inline objj_msgSend function. Generate faster code for Array and Dictionary Literals. --- Objective-J/ObjJAcornCompiler.js | 267 +++++++++++++++++++++++++------ 1 file changed, 217 insertions(+), 50 deletions(-) diff --git a/Objective-J/ObjJAcornCompiler.js b/Objective-J/ObjJAcornCompiler.js index fd7e0e1ec..89d1d6d76 100644 --- a/Objective-J/ObjJAcornCompiler.js +++ b/Objective-J/ObjJAcornCompiler.js @@ -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()". 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()". 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()". 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()". 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("\""); From e45e31d2236170859ae08bfd4f019d87a88a0aac Mon Sep 17 00:00:00 2001 From: Martin Carlberg Date: Tue, 6 Oct 2015 13:34:28 +0200 Subject: [PATCH 03/25] =?UTF-8?q?Fixed:=20Introduce=20=E2=80=99jake=20inst?= =?UTF-8?q?all-inline=E2=80=99=20task=20to=20generate=20the=20cappuccino?= =?UTF-8?q?=20framework=20with=20objj=5FmsgSend=20function=20inlined.=20Al?= =?UTF-8?q?so=20introduced=20options=20in=20=E2=80=99index-debug.html?= =?UTF-8?q?=E2=80=99=20templates=20to=20allow=20inline=20of=20objj=5FmsgSe?= =?UTF-8?q?nd=20function=20when=20compiling=20in=20browser.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AppKit/Jakefile | 5 +++-- AppKit/Themes/BlendKit/Jakefile | 2 +- Foundation/Jakefile | 2 +- Jakefile | 14 +++++++++++--- Objective-J/CFHTTPRequest.js | 2 +- Objective-J/CommonJS/lib/objective-j/compiler.js | 6 +++++- .../CommonJS/lib/objective-j/jake/bundletask.js | 2 +- Objective-J/FileExecutable.js | 2 +- .../Preprocessor/OutputTests/OutputTest.j | 2 +- .../capp/Resources/Templates/Application/Jakefile | 2 +- .../Templates/Application/index-debug.html | 5 +++++ Tools/capp/Resources/Templates/Framework/Jakefile | 2 +- .../Resources/Templates/NibApplication/Jakefile | 2 +- .../Templates/NibApplication/index-debug.html | 5 +++++ .../Templates/ThemeDescriptor/index-debug.html | 5 +++++ common.jake | 8 ++++++++ 16 files changed, 51 insertions(+), 15 deletions(-) diff --git a/AppKit/Jakefile b/AppKit/Jakefile index 69f958e4c..b08853fda 100644 --- a/AppKit/Jakefile +++ b/AppKit/Jakefile @@ -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(($INLINE_MSG_SEND ? "-O2 " : "-O ") + INCLUDES); + } else appKitTask.setCompilerFlags("-DDEBUG -g " + INCLUDES); }); diff --git a/AppKit/Themes/BlendKit/Jakefile b/AppKit/Themes/BlendKit/Jakefile index da9439c09..f8797ec56 100644 --- a/AppKit/Themes/BlendKit/Jakefile +++ b/AppKit/Themes/BlendKit/Jakefile @@ -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($INLINE_MSG_SEND ? "-O2" : "-O"); else blendKitTask.setCompilerFlags("-DDEBUG -g"); }); diff --git a/Foundation/Jakefile b/Foundation/Jakefile index 20d218c9e..e180f19b0 100644 --- a/Foundation/Jakefile +++ b/Foundation/Jakefile @@ -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(($INLINE_MSG_SEND ? "-O2 " : "-O ") + INCLUDES); else foundationTask.setCompilerFlags("-DDEBUG -g " + INCLUDES); }); diff --git a/Jakefile b/Jakefile index 9bbc5ff57..107458477 100644 --- a/Jakefile +++ b/Jakefile @@ -21,7 +21,7 @@ var subprojects = ["Objective-J", "CommonJS", "Foundation", "AppKit", "Tools"]; $BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS = FILE.join($BUILD_CJS_OBJECTIVE_J, "Frameworks", "Debug"); -filedir ($BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS, ["debug", "release"], function() +filedir ($BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS, [], function() { FILE.mkdirs($BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS); @@ -30,7 +30,7 @@ filedir ($BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS, ["debug", "release"], function $BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS = FILE.join($BUILD_CJS_CAPPUCCINO, "Frameworks", "Debug"); -filedir ($BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS, ["debug", "release"], function() +filedir ($BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS, [], function() { FILE.mkdirs($BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS); @@ -39,7 +39,9 @@ filedir ($BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS, ["debug", "release"], function( cp_r(FILE.join($BUILD_DIR, "Debug", "BlendKit"), FILE.join($BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS, "BlendKit")); }); -task ("CommonJS", [$BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS, $BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS, "debug", "release"]); +task ("CommonJS", ["debug", "release", $BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS, $BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS, "debug", "release"]); + +task ("CommonJS-inline", ["debug", "release-inline", $BUILD_CJS_OBJECTIVE_J_DEBUG_FRAMEWORKS, $BUILD_CJS_CAPPUCCINO_DEBUG_FRAMEWORKS, "debug", "release-inline"]); task ("install", ["CommonJS"], function() { @@ -47,6 +49,12 @@ task ("install", ["CommonJS"], function() installCopy($BUILD_CJS_CAPPUCCINO, false); }); +task ("install-inline", ["CommonJS-inline"], function() +{ + installCopy($BUILD_CJS_OBJECTIVE_J, false); + installCopy($BUILD_CJS_CAPPUCCINO, false); +}); + task ("sudo-install", ["CommonJS"], function() { installCopy($BUILD_CJS_OBJECTIVE_J, true); diff --git a/Objective-J/CFHTTPRequest.js b/Objective-J/CFHTTPRequest.js index eff9a49df..a961cc67b 100644 --- a/Objective-J/CFHTTPRequest.js +++ b/Objective-J/CFHTTPRequest.js @@ -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 = ""; diff --git a/Objective-J/CommonJS/lib/objective-j/compiler.js b/Objective-J/CommonJS/lib/objective-j/compiler.js index 34416cde0..6f7f91972 100644 --- a/Objective-J/CommonJS/lib/objective-j/compiler.js +++ b/Objective-J/CommonJS/lib/objective-j/compiler.js @@ -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; diff --git a/Objective-J/CommonJS/lib/objective-j/jake/bundletask.js b/Objective-J/CommonJS/lib/objective-j/jake/bundletask.js index e71b9129f..613d9b254 100644 --- a/Objective-J/CommonJS/lib/objective-j/jake/bundletask.js +++ b/Objective-J/CommonJS/lib/objective-j/jake/bundletask.js @@ -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); diff --git a/Objective-J/FileExecutable.js b/Objective-J/FileExecutable.js index 8e9bcac7a..a3b471a7e 100644 --- a/Objective-J/FileExecutable.js +++ b/Objective-J/FileExecutable.js @@ -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); diff --git a/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j b/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j index fcd96ba3c..5b5ffa070 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j +++ b/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j @@ -49,7 +49,7 @@ var FILENAMES = [ correct = FILE.read(FILE.join(FILE.dirname(module.path), filename + ".js")); [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 }); }]; diff --git a/Tools/capp/Resources/Templates/Application/Jakefile b/Tools/capp/Resources/Templates/Application/Jakefile index 08a8c0c8b..a25464947 100644 --- a/Tools/capp/Resources/Templates/Application/Jakefile +++ b/Tools/capp/Resources/Templates/Application/Jakefile @@ -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() diff --git a/Tools/capp/Resources/Templates/Application/index-debug.html b/Tools/capp/Resources/Templates/Application/index-debug.html index d862fd07e..96a9a1106 100644 --- a/Tools/capp/Resources/Templates/Application/index-debug.html +++ b/Tools/capp/Resources/Templates/Application/index-debug.html @@ -61,6 +61,11 @@