/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. #ifdef BROWSER
  23. CPLogRegister(CPLogDefault);
  24. #endif
  25. // formatting helpers
  26. function objj_debug_object_format(aReceiver)
  27. {
  28. return (aReceiver && aReceiver.isa) ? exports.sprintf("<%s %#08x>", GETMETA(aReceiver).name, aReceiver._UID) : String(aReceiver);
  29. }
  30. function objj_debug_message_format(aReceiver, aSelector)
  31. {
  32. return exports.sprintf("[%s %s]", objj_debug_object_format(aReceiver), aSelector);
  33. }
  34. // save the original msgSend implementations so we can restore them later
  35. var objj_msgSend_original = objj_msgSend,
  36. objj_msgSendSuper_original = objj_msgSendSuper,
  37. objj_msgSendFast_original = objj_msgSendFast,
  38. objj_msgSendFast0_original = objj_msgSendFast0,
  39. objj_msgSendFast1_original = objj_msgSendFast1,
  40. objj_msgSendFast2_original = objj_msgSendFast2,
  41. objj_msgSendFast3_original = objj_msgSendFast3;
  42. function objj_msgSend_reset_all_classes() {
  43. objj_enumerateClassesUsingBlock(function(aClass) {
  44. if (aClass.hasOwnProperty("objj_msgSend"))
  45. {
  46. aClass.objj_msgSend = objj_msgSendFast;
  47. aClass.objj_msgSend0 = objj_msgSendFast0;
  48. aClass.objj_msgSend1 = objj_msgSendFast1;
  49. aClass.objj_msgSend2 = objj_msgSendFast2;
  50. aClass.objj_msgSend3 = objj_msgSendFast3;
  51. }
  52. });
  53. }
  54. // decorator management functions
  55. // reset to default objj_msgSend* implementations
  56. GLOBAL(objj_msgSend_reset) = function()
  57. {
  58. objj_msgSend = objj_msgSend_original;
  59. objj_msgSendSuper = objj_msgSendSuper_original;
  60. objj_msgSendFast = objj_msgSendFast_original;
  61. objj_msgSendFast0 = objj_msgSendFast0_original;
  62. objj_msgSendFast1 = objj_msgSendFast1_original;
  63. objj_msgSendFast2 = objj_msgSendFast2_original;
  64. objj_msgSendFast3 = objj_msgSendFast3_original;
  65. objj_msgSend_reset_all_classes();
  66. }
  67. // decorate both objj_msgSend and objj_msgSendSuper
  68. GLOBAL(objj_msgSend_decorate) = function()
  69. {
  70. var index = 0,
  71. count = arguments.length;
  72. for (; index < count; ++index)
  73. {
  74. objj_msgSend = arguments[index](objj_msgSend);
  75. objj_msgSendSuper = arguments[index](objj_msgSendSuper);
  76. objj_msgSendFast = arguments[index](objj_msgSendFast);
  77. objj_msgSendFast0 = arguments[index](objj_msgSendFast0);
  78. objj_msgSendFast1 = arguments[index](objj_msgSendFast1);
  79. objj_msgSendFast2 = arguments[index](objj_msgSendFast2);
  80. objj_msgSendFast3 = arguments[index](objj_msgSendFast3);
  81. }
  82. if (count)
  83. objj_msgSend_reset_all_classes();
  84. }
  85. // reset then decorate both objj_msgSend and objj_msgSendSuper
  86. GLOBAL(objj_msgSend_set_decorators) = function()
  87. {
  88. objj_msgSend_reset();
  89. objj_msgSend_decorate.apply(NULL, arguments);
  90. }
  91. // backtrace decorator
  92. var objj_backtrace = [];
  93. GLOBAL(objj_backtrace_print) = function(/*Callable*/ aStream)
  94. {
  95. var index = 0,
  96. count = objj_backtrace.length;
  97. for (; index < count; ++index)
  98. {
  99. var frame = objj_backtrace[index];
  100. aStream(objj_debug_message_format(frame.receiver, frame.selector));
  101. }
  102. }
  103. GLOBAL(objj_backtrace_decorator) = function(msgSend)
  104. {
  105. return function(aReceiverOrSuper, aSelector)
  106. {
  107. var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
  108. // push the receiver and selector onto the backtrace stack
  109. objj_backtrace.push({ receiver: aReceiver, selector : aSelector });
  110. try
  111. {
  112. return msgSend.apply(this, arguments);
  113. }
  114. catch (anException)
  115. {
  116. if (objj_backtrace.length)
  117. {
  118. // print the exception and backtrace
  119. CPLog.warn("Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector));
  120. objj_backtrace_print(CPLog.warn);
  121. objj_backtrace = [];
  122. }
  123. // re-throw the exception
  124. throw anException;
  125. }
  126. finally
  127. {
  128. // make sure to always pop
  129. objj_backtrace.pop();
  130. }
  131. };
  132. }
  133. GLOBAL(objj_supress_exceptions_decorator) = function(msgSend)
  134. {
  135. return function(aReceiverOrSuper, aSelector)
  136. {
  137. var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
  138. try
  139. {
  140. return msgSend.apply(this, arguments);
  141. }
  142. catch (anException)
  143. {
  144. // print the exception and backtrace
  145. CPLog.warn("Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector));
  146. }
  147. };
  148. }
  149. // type checking decorator
  150. var objj_typechecks_reported = {},
  151. objj_typecheck_prints_backtrace = NO;
  152. GLOBAL(objj_typecheck_decorator) = function(msgSend)
  153. {
  154. return function(aReceiverOrSuper, aSelector)
  155. {
  156. var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
  157. if (!aReceiver)
  158. return msgSend.apply(this, arguments);
  159. var types = aReceiver.isa.method_dtable[aSelector].types;
  160. for (var i = 2; i < arguments.length; i++)
  161. {
  162. try
  163. {
  164. objj_debug_typecheck(types[i-1], arguments[i]);
  165. }
  166. catch (e)
  167. {
  168. var key = [GETMETA(aReceiver).name, aSelector, i, e].join(";");
  169. if (!objj_typechecks_reported[key]) {
  170. objj_typechecks_reported[key] = YES;
  171. CPLog.warn("Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
  172. if (objj_typecheck_prints_backtrace)
  173. objj_backtrace_print(CPLog.warn);
  174. }
  175. }
  176. }
  177. var result = msgSend.apply(NULL, arguments);
  178. try
  179. {
  180. objj_debug_typecheck(types[0], result);
  181. }
  182. catch (e)
  183. {
  184. var key = [GETMETA(aReceiver).name, aSelector, "ret", e].join(";");
  185. if (!objj_typechecks_reported[key]) {
  186. objj_typechecks_reported[key] = YES;
  187. CPLog.warn("Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
  188. if (objj_typecheck_prints_backtrace)
  189. objj_backtrace_print(CPLog.warn);
  190. }
  191. }
  192. return result;
  193. };
  194. }
  195. // type checking logic:
  196. GLOBAL(objj_debug_typecheck) = function(expectedType, object)
  197. {
  198. var objjClass;
  199. if (!expectedType)
  200. {
  201. return;
  202. }
  203. else if (expectedType === "id")
  204. {
  205. if (object !== undefined)
  206. return;
  207. }
  208. else if (expectedType === "void")
  209. {
  210. if (object === undefined)
  211. return;
  212. }
  213. else if (objjClass = objj_getClass(expectedType))
  214. {
  215. if (object === nil)
  216. {
  217. return;
  218. }
  219. else if (object !== undefined && object.isa)
  220. {
  221. var theClass = object.isa;
  222. for (; theClass; theClass = theClass.super_class)
  223. if (theClass === objjClass)
  224. return;
  225. }
  226. }
  227. else
  228. {
  229. return;
  230. }
  231. var actualType;
  232. if (object === NULL)
  233. actualType = "null";
  234. else if (object === undefined)
  235. actualType = "void";
  236. else if (object.isa)
  237. actualType = GETMETA(object).name;
  238. else
  239. actualType = typeof object;
  240. throw ("expected=" + expectedType + ", actual=" + actualType);
  241. }