|
|
1.1 ! root 1: /* js_internal.c */ ! 2: ! 3: /* Synchronet "js" object, for internal JavaScript branch and GC control */ ! 4: ! 5: /* $Id: js_internal.c,v 1.21 2004/12/30 09:51:52 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #include "sbbs.h" ! 39: ! 40: #include <jscntxt.h> /* Needed for Context-private data structure */ ! 41: ! 42: enum { ! 43: PROP_VERSION ! 44: ,PROP_TERMINATED ! 45: ,PROP_AUTO_TERMINATE ! 46: ,PROP_BRANCH_COUNTER ! 47: ,PROP_BRANCH_LIMIT ! 48: ,PROP_YIELD_INTERVAL ! 49: ,PROP_GC_INTERVAL ! 50: ,PROP_GC_ATTEMPTS ! 51: #ifdef jscntxt_h___ ! 52: ,PROP_GC_COUNTER ! 53: ,PROP_GC_LASTBYTES ! 54: ,PROP_BYTES ! 55: ,PROP_MAXBYTES ! 56: #endif ! 57: }; ! 58: ! 59: static JSBool js_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ! 60: { ! 61: jsint tiny; ! 62: js_branch_t* branch; ! 63: ! 64: if((branch=(js_branch_t*)JS_GetPrivate(cx,obj))==NULL) ! 65: return(JS_FALSE); ! 66: ! 67: tiny = JSVAL_TO_INT(id); ! 68: ! 69: switch(tiny) { ! 70: case PROP_VERSION: ! 71: *vp=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,(char *)JS_GetImplementationVersion())); ! 72: break; ! 73: case PROP_TERMINATED: ! 74: if(branch->terminated==NULL) ! 75: *vp=JSVAL_FALSE; ! 76: else ! 77: *vp=BOOLEAN_TO_JSVAL(*branch->terminated); ! 78: break; ! 79: case PROP_AUTO_TERMINATE: ! 80: *vp=BOOLEAN_TO_JSVAL(branch->auto_terminate); ! 81: break; ! 82: case PROP_BRANCH_COUNTER: ! 83: JS_NewNumberValue(cx,branch->counter,vp); ! 84: break; ! 85: case PROP_BRANCH_LIMIT: ! 86: JS_NewNumberValue(cx,branch->limit,vp); ! 87: break; ! 88: case PROP_YIELD_INTERVAL: ! 89: JS_NewNumberValue(cx,branch->yield_interval,vp); ! 90: break; ! 91: case PROP_GC_INTERVAL: ! 92: JS_NewNumberValue(cx,branch->gc_interval,vp); ! 93: break; ! 94: case PROP_GC_ATTEMPTS: ! 95: JS_NewNumberValue(cx,branch->gc_attempts,vp); ! 96: break; ! 97: #ifdef jscntxt_h___ ! 98: case PROP_GC_COUNTER: ! 99: JS_NewNumberValue(cx,cx->runtime->gcNumber,vp); ! 100: break; ! 101: case PROP_GC_LASTBYTES: ! 102: JS_NewNumberValue(cx,cx->runtime->gcLastBytes,vp); ! 103: break; ! 104: case PROP_BYTES: ! 105: JS_NewNumberValue(cx,cx->runtime->gcBytes,vp); ! 106: break; ! 107: case PROP_MAXBYTES: ! 108: JS_NewNumberValue(cx,cx->runtime->gcMaxBytes,vp); ! 109: break; ! 110: #endif ! 111: } ! 112: ! 113: return(JS_TRUE); ! 114: } ! 115: ! 116: static JSBool js_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ! 117: { ! 118: jsint tiny; ! 119: js_branch_t* branch; ! 120: ! 121: if((branch=(js_branch_t*)JS_GetPrivate(cx,obj))==NULL) ! 122: return(JS_FALSE); ! 123: ! 124: tiny = JSVAL_TO_INT(id); ! 125: ! 126: switch(tiny) { ! 127: case PROP_TERMINATED: ! 128: if(branch->terminated!=NULL) ! 129: JS_ValueToBoolean(cx, *vp, branch->terminated); ! 130: break; ! 131: case PROP_AUTO_TERMINATE: ! 132: JS_ValueToBoolean(cx,*vp,&branch->auto_terminate); ! 133: break; ! 134: case PROP_BRANCH_COUNTER: ! 135: JS_ValueToInt32(cx, *vp, (int32*)&branch->counter); ! 136: break; ! 137: case PROP_BRANCH_LIMIT: ! 138: JS_ValueToInt32(cx, *vp, (int32*)&branch->limit); ! 139: break; ! 140: case PROP_GC_INTERVAL: ! 141: JS_ValueToInt32(cx, *vp, (int32*)&branch->gc_interval); ! 142: break; ! 143: case PROP_YIELD_INTERVAL: ! 144: JS_ValueToInt32(cx, *vp, (int32*)&branch->yield_interval); ! 145: break; ! 146: #ifdef jscntxt_h___ ! 147: case PROP_MAXBYTES: ! 148: JS_ValueToInt32(cx, *vp, (int32*)&cx->runtime->gcMaxBytes); ! 149: break; ! 150: #endif ! 151: } ! 152: ! 153: return(JS_TRUE); ! 154: } ! 155: ! 156: #define PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY ! 157: ! 158: static jsSyncPropertySpec js_properties[] = { ! 159: /* name, tinyid, flags, ver */ ! 160: ! 161: { "version", PROP_VERSION, PROP_FLAGS, 311 }, ! 162: { "auto_terminate", PROP_AUTO_TERMINATE,JSPROP_ENUMERATE, 311 }, ! 163: { "terminated", PROP_TERMINATED, JSPROP_ENUMERATE, 311 }, ! 164: { "branch_counter", PROP_BRANCH_COUNTER,JSPROP_ENUMERATE, 311 }, ! 165: { "branch_limit", PROP_BRANCH_LIMIT, JSPROP_ENUMERATE, 311 }, ! 166: { "yield_interval", PROP_YIELD_INTERVAL,JSPROP_ENUMERATE, 311 }, ! 167: { "gc_interval", PROP_GC_INTERVAL, JSPROP_ENUMERATE, 311 }, ! 168: { "gc_attempts", PROP_GC_ATTEMPTS, PROP_FLAGS, 311 }, ! 169: #ifdef jscntxt_h___ ! 170: { "gc_counter", PROP_GC_COUNTER, PROP_FLAGS, 311 }, ! 171: { "gc_last_bytes", PROP_GC_LASTBYTES, PROP_FLAGS, 311 }, ! 172: { "bytes", PROP_BYTES, PROP_FLAGS, 311 }, ! 173: { "max_bytes", PROP_MAXBYTES, JSPROP_ENUMERATE, 311 }, ! 174: #endif ! 175: {0} ! 176: }; ! 177: ! 178: #ifdef _DEBUG ! 179: static char* prop_desc[] = { ! 180: "JavaScript engine version information (AKA system.js_version)" ! 181: ,"set to <i>false</i> to disable the automatic termination of the script upon external request" ! 182: ,"termination has been requested (stop execution as soon as possible)" ! 183: ,"number of branch operations performed in this runtime" ! 184: ,"maximum number of branches, used for infinite-loop detection (0=disabled)" ! 185: ,"interval of periodic time-slice yields (lower number=higher frequency, 0=disabled)" ! 186: ,"interval of periodic garbage collection attempts (lower number=higher frequency, 0=disabled)" ! 187: ,"number of garbage collections attempted in this runtime - <small>READ ONLY</small>" ! 188: #ifdef jscntxt_h___ ! 189: ,"number of garbage collections performed in this runtime - <small>READ ONLY</small>" ! 190: ,"number of heap bytes in use after last garbage collection - <small>READ ONLY</small>" ! 191: ,"number of heap bytes currently in use - <small>READ ONLY</small>" ! 192: ,"maximum number of bytes available for heap" ! 193: #endif ! 194: ,NULL ! 195: }; ! 196: #endif ! 197: ! 198: DLLEXPORT JSBool DLLCALL ! 199: js_CommonBranchCallback(JSContext *cx, js_branch_t* branch) ! 200: { ! 201: branch->counter++; ! 202: ! 203: /* Terminated? */ ! 204: if(branch->auto_terminate && ! 205: (branch->terminated!=NULL && *branch->terminated)) { ! 206: JS_ReportError(cx,"Terminated"); ! 207: branch->counter=0; ! 208: return(JS_FALSE); ! 209: } ! 210: ! 211: /* Infinite loop? */ ! 212: if(branch->limit && branch->counter > branch->limit) { ! 213: JS_ReportError(cx,"Infinite loop (%lu branches) detected",branch->counter); ! 214: branch->counter=0; ! 215: return(JS_FALSE); ! 216: } ! 217: ! 218: /* Give up timeslices every once in a while */ ! 219: if(branch->yield_interval && (branch->counter%branch->yield_interval)==0) ! 220: YIELD(); ! 221: ! 222: /* Periodic Garbage Collection */ ! 223: if(branch->gc_interval && (branch->counter%branch->gc_interval)==0) ! 224: JS_MaybeGC(cx), branch->gc_attempts++; ! 225: ! 226: return(JS_TRUE); ! 227: } ! 228: ! 229: /* Execute a string in its own context (away from Synchronet objects) */ ! 230: static JSBool ! 231: js_eval(JSContext *parent_cx, JSObject *parent_obj, uintN argc, jsval *argv, jsval *rval) ! 232: { ! 233: char* buf; ! 234: JSScript* script; ! 235: JSContext* cx; ! 236: JSObject* obj; ! 237: JSErrorReporter reporter; ! 238: #ifndef EVAL_BRANCH_CALLBACK ! 239: JSBranchCallback callback; ! 240: #endif ! 241: ! 242: *rval=JSVAL_VOID; ! 243: ! 244: if(argc<1) ! 245: return(JS_TRUE); ! 246: ! 247: if((buf=JS_GetStringBytes(JS_ValueToString(parent_cx, argv[0])))==NULL) ! 248: return(JS_FALSE); ! 249: ! 250: if((cx=JS_NewContext(JS_GetRuntime(parent_cx),JAVASCRIPT_CONTEXT_STACK))==NULL) ! 251: return(JS_FALSE); ! 252: ! 253: /* Use the error reporter from the parent context */ ! 254: reporter=JS_SetErrorReporter(parent_cx,NULL); ! 255: JS_SetErrorReporter(parent_cx,reporter); ! 256: JS_SetErrorReporter(cx,reporter); ! 257: ! 258: #ifdef EVAL_BRANCH_CALLBACK ! 259: JS_SetContextPrivate(cx, JS_GetPrivate(parent_cx, parent_obj)); ! 260: JS_SetBranchCallback(cx, js_BranchCallback); ! 261: #else /* Use the branch callback from the parent context */ ! 262: JS_SetContextPrivate(cx, JS_GetContextPrivate(parent_cx)); ! 263: callback=JS_SetBranchCallback(parent_cx,NULL); ! 264: JS_SetBranchCallback(parent_cx, callback); ! 265: JS_SetBranchCallback(cx, callback); ! 266: #endif ! 267: ! 268: if((obj=JS_NewObject(cx, NULL, NULL, NULL))==NULL ! 269: || !JS_InitStandardClasses(cx,obj)) { ! 270: JS_DestroyContext(cx); ! 271: return(JS_FALSE); ! 272: } ! 273: ! 274: if((script=JS_CompileScript(cx, obj, buf, strlen(buf), NULL, 0))!=NULL) { ! 275: JS_ExecuteScript(cx, obj, script, rval); ! 276: JS_DestroyScript(cx, script); ! 277: } ! 278: ! 279: JS_DestroyContext(cx); ! 280: ! 281: return(JS_TRUE); ! 282: } ! 283: ! 284: static JSBool ! 285: js_gc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 286: { ! 287: JSBool forced=JS_TRUE; ! 288: js_branch_t* branch; ! 289: ! 290: if((branch=(js_branch_t*)JS_GetPrivate(cx,obj))==NULL) ! 291: return(JS_FALSE); ! 292: ! 293: *rval=JSVAL_VOID; ! 294: ! 295: if(argc) ! 296: JS_ValueToBoolean(cx,argv[0],&forced); ! 297: ! 298: if(forced) ! 299: JS_GC(cx); ! 300: else ! 301: JS_MaybeGC(cx); ! 302: ! 303: branch->gc_attempts++; ! 304: ! 305: return(JS_TRUE); ! 306: } ! 307: ! 308: ! 309: static JSClass js_internal_class = { ! 310: "JsInternal" /* name */ ! 311: ,JSCLASS_HAS_PRIVATE /* flags */ ! 312: ,JS_PropertyStub /* addProperty */ ! 313: ,JS_PropertyStub /* delProperty */ ! 314: ,js_get /* getProperty */ ! 315: ,js_set /* setProperty */ ! 316: ,JS_EnumerateStub /* enumerate */ ! 317: ,JS_ResolveStub /* resolve */ ! 318: ,JS_ConvertStub /* convert */ ! 319: ,JS_FinalizeStub /* finalize */ ! 320: }; ! 321: ! 322: static jsSyncMethodSpec js_functions[] = { ! 323: {"eval", js_eval, 0, JSTYPE_UNDEF, JSDOCSTR("string script") ! 324: ,JSDOCSTR("evaluate a JavaScript string in its own (secure) context, returning the result") ! 325: ,311 ! 326: }, ! 327: {"gc", js_gc, 0, JSTYPE_VOID, JSDOCSTR("bool forced") ! 328: ,JSDOCSTR("perform a garbage collection operation (freeing memory for unused allocated objects), " ! 329: "if <i>forced</i> is <i>true</i> (the default) a garbage collection is always performed, " ! 330: "otherwise it is only performed if deemed appropriate by the JavaScript engine") ! 331: ,311 ! 332: }, ! 333: {0} ! 334: }; ! 335: ! 336: JSObject* DLLCALL js_CreateInternalJsObject(JSContext* cx, JSObject* parent, js_branch_t* branch) ! 337: { ! 338: JSObject* obj; ! 339: ! 340: if((obj = JS_DefineObject(cx, parent, "js", &js_internal_class, NULL ! 341: ,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL) ! 342: return(NULL); ! 343: ! 344: if(!JS_SetPrivate(cx, obj, branch)) /* Store a pointer to js_branch_t */ ! 345: return(NULL); ! 346: ! 347: if(!js_DefineSyncProperties(cx, obj, js_properties)) /* expose them */ ! 348: return(NULL); ! 349: ! 350: if(!js_DefineSyncMethods(cx, obj, js_functions, /* append? */ FALSE)) ! 351: return(NULL); ! 352: ! 353: #ifdef _DEBUG ! 354: js_DescribeSyncObject(cx,obj,"JavaScript execution and garbage collection control object",311); ! 355: js_CreateArrayOfStrings(cx, obj, "_property_desc_list", prop_desc, JSPROP_READONLY); ! 356: #endif ! 357: ! 358: return(obj); ! 359: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.