Last active
December 23, 2015 07:09
-
-
Save ruby0x1/6598945 to your computer and use it in GitHub Desktop.
My SpiderMonkey helper code from my engine.
This is under MIT license.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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