Skip to content

Instantly share code, notes, and snippets.

@ruby0x1
Last active December 23, 2015 07:09
Show Gist options
  • Save ruby0x1/6598945 to your computer and use it in GitHub Desktop.
Save ruby0x1/6598945 to your computer and use it in GitHub Desktop.
My SpiderMonkey helper code from my engine. This is under MIT license.
//General crap from startup and shutdown
void startup(void) {
//Create the objects we need to execute js in spidermonkey
spiderRuntime = JS_NewRuntime(0x100000);
spiderContext = JS_NewContext(spiderRuntime, 0x1000);
//for reference,
// extern JSRuntime *spiderRuntime;
// extern JSContext *spiderContext;
// extern JSObject *spiderGlobal;
//make spidermonkey threadsafe
JS_BeginRequest(spiderContext);
//create the global objects
spiderGlobal = JS_NewObject(spiderContext, &spiderGlobalClass, NULL, NULL);//JS_NewCompartmentAndGlobalObject(spiderContext, &spiderGlobalClass, NULL);
JS_SetGlobalObject(spiderContext, spiderGlobal);
//init the global object and contexts
JS_InitStandardClasses(spiderContext, spiderGlobal);
JS_SetErrorReporter(spiderContext, spiderErrorReporter);
//use this to debug GC crashes, 1 is moderate 2 is agressive. Then you get a callstack closer to the error
// JS_SetGCZeal(spiderContext, 1);
};
void shutdown(void) {
JS_EndRequest(spiderContext);
JS_DestroyContext(spiderContext);
};
// Running a script in the default context
bool spiderExecuteString( std::string &src, std::string &name, bool printresult, bool reporterrors ) {
//Execute the script and get the results
jsval returnVal; JSBool success;
success = JS_EvaluateScript( spiderContext, spiderGlobal, src.c_str(), strlen(src.c_str()), name.c_str() , 1, &returnVal);
if(success) {
if(printresult) {
std::string rs;
FromJSVal( spiderContext, returnVal, rs );
CORE->debug->log(rs);
}
return true;
} else {
return false;
}
return false;
}
`
template<typename T> jsval ToJSVal(JSContext* cx, T const& val);
template<typename T> bool FromJSVal(JSContext* cx, jsval val, T& ret);
//Template converters above handle a bunch of normal stuff, but more can be added...
// usage is shown above a bit,
// to get a string value,
/*
std::string stringval;
FromJSVal( context, js_string_val_from_SM , stringval );
stringval is now filled with the string, etc
jsval str = ToJSVal( context, std::string )
jsval dbl = ToJSVal( context, double ) etc
*/
#define FAIL(msg) JS_ReportError(spiderContext, msg); return false;
// Implicit type conversions often hide bugs, so warn about them
#define WARN_IF_NOT(c, v) if (!(c)) { /*JS_ReportWarning(cx, "Script value conversion check //FAILed: %s (got type %s)", #c, JS_GetTypeName(cx, JS_TypeOfValue(cx, v)));*/ }
template<> bool FromJSVal<bool>(JSContext* cx, jsval v, bool& out)
{
JSBool ret;
WARN_IF_NOT(JSVAL_IS_BOOLEAN(v), v);
if (!JS_ValueToBoolean(cx, v, &ret))
return false;
out = (ret ? true : false);
return true;
}
template<> bool FromJSVal<float>(JSContext* cx, jsval v, float& out)
{
jsdouble ret;
WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
if (!JS_ValueToNumber(cx, v, &ret))
return false;
out = ret;
return true;
}
template<> bool FromJSVal<double>(JSContext* cx, jsval v, double& out)
{
jsdouble ret;
WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
if (!JS_ValueToNumber(cx, v, &ret))
return false;
out = ret;
return true;
}
template<> bool FromJSVal<int>(JSContext* cx, jsval v, int& out)
{
int32 ret;
WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
if (!JS_ValueToECMAInt32(cx, v, &ret))
return false;
out = ret;
return true;
}
template<> bool FromJSVal<std::wstring>(JSContext* cx, jsval v, std::wstring& out)
{
WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions
JSString* ret = JS_ValueToString(cx, v);
if (!ret) {
FAIL("Argument must be convertible to a string");
}
const jschar* ch = JS_GetStringCharsZ(Core::Script::spiderContext, ret);
out = std::wstring(ch, ch + JS_GetStringLength(ret));
return true;
}
template<> bool FromJSVal<std::string>(JSContext* cx, jsval v, std::string& out)
{
WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions
JSString* ret = JS_ValueToString(cx, v);
if (!ret) {
FAIL("Argument must be convertible to a string");
}
char* ch = JS_EncodeString(cx, ret); // chops off high byte of each jschar
if (!ch) {
FAIL("JS_EncodeString FAILed"); // out of memory
}
out = std::string(ch, ch + JS_GetStringLength(ret));
JS_free(cx, ch);
return true;
}
template<> jsval ToJSVal<bool>(JSContext* cx, const bool& val)
{
return val ? JSVAL_TRUE : JSVAL_FALSE;
}
template<> jsval ToJSVal<float>(JSContext* cx, const float& val)
{
jsval rval = JSVAL_VOID;
JS_NewNumberValue(cx, val, &rval); // ignore return value
return rval;
}
template<> jsval ToJSVal<double>(JSContext* cx, const double& val)
{
jsval rval = JSVAL_VOID;
JS_NewNumberValue(cx, val, &rval); // ignore return value
return rval;
}
template<> jsval ToJSVal<int>(JSContext* cx, const int& val)
{
jsval rval = JSVAL_VOID;
JS_NewNumberValue(cx, val, &rval); // ignore return value
return rval;
}
template<> jsval ToJSVal<std::wstring>(JSContext* cx, const std::wstring& val)
{
std::string utf16(val.begin(), val.end());
JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast<const jschar*> (utf16.c_str()), utf16.length());
if (str)
return STRING_TO_JSVAL(str);
return JSVAL_VOID;
}
template<> jsval ToJSVal<std::string>(JSContext* cx, const std::string& val)
{
JSString* str = JS_NewStringCopyN(cx, val.c_str(), val.length());
if (str)
return STRING_TO_JSVAL(str);
return JSVAL_VOID;
}
template<> jsval ToJSVal<const wchar_t*>(JSContext* cx, const wchar_t* const& val)
{
return ToJSVal(cx, std::wstring(val));
}
template<> jsval ToJSVal<const char*>(JSContext* cx, const char* const& val)
{
JSString* str = JS_NewStringCopyZ(cx, val);
if (str)
return STRING_TO_JSVAL(str);
return JSVAL_VOID;
}
template<typename T> static jsval ToJSVal_vector(JSContext* cx, const std::vector<T>& val)
{
JSObject* obj = JS_NewArrayObject(cx, 0, NULL);
if (!obj)
return JSVAL_VOID;
for (size_t i = 0; i < val.size(); ++i)
{
jsval el = ToJSVal<T>(cx, val[i]);
JS_SetElement(cx, obj, (jsint)i, &el);
}
return OBJECT_TO_JSVAL(obj);
}
template<typename T> static bool FromJSVal_vector(JSContext* cx, jsval v, std::vector<T>& out)
{
JSObject* obj;
if (!JS_ValueToObject(cx, v, &obj) || obj == NULL || !(JS_IsArrayObject(cx, obj) /*|| js_IsTypedArray(obj)*/)) {
//FAIL("Argument must be an array");
}
jsuint length;
if (!JS_GetArrayLength(cx, obj, &length)) {
//FAIL("//FAILed to get array length");
}
out.reserve(length);
for (jsuint i = 0; i < length; ++i)
{
jsval el;
if (!JS_GetElement(cx, obj, i, &el)) {
//FAIL("//FAILed to read array element");
}
T el2;
if (!FromJSVal<T>(cx, el, el2))
return false;
out.push_back(el2);
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment