static JSBool NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval) { jsval vec[2]; JSTempValueRooter tvr; JSObject *aobj; vec[0] = ID_TO_VALUE(key); vec[1] = val; JS_PUSH_TEMP_ROOT(cx, 2, vec, &tvr); aobj = js_NewArrayObject(cx, 2, vec); *rval = OBJECT_TO_JSVAL(aobj); JS_POP_TEMP_ROOT(cx, &tvr); return aobj != NULL; }
/* * Return a string that may eval to something similar to the original object. */ static JSBool exn_toSource(JSContext *cx, uintN argc, jsval *vp) { JSObject *obj; JSString *name, *message, *filename, *lineno_as_str, *result; jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; JSTempValueRooter tvr; JSBool ok; uint32 lineno; size_t lineno_length, name_length, message_length, filename_length, length; jschar *chars, *cp; obj = JS_THIS_OBJECT(cx, vp); if (!obj || !OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp)) { return JS_FALSE; } name = js_ValueToString(cx, *vp); if (!name) return JS_FALSE; *vp = STRING_TO_JSVAL(name); /* After this, control must flow through label out: to exit. */ JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr); #ifdef __GNUC__ message = filename = NULL; #endif ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) && (message = js_ValueToSource(cx, localroots[0])); if (!ok) goto out; localroots[0] = STRING_TO_JSVAL(message); ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) && (filename = js_ValueToSource(cx, localroots[1])); if (!ok) goto out; localroots[1] = STRING_TO_JSVAL(filename); ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]); if (!ok) goto out; lineno = js_ValueToECMAUint32 (cx, &localroots[2]); ok = !JSVAL_IS_NULL(localroots[2]); if (!ok) goto out; if (lineno != 0) { lineno_as_str = js_ValueToString(cx, localroots[2]); if (!lineno_as_str) { ok = JS_FALSE; goto out; } lineno_length = JSSTRING_LENGTH(lineno_as_str); } else { lineno_as_str = NULL; lineno_length = 0; } /* Magic 8, for the characters in ``(new ())''. */ name_length = JSSTRING_LENGTH(name); message_length = JSSTRING_LENGTH(message); length = 8 + name_length + message_length; filename_length = JSSTRING_LENGTH(filename); if (filename_length != 0) { /* append filename as ``, {filename}'' */ length += 2 + filename_length; if (lineno_as_str) { /* append lineno as ``, {lineno_as_str}'' */ length += 2 + lineno_length; } } else { if (lineno_as_str) { /* * no filename, but have line number, * need to append ``, "", {lineno_as_str}'' */ length += 6 + lineno_length; } } cp = chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar)); if (!chars) { ok = JS_FALSE; goto out; } *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; js_strncpy(cp, JSSTRING_CHARS(name), name_length); cp += name_length; *cp++ = '('; if (message_length != 0) { js_strncpy(cp, JSSTRING_CHARS(message), message_length); cp += message_length; } if (filename_length != 0) { /* append filename as ``, {filename}'' */ *cp++ = ','; *cp++ = ' '; js_strncpy(cp, JSSTRING_CHARS(filename), filename_length); cp += filename_length; } else { if (lineno_as_str) { /* * no filename, but have line number, * need to append ``, "", {lineno_as_str}'' */ *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; } } if (lineno_as_str) { /* append lineno as ``, {lineno_as_str}'' */ *cp++ = ','; *cp++ = ' '; js_strncpy(cp, JSSTRING_CHARS(lineno_as_str), lineno_length); cp += lineno_length; } *cp++ = ')'; *cp++ = ')'; *cp = 0; result = js_NewString(cx, chars, length); if (!result) { JS_free(cx, chars); ok = JS_FALSE; goto out; } *vp = STRING_TO_JSVAL(result); ok = JS_TRUE; out: JS_POP_TEMP_ROOT(cx, &tvr); return ok; }
JSBool js_ReportUncaughtException(JSContext *cx) { jsval exn; JSObject *exnObject; jsval roots[5]; JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; const char *bytes; JSBool ok; if (!JS_IsExceptionPending(cx)) return JS_TRUE; if (!JS_GetPendingException(cx, &exn)) return JS_FALSE; memset(roots, 0, sizeof roots); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); /* * Because js_ValueToString below could error and an exception object * could become unrooted, we must root exnObject. Later, if exnObject is * non-null, we need to root other intermediates, so allocate an operand * stack segment to protect all of these values. */ if (JSVAL_IS_PRIMITIVE(exn)) { exnObject = NULL; } else { exnObject = JSVAL_TO_OBJECT(exn); roots[0] = exn; } JS_ClearPendingException(cx); reportp = js_ErrorFromException(cx, exn); /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ str = js_ValueToString(cx, exn); if (!str) { bytes = "unknown (can't convert to string)"; } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_TRUE; if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { const char *filename; uint32 lineno; ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); if (!ok) goto out; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); if (!ok) goto out; str = js_ValueToString(cx, roots[3]); if (!str) { ok = JS_FALSE; goto out; } filename = StringToFilename(cx, str); if (!filename) { ok = JS_FALSE; goto out; } ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); if (!ok) goto out; lineno = js_ValueToECMAUint32 (cx, &roots[4]); ok = !JSVAL_IS_NULL(roots[4]); if (!ok) goto out; reportp = &report; memset(&report, 0, sizeof report); report.filename = filename; report.lineno = (uintN) lineno; } if (!reportp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNCAUGHT_EXCEPTION, bytes); } else { /* Flag the error as an exception. */ reportp->flags |= JSREPORT_EXCEPTION; /* Pass the exception object. */ JS_SetPendingException(cx, exn); js_ReportErrorAgain(cx, bytes, reportp); JS_ClearPendingException(cx); } out: JS_POP_TEMP_ROOT(cx, &tvr); return ok; }
JSBool js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp) { JSErrNum errorNumber; const JSErrorFormatString *errorString; JSExnType exn; jsval tv[4]; JSTempValueRooter tvr; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; /* * Tell our caller to report immediately if cx has no active frames, or if * this report is just a warning. */ JS_ASSERT(reportp); if (!cx->fp || JSREPORT_IS_WARNING(reportp->flags)) return JS_FALSE; /* Find the exception index associated with this error. */ errorNumber = (JSErrNum) reportp->errorNumber; errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber); exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE; JS_ASSERT(exn < JSEXN_LIMIT); #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) /* Print the error name and the associated exception name to stderr */ fprintf(stderr, "%s\t%s\n", errortoexnname[errorNumber].name, errortoexnname[errorNumber].exception); #endif /* * Return false (no exception raised) if no exception is associated * with the given error number. */ if (exn == JSEXN_NONE) return JS_FALSE; /* * Prevent runaway recursion, via cx->generatingError. If an out-of-memory * error occurs, no exception object will be created, but we don't assume * that OOM is the only kind of error that subroutines of this function * called below might raise. */ if (cx->generatingError) return JS_FALSE; /* After this point the control must flow through the label out. */ cx->generatingError = JS_TRUE; /* Protect the newly-created strings below from nesting GCs. */ memset(tv, 0, sizeof tv); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); /* * Try to get an appropriate prototype by looking up the corresponding * exception constructor name in the scope chain of the current context's * top stack frame, or in the global object if no frame is active. */ ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(exceptions[exn].key), &errProto); if (!ok) goto out; tv[0] = OBJECT_TO_JSVAL(errProto); errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL, 0); if (!errObject) { ok = JS_FALSE; goto out; } tv[1] = OBJECT_TO_JSVAL(errObject); messageStr = JS_NewStringCopyZ(cx, message); if (!messageStr) { ok = JS_FALSE; goto out; } tv[2] = STRING_TO_JSVAL(messageStr); filenameStr = JS_NewStringCopyZ(cx, reportp->filename); if (!filenameStr) { ok = JS_FALSE; goto out; } tv[3] = STRING_TO_JSVAL(filenameStr); ok = InitExnPrivate(cx, errObject, messageStr, filenameStr, reportp->lineno, reportp); if (!ok) goto out; JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); /* Flag the error report passed in to indicate an exception was raised. */ reportp->flags |= JSREPORT_EXCEPTION; out: JS_POP_TEMP_ROOT(cx, &tvr); cx->generatingError = JS_FALSE; return ok; }
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { CxObj *cxobj = (CxObj*)GetWindowLong(hWnd, GWL_USERDATA); if ( cxobj == NULL ) return DefWindowProc(hWnd, message, wParam, lParam); JSContext *cx = cxobj->cx; JS::RootedObject obj(cx, cxobj->obj); jsval rval; jsval functionVal; LRESULT returnValue = 0; switch (message) { //case WM_COMMAND: //case WM_PAINT case WM_DESTROY: PostQuitMessage(0); return 0; case WM_CHAR: JS_GetProperty(cx, obj, "onchar", &functionVal); if ( !functionVal.isUndefined() ) { JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) char c = wParam; jsval argv[] = { STRING_TO_JSVAL(JS_NewStringCopyN(cx, &c, 1)), INT_TO_JSVAL(lParam) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // needed to protect the new string bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; case WM_KEYUP: JS_GetProperty(cx, obj, "onkeyup", &functionVal); if ( !functionVal.isUndefined() ) { JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) jsval argv[] = { INT_TO_JSVAL(wParam), INT_TO_JSVAL(lParam) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; case WM_KEYDOWN: JS_GetProperty(cx, obj, "onkeydown", &functionVal); if ( !functionVal.isUndefined() ) { JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) jsval argv[] = { INT_TO_JSVAL(wParam), INT_TO_JSVAL(lParam) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; case WM_ACTIVATE: JS_GetProperty(cx, obj, "onactivate", &functionVal); if ( !functionVal.isUndefined() ) { JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) jsval argv[] = { BOOLEAN_TO_JSVAL(wParam != WA_INACTIVE) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; // case WM_SIZING: case WM_SIZE: JS_GetProperty(cx, obj, "onsize", &functionVal); if ( !functionVal.isUndefined() ) { JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) jsval argv[] = { INT_TO_JSVAL((short)LOWORD(lParam)), INT_TO_JSVAL((short)HIWORD(lParam)) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; case WM_MOUSEMOVE: JS_GetProperty(cx, obj, "onmousemove", &functionVal); if ( !functionVal.isUndefined() ) { JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) jsval argv[] = { INT_TO_JSVAL(MAKEPOINTS(lParam).x), INT_TO_JSVAL(MAKEPOINTS(lParam).y), BOOLEAN_TO_JSVAL(wParam & MK_LBUTTON), BOOLEAN_TO_JSVAL(wParam & MK_RBUTTON), BOOLEAN_TO_JSVAL(wParam & MK_MBUTTON) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; case WM_MOUSEWHEEL: JS_GetProperty(cx, obj, "onmousewheel", &functionVal); if ( !functionVal.isUndefined() ) { JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) jsval argv[] = { INT_TO_JSVAL( GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA ), BOOLEAN_TO_JSVAL(wParam & MK_LBUTTON), BOOLEAN_TO_JSVAL(wParam & MK_RBUTTON), BOOLEAN_TO_JSVAL(wParam & MK_MBUTTON) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: JS_GetProperty(cx, obj, "onmousedown", &functionVal); if ( !functionVal.isUndefined() ) { // xPos = GET_X_LPARAM(lParam); // yPos = GET_Y_LPARAM(lParam); JL_ASSERT_FUNCTION(functionVal); // (TBD) return value of assert is not compatible with this function (WndProc) jsval argv[] = { INT_TO_JSVAL( message==WM_LBUTTONDOWN ? 1 : message==WM_RBUTTONDOWN ? 2 : message==WM_MBUTTONDOWN ? 3 : 0 ), JSVAL_TRUE }; // BOOLEAN_TO_JSVAL(wParam & MK_LBUTTON), // BOOLEAN_TO_JSVAL(wParam & MK_RBUTTON), // BOOLEAN_TO_JSVAL(wParam & MK_MBUTTON) }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: JS_GetProperty(cx, obj, "onmouseup", &functionVal); if ( !functionVal.isUndefined() ) { // xPos = GET_X_LPARAM(lParam); // yPos = GET_Y_LPARAM(lParam); JL_ASSERT( JS_TypeOfValue( cx, functionVal ) == JSTYPE_FUNCTION, "Need a function." ); jsval argv[] = { INT_TO_JSVAL( message==WM_LBUTTONUP ? 1 : message==WM_RBUTTONUP ? 2 : message==WM_MBUTTONUP ? 3 : 0 ), JSVAL_FALSE }; JSTempValueRooter tvr; JS_PUSH_TEMP_ROOT(cx, COUNTOF(argv), argv, &tvr); // not really needed bool status = JS_CallFunctionValue(cx, obj, functionVal, COUNTOF(argv), argv, &rval); JS_POP_TEMP_ROOT(cx, &tvr); JL_CHK( status ); return 0; } break; //case WM_MOUSELEAVE: // need TrackMouseEvent() ... // JS_GetProperty(cx, obj, "onmouseleave", &functionVal); // if ( !JSVAL_IS_VOID( functionVal ) ) { // JS_CallFunctionValue(cx, obj, functionVal, 0, NULL, &rval); // } // break; } return DefWindowProc(hWnd, message, wParam, lParam); // We do not want to handle this message so pass back to Windows to handle it in a default way }
js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) { JSObject *obj; JSTempValueRooter tvr; JSAtom *atom; JSClass *clasp; JSExtendedClass *xclasp; JSBool ok; JSObject *iterobj; jsval arg; JS_ASSERT(!(flags & ~(JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE))); /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH)); /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(*vp)) { obj = JSVAL_TO_OBJECT(*vp); } else { /* * Enumerating over null and undefined gives an empty enumerator. * This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of * the first production in 12.6.4 and step 4 of the second production, * but it's "web JS" compatible. */ if ((flags & JSITER_ENUMERATE)) { if (!js_ValueToObject(cx, *vp, &obj)) return JS_FALSE; if (!obj) goto default_iter; } else { obj = js_ValueToNonNullObject(cx, *vp); if (!obj) return JS_FALSE; } } JS_ASSERT(obj); JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); clasp = OBJ_GET_CLASS(cx, obj); if ((clasp->flags & JSCLASS_IS_EXTENDED) && (xclasp = (JSExtendedClass *) clasp)->iteratorObject) { iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) goto bad; *vp = OBJECT_TO_JSVAL(iterobj); } else { atom = cx->runtime->atomState.iteratorAtom; #if JS_HAS_XML_SUPPORT if (OBJECT_IS_XML(cx, obj)) { if (!js_GetXMLFunction(cx, obj, ATOM_TO_JSID(atom), vp)) goto bad; } else #endif { if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp)) goto bad; } if (JSVAL_IS_VOID(*vp)) { default_iter: /* * Fail over to the default enumerating native iterator. * * Create iterobj with a NULL parent to ensure that we use the * correct scope chain to lookup the iterator's constructor. Since * we use the parent slot to keep track of the iterable, we must * fix it up after. */ iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL, 0); if (!iterobj) goto bad; /* Store in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); if (!InitNativeIterator(cx, iterobj, obj, flags)) goto bad; } else { arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, vp)) { goto bad; } if (JSVAL_IS_PRIMITIVE(*vp)) { const char *printable = js_AtomToPrintableString(cx, atom); if (printable) { js_ReportValueError2(cx, JSMSG_BAD_ITERATOR_RETURN, JSDVG_SEARCH_STACK, *vp, NULL, printable); } goto bad; } } } ok = JS_TRUE; out: if (obj) JS_POP_TEMP_ROOT(cx, &tvr); return ok; bad: ok = JS_FALSE; goto out; }