Line data Source code
1 0 : /* 2 : 3 : OOJSEngineNativeWrappers.h 4 : (Included by OOJavaScriptEngine.h) 5 : 6 : Exception safety and profiling macros. 7 : 8 : Every JavaScript native callback that could concievably cause an 9 : Objective-C exception should begin with OOJS_NATIVE_ENTER() and end with 10 : OOJS_NATIVE_EXIT. Callbacks which have been carefully audited for potential 11 : exceptions, and support functions called from JavaScript native callbacks, 12 : may start with OOJS_PROFILE_ENTER and end with OOJS_PROFILE_EXIT to be 13 : included in profiling reports. 14 : 15 : Functions using either of these pairs _must_ return before 16 : OOJS_NATIVE_EXIT/OOJS_PROFILE_EXIT, or they will crash. 17 : 18 : For functions with a non-scalar return type, OOJS_PROFILE_EXIT should be 19 : replaced with OOJS_PROFILE_EXIT_VAL(returnValue). The returnValue is never 20 : used (and should be a constant expression), but is required to placate the 21 : compiler. 22 : 23 : For values with void return, use OOJS_PROFILE_EXIT_VOID. It is not 24 : necessary to insert a return statement before OOJS_PROFILE_EXIT_VOID. 25 : 26 : 27 : JavaScript support for Oolite 28 : Copyright (C) 2007-2013 David Taylor and Jens Ayton. 29 : 30 : This program is free software; you can redistribute it and/or 31 : modify it under the terms of the GNU General Public License 32 : as published by the Free Software Foundation; either version 2 33 : of the License, or (at your option) any later version. 34 : 35 : This program is distributed in the hope that it will be useful, 36 : but WITHOUT ANY WARRANTY; without even the implied warranty of 37 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 : GNU General Public License for more details. 39 : 40 : You should have received a copy of the GNU General Public License 41 : along with this program; if not, write to the Free Software 42 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 43 : MA 02110-1301, USA. 44 : 45 : */ 46 : 47 : #import "OOCocoa.h" 48 : 49 : 50 0 : #define OOJS_PROFILE OOLITE_DEBUG 51 : 52 : #if OOJS_PROFILE 53 : 54 : 55 : #define OOJS_PROFILE_ENTER_NAMED(NAME) \ 56 : { \ 57 : OOJS_DECLARE_PROFILE_STACK_FRAME(oojsProfilerStackFrame) \ 58 : @try { \ 59 : OOJSProfileEnter(&oojsProfilerStackFrame, NAME); 60 : 61 : #define OOJS_PROFILE_ENTER \ 62 : OOJS_PROFILE_ENTER_NAMED(__FUNCTION__) 63 : 64 : #define OOJS_PROFILE_EXIT_VAL(rval) \ 65 : } @finally { \ 66 : OOJSProfileExit(&oojsProfilerStackFrame); \ 67 : } \ 68 : OOJSUnreachable(__FUNCTION__, __FILE__, __LINE__); \ 69 : return rval; \ 70 : } 71 : #define OOJS_PROFILE_EXIT_VOID return; OOJS_PROFILE_EXIT_VAL() 72 : 73 : #define OOJS_PROFILE_ENTER_FOR_NATIVE OOJS_PROFILE_ENTER 74 : 75 : #else 76 : 77 0 : #define OOJS_PROFILE_ENTER { 78 0 : #define OOJS_PROFILE_EXIT_VAL(rval) } OOJSUnreachable(__FUNCTION__, __FILE__, __LINE__); return (rval); 79 0 : #define OOJS_PROFILE_EXIT_VOID } return; 80 0 : #define OOJS_PROFILE_ENTER_FOR_NATIVE @try { 81 : 82 : #endif // OOJS_PROFILE 83 : 84 0 : #define OOJS_NATIVE_ENTER(cx) \ 85 : { \ 86 : JSContext *oojsNativeContext = (cx); \ 87 : OOJS_PROFILE_ENTER_FOR_NATIVE 88 : 89 0 : #define OOJS_NATIVE_EXIT \ 90 : } @catch(id exception) { \ 91 : OOJSReportWrappedException(oojsNativeContext, exception); \ 92 : return NO; \ 93 : OOJS_PROFILE_EXIT_VAL(NO) \ 94 : } 95 : 96 : 97 0 : void OOJSReportWrappedException(JSContext *context, id exception); 98 : 99 : 100 : #ifndef NDEBUG 101 0 : void OOJSUnreachable(const char *function, const char *file, unsigned line) NO_RETURN_FUNC; 102 : #else 103 : #define OOJSUnreachable(function, file, line) OO_UNREACHABLE() 104 : #endif 105 : 106 : 107 0 : #define OOJS_PROFILE_EXIT OOJS_PROFILE_EXIT_VAL(0) 108 0 : #define OOJS_PROFILE_EXIT_JSVAL OOJS_PROFILE_EXIT_VAL(JSVAL_VOID) 109 : 110 : 111 : /* 112 : OOJS_BEGIN_FULL_NATIVE() and OOJS_END_FULL_NATIVE 113 : These macros are used to bracket sections of native Oolite code within JS 114 : callbacks which may take a long time. Thet do two things: pause the 115 : time limiter, and (in JS_THREADSAFE builds) suspend the current JS context 116 : request. 117 : 118 : These macros must be used in balanced pairs. They introduce a scope. 119 : 120 : JSAPI functions may not be used, directly or indirectily, between these 121 : macros unless explicitly opening a request first. 122 : */ 123 : #if JS_THREADSAFE 124 : #define OOJS_BEGIN_FULL_NATIVE(context) \ 125 : { \ 126 : OOJSPauseTimeLimiter(); \ 127 : JSContext *oojsRequestContext = (context); \ 128 : jsrefcount oojsRequestRefCount = JS_SuspendRequest(oojsRequestContext); \ 129 : @try \ 130 : { 131 : 132 : #define OOJS_END_FULL_NATIVE \ 133 : } \ 134 : @finally \ 135 : { \ 136 : JS_ResumeRequest(oojsRequestContext, oojsRequestRefCount); \ 137 : OOJSResumeTimeLimiter(); \ 138 : } \ 139 : } 140 : #else 141 0 : #define OOJS_BEGIN_FULL_NATIVE(context) \ 142 : { \ 143 : (void)(context); \ 144 : OOJSPauseTimeLimiter(); \ 145 : @try \ 146 : { 147 : 148 0 : #define OOJS_END_FULL_NATIVE \ 149 : } \ 150 : @finally \ 151 : { \ 152 : OOJSResumeTimeLimiter(); \ 153 : } \ 154 : } 155 : #endif 156 : 157 : 158 : 159 : #if OOJS_PROFILE 160 : 161 : #import "OOProfilingStopwatch.h" 162 : 163 : /* 164 : Profiler implementation details. This should be internal to 165 : OOJSTimeManagement.m, but needs to be declared on the stack by the macros 166 : above when profiling is enabled. 167 : */ 168 : 169 : typedef struct OOJSProfileStackFrame OOJSProfileStackFrame; 170 : struct OOJSProfileStackFrame 171 : { 172 : OOJSProfileStackFrame *back; // Stack link 173 : const void *key; // Key to look up profile entries. May be any pointer; currently const char * for native frames and JSFunction * for JS frames. 174 : const char *function; // Name of function, for native frames. 175 : OOHighResTimeValue startTime; // Time frame was entered. 176 : OOTimeDelta subTime; // Time spent in subroutine calls. 177 : OOTimeDelta *total; // Pointer to accumulator for this type of frame. 178 : void (*cleanup)(OOJSProfileStackFrame *); // Cleanup function if needed (used for JS frames). 179 : }; 180 : 181 : 182 : 183 : #define OOJS_DECLARE_PROFILE_STACK_FRAME(name) OOJSProfileStackFrame name; 184 : void OOJSProfileEnter(OOJSProfileStackFrame *frame, const char *function); 185 : void OOJSProfileExit(OOJSProfileStackFrame *frame); 186 : 187 : #else 188 : 189 0 : #define OOJS_DECLARE_PROFILE_STACK_FRAME(name) 190 0 : #define OOJSProfileEnter(frame, function) do {} while (0) 191 0 : #define OOJSProfileExit(frame) do {} while (0) 192 : 193 : #endif