PageRenderTime 63ms CodeModel.GetById 22ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

/Objective-J/Debug.js

http://github.com/cacaodev/cappuccino
JavaScript | 278 lines | 206 code | 37 blank | 35 comment | 38 complexity | 8681d50a8703c8e7b26e5e880280488a MD5 | raw file
  1/*
  2 * Debug.js
  3 * Objective-J
  4 *
  5 * Created by Thomas Robinson.
  6 * Copyright 2008-2010, 280 North, Inc.
  7 *
  8 * This library is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU Lesser General Public
 10 * License as published by the Free Software Foundation; either
 11 * version 2.1 of the License, or (at your option) any later version.
 12 *
 13 * This library is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 16 * Lesser General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU Lesser General Public
 19 * License along with this library; if not, write to the Free Software
 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 21 */
 22
 23#ifdef BROWSER
 24CPLogRegister(CPLogDefault);
 25#endif
 26
 27// formatting helpers
 28
 29function objj_debug_object_format(aReceiver)
 30{
 31    return (aReceiver && aReceiver.isa) ? exports.sprintf("<%s %#08x>", GETMETA(aReceiver).name, aReceiver._UID) : String(aReceiver);
 32}
 33
 34function objj_debug_message_format(aReceiver, aSelector)
 35{
 36    return exports.sprintf("[%s %s]", objj_debug_object_format(aReceiver), aSelector);
 37}
 38
 39
 40// save the original msgSend implementations so we can restore them later
 41var objj_msgSend_original = objj_msgSend,
 42    objj_msgSendSuper_original = objj_msgSendSuper,
 43    objj_msgSendFast_original = objj_msgSendFast,
 44    objj_msgSendFast0_original = objj_msgSendFast0,
 45    objj_msgSendFast1_original = objj_msgSendFast1,
 46    objj_msgSendFast2_original = objj_msgSendFast2,
 47    objj_msgSendFast3_original = objj_msgSendFast3;
 48
 49function objj_msgSend_reset_all_classes() {
 50    objj_enumerateClassesUsingBlock(function(aClass) {
 51        if (aClass.hasOwnProperty("objj_msgSend"))
 52        {
 53            aClass.objj_msgSend = objj_msgSendFast;
 54            aClass.objj_msgSend0 = objj_msgSendFast0;
 55            aClass.objj_msgSend1 = objj_msgSendFast1;
 56            aClass.objj_msgSend2 = objj_msgSendFast2;
 57            aClass.objj_msgSend3 = objj_msgSendFast3;
 58        }
 59    });
 60}
 61
 62// decorator management functions
 63
 64// reset to default objj_msgSend* implementations
 65GLOBAL(objj_msgSend_reset) = function()
 66{
 67    objj_msgSend = objj_msgSend_original;
 68    objj_msgSendSuper = objj_msgSendSuper_original;
 69    objj_msgSendFast = objj_msgSendFast_original;
 70    objj_msgSendFast0 = objj_msgSendFast0_original;
 71    objj_msgSendFast1 = objj_msgSendFast1_original;
 72    objj_msgSendFast2 = objj_msgSendFast2_original;
 73    objj_msgSendFast3 = objj_msgSendFast3_original;
 74
 75    objj_msgSend_reset_all_classes();
 76}
 77
 78// decorate both objj_msgSend and objj_msgSendSuper
 79GLOBAL(objj_msgSend_decorate) = function()
 80{
 81    var index = 0,
 82        count = arguments.length;
 83
 84    for (; index < count; ++index)
 85    {
 86        objj_msgSend = arguments[index](objj_msgSend);
 87        objj_msgSendSuper = arguments[index](objj_msgSendSuper);
 88        objj_msgSendFast = arguments[index](objj_msgSendFast);
 89        objj_msgSendFast0 = arguments[index](objj_msgSendFast0);
 90        objj_msgSendFast1 = arguments[index](objj_msgSendFast1);
 91        objj_msgSendFast2 = arguments[index](objj_msgSendFast2);
 92        objj_msgSendFast3 = arguments[index](objj_msgSendFast3);
 93    }
 94
 95    if (count)
 96        objj_msgSend_reset_all_classes();
 97}
 98
 99// reset then decorate both objj_msgSend and objj_msgSendSuper
