2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "NGJavaScriptContext.h"
24 #include "NGJavaScriptRuntime.h"
25 #include "NGJavaScriptObject.h"
26 #include "NGJavaScriptFunction.h"
27 #include "NGJavaScriptObjectHandler.h"
28 #include "NGJavaScriptError.h"
29 #include "NSString+JS.h"
33 @interface NGJavaScriptContext(PrivateMethods)
38 Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
40 @implementation NGJavaScriptContext
42 static BOOL abortOnJSError = NO;
43 static BOOL debugDealloc = NO;
44 NSMapTable *jsctxToObjC = NULL;
47 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
49 abortOnJSError = [ud boolForKey:@"JSAbortOnError"];
50 debugDealloc = [ud boolForKey:@"JSDebugContextDealloc"];
53 static JSFunctionSpec functions[] = {
59 static void jsErrorReporter(JSContext *cx, const char *msg, JSErrorReport *rp);
60 static JSBool jsGCCallback(JSContext *cx, JSGCStatus status)
61 __attribute__((unused));
64 static JSBool global_resolve(JSContext *cx, JSObject *obj, jsval _id)
65 __attribute__((unused));
66 static JSBool global_resolve(JSContext *cx, JSObject *obj, jsval _id) {
67 NGJavaScriptContext *self;
69 self = NSMapGet(jsctxToObjC, cx);
71 NSLog(@"resolve called on %@.", self);
72 return JS_ResolveStub(cx, obj, _id);
75 + (NGJavaScriptContext *)jsContextForHandle:(void *)_handle {
76 NGJavaScriptContext *ctx;
78 ctx = NSMapGet(jsctxToObjC, _handle);
82 - (id)initWithRuntime:(NGJavaScriptRuntime *)_rt
83 maximumStackSize:(unsigned)_size
85 self->handle = JS_NewContext([_rt handle], _size ? _size : 8192);
86 if (self->handle == NULL) {
87 NSLog(@"WARNING(%s): got no handle !", __PRETTY_FUNCTION__);
92 if (jsctxToObjC == NULL) {
93 jsctxToObjC = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
94 NSNonRetainedObjectMapValueCallBacks,
97 NSMapInsert(jsctxToObjC, self->handle, self);
98 JS_SetErrorReporter(self->handle, jsErrorReporter);
100 // JSSetGCCallback(self->handle, jsGCCallback);
103 /* setup initial global */
105 NGJavaScriptObject *oglob;
107 oglob = [[NGJavaScriptObject alloc] initWithJSContext:self];
114 [oglob release]; oglob = nil;
118 ASSIGN(self->rt, _rt);
122 - (id)initWithRuntime:(NGJavaScriptRuntime *)_rt {
123 return [self initWithRuntime:_rt maximumStackSize:0];
126 return [self initWithRuntime:[NGJavaScriptRuntime standardJavaScriptRuntime]
131 if (debugDealloc) NSLog(@"dealloc context: %@", self);
133 [self collectGarbage];
136 JS_DestroyContext(self->handle);
137 NSMapRemove(jsctxToObjC, self->handle);
143 if (debugDealloc) NSLog(@"did dealloc context: 0x%08X", self);
146 - (BOOL)loadStandardClasses {
149 if ((glob = JS_GetGlobalObject(self->handle)) == NULL) {
150 NSLog(@"NGJavaScriptContext: no global object set ..");
154 //NSLog(@"NGJavaScriptContext: loading std classes ..");
156 if (!JS_InitStandardClasses(self->handle, glob)) {
157 NSLog(@"NGJavaScriptContext: could not init standard classes ...");
160 if (!JS_DefineFunctions(self->handle, glob, functions)) {
161 NSLog(@"NGJavaScriptContext: could not define global funcs ...");
174 - (NGJavaScriptRuntime *)runtime {
179 return JS_IsRunning(self->handle) ? YES : NO;
182 - (BOOL)isConstructing {
183 return JS_IsConstructing(self->handle) ? YES : NO;
186 - (void)setJavaScriptVersion:(int)_version {
187 JS_SetVersion(self->handle, _version);
189 - (int)javaScriptVersion {
190 return JS_GetVersion(self->handle);
197 NGJavaScriptObjectHandler *oglobal;
199 global = JS_GetGlobalObject(self->handle);
200 NSAssert(global, @"missing global object !");
202 if ((oglobal = JS_GetPrivate(self->handle, global)) == nil)
205 return [[oglobal retain] autorelease];
210 - (id)evaluateScript:(NSString *)_script {
211 return [[self globalObject] evaluateScript:_script];
216 - (id)callFunctionNamed:(NSString *)_funcName, ... {
217 return [[self globalObject] callFunctionNamed:_funcName, nil];
222 - (void)reportException:(NSException *)_exc {
223 JS_ReportError(self->handle, "%s", [[_exc description] cString]);
226 - (void)reportError:(NSString *)_fmt, ... {
232 #if NG_VARARGS_AS_REFERENCE /* in common.h */
233 s = [[[NSString alloc] initWithFormat:_fmt arguments:va] autorelease];
235 s = [NSString stringWithFormat:_fmt arguments:&va];
239 JS_ReportError(self->handle, "%s", [s cString]);
242 - (void)reportOutOfMemory {
243 JS_ReportOutOfMemory(self->handle);
246 - (void)logReportedJavaScriptError:(NGJavaScriptError *)_error {
247 NSLog(@"JS ERROR(%@:%d): %@", [_error path], [_error line], [_error reason]);
248 if (abortOnJSError) abort();
251 - (void)reportError:(NSString *)_msg
252 inFile:(NSString *)_path inLine:(unsigned)_line
253 report:(void *)_report
255 NGJavaScriptError *e;
257 e = [[NGJavaScriptError alloc] initWithErrorReport:_report message:_msg context:self];
259 [self logReportedJavaScriptError:e];
260 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AbortOnJSError"])
263 ASSIGN(self->lastError, e);
265 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"RaiseOnJSError"])
266 [self->lastError raise];
269 - (NSException *)lastError {
270 return self->lastError;
272 - (void)clearLastError {
273 [self->lastError release]; self->lastError = nil;
276 /* garbage collector */
278 - (void)collectGarbage {
281 - (void)maybeCollectGarbage {
282 JS_MaybeGC(self->handle);
285 - (void *)malloc:(unsigned)_size {
286 return JS_malloc(self->handle, _size);
288 - (void *)realloc:(void *)_pointer size:(unsigned)_size {
289 return JS_realloc(self->handle, _pointer, _size);
291 - (void)freePointer:(void *)_pointer {
292 JS_free(self->handle, _pointer);
295 - (BOOL)addRootPointer:(void *)_root {
296 return JS_AddRoot(self->handle, _root) ? YES : NO;
298 - (BOOL)addRootPointer:(void *)_root name:(NSString *)_name {
299 return JS_AddNamedRoot(self->handle, _root, [_name cString]) ? YES : NO;
301 - (BOOL)removeRootPointer:(void *)_root {
302 return JS_RemoveRoot(self->handle, _root) ? YES : NO;
305 - (BOOL)lockGCThing:(void *)_ptr {
306 return JS_LockGCThing(self->handle, _ptr) ? YES : NO;
308 - (BOOL)unlockGCThing:(void *)_ptr {
309 return JS_UnlockGCThing(self->handle, _ptr) ? YES : NO;
312 - (BOOL)beginGarbageCollection {
315 - (BOOL)endGarbageCollection {
322 - (void)beginRequest {
323 JS_BeginRequest(self->handle);
326 JS_EndRequest(self->handle);
328 - (void)suspendRequest {
329 JS_SuspendRequest(self->handle);
331 - (void)resumeRequest {
332 JS_ResumeRequest(self->handle);
335 - (void)beginRequest {
336 #if LIB_FOUNDATION_LIBRARY
337 [self notImplemented:_cmd];
339 [self doesNotRecognizeSelector:_cmd];
343 #if LIB_FOUNDATION_LIBRARY
344 [self notImplemented:_cmd];
346 [self doesNotRecognizeSelector:_cmd];
349 - (void)suspendRequest {
350 #if LIB_FOUNDATION_LIBRARY
351 [self notImplemented:_cmd];
353 [self doesNotRecognizeSelector:_cmd];
356 - (void)resumeRequest {
357 #if LIB_FOUNDATION_LIBRARY
358 [self notImplemented:_cmd];
360 [self doesNotRecognizeSelector:_cmd];
367 - (NSString *)description {
368 return [NSString stringWithFormat:
369 @"<%@[0x%08X]: %@%@handle=0x%08X version=%i runtime=%@>",
370 NSStringFromClass([self class]), self,
371 [self isRunning] ? @"running " : @"",
372 [self isConstructing] ? @"constructing " : @"",
374 [self javaScriptVersion],
380 static void jsErrorReporter(JSContext *cx, const char *msg, JSErrorReport *rp) {
381 NGJavaScriptContext *self;
383 self = NSMapGet(jsctxToObjC, cx);
386 fprintf(stderr, "ERROR(missing ObjC object): %s\n", msg);
389 [self reportError:msg?[NSString stringWithCString:msg]:@"unknown JavaScript error"
390 inFile:rp->filename?[NSString stringWithCString:rp->filename]:@""
395 static JSBool jsGCCallback(JSContext *cx, JSGCStatus status) {
396 NGJavaScriptContext *self;
398 self = NSMapGet(jsctxToObjC, cx);
400 return (status == JSGC_BEGIN)
401 ? ([self beginGarbageCollection] ? JSVAL_TRUE : JSVAL_FALSE)
402 : ([self endGarbageCollection] ? JSVAL_TRUE : JSVAL_FALSE);
405 @end /* NGJavaScriptContext */
408 Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
413 for (i = n = 0; i < argc; i++) {
414 str = JS_ValueToString(cx, argv[i]);
417 fprintf(stdout, "%s%s", i ? " " : "", JS_GetStringBytes(str));