100GLOBAL(objj_msgSend_set_decorators) = function()
101{
102    objj_msgSend_reset();
103    objj_msgSend_decorate.apply(NULL, arguments);
104}
105
106
107// backtrace decorator
108
109var objj_backtrace = [];
110
111GLOBAL(objj_backtrace_print) = function(/*Callable*/ aStream)
112{
113    var index = 0,
114        count = objj_backtrace.length;
115
116    for (; index < count; ++index)
117    {
118        var frame = objj_backtrace[index];
119
120        aStream(objj_debug_message_format(frame.receiver, frame.selector));
121    }
122}
123
124GLOBAL(objj_backtrace_decorator) = function(msgSend)
125{
126    return function(aReceiverOrSuper, aSelector)
127    {
128        var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
129
130        // push the receiver and selector onto the backtrace stack
131        objj_backtrace.push({ receiver: aReceiver, selector : aSelector });
132        try
133        {
134            return msgSend.apply(this, arguments);
135        }
136        catch (anException)
137        {
138            if (objj_backtrace.length)
139            {
140                // print the exception and backtrace
141                CPLog.warn("Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector));
142                objj_backtrace_print(CPLog.warn);
143                objj_backtrace = [];
144            }
145            // re-throw the exception
146            throw anException;
147        }
148        finally
149        {
150            // make sure to always pop
151            objj_backtrace.pop();
152        }
153    };
154}
155
156GLOBAL(objj_supress_exceptions_decorator) = function(msgSend)
157{
158    return function(aReceiverOrSuper, aSelector)
159    {
160        var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
161
162        try
163        {
164            return msgSend.apply(this, arguments);
165        }
166        catch (anException)
167        {
168            // print the exception and backtrace
169            CPLog.warn("Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector));
170        }
171    };
172}
173
174// type checking decorator
175
176var objj_typechecks_reported = {},
177    objj_typecheck_prints_backtrace = NO;
178
179GLOBAL(objj_typecheck_decorator) = function(msgSend)
180{
181    return function(aReceiverOrSuper, aSelector)
182    {
183        var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
184
185        if (!aReceiver)
186            return msgSend.apply(this, arguments);
187
188        var types = aReceiver.isa.method_dtable[aSelector].types;
189        for (var i = 2; i < arguments.length; i++)
190        {
191            try
192            {
193                objj_debug_typecheck(types[i-1], arguments[i]);
194            }
195            catch (e)
196            {
197                var key = [GETMETA(aReceiver).name, aSelector, i, e].join(";");
198                if (!objj_typechecks_reported[key]) {
199                    objj_typechecks_reported[key] = YES;
200                    CPLog.warn("Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
201                    if (objj_typecheck_prints_backtrace)
202                        objj_backtrace_print(CPLog.warn);
203                }
204            }
205        }
206
207        var result = msgSend.apply(NULL, arguments);
208
209        try
210        {
211            objj_debug_typecheck(types[0], result);
212        }
213        catch (e)
214        {
215            var key = [GETMETA(aReceiver).name, aSelector, "ret", e].join(";");
216            if (!objj_typechecks_reported[key]) {
217                objj_typechecks_reported[key] = YES;
218                CPLog.warn("Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
219                if (objj_typecheck_prints_backtrace)
220                    objj_backtrace_print(CPLog.warn);
221            }
222        }
223
224        return result;
225    };
226}
227
228// type checking logic:
229GLOBAL(objj_debug_typecheck) = function(expectedType, object)
230{
231    var objjClass;
232
233    if (!expectedType)
234    {
235        return;
236    }
237    else if (expectedType === "id")
238    {
239        if (object !== undefined)
240            return;
241    }
242    else if (expectedType === "void")
243    {
244        if (object === undefined)
245            return;
246    }
247    else if (objjClass = objj_getClass(expectedType))
248    {
249        if (object === nil)
250        {
251            return;
252        }
253        else if (object !== undefined && object.isa)
254        {
255            var theClass = object.isa;
256
257            for (; theClass; theClass = theClass.super_class)
258                if (theClass === objjClass)
259                    return;
260        }
261    }
262    else
263    {
264        return;
265    }
266
267    var actualType;
268    if (object === NULL)
269        actualType = "null";
270    else if (object === undefined)
271        actualType = "void";
272    else if (object.isa)
273        actualType = GETMETA(object).name;
274    else
275        actualType = typeof object;
276
277    throw ("expected=" + expectedType + ", actual=" + actualType);
278}