Ticket #1886: SpiderMonkeyESR24_v0.11.diff
File SpiderMonkeyESR24_v0.11.diff, 184.6 KB (added by , 10 years ago) |
---|
-
build/premake/extern_libs4.lua
Kann nicht anzeigen: Dateityp ist als binär angegeben. svn:mime-type = application/octet-stream Kann nicht anzeigen: Dateityp ist als binär angegeben. svn:mime-type = application/octet-stream
562 562 }, 563 563 spidermonkey = { 564 564 compile_settings = function() 565 if _OPTIONS["with-system-mozjs185"] then 566 if not _OPTIONS["android"] then 567 pkgconfig_cflags("mozjs185") 568 end 569 defines { "WITH_SYSTEM_MOZJS185" } 565 if _OPTIONS["with-system-mozjs24"] then 566 -- to be implemented when such system packages exist 567 --if not _OPTIONS["android"] then 568 -- pkgconfig_cflags("mozjs24") 569 --end 570 --defines { "WITH_SYSTEM_MOZJS24" } 570 571 else 571 572 if os.is("windows") then 572 573 include_dir = "include-win32" 573 574 elseif os.is("macosx") then 574 include_dir = "include "575 include_dir = "include-unix" 575 576 else 576 577 include_dir = "include-unix" 577 578 end 578 579 configuration "Debug" 579 includedirs { libraries_source_dir.."spidermonkey/"..include_dir } 580 includedirs { libraries_source_dir.."spidermonkey/"..include_dir.."-debug" } 581 defines { "DEBUG" } 580 582 configuration "Release" 581 includedirs { libraries_source_dir.."spidermonkey/"..include_dir }583 includedirs { libraries_source_dir.."spidermonkey/"..include_dir.."-release" } 582 584 configuration { } 583 585 end 584 586 end, 585 587 link_settings = function() 586 if _OPTIONS["with-system-mozjs185"] then 587 if _OPTIONS["android"] then 588 links { "mozjs185-1.0" } 589 else 590 pkgconfig_libs("mozjs185") 591 end 588 if _OPTIONS["with-system-mozjs24"] then 589 -- to be implemented when such system packages exist 590 --if _OPTIONS["android"] then 591 -- links { "mozjs185-1.0" } 592 --else 593 -- pkgconfig_libs("mozjs185") 594 --end 592 595 else 593 596 configuration "Debug" 594 links { "mozjs 185-ps-debug" }597 links { "mozjs24-ps-debug" } 595 598 configuration "Release" 596 links { "mozjs 185-ps-release" }599 links { "mozjs24-ps-release" } 597 600 configuration { } 598 601 add_source_lib_paths("spidermonkey") 599 602 end -
build/premake/premake4.lua
15 15 newoption { trigger = "with-system-nvtt", description = "Search standard paths for nvidia-texture-tools library, instead of using bundled copy" } 16 16 newoption { trigger = "with-system-enet", description = "Search standard paths for libenet, instead of using bundled copy" } 17 17 newoption { trigger = "with-system-miniupnpc", description = "Search standard paths for libminiupnpc, instead of using bundled copy" } 18 newoption { trigger = "with-system-mozjs 185", description = "Search standard paths for libmozjs185, instead of using bundled copy" }18 newoption { trigger = "with-system-mozjs24", description = "Search standard paths for libmozjs24, instead of using bundled copy" } 19 19 newoption { trigger = "with-c++11", description = "Enable C++11 on GCC" } 20 20 newoption { trigger = "sysroot", description = "Set compiler system root path, used for building against a non-system SDK. For example /usr/local becomes SYSROOT/user/local" } 21 21 newoption { trigger = "macosx-version-min", description = "Set minimum required version of the OS X API, the build will possibly fail if an older SDK is used, while newer API functions will be weakly linked (i.e. resolved at runtime)" } -
build/workspaces/update-workspaces.sh
37 37 with_system_nvtt=false 38 38 with_system_enet=false 39 39 with_system_miniupnpc=false 40 with_system_mozjs 185=false40 with_system_mozjs24=false 41 41 enable_atlas=true 42 42 43 43 for i in "$@" … … 47 47 --with-system-nvtt ) with_system_nvtt=true; premake_args="${premake_args} --with-system-nvtt" ;; 48 48 --with-system-enet ) with_system_enet=true; premake_args="${premake_args} --with-system-enet" ;; 49 49 --with-system-miniupnpc ) with_system_miniupnpc=true; premake_args="${premake_args} --with-system-miniupnpc" ;; 50 --with-system-mozjs 185 ) with_system_mozjs185=true; premake_args="${premake_args} --with-system-mozjs185" ;;50 --with-system-mozjs24 ) with_system_mozjs24=true; premake_args="${premake_args} --with-system-mozjs24" ;; 51 51 --enable-atlas ) enable_atlas=true ;; 52 52 --disable-atlas ) enable_atlas=false ;; 53 53 -j* ) JOBS=$i ;; … … 81 81 # Build/update bundled external libraries 82 82 (cd ../../libraries/source/fcollada/src && ${MAKE} ${JOBS}) || die "FCollada build failed" 83 83 echo 84 if [ "$with_system_mozjs 185" = "false" ]; then84 if [ "$with_system_mozjs24" = "false" ]; then 85 85 (cd ../../libraries/source/spidermonkey && MAKE=${MAKE} JOBS=${JOBS} ./build.sh) || die "SpiderMonkey build failed" 86 86 fi 87 87 echo -
libraries/source/spidermonkey/README.txt
5 5 then run start-msvc8.bat and run ./build.sh here. 6 6 7 7 This version of SpiderMonkey comes from 8 http://ftp.mozilla.org/pub/mozilla.org/js/js185-1.0.0.tar.gz 9 (see also https://developer.mozilla.org/en/SpiderMonkey/1.8.5) 8 https://ftp.mozilla.org/pub/mozilla.org/js/mozjs-24.2.0.tar.bz2 10 9 11 The game must be compiled with precisely this version, and must not use a 12 standard system-provided version of the library, since SpiderMonkey does not 13 guarantee API stability and may have behavioural changes that cause subtle 14 bugs or network out-of-sync errors. 10 The game must be compiled with precisely this version since SpiderMonkey 11 does not guarantee API stability and may have behavioural changes that 12 cause subtle bugs or network out-of-sync errors. 13 A standard system-provided version of the library may only be used if it's 14 exactly the same version or if it's another minor release that does not 15 change the behaviour of the scripts executed by SpiderMonkey. -
libraries/source/spidermonkey/build.sh
17 17 echo "Building SpiderMonkey..." 18 18 echo 19 19 20 JOBS=${JOBS:="-j2"}21 20 MAKE=${MAKE:="make"} 22 21 23 22 MAKE_OPTS="${JOBS}" 23 NSPR_INCLUDES="`pkg-config nspr --cflags`" 24 NSPR_LIBS="`pkg-config nspr --libs`" 24 25 25 CONF_OPTS="--disable-tests" 26 # (We don't use --enable-threadsafe because we don't use a single runtime in 27 # multiple threads, so it is unnecessary complexity and performance overhead) 26 CONF_OPTS="--enable-threadsafe --enable-shared-js --disable-tests" # --enable-trace-logging" 28 27 29 28 # If Valgrind looks like it's installed, then set up SM to support it 30 29 # (else the JITs will interact poorly with it) … … 33 32 CONF_OPTS="${CONF_OPTS} --enable-valgrind" 34 33 fi 35 34 36 #CONF_OPTS="${CONF_OPTS} --enable-threadsafe --with-system-nspr"37 #CONF_OPTS="${CONF_OPTS} --enable-trace-jscalls"38 39 35 # We need to be able to override CHOST in case it is 32bit userland on 64bit kernel 40 36 CONF_OPTS="${CONF_OPTS} \ 41 37 ${CBUILD:+--build=${CBUILD}} \ … … 43 39 ${CTARGET:+--target=${CTARGET}}" 44 40 45 41 echo "SpiderMonkey build options: ${CONF_OPTS}" 42 echo ${CONF_OPTS} 46 43 47 # Extract the tarball 48 tar xzf js185-1.0.0.tar.gz 44 # Delete the existing directory to avoid conflicts and extract the tarball 45 rm -rf mozjs24 46 tar xjf mozjs-24.2.0.tar.bz2 49 47 50 # Apply patches 51 patch -p0 < openbsd-spidermonkey-650742.diff 52 patch -p0 < openbsd-spidermonkey-634609.diff 48 # Apply patches if needed 49 #patch -p0 < name_of_thepatch.diff 53 50 54 cd js-1.8.5/js/src 51 # rename the extracted directory to something shorter 52 mv mozjs-24.2.0 mozjs24 55 53 54 cd mozjs24/js/src 55 56 56 # We want separate debug/release versions of the library, so we have to change 57 57 # the LIBRARY_NAME for each build. 58 58 # (We use perl instead of sed so that it works with MozillaBuild on Windows, 59 59 # which has an ancient sed.) 60 perl -i.bak -pe 's/ ^(LIBRARY_NAME\s+= mozjs185)(-ps-debug|-ps-release)?/$1-ps-debug/' Makefile.in60 perl -i.bak -pe 's/(^LIBRARY_NAME\s+=).*/$1mozjs24-ps-debug/' Makefile.in 61 61 mkdir -p build-debug 62 62 cd build-debug 63 ../configure ${CONF_OPTS} -- enable-debug --disable-optimize63 ../configure ${CONF_OPTS} --with-nspr-libs="$NSPR_LIBS" --with-nspr-cflags="$NSPR_INCLUDES" --enable-debug --disable-optimize --enable-js-diagnostics --enable-gczeal # --enable-root-analysis 64 64 ${MAKE} ${MAKE_OPTS} 65 65 cd .. 66 66 67 perl -i.bak -pe 's/ ^(LIBRARY_NAME\s+= mozjs185)(-ps-debug|-ps-release)?/$1-ps-release/' Makefile.in67 perl -i.bak -pe 's/(^LIBRARY_NAME\s+=).*/$1mozjs24-ps-release/' Makefile.in 68 68 mkdir -p build-release 69 69 cd build-release 70 ../configure ${CONF_OPTS} # --enable-gczeal --enable-debug-symbols70 ../configure ${CONF_OPTS} --with-nspr-libs="$NSPR_LIBS" --with-nspr-cflags="$NSPR_INCLUDES" --enable-optimize # --enable-gczeal --enable-debug-symbols 71 71 ${MAKE} ${MAKE_OPTS} 72 72 cd .. 73 73 74 # Remove the library suffixes to avoid spurious SVN diffs75 perl -i.bak -pe 's/^(LIBRARY_NAME\s+= mozjs185)(-ps-debug|-ps-release)?/$1/' Makefile.in76 77 74 cd ../../.. 78 75 79 76 if [ "${OS}" = "Windows_NT" ] 80 77 then 81 INCLUDE_DIR=include-win32 78 INCLUDE_DIR_DEBUG=include-win32-debug 79 INCLUDE_DIR_RELEASE=include-win32-release 82 80 DLL_SRC_SUFFIX=-1.0.dll 83 81 DLL_DST_SUFFIX=-1.0.dll 84 82 LIB_PREFIX= 85 83 LIB_SRC_SUFFIX=-1.0.lib 86 84 LIB_DST_SUFFIX=.lib 87 85 else 88 INCLUDE_DIR=include-unix 86 INCLUDE_DIR_DEBUG=include-unix-debug 87 INCLUDE_DIR_RELEASE=include-unix-release 89 88 DLL_SRC_SUFFIX=.so 90 DLL_DST_SUFFIX=.so .1.089 DLL_DST_SUFFIX=.so 91 90 LIB_PREFIX=lib 92 91 LIB_SRC_SUFFIX=.so 93 92 LIB_DST_SUFFIX=.so … … 102 101 103 102 # Copy files into the necessary locations for building and running the game 104 103 105 # js-config.h is the same for both debug and release builds, so we only need to copy one 106 mkdir -p ${INCLUDE_DIR}/js 107 cp -L js-1.8.5/js/src/build-release/dist/include/* ${INCLUDE_DIR}/js/ 104 # js-config.h is different for debug and release builds, so we need different include directories for both 105 mkdir -p ${INCLUDE_DIR_DEBUG} 106 mkdir -p ${INCLUDE_DIR_RELEASE} 107 cp -R -L mozjs24/js/src/build-release/dist/include/* ${INCLUDE_DIR_RELEASE}/ 108 cp -R -L mozjs24/js/src/build-debug/dist/include/* ${INCLUDE_DIR_DEBUG}/ 108 109 109 110 mkdir -p lib/ 110 cp -L js-1.8.5/js/src/build-debug/dist/lib/${LIB_PREFIX}mozjs185-ps-debug${LIB_SRC_SUFFIX} lib/${LIB_PREFIX}mozjs185-ps-debug${LIB_DST_SUFFIX}111 cp -L js-1.8.5/js/src/build-release/dist/lib/${LIB_PREFIX}mozjs185-ps-release${LIB_SRC_SUFFIX} lib/${LIB_PREFIX}mozjs185-ps-release${LIB_DST_SUFFIX}112 cp -L js-1.8.5/js/src/build-debug/dist/bin/${LIB_PREFIX}mozjs185-ps-debug${DLL_SRC_SUFFIX} ../../../binaries/system/${LIB_PREFIX}mozjs185-ps-debug${DLL_DST_SUFFIX}113 cp -L js-1.8.5/js/src/build-release/dist/bin/${LIB_PREFIX}mozjs185-ps-release${DLL_SRC_SUFFIX} ../../../binaries/system/${LIB_PREFIX}mozjs185-ps-release${DLL_DST_SUFFIX}111 cp -L mozjs24/js/src/build-debug/dist/lib/${LIB_PREFIX}mozjs24-ps-debug${LIB_SRC_SUFFIX} lib/${LIB_PREFIX}mozjs24-ps-debug${LIB_DST_SUFFIX} 112 cp -L mozjs24/js/src/build-release/dist/lib/${LIB_PREFIX}mozjs24-ps-release${LIB_SRC_SUFFIX} lib/${LIB_PREFIX}mozjs24-ps-release${LIB_DST_SUFFIX} 113 cp -L mozjs24/js/src/build-debug/dist/bin/${LIB_PREFIX}mozjs24-ps-debug${DLL_SRC_SUFFIX} ../../../binaries/system/${LIB_PREFIX}mozjs24-ps-debug${DLL_DST_SUFFIX} 114 cp -L mozjs24/js/src/build-release/dist/bin/${LIB_PREFIX}mozjs24-ps-release${DLL_SRC_SUFFIX} ../../../binaries/system/${LIB_PREFIX}mozjs24-ps-release${DLL_DST_SUFFIX} 114 115 115 116 # Flag that it's already been built successfully so we can skip it next time 116 117 touch .already-built -
libraries/source/spidermonkey/openbsd-spidermonkey-634609.diff
Kann nicht anzeigen: Dateityp ist als binär angegeben. svn:mime-type = application/octet-stream Kann nicht anzeigen: Dateityp ist als binär angegeben. svn:mime-type = application/octet-stream Kann nicht anzeigen: Dateityp ist als binär angegeben. svn:mime-type = application/octet-stream
1 --- js-1.8.5/js/src/jsnativestack.cpp2 +++ js-1.8.5/js/src/jsnativestack.cpp3 @@ -50,7 +50,7 @@4 #elif defined(XP_MACOSX) || defined(DARWIN) || defined(XP_UNIX)5 # include <pthread.h>6 7 -# if defined(__FreeBSD__)8 +# if defined(__FreeBSD__) || defined(__OpenBSD__)9 # include <pthread_np.h>10 # endif11 12 @@ -196,7 +196,9 @@13 # else14 pthread_attr_t sattr;15 pthread_attr_init(&sattr);16 -# if defined(PTHREAD_NP_H) || defined(_PTHREAD_NP_H_) || defined(NETBSD)17 +# if defined(__OpenBSD__)18 + stack_t ss;19 +# elif defined(PTHREAD_NP_H) || defined(_PTHREAD_NP_H_) || defined(NETBSD)20 /* e.g. on FreeBSD 4.8 or newer, neundorf@kde.org */21 pthread_attr_get_np(thread, &sattr);22 # else23 @@ -212,7 +214,13 @@24 # ifdef DEBUG25 int rc =26 # endif27 +# if defined(__OpenBSD__)28 + pthread_stackseg_np(pthread_self(), &ss);29 + stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);30 + stackSize = ss.ss_size;31 +# else32 pthread_attr_getstack(&sattr, &stackBase, &stackSize);33 +# endif34 JS_ASSERT(!rc);35 JS_ASSERT(stackBase);36 pthread_attr_destroy(&sattr); -
libraries/source/spidermonkey/openbsd-spidermonkey-650742.diff
1 --- js-1.8.5/js/src/configure.in2 +++ js-1.8.5/js/src/configure.in3 @@ -3041,6 +3041,9 @@4 *-freebsd*|*-kfreebsd*)5 AC_DEFINE(AVMPLUS_UNIX)6 ;;7 +*-openbsd*)8 + AC_DEFINE(AVMPLUS_UNIX)9 + ;;10 *-gnu*)11 AC_DEFINE(AVMPLUS_UNIX)12 ;;13 --- js-1.8.5/js/src/configure14 +++ js-1.8.5/js/src/configure15 @@ -8093,6 +8093,12 @@16 EOF17 18 ;;19 +*-openbsd*)20 + cat >> confdefs.h <<\EOF21 +#define AVMPLUS_UNIX 122 +EOF23 +24 + ;;25 *-gnu*)26 cat >> confdefs.h <<\EOF27 #define AVMPLUS_UNIX 1 -
source/gui/GUIManager.cpp
71 71 shared_ptr<ScriptInterface::StructuredClone> initDataClone; 72 72 if (initData.get() != JSVAL_VOID) 73 73 { 74 ENSURE(srcScriptInterface); 75 // TODO: Fix this horribly ugly hack as soon as we have integrated the new SpiderMonkey library version. 76 // In SpiderMonkey 1.8.5, StructuredClone data needs to be freed with JS_Free. 77 // JS_Free takes a JSContext as argument which must be the one the clone was created wtih. 78 // This means we must ensure to call the destructor of all structuredclones before the context is destroyed. 79 // To achieve this, we write all initData structured clones with the GUIManager's JSContext. 80 // That's why we have to clone the value twice here. 81 // Calling WriteStructuredClone with a context in another compartment than the value works, but I don't think that's 82 // supposed to work and will probably break under some conditions. 83 // Newer SpiderMonkey versions introduce JS_ClearStructuredClone instead of JS_Free which does not require a context. 84 if (srcScriptInterface != m_ScriptInterface.get()) 85 { 86 CScriptVal cloneSaveInitData; 87 cloneSaveInitData = m_ScriptInterface->CloneValueFromOtherContext(*srcScriptInterface, initData.get()); 88 initDataClone = m_ScriptInterface->WriteStructuredClone(cloneSaveInitData.get()); 89 } 90 else 91 initDataClone = m_ScriptInterface->WriteStructuredClone(initData.get()); 74 initDataClone = srcScriptInterface->WriteStructuredClone(initData.get()); 92 75 } 93 76 m_PageStack.clear(); 94 77 PushPage(pageName, initDataClone); -
source/gui/IGUIObject.cpp
422 422 throw PSERROR_GUI_OperationNeedsGUIObject(); 423 423 424 424 JSContext* cx = pGUI->GetScriptInterface()->GetContext(); 425 JSAutoRequest rq(cx); 425 426 426 427 const int paramCount = 1; 427 428 const char* paramNames[paramCount] = { "mouse" }; … … 469 470 return; 470 471 471 472 JSContext* cx = m_pGUI->GetScriptInterface()->GetContext(); 472 473 JSAutoRequest rq(cx); 474 473 475 // Set up the 'mouse' parameter 474 476 CScriptVal mouse; 475 477 m_pGUI->GetScriptInterface()->Eval("({})", mouse); … … 480 482 jsval paramData[] = { mouse.get() }; 481 483 482 484 jsval result; 483 JSBool ok = JS_CallFunctionValue(cx, GetJSObject(), (*it).second.get(), ARRAY_SIZE(paramData), paramData, &result);485 bool ok = JS_CallFunctionValue(cx, GetJSObject(), (*it).second.get(), ARRAY_SIZE(paramData), paramData, &result); 484 486 if (!ok) 485 487 { 486 488 // We have no way to propagate the script exception, so just ignore it … … 490 492 491 493 void IGUIObject::ScriptEvent(const CStr& Action, const CScriptValRooted& Argument) 492 494 { 493 JSContext* cx = m_pGUI->GetScriptInterface()->GetContext();494 495 std::map<CStr, CScriptValRooted>::iterator it = m_ScriptHandlers.find(Action); 495 496 if (it == m_ScriptHandlers.end()) 496 497 return; 497 498 499 JSContext* cx = m_pGUI->GetScriptInterface()->GetContext(); 500 JSAutoRequest rq(cx); 501 498 502 JSObject* object = GetJSObject(); 499 503 500 504 jsval arg = Argument.get(); 501 505 502 506 jsval result; 503 JSBool ok = JS_CallFunctionValue(cx, object, (*it).second.get(), 1, &arg, &result);507 bool ok = JS_CallFunctionValue(cx, object, (*it).second.get(), 1, &arg, &result); 504 508 if (!ok) 505 509 { 506 510 JS_ReportError(cx, "Errors executing script action \"%s\"", Action.c_str()); … … 510 514 JSObject* IGUIObject::GetJSObject() 511 515 { 512 516 JSContext* cx = m_pGUI->GetScriptInterface()->GetContext(); 517 JSAutoRequest rq(cx); 513 518 // Cache the object when somebody first asks for it, because otherwise 514 519 // we end up doing far too much object allocation. TODO: Would be nice to 515 520 // not have these objects hang around forever using up memory, though. … … 517 522 { 518 523 JSObject* obj = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL); 519 524 m_JSObject = CScriptValRooted(cx, OBJECT_TO_JSVAL(obj)); 520 JS_SetPrivate( cx,JSVAL_TO_OBJECT(m_JSObject.get()), this);525 JS_SetPrivate(JSVAL_TO_OBJECT(m_JSObject.get()), this); 521 526 } 522 527 return JSVAL_TO_OBJECT(m_JSObject.get());; 523 528 } -
source/gui/IGUIObject.h
142 142 friend class GUITooltip; 143 143 144 144 // Allow getProperty to access things like GetParent() 145 friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS Object* obj, jsid id, jsval*vp);146 friend JSBool JSI_IGUIObject::setProperty(JSContext* cx, JS Object* obj, jsid id, JSBool strict, jsval*vp);147 friend JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uint Nargc, jsval* vp);145 friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<jsval> vp); 146 friend JSBool JSI_IGUIObject::setProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JSBool UNUSED(strict), JS::MutableHandle<jsval> vp); 147 friend JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, jsval* vp); 148 148 149 149 public: 150 150 IGUIObject(); -
source/gui/scripting/GuiScriptConversions.cpp
23 23 #include "lib/external_libraries/libsdl.h" 24 24 #include "ps/Hotkey.h" 25 25 26 #include "js/jsapi.h" 27 28 #define SET(obj, name, value) STMT(jsval v_ = ToJSVal(cx, (value)); JS_SetProperty(cx, (obj), (name), &v_)) 26 #define SET(obj, name, value) STMT(JS::RootedValue v_(cx, ToJSVal(cx, (value))); JS_SetProperty(cx, (obj), (name), v_.address())) 29 27 // ignore JS_SetProperty return value, because errors should be impossible 30 28 // and we can't do anything useful in the case of errors anyway 31 29 32 30 template<> jsval ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, SDL_Event_ const& val) 33 31 { 32 JSAutoRequest rq(cx); 34 33 const char* typeName; 35 34 36 35 switch (val.ev.type) … … 78 77 JSObject* keysym = JS_NewObject(cx, NULL, NULL, NULL); 79 78 if (! keysym) 80 79 return JSVAL_VOID; 81 jsval keysymVal = OBJECT_TO_JSVAL(keysym);82 JS_SetProperty(cx, obj, "keysym", &keysymVal);80 JS::RootedValue keysymVal(cx, OBJECT_TO_JSVAL(keysym)); 81 JS_SetProperty(cx, obj, "keysym", keysymVal.address()); 83 82 84 83 // SET(keysym, "scancode", (int)val.ev.key.keysym.scancode); // (not in wsdl.h) 85 84 SET(keysym, "sym", (int)val.ev.key.keysym.sym); -
source/gui/scripting/JSInterface_GUITypes.cpp
23 23 /**** GUISize ****/ 24 24 JSClass JSI_GUISize::JSI_class = { 25 25 "GUISize", 0, 26 JS_PropertyStub, JS_ PropertyStub,26 JS_PropertyStub, JS_DeletePropertyStub, 27 27 JS_PropertyStub, JS_StrictPropertyStub, 28 28 JS_EnumerateStub, JS_ResolveStub, 29 JS_ConvertStub, JS_FinalizeStub,29 JS_ConvertStub, NULL, 30 30 NULL, NULL, NULL, JSI_GUISize::construct 31 31 }; 32 32 … … 45 45 46 46 JSFunctionSpec JSI_GUISize::JSI_methods[] = 47 47 { 48 { "toString", JSI_GUISize::toString, 0, 0 },49 { 0 }48 JS_FS("toString", JSI_GUISize::toString, 0, 0), 49 JS_FS_END 50 50 }; 51 51 52 JSBool JSI_GUISize::construct(JSContext* cx, uint Nargc, jsval* vp)52 JSBool JSI_GUISize::construct(JSContext* cx, uint argc, jsval* vp) 53 53 { 54 54 JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL); 55 55 56 // TODO: ugly with so much repetition...? 56 57 if (argc == 8) 57 58 { 58 JS_SetProperty(cx, obj, "left", &JS_ARGV(cx, vp)[0]); 59 JS_SetProperty(cx, obj, "top", &JS_ARGV(cx, vp)[1]); 60 JS_SetProperty(cx, obj, "right", &JS_ARGV(cx, vp)[2]); 61 JS_SetProperty(cx, obj, "bottom", &JS_ARGV(cx, vp)[3]); 62 JS_SetProperty(cx, obj, "rleft", &JS_ARGV(cx, vp)[4]); 63 JS_SetProperty(cx, obj, "rtop", &JS_ARGV(cx, vp)[5]); 64 JS_SetProperty(cx, obj, "rright", &JS_ARGV(cx, vp)[6]); 65 JS_SetProperty(cx, obj, "rbottom", &JS_ARGV(cx, vp)[7]); 59 JS::RootedValue v0(cx, JS_ARGV(cx, vp)[0]); 60 JS::RootedValue v1(cx, JS_ARGV(cx, vp)[1]); 61 JS::RootedValue v2(cx, JS_ARGV(cx, vp)[2]); 62 JS::RootedValue v3(cx, JS_ARGV(cx, vp)[3]); 63 JS::RootedValue v4(cx, JS_ARGV(cx, vp)[4]); 64 JS::RootedValue v5(cx, JS_ARGV(cx, vp)[5]); 65 JS::RootedValue v6(cx, JS_ARGV(cx, vp)[6]); 66 JS::RootedValue v7(cx, JS_ARGV(cx, vp)[7]); 67 JS_SetProperty(cx, obj, "left", v0.address()); 68 JS_SetProperty(cx, obj, "top", v1.address()); 69 JS_SetProperty(cx, obj, "right", v2.address()); 70 JS_SetProperty(cx, obj, "bottom", v3.address()); 71 JS_SetProperty(cx, obj, "rleft", v4.address()); 72 JS_SetProperty(cx, obj, "rtop", v5.address()); 73 JS_SetProperty(cx, obj, "rright", v6.address()); 74 JS_SetProperty(cx, obj, "rbottom", v7.address()); 66 75 } 67 76 else if (argc == 4) 68 77 { 69 jsval zero = JSVAL_ZERO; 70 JS_SetProperty(cx, obj, "left", &JS_ARGV(cx, vp)[0]); 71 JS_SetProperty(cx, obj, "top", &JS_ARGV(cx, vp)[1]); 72 JS_SetProperty(cx, obj, "right", &JS_ARGV(cx, vp)[2]); 73 JS_SetProperty(cx, obj, "bottom", &JS_ARGV(cx, vp)[3]); 74 JS_SetProperty(cx, obj, "rleft", &zero); 75 JS_SetProperty(cx, obj, "rtop", &zero); 76 JS_SetProperty(cx, obj, "rright", &zero); 77 JS_SetProperty(cx, obj, "rbottom", &zero); 78 JS::RootedValue zero(cx, JSVAL_ZERO); 79 JS::RootedValue v0(cx, JS_ARGV(cx, vp)[0]); 80 JS::RootedValue v1(cx, JS_ARGV(cx, vp)[1]); 81 JS::RootedValue v2(cx, JS_ARGV(cx, vp)[2]); 82 JS::RootedValue v3(cx, JS_ARGV(cx, vp)[3]); 83 JS_SetProperty(cx, obj, "left", v0.address()); 84 JS_SetProperty(cx, obj, "top", v1.address()); 85 JS_SetProperty(cx, obj, "right", v2.address()); 86 JS_SetProperty(cx, obj, "bottom", v3.address()); 87 JS_SetProperty(cx, obj, "rleft", zero.address()); 88 JS_SetProperty(cx, obj, "rtop", zero.address()); 89 JS_SetProperty(cx, obj, "rright", zero.address()); 90 JS_SetProperty(cx, obj, "rbottom", zero.address()); 78 91 } 79 92 else 80 93 { 81 jsval zero = JSVAL_ZERO;82 JS_SetProperty(cx, obj, "left", &zero);83 JS_SetProperty(cx, obj, "top", &zero);84 JS_SetProperty(cx, obj, "right", &zero);85 JS_SetProperty(cx, obj, "bottom", &zero);86 JS_SetProperty(cx, obj, "rleft", &zero);87 JS_SetProperty(cx, obj, "rtop", &zero);88 JS_SetProperty(cx, obj, "rright", &zero);89 JS_SetProperty(cx, obj, "rbottom", &zero);94 JS::RootedValue zero(cx, JSVAL_ZERO); 95 JS_SetProperty(cx, obj, "left", zero.address()); 96 JS_SetProperty(cx, obj, "top", zero.address()); 97 JS_SetProperty(cx, obj, "right", zero.address()); 98 JS_SetProperty(cx, obj, "bottom", zero.address()); 99 JS_SetProperty(cx, obj, "rleft", zero.address()); 100 JS_SetProperty(cx, obj, "rtop", zero.address()); 101 JS_SetProperty(cx, obj, "rright", zero.address()); 102 JS_SetProperty(cx, obj, "rbottom", zero.address()); 90 103 } 91 104 92 105 JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); … … 102 115 return CStr::FromDouble(per)+"%"+( pix == 0.0 ? CStr() : pix > 0.0 ? CStr("+")+CStr::FromDouble(pix) : CStr::FromDouble(pix) ); 103 116 } 104 117 105 JSBool JSI_GUISize::toString(JSContext* cx, uint Nargc, jsval* vp)118 JSBool JSI_GUISize::toString(JSContext* cx, uint argc, jsval* vp) 106 119 { 107 120 UNUSED2(argc); 108 121 … … 141 154 142 155 JSClass JSI_GUIColor::JSI_class = { 143 156 "GUIColor", 0, 144 JS_PropertyStub, JS_ PropertyStub,157 JS_PropertyStub, JS_DeletePropertyStub, 145 158 JS_PropertyStub, JS_StrictPropertyStub, 146 159 JS_EnumerateStub, JS_ResolveStub, 147 JS_ConvertStub, JS_FinalizeStub,160 JS_ConvertStub, NULL, 148 161 NULL, NULL, NULL, JSI_GUIColor::construct 149 162 }; 150 163 … … 159 172 160 173 JSFunctionSpec JSI_GUIColor::JSI_methods[] = 161 174 { 162 { "toString", JSI_GUIColor::toString, 0, 0 },163 { 0 }175 JS_FS("toString", JSI_GUIColor::toString, 0, 0), 176 JS_FS_END 164 177 }; 165 178 166 JSBool JSI_GUIColor::construct(JSContext* cx, uint Nargc, jsval* vp)179 JSBool JSI_GUIColor::construct(JSContext* cx, uint argc, jsval* vp) 167 180 { 168 181 JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL); 169 182 … … 177 190 else 178 191 { 179 192 // Nice magenta: 180 jsval c;181 if ( !JS_NewNumberValue(cx, 1.0, &c))193 JS::RootedValue c(cx, JS_NumberValue(1.0)); 194 if (JSVAL_IS_NULL(c)) 182 195 return JS_FALSE; 183 JS_SetProperty(cx, obj, "r", &c); 184 JS_SetProperty(cx, obj, "b", &c); 185 JS_SetProperty(cx, obj, "a", &c); 186 if (!JS_NewNumberValue(cx, 0.0, &c)) 196 JS_SetProperty(cx, obj, "r", c.address()); 197 JS_SetProperty(cx, obj, "b", c.address()); 198 JS_SetProperty(cx, obj, "a", c.address()); 199 c = JS_NumberValue(0.0); 200 if (JSVAL_IS_NULL(c)) 187 201 return JS_FALSE; 188 JS_SetProperty(cx, obj, "g", &c);202 JS_SetProperty(cx, obj, "g", c.address()); 189 203 } 190 204 191 205 JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); 192 206 return JS_TRUE; 193 207 } 194 208 195 JSBool JSI_GUIColor::toString(JSContext* cx, uint Nargc, jsval* vp)209 JSBool JSI_GUIColor::toString(JSContext* cx, uint argc, jsval* vp) 196 210 { 197 211 UNUSED2(argc); 198 212 … … 218 232 219 233 JSClass JSI_GUIMouse::JSI_class = { 220 234 "GUIMouse", 0, 221 JS_PropertyStub, JS_ PropertyStub,235 JS_PropertyStub, JS_DeletePropertyStub, 222 236 JS_PropertyStub, JS_StrictPropertyStub, 223 237 JS_EnumerateStub, JS_ResolveStub, 224 JS_ConvertStub, JS_FinalizeStub,238 JS_ConvertStub, NULL, 225 239 NULL, NULL, NULL, JSI_GUIMouse::construct 226 240 }; 227 241 … … 235 249 236 250 JSFunctionSpec JSI_GUIMouse::JSI_methods[] = 237 251 { 238 { "toString", JSI_GUIMouse::toString, 0, 0 },239 { 0 }252 JS_FS("toString", JSI_GUIMouse::toString, 0, 0), 253 JS_FS_END 240 254 }; 241 255 242 JSBool JSI_GUIMouse::construct(JSContext* cx, uint Nargc, jsval* vp)256 JSBool JSI_GUIMouse::construct(JSContext* cx, uint argc, jsval* vp) 243 257 { 244 258 JSObject* obj = JS_NewObject(cx, &JSI_GUIMouse::JSI_class, NULL, NULL); 245 259 246 260 if (argc == 3) 247 261 { 248 JS_SetProperty(cx, obj, "x", &JS_ARGV(cx, vp)[0]); 249 JS_SetProperty(cx, obj, "y", &JS_ARGV(cx, vp)[1]); 250 JS_SetProperty(cx, obj, "buttons", &JS_ARGV(cx, vp)[2]); 262 JS::RootedValue v0(cx, JS_ARGV(cx, vp)[0]); 263 JS::RootedValue v1(cx, JS_ARGV(cx, vp)[1]); 264 JS::RootedValue v2(cx, JS_ARGV(cx, vp)[2]); 265 JS_SetProperty(cx, obj, "x", v0.address()); 266 JS_SetProperty(cx, obj, "y", v1.address()); 267 JS_SetProperty(cx, obj, "buttons", v2.address()); 251 268 } 252 269 else 253 270 { 254 jsval zero = JSVAL_ZERO;255 JS_SetProperty(cx, obj, "x", &zero);256 JS_SetProperty(cx, obj, "y", &zero);257 JS_SetProperty(cx, obj, "buttons", &zero);271 JS::RootedValue zero (cx, JSVAL_ZERO); 272 JS_SetProperty(cx, obj, "x", zero.address()); 273 JS_SetProperty(cx, obj, "y", zero.address()); 274 JS_SetProperty(cx, obj, "buttons", zero.address()); 258 275 } 259 276 260 277 JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); 261 278 return JS_TRUE; 262 279 } 263 280 264 JSBool JSI_GUIMouse::toString(JSContext* cx, uint Nargc, jsval* vp)281 JSBool JSI_GUIMouse::toString(JSContext* cx, uint argc, jsval* vp) 265 282 { 266 283 UNUSED2(argc); 267 284 268 int32 x, y, buttons;285 int32_t x, y, buttons; 269 286 ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; 270 287 pScriptInterface->GetProperty(JS_THIS_VALUE(cx, vp), "x", x); 271 288 pScriptInterface->GetProperty(JS_THIS_VALUE(cx, vp), "y", y); -
source/gui/scripting/JSInterface_GUITypes.h
26 26 extern JSClass JSI_class; \ 27 27 extern JSPropertySpec JSI_props[]; \ 28 28 extern JSFunctionSpec JSI_methods[]; \ 29 JSBool construct(JSContext* cx, uint Nargc, jsval* vp); \30 JSBool toString(JSContext* cx, uint Nargc, jsval* vp); \29 JSBool construct(JSContext* cx, uint argc, jsval* vp); \ 30 JSBool toString(JSContext* cx, uint argc, jsval* vp); \ 31 31 } 32 32 33 33 GUISTDTYPE(Size) -
source/gui/scripting/JSInterface_IGUIObject.cpp
32 32 33 33 JSClass JSI_IGUIObject::JSI_class = { 34 34 "GUIObject", JSCLASS_HAS_PRIVATE, 35 JS_PropertyStub, JS_ PropertyStub,35 JS_PropertyStub, JS_DeletePropertyStub, 36 36 JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty, 37 37 JS_EnumerateStub, JS_ResolveStub, 38 JS_ConvertStub, JS_FinalizeStub,38 JS_ConvertStub, NULL, 39 39 NULL, NULL, NULL, JSI_IGUIObject::construct 40 40 }; 41 41 42 JSPropertySpec JSI_IGUIObject::JSI_props[] = 42 JSPropertySpec JSI_IGUIObject::JSI_props[] = 43 43 { 44 44 { 0 } 45 45 }; 46 46 47 JSFunctionSpec JSI_IGUIObject::JSI_methods[] = 47 JSFunctionSpec JSI_IGUIObject::JSI_methods[] = 48 48 { 49 { "toString", JSI_IGUIObject::toString, 0, 0 },50 { "focus", JSI_IGUIObject::focus, 0, 0 },51 { "blur", JSI_IGUIObject::blur, 0, 0 },52 { "getComputedSize", JSI_IGUIObject::getComputedSize, 0, 0 },53 { 0 }49 JS_FS("toString", JSI_IGUIObject::toString, 0, 0), 50 JS_FS("focus", JSI_IGUIObject::focus, 0, 0), 51 JS_FS("blur", JSI_IGUIObject::blur, 0, 0), 52 JS_FS("getComputedSize", JSI_IGUIObject::getComputedSize, 0, 0), 53 JS_FS_END 54 54 }; 55 55 56 JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS Object* obj, jsid id, jsval*vp)56 JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<jsval> vp) 57 57 { 58 58 IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); 59 59 if (!e) … … 88 88 CStr eventName (CStr(propName.substr(2)).LowerCase()); 89 89 std::map<CStr, CScriptValRooted>::iterator it = e->m_ScriptHandlers.find(eventName); 90 90 if (it == e->m_ScriptHandlers.end()) 91 *vp = JSVAL_NULL;91 vp.set(JSVAL_NULL); 92 92 else 93 *vp = it->second.get();93 vp.set((*it).second.get()); 94 94 return JS_TRUE; 95 95 } 96 96 … … 102 102 if (parent) 103 103 { 104 104 // If the object isn't parentless, return a new object 105 *vp = OBJECT_TO_JSVAL(parent->GetJSObject());105 vp.set(OBJECT_TO_JSVAL(parent->GetJSObject())); 106 106 } 107 107 else 108 108 { 109 109 // Return null if there's no parent 110 *vp = JSVAL_NULL;110 vp.set(JSVAL_NULL); 111 111 } 112 112 return JS_TRUE; 113 113 } 114 114 // Also handle "name" specially 115 115 else if (propName == "name") 116 116 { 117 *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, e->GetName().c_str()));117 vp.set(STRING_TO_JSVAL(JS_NewStringCopyZ(cx, e->GetName().c_str()))); 118 118 return JS_TRUE; 119 119 } 120 120 // Handle all other properties … … 135 135 { 136 136 bool value; 137 137 GUI<bool>::GetSetting(e, propName, value); 138 *vp = value ? JSVAL_TRUE : JSVAL_FALSE; 138 vp.set(BOOLEAN_TO_JSVAL(value)); 139 //value ? JSVAL_TRUE : JSVAL_FALSE; 139 140 break; 140 141 } 141 142 … … 143 144 { 144 145 int value; 145 146 GUI<int>::GetSetting(e, propName, value); 146 *vp = INT_TO_JSVAL(value);147 vp.set(INT_TO_JSVAL(value)); 147 148 break; 148 149 } 149 150 … … 152 153 float value; 153 154 GUI<float>::GetSetting(e, propName, value); 154 155 // Create a garbage-collectable double 155 return JS_NewNumberValue(cx, value, vp); 156 vp.set(JS_NumberValue(value)); 157 return !JSVAL_IS_NULL(vp.get()); 156 158 } 157 159 158 160 case GUIST_CColor: … … 160 162 CColor colour; 161 163 GUI<CColor>::GetSetting(e, propName, colour); 162 164 JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL); 163 *vp = OBJECT_TO_JSVAL(obj); // root it165 vp.set(OBJECT_TO_JSVAL(obj)); // root it 164 166 165 jsval c;167 JS::RootedValue c(cx); 166 168 // Attempt to minimise ugliness through macrosity 167 #define P(x) if (!JS_NewNumberValue(cx, colour.x, &c)) return JS_FALSE; JS_SetProperty(cx, obj, #x, &c) 169 #define P(x) c = JS_NumberValue(colour.x); \ 170 if (JSVAL_IS_NULL(c)) return false; JS_SetProperty(cx, obj, #x, c.address()) 168 171 P(r); 169 172 P(g); 170 173 P(b); … … 179 182 CClientArea area; 180 183 GUI<CClientArea>::GetSetting(e, propName, area); 181 184 JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL); 182 *vp = OBJECT_TO_JSVAL(obj); // root it185 vp.set(OBJECT_TO_JSVAL(obj)); // root it 183 186 try 184 187 { 185 188 ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; … … 207 210 { 208 211 CGUIString value; 209 212 GUI<CGUIString>::GetSetting(e, propName, value); 210 *vp = ScriptInterface::ToJSVal(cx, value.GetOriginalString());213 vp.set(ScriptInterface::ToJSVal(cx, value.GetOriginalString())); 211 214 break; 212 215 } 213 216 … … 215 218 { 216 219 CStr value; 217 220 GUI<CStr>::GetSetting(e, propName, value); 218 *vp = ScriptInterface::ToJSVal(cx, value);221 vp.set(ScriptInterface::ToJSVal(cx, value)); 219 222 break; 220 223 } 221 224 … … 223 226 { 224 227 CStrW value; 225 228 GUI<CStrW>::GetSetting(e, propName, value); 226 *vp = ScriptInterface::ToJSVal(cx, value);229 vp.set(ScriptInterface::ToJSVal(cx, value)); 227 230 break; 228 231 } 229 232 … … 231 234 { 232 235 CGUISpriteInstance *value; 233 236 GUI<CGUISpriteInstance>::GetSettingPointer(e, propName, value); 234 *vp = ScriptInterface::ToJSVal(cx, value->GetName());237 vp.set(ScriptInterface::ToJSVal(cx, value->GetName())); 235 238 break; 236 239 } 237 240 … … 247 250 case EAlign_Center: word = "center"; break; 248 251 default: debug_warn(L"Invalid EAlign!"); word = "error"; break; 249 252 } 250 *vp = ScriptInterface::ToJSVal(cx, word);253 vp.set(ScriptInterface::ToJSVal(cx, word)); 251 254 break; 252 255 } 253 256 … … 263 266 case EVAlign_Center: word = "center"; break; 264 267 default: debug_warn(L"Invalid EVAlign!"); word = "error"; break; 265 268 } 266 *vp = ScriptInterface::ToJSVal(cx, word);269 vp.set(ScriptInterface::ToJSVal(cx, word)); 267 270 break; 268 271 } 269 272 … … 273 276 GUI<CGUIList>::GetSetting(e, propName, value); 274 277 275 278 JSObject *obj = JS_NewArrayObject(cx, 0, NULL); 276 *vp = OBJECT_TO_JSVAL(obj); // root it277 279 vp.set(OBJECT_TO_JSVAL(obj)); // root it 280 278 281 for (size_t i = 0; i < value.m_Items.size(); ++i) 279 282 { 280 jsval val = ScriptInterface::ToJSVal(cx, value.m_Items[i].GetOriginalString());281 JS_SetElement(cx, obj, ( jsint)i, &val);283 JS::RootedValue val(cx, ScriptInterface::ToJSVal(cx, value.m_Items[i].GetOriginalString())); 284 JS_SetElement(cx, obj, (uint32_t)i, val.address()); 282 285 } 283 286 284 287 break; … … 294 297 } 295 298 } 296 299 297 JSBool JSI_IGUIObject::setProperty(JSContext* cx, JS Object* obj, jsid id, JSBool UNUSED(strict), jsval*vp)300 JSBool JSI_IGUIObject::setProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JSBool UNUSED(strict), JS::MutableHandle<jsval> vp) 298 301 { 299 302 IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); 300 303 if (!e) … … 311 314 if (propName == "name") 312 315 { 313 316 std::string value; 314 if (!ScriptInterface::FromJSVal(cx, *vp, value))317 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 315 318 return JS_FALSE; 316 319 e->SetName(value); 317 320 return JS_TRUE; … … 320 323 // Use onWhatever to set event handlers 321 324 if (propName.substr(0, 2) == "on") 322 325 { 323 if ( !JSVAL_IS_OBJECT(*vp) || !JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(*vp)))326 if (JSVAL_IS_PRIMITIVE(vp.get()) || !JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(vp.get()))) 324 327 { 325 328 JS_ReportError(cx, "on- event-handlers must be functions"); 326 329 return JS_FALSE; 327 330 } 328 331 329 332 CStr eventName (CStr(propName.substr(2)).LowerCase()); 330 e->SetScriptHandler(eventName, JSVAL_TO_OBJECT( *vp));333 e->SetScriptHandler(eventName, JSVAL_TO_OBJECT(vp.get())); 331 334 332 335 return JS_TRUE; 333 336 } … … 346 349 case GUIST_CStr: 347 350 { 348 351 std::string value; 349 if (!ScriptInterface::FromJSVal(cx, *vp, value))352 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 350 353 return JS_FALSE; 351 354 352 355 GUI<CStr>::SetSetting(e, propName, value); … … 356 359 case GUIST_CStrW: 357 360 { 358 361 std::wstring value; 359 if (!ScriptInterface::FromJSVal(cx, *vp, value))360 return JS_FALSE;362 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 363 return false; 361 364 362 365 GUI<CStrW>::SetSetting(e, propName, value); 363 366 break; … … 366 369 case GUIST_CGUISpriteInstance: 367 370 { 368 371 std::string value; 369 if (!ScriptInterface::FromJSVal(cx, *vp, value))370 return JS_FALSE;372 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 373 return false; 371 374 372 375 GUI<CGUISpriteInstance>::SetSetting(e, propName, CGUISpriteInstance(value)); 373 376 break; … … 376 379 case GUIST_CGUIString: 377 380 { 378 381 std::wstring value; 379 if (!ScriptInterface::FromJSVal(cx, *vp, value))382 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 380 383 return JS_FALSE; 381 384 382 385 CGUIString str; … … 388 391 case GUIST_EAlign: 389 392 { 390 393 std::string value; 391 if (!ScriptInterface::FromJSVal(cx, *vp, value))394 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 392 395 return JS_FALSE; 393 396 394 397 EAlign a; … … 407 410 case GUIST_EVAlign: 408 411 { 409 412 std::string value; 410 if (!ScriptInterface::FromJSVal(cx, *vp, value))413 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 411 414 return JS_FALSE; 412 415 413 416 EVAlign a; … … 425 428 426 429 case GUIST_int: 427 430 { 428 int32 value;429 if (JS_ValueToInt32(cx, *vp, &value) == JS_TRUE)431 int32_t value; 432 if (JS_ValueToInt32(cx, vp.get(), &value) == true) 430 433 GUI<int>::SetSetting(e, propName, value); 431 434 else 432 435 { … … 438 441 439 442 case GUIST_float: 440 443 { 441 jsdouble value;442 if (JS_ValueToNumber(cx, *vp, &value) == JS_TRUE)444 double value; 445 if (JS_ValueToNumber(cx, vp.get(), &value) == true) 443 446 GUI<float>::SetSetting(e, propName, (float)value); 444 447 else 445 448 { … … 452 455 case GUIST_bool: 453 456 { 454 457 JSBool value; 455 if (JS_ValueToBoolean(cx, *vp, &value) == JS_TRUE)456 GUI<bool>::SetSetting(e, propName, value == JS_TRUE);458 if (JS_ValueToBoolean(cx, vp.get(), &value)) 459 GUI<bool>::SetSetting(e, propName, value); 457 460 else 458 461 { 459 462 JS_ReportError(cx, "Cannot convert value to bool"); … … 464 467 465 468 case GUIST_CClientArea: 466 469 { 467 if (JSVAL_IS_STRING( *vp))470 if (JSVAL_IS_STRING(vp.get())) 468 471 { 469 472 std::wstring value; 470 if (!ScriptInterface::FromJSVal(cx, *vp, value))473 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 471 474 return JS_FALSE; 472 475 473 476 if (e->SetSetting(propName, value) != PSRETURN_OK) … … 476 479 return JS_FALSE; 477 480 } 478 481 } 479 else if ( JSVAL_IS_OBJECT(*vp) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &JSI_GUISize::JSI_class, NULL))482 else if (!JSVAL_IS_PRIMITIVE(vp.get()) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(vp.get()), &JSI_GUISize::JSI_class, NULL)) 480 483 { 481 484 CClientArea area; 482 485 GUI<CClientArea>::GetSetting(e, propName, area); 483 486 484 JSObject* obj = JSVAL_TO_OBJECT( *vp);487 JSObject* obj = JSVAL_TO_OBJECT(vp.get()); 485 488 ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; 486 489 #define P(x, y, z) pScriptInterface->GetProperty(OBJECT_TO_JSVAL(obj), #z, area.x.y) 487 490 P(pixel, left, left); … … 506 509 507 510 case GUIST_CColor: 508 511 { 509 if (JSVAL_IS_STRING( *vp))512 if (JSVAL_IS_STRING(vp.get())) 510 513 { 511 514 std::wstring value; 512 if (!ScriptInterface::FromJSVal(cx, *vp, value))515 if (!ScriptInterface::FromJSVal(cx, vp.get(), value)) 513 516 return JS_FALSE; 514 517 515 518 if (e->SetSetting(propName, value) != PSRETURN_OK) … … 518 521 return JS_FALSE; 519 522 } 520 523 } 521 else if ( JSVAL_IS_OBJECT(*vp) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &JSI_GUIColor::JSI_class, NULL))524 else if (!JSVAL_IS_PRIMITIVE(vp.get()) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(vp.get()), &JSI_GUIColor::JSI_class, NULL)) 522 525 { 523 526 CColor colour; 524 JSObject* obj = JSVAL_TO_OBJECT(*vp); 525 jsval t; double s; 526 #define PROP(x) JS_GetProperty(cx, obj, #x, &t); \ 527 JSObject* obj = JSVAL_TO_OBJECT(vp.get()); 528 JS::RootedValue t(cx); 529 double s; 530 #define PROP(x) JS_GetProperty(cx, obj, #x, t.address()); \ 527 531 JS_ValueToNumber(cx, t, &s); \ 528 532 colour.x = (float)s 529 533 PROP(r); PROP(g); PROP(b); PROP(a); … … 541 545 542 546 case GUIST_CGUIList: 543 547 { 544 JSObject* obj = JSVAL_TO_OBJECT( *vp);545 jsuint length;546 if ( JSVAL_IS_OBJECT(*vp) && JS_GetArrayLength(cx, obj, &length) == JS_TRUE)548 JSObject* obj = JSVAL_TO_OBJECT(vp.get()); 549 uint length; 550 if (!JSVAL_IS_PRIMITIVE(vp.get()) && JS_GetArrayLength(cx, obj, &length) == true) 547 551 { 548 552 CGUIList list; 549 553 550 554 for (int i=0; i<(int)length; ++i) 551 555 { 552 jsval element;553 if (! JS_GetElement(cx, obj, i, &element))556 JS::RootedValue element(cx); 557 if (! JS_GetElement(cx, obj, i, element.address())) 554 558 { 555 559 JS_ReportError(cx, "Failed to get list element"); 556 560 return JS_FALSE; … … 562 566 563 567 CGUIString str; 564 568 str.SetValue(value); 565 569 566 570 list.m_Items.push_back(str); 567 571 } 568 572 … … 587 591 } 588 592 589 593 590 JSBool JSI_IGUIObject::construct(JSContext* cx, uint Nargc, jsval* vp)594 JSBool JSI_IGUIObject::construct(JSContext* cx, uint argc, jsval* vp) 591 595 { 592 596 if (argc == 0) 593 597 { … … 599 603 600 604 // Store the IGUIObject in the JS object's 'private' area 601 605 IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(JS_ARGV(cx, vp)[0]); 602 JS_SetPrivate( cx,obj, guiObject);606 JS_SetPrivate(obj, guiObject); 603 607 604 608 JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); 605 609 return JS_TRUE; … … 610 614 scriptInterface.DefineCustomObjectType(&JSI_class, construct, 1, JSI_props, JSI_methods, NULL, NULL); 611 615 } 612 616 613 JSBool JSI_IGUIObject::toString(JSContext* cx, uint Nargc, jsval* vp)617 JSBool JSI_IGUIObject::toString(JSContext* cx, uint argc, jsval* vp) 614 618 { 615 619 UNUSED2(argc); 616 620 … … 625 629 return JS_TRUE; 626 630 } 627 631 628 JSBool JSI_IGUIObject::focus(JSContext* cx, uint Nargc, jsval* vp)632 JSBool JSI_IGUIObject::focus(JSContext* cx, uint argc, jsval* vp) 629 633 { 630 634 UNUSED2(argc); 631 635 … … 639 643 return JS_TRUE; 640 644 } 641 645 642 JSBool JSI_IGUIObject::blur(JSContext* cx, uint Nargc, jsval* vp)646 JSBool JSI_IGUIObject::blur(JSContext* cx, uint argc, jsval* vp) 643 647 { 644 648 UNUSED2(argc); 645 649 … … 653 657 return JS_TRUE; 654 658 } 655 659 656 JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uint Nargc, jsval* vp)660 JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, jsval* vp) 657 661 { 658 662 UNUSED2(argc); 659 663 IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL); -
source/gui/scripting/JSInterface_IGUIObject.h
25 25 extern JSClass JSI_class; 26 26 extern JSPropertySpec JSI_props[]; 27 27 extern JSFunctionSpec JSI_methods[]; 28 JSBool getProperty(JSContext* cx, JS Object* obj, jsid id, jsval*vp);29 JSBool setProperty(JSContext* cx, JS Object* obj, jsid id, JSBool strict, jsval*vp);30 JSBool construct(JSContext* cx, uint Nargc, jsval* vp);31 JSBool toString(JSContext* cx, uint Nargc, jsval* vp);32 JSBool focus(JSContext* cx, uint Nargc, jsval* vp);33 JSBool blur(JSContext* cx, uint Nargc, jsval* vp);34 JSBool getComputedSize(JSContext* cx, uint Nargc, jsval* vp);28 JSBool getProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<jsval> vp); 29 JSBool setProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JSBool UNUSED(strict), JS::MutableHandle<jsval> vp); 30 JSBool construct(JSContext* cx, uint argc, jsval* vp); 31 JSBool toString(JSContext* cx, uint argc, jsval* vp); 32 JSBool focus(JSContext* cx, uint argc, jsval* vp); 33 JSBool blur(JSContext* cx, uint argc, jsval* vp); 34 JSBool getComputedSize(JSContext* cx, uint argc, jsval* vp); 35 35 void init(ScriptInterface& scriptInterface); 36 36 } 37 37 -
source/gui/scripting/ScriptFunctions.cpp
69 69 #include "soundmanager/SoundManager.h" 70 70 #include "soundmanager/scripting/JSInterface_Sound.h" 71 71 72 #include "js/jsapi.h"73 72 /* 74 73 * This file defines a set of functions that are available to GUI scripts, to allow 75 74 * interaction with the rest of the engine. … … 88 87 // TODO: Use LOGERROR to print a friendly error message when the requirements aren't met instead of failing with debug_warn when cloning. 89 88 void PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring name, CScriptVal initData) 90 89 { 91 // TODO: Check the comment in CGUIManager::SwitchPage for a detailed explanation of this hack. 92 CScriptVal cloneSaveInitData; 93 cloneSaveInitData = g_GUI->GetScriptInterface()->CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), initData.get()); 94 g_GUI->PushPage(name, g_GUI->GetScriptInterface()->WriteStructuredClone(cloneSaveInitData.get())); 90 g_GUI->PushPage(name, pCxPrivate->pScriptInterface->WriteStructuredClone(initData.get())); 95 91 } 96 92 97 93 void SwitchGuiPage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring name, CScriptVal initData) … … 557 553 void ForceGC(ScriptInterface::CxPrivate* pCxPrivate) 558 554 { 559 555 double time = timer_Time(); 560 JS_GC(pCxPrivate->pScriptInterface->Get Context());556 JS_GC(pCxPrivate->pScriptInterface->GetJSRuntime()); 561 557 time = timer_Time() - time; 562 558 g_Console->InsertMessage(L"Garbage collection completed in: %f", time); 563 559 } -
source/lib/types.h
29 29 30 30 #include "lib/posix/posix_types.h" 31 31 32 // defines instead of typedefs so we can #undef in case of conflicts 32 typedef int8_t i8; 33 typedef int16_t i16; 34 typedef int32_t i32; 35 typedef int64_t i64; 33 36 34 #define i8 int8_t 35 #define i16 int16_t 36 #define i32 int32_t 37 #define i64 int64_t 37 typedef uint8_t u8; 38 typedef uint16_t u16; 39 typedef uint32_t u32; 40 typedef uint64_t u64; 38 41 39 #define u8 uint8_t40 #define u16 uint16_t41 #define u32 uint32_t42 #define u64 uint64_t43 44 42 #endif // #ifndef INCLUDED_TYPES -
source/lobby/XmppClient.cpp
309 309 void XmppClient::SendIqGameReport(ScriptInterface& scriptInterface, CScriptVal data) 310 310 { 311 311 glooxwrapper::JID xpartamuppJid(m_xpartamuppId); 312 jsval dataval = data.get();312 JS::RootedValue dataval(scriptInterface.GetContext(), data.get()); 313 313 314 314 // Setup some base stanza attributes 315 315 GameReport* game = new GameReport(); … … 317 317 318 318 // Iterate through all the properties reported and add them to the stanza. 319 319 std::vector<std::string> properties; 320 scriptInterface.EnumeratePropertyNamesWithPrefix( dataval, "", properties);320 scriptInterface.EnumeratePropertyNamesWithPrefix(JS::RootedObject(scriptInterface.GetContext(), JSVAL_TO_OBJECT(dataval)), "", properties); 321 321 for (std::vector<int>::size_type i = 0; i != properties.size(); i++) 322 322 { 323 323 std::wstring value; … … 343 343 void XmppClient::SendIqRegisterGame(ScriptInterface& scriptInterface, CScriptVal data) 344 344 { 345 345 glooxwrapper::JID xpartamuppJid(m_xpartamuppId); 346 jsval dataval = data.get();346 JS::RootedValue dataval(scriptInterface.GetContext(), data.get()); 347 347 348 348 // Setup some base stanza attributes 349 349 GameListQuery* g = new GameListQuery(); … … 354 354 355 355 // Iterate through all the properties reported and add them to the stanza. 356 356 std::vector<std::string> properties; 357 scriptInterface.EnumeratePropertyNamesWithPrefix(dataval, "", properties); 357 JS::RootedObject dataobj(scriptInterface.GetContext(), JSVAL_TO_OBJECT(dataval.get())); 358 scriptInterface.EnumeratePropertyNamesWithPrefix(dataobj, "", properties); 358 359 for (std::vector<int>::size_type i = 0; i != properties.size(); i++) 359 360 { 360 361 std::wstring value; -
source/network/NetServer.cpp
342 342 343 343 void CNetServerWorker::Run() 344 344 { 345 // The script runtime uses the profiler and therefore the thread must be registered before the runtime is created 346 g_Profiler2.RegisterCurrentThread("Net server"); 347 345 348 // To avoid the need for JS_SetContextThread, we create and use and destroy 346 349 // the script interface entirely within this network thread 347 350 m_ScriptInterface = new ScriptInterface("Engine", "Net server", ScriptInterface::CreateRuntime()); -
source/ps/Errors.h
72 72 73 73 #include <exception> 74 74 75 typedef u 32PSRETURN;75 typedef uint32_t PSRETURN; 76 76 77 77 class PSERROR : public std::exception 78 78 { -
source/ps/GameSetup/GameSetup.cpp
560 560 SAFE_DELETE(g_GUI); 561 561 562 562 SAFE_DELETE(g_Console); 563 564 // This is needed to ensure that no callbacks from the JSAPI try to use 565 // the profiler when it's already destructed 566 g_ScriptRuntime.reset(); 563 567 564 568 // disable the special Windows cursor, or free textures for OGL cursors 565 569 cursor_draw(g_VFS, 0, g_mouse_x, g_yres-g_mouse_y, false); … … 858 862 g_Logger = new CLogger; 859 863 860 864 // Workaround until Simulation and AI use their own threads and also their own runtimes 861 g_ScriptRuntime = ScriptInterface::CreateRuntime( 128* 1024 * 1024);865 g_ScriptRuntime = ScriptInterface::CreateRuntime(384 * 1024 * 1024); 862 866 863 867 // Special command-line mode to dump the entity schemas instead of running the game. 864 868 // (This must be done after loading VFS etc, but should be done before wasting time … … 1104 1108 CStr seedArg = args.Get("autostart-random"); 1105 1109 1106 1110 // Default seed is 0 1107 uint32 seed = 0;1111 uint32_t seed = 0; 1108 1112 if (!seedArg.empty()) 1109 1113 { 1110 1114 if (seedArg.compare("-1") == 0) -
source/ps/Profile.cpp
29 29 # define USE_CRT_SET_ALLOC_HOOK 30 30 #endif 31 31 32 #if defined(__GLIBC__) && !defined(NDEBUG)33 //# define USE_GLIBC_MALLOC_HOOK34 # define USE_GLIBC_MALLOC_OVERRIDE35 # include <dlfcn.h>36 # include <malloc.h>37 # include "lib/sysdep/cpu.h"38 #endif39 40 32 #include <numeric> 41 33 42 34 /////////////////////////////////////////////////////////////////////////////////////////////// -
source/ps/Replay.cpp
127 127 new CProfileManager; 128 128 g_ScriptStatsTable = new CScriptStatsTable; 129 129 g_ProfileViewer.AddRootTable(g_ScriptStatsTable); 130 g_ScriptRuntime = ScriptInterface::CreateRuntime( 128* 1024 * 1024);130 g_ScriptRuntime = ScriptInterface::CreateRuntime(384 * 1024 * 1024); 131 131 132 132 CGame game(true); 133 133 g_Game = &game; … … 210 210 g_Profiler2.IncrementFrameNumber(); 211 211 PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); 212 212 213 game.GetSimulation2()->Tick(); 213 214 game.GetSimulation2()->Update(turnLength, commands); 214 215 commands.clear(); 215 216 } … … 217 218 // std::string hash; 218 219 // bool ok = game.GetSimulation2()->ComputeStateHash(hash, true); 219 220 // ENSURE(ok); 220 // debug_printf(L" %hs", Hexify(hash).c_str());221 // debug_printf(L"turn hash (%u) : %hs", turn, Hexify(hash).c_str()); 221 222 222 223 debug_printf(L"\n"); 223 224 … … 244 245 245 246 timer_DisplayClientTotals(); 246 247 248 // Must be explicitly destructed here to avoid callbacks from the JSAPI trying to use g_Profiler2 when 249 // it's already destructed. 250 g_ScriptRuntime.reset(); 251 247 252 // Clean up 248 253 delete &g_TexMan; 249 254 tex_codec_unregister_all(); -
source/ps/scripting/JSInterface_VFS.cpp
68 68 { 69 69 BuildDirEntListState* s = (BuildDirEntListState*)cbData; 70 70 71 jsval val = ScriptInterface::ToJSVal(s->cx, CStrW(pathname.string()));72 JS_SetElement(s->cx, s->filename_array, s->cur_idx++, &val);71 JS::RootedValue val(s->cx, ScriptInterface::ToJSVal( s->cx, CStrW(pathname.string()) )); 72 JS_SetElement(s->cx, s->filename_array, s->cur_idx++, val.address()); 73 73 return INFO::OK; 74 74 } 75 75 … … 191 191 while (std::getline(ss, line)) 192 192 { 193 193 // Decode each line as UTF-8 194 jsval val = ScriptInterface::ToJSVal(cx, CStr(line).FromUTF8());195 JS_SetElement(cx, line_array, cur_line++, &val);194 JS::RootedValue val(cx, ScriptInterface::ToJSVal(cx, CStr(line).FromUTF8())); 195 JS_SetElement(cx, line_array, cur_line++, val.address()); 196 196 } 197 197 198 198 return OBJECT_TO_JSVAL( line_array ); -
source/scriptinterface/AutoRooters.cpp
40 40 41 41 for (size_t i = 0; i < m_Objects.size(); ++i) 42 42 { 43 JS_C ALL_OBJECT_TRACER(trc,m_Objects[i], "AutoGCRooter object");43 JS_CallObjectTracer(trc, &m_Objects[i], "AutoGCRooter object"); 44 44 } 45 45 46 46 for (size_t i = 0; i < m_Vals.size(); ++i) 47 47 { 48 JS_C ALL_VALUE_TRACER(trc,m_Vals[i], "AutoGCRooter val");48 JS_CallValueTracer(trc, &m_Vals[i], "AutoGCRooter val"); 49 49 } 50 50 51 51 for (size_t i = 0; i < m_IdArrays.size(); ++i) 52 52 { 53 for ( jsint j = 0; j < m_IdArrays[i]->length; ++j)53 for (size_t j = 0; j < JS_IdArrayLength(m_ScriptInterface.GetContext(), m_IdArrays[i]); ++j) 54 54 { 55 55 jsval val = JSVAL_VOID; 56 JS_IdToValue(m_ScriptInterface.GetContext(), m_IdArrays[i]->vector[j], &val);57 JS_C ALL_VALUE_TRACER(trc,val, "AutoGCRooter id array");56 JS_IdToValue(m_ScriptInterface.GetContext(), JS_IdArrayGet(m_ScriptInterface.GetContext(), m_IdArrays[i], j), &val); 57 JS_CallValueTracer(trc, &val, "AutoGCRooter id array"); 58 58 } 59 59 } 60 60 -
source/scriptinterface/AutoRooters.h
20 20 21 21 #include "scriptinterface/ScriptTypes.h" 22 22 23 #include "js/jsapi.h"24 23 25 24 /** 26 25 * Helper for rooting large groups of script values. -
source/scriptinterface/NativeWrapperDecls.h
26 26 #define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i 27 27 // Some other things 28 28 #define TYPED_ARGS(z, i, data) , T##i a##i 29 #define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal<T##i>(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) return JS_FALSE;29 #define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal<T##i>(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) return false; 30 30 31 31 // List-generating macros, named roughly after their first list item 32 32 #define TYPENAME_T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, typename T) // "typename T0, typename T1, " … … 51 51 // (Definition comes later, since it depends on some things we haven't defined yet) 52 52 #define OVERLOADS(z, i, data) \ 53 53 template <typename R, TYPENAME_T0_HEAD(z,i) R (*fptr) ( ScriptInterface::CxPrivate* T0_TAIL(z,i) )> \ 54 static JSBool call(JSContext* cx, uint Nargc, jsval* vp);54 static JSBool call(JSContext* cx, uint32_t argc, jsval* vp); 55 55 BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) 56 56 #undef OVERLOADS 57 57 58 58 // Similar, for class methods 59 59 #define OVERLOADS(z, i, data) \ 60 60 template <typename R, TYPENAME_T0_HEAD(z,i) JSClass* CLS, typename TC, R (TC::*fptr) ( T0(z,i) )> \ 61 static JSBool callMethod(JSContext* cx, uint Nargc, jsval* vp);61 static JSBool callMethod(JSContext* cx, uint32_t argc, jsval* vp); 62 62 BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) 63 63 #undef OVERLOADS 64 64 -
source/scriptinterface/NativeWrapperDefns.h
79 79 #define SCRIPT_PROFILE \ 80 80 if (g_ScriptProfilingEnabled) \ 81 81 { \ 82 ENSURE( JSVAL_IS_OBJECT(JS_CALLEE(cx, vp)) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)))); \82 ENSURE(!JSVAL_IS_PRIMITIVE(JS_CALLEE(cx, vp)) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)))); \ 83 83 const char* name = "(unknown)"; \ 84 84 jsval nameval; \ 85 if (JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0, &nameval)\86 &&!JSVAL_IS_VOID(nameval)) \85 nameval = JS_GetReservedSlot(JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0); \ 86 if (!JSVAL_IS_VOID(nameval)) \ 87 87 name = static_cast<const char*>(JSVAL_TO_PRIVATE(nameval)); \ 88 88 CProfileSampleScript profile(name); \ 89 89 } … … 91 91 // JSFastNative-compatible function that wraps the function identified in the template argument list 92 92 #define OVERLOADS(z, i, data) \ 93 93 template <typename R, TYPENAME_T0_HEAD(z,i) R (*fptr) ( ScriptInterface::CxPrivate* T0_TAIL(z,i) )> \ 94 JSBool ScriptInterface::call(JSContext* cx, uint Nargc, jsval* vp) { \94 JSBool ScriptInterface::call(JSContext* cx, uint32_t argc, jsval* vp) { \ 95 95 UNUSED2(argc); \ 96 96 SCRIPT_PROFILE \ 97 97 BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ 98 98 jsval rval = JSVAL_VOID; \ 99 99 ScriptInterface_NativeWrapper<R>::call(cx, rval, fptr A0_TAIL(z,i)); \ 100 100 JS_SET_RVAL(cx, vp, rval); \ 101 return (ScriptInterface::IsExceptionPending(cx) ? JS_FALSE : JS_TRUE); \101 return !ScriptInterface::IsExceptionPending(cx); \ 102 102 } 103 103 BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) 104 104 #undef OVERLOADS … … 106 106 // Same idea but for methods 107 107 #define OVERLOADS(z, i, data) \ 108 108 template <typename R, TYPENAME_T0_HEAD(z,i) JSClass* CLS, typename TC, R (TC::*fptr) ( T0(z,i) )> \ 109 JSBool ScriptInterface::callMethod(JSContext* cx, uint Nargc, jsval* vp) { \109 JSBool ScriptInterface::callMethod(JSContext* cx, uint32_t argc, jsval* vp) { \ 110 110 UNUSED2(argc); \ 111 111 SCRIPT_PROFILE \ 112 if (ScriptInterface::GetClass( cx, JS_THIS_OBJECT(cx, vp)) != CLS) return JS_FALSE; \113 TC* c = static_cast<TC*>(ScriptInterface::GetPrivate( cx,JS_THIS_OBJECT(cx, vp))); \114 if (! c) return JS_FALSE; \112 if (ScriptInterface::GetClass(JS_THIS_OBJECT(cx, vp)) != CLS) return false; \ 113 TC* c = static_cast<TC*>(ScriptInterface::GetPrivate(JS_THIS_OBJECT(cx, vp))); \ 114 if (! c) return false; \ 115 115 BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ 116 116 jsval rval = JSVAL_VOID; \ 117 117 ScriptInterface_NativeMethodWrapper<R, TC>::call(cx, rval, c, fptr A0_TAIL(z,i)); \ 118 118 JS_SET_RVAL(cx, vp, rval); \ 119 return (ScriptInterface::IsExceptionPending(cx) ? JS_FALSE : JS_TRUE); \119 return !ScriptInterface::IsExceptionPending(cx); \ 120 120 } 121 121 BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) 122 122 #undef OVERLOADS -
source/scriptinterface/ScriptConversions.cpp
32 32 33 33 template<> bool ScriptInterface::FromJSVal<bool>(JSContext* cx, jsval v, bool& out) 34 34 { 35 JSAutoRequest rq(cx); 35 36 JSBool ret; 36 37 WARN_IF_NOT(JSVAL_IS_BOOLEAN(v), v); 37 38 if (!JS_ValueToBoolean(cx, v, &ret)) … … 42 43 43 44 template<> bool ScriptInterface::FromJSVal<float>(JSContext* cx, jsval v, float& out) 44 45 { 45 jsdouble ret; 46 JSAutoRequest rq(cx); 47 double ret; 46 48 WARN_IF_NOT(JSVAL_IS_NUMBER(v), v); 47 49 if (!JS_ValueToNumber(cx, v, &ret)) 48 50 return false; … … 52 54 53 55 template<> bool ScriptInterface::FromJSVal<double>(JSContext* cx, jsval v, double& out) 54 56 { 55 jsdouble ret; 57 JSAutoRequest rq(cx); 58 double ret; 56 59 WARN_IF_NOT(JSVAL_IS_NUMBER(v), v); 57 60 if (!JS_ValueToNumber(cx, v, &ret)) 58 61 return false; … … 62 65 63 66 template<> bool ScriptInterface::FromJSVal<i32>(JSContext* cx, jsval v, i32& out) 64 67 { 65 int32 ret; 68 JSAutoRequest rq(cx); 69 // TODO: Change FromJSVal to use JS::RootedValue and remove this temporary workaround here 70 JS::RootedValue v1(cx, v); 71 int32_t ret; 66 72 WARN_IF_NOT(JSVAL_IS_NUMBER(v), v); 67 if (!JS _ValueToECMAInt32(cx, v, &ret))73 if (!JS::ToInt32(cx, v1, &ret)) 68 74 return false; 69 75 out = ret; 70 76 return true; … … 72 78 73 79 template<> bool ScriptInterface::FromJSVal<u32>(JSContext* cx, jsval v, u32& out) 74 80 { 75 uint32 ret; 81 JSAutoRequest rq(cx); 82 uint32_t ret; 76 83 WARN_IF_NOT(JSVAL_IS_NUMBER(v), v); 77 84 if (!JS_ValueToECMAUint32(cx, v, &ret)) 78 85 return false; … … 82 89 83 90 template<> bool ScriptInterface::FromJSVal<u16>(JSContext* cx, jsval v, u16& out) 84 91 { 85 uint16 ret; 92 JSAutoRequest rq(cx); 93 uint16_t ret; 86 94 WARN_IF_NOT(JSVAL_IS_NUMBER(v), v); 87 95 if (!JS_ValueToUint16(cx, v, &ret)) 88 96 return false; … … 92 100 93 101 template<> bool ScriptInterface::FromJSVal<u8>(JSContext* cx, jsval v, u8& out) 94 102 { 95 uint16 ret; 103 JSAutoRequest rq(cx); 104 uint16_t ret; 96 105 WARN_IF_NOT(JSVAL_IS_NUMBER(v), v); 97 106 if (!JS_ValueToUint16(cx, v, &ret)) 98 107 return false; … … 102 111 103 112 template<> bool ScriptInterface::FromJSVal<long>(JSContext* cx, jsval v, long& out) 104 113 { 105 int32 tmp;106 JSBool ok = JS_ValueToInt32(cx, v, &tmp);114 int32_t tmp; 115 bool ok = JS_ValueToInt32(cx, v, &tmp); 107 116 out = (long)tmp; 108 return ok == JS_TRUE;117 return ok; 109 118 } 110 119 111 120 template<> bool ScriptInterface::FromJSVal<unsigned long>(JSContext* cx, jsval v, unsigned long& out) 112 121 { 113 int32 tmp;114 JSBool ok = JS_ValueToInt32(cx, v, &tmp);122 int32_t tmp; 123 bool ok = JS_ValueToInt32(cx, v, &tmp); 115 124 out = (unsigned long)tmp; 116 return ok == JS_TRUE;125 return ok; 117 126 } 118 127 119 128 // see comment below (where the same preprocessor condition is used) … … 143 152 144 153 #endif 145 154 146 // NOTE: we can't define a jsval specialisation, because that conflicts with integer types 155 template<> jsval ScriptInterface::ToJSVal<JS::Value>(JSContext* UNUSED(cx), const JS::Value& val) 156 { 157 return val; 158 } 159 147 160 template<> bool ScriptInterface::FromJSVal<CScriptVal>(JSContext* UNUSED(cx), jsval v, CScriptVal& out) 148 161 { 149 162 out = v; 150 163 return true; 151 164 } 152 165 166 template<> bool ScriptInterface::FromJSVal<JS::RootedObject>(JSContext* UNUSED(cx), jsval v, JS::RootedObject& out) 167 { 168 if (v.isObjectOrNull()) 169 { 170 out.set(JSVAL_TO_OBJECT(v)); 171 return true; 172 } 173 return false; 174 } 175 153 176 template<> bool ScriptInterface::FromJSVal<CScriptValRooted>(JSContext* cx, jsval v, CScriptValRooted& out) 154 177 { 155 178 out = CScriptValRooted(cx, v); … … 158 181 159 182 template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, jsval v, std::wstring& out) 160 183 { 184 JSAutoRequest rq(cx); 161 185 WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions 162 186 JSString* ret = JS_ValueToString(cx, v); 163 187 if (!ret) … … 181 205 182 206 template<> bool ScriptInterface::FromJSVal<std::string>(JSContext* cx, jsval v, std::string& out) 183 207 { 208 JSAutoRequest rq(cx); 184 209 WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions 185 210 JSString* ret = JS_ValueToString(cx, v); 186 211 if (!ret) … … 205 230 206 231 template<> bool ScriptInterface::FromJSVal<Entity>(JSContext* cx, jsval v, Entity& out) 207 232 { 233 JSAutoRequest rq(cx); 208 234 JSObject* obj; 209 235 if (!JS_ValueToObject(cx, v, &obj) || obj == NULL) 210 236 FAIL("Argument must be an object"); 211 237 212 jsval templateName, id, player, position, rotation; 238 JS::RootedValue templateName(cx); 239 JS::RootedValue id(cx); 240 JS::RootedValue player(cx); 241 JS::RootedValue position(cx); 242 JS::RootedValue rotation(cx); 213 243 214 244 // TODO: Report type errors 215 if(!JS_GetProperty(cx, obj, "player", &player) || !FromJSVal(cx, player, out.playerID))245 if(!JS_GetProperty(cx, obj, "player", player.address()) || !FromJSVal(cx, player, out.playerID)) 216 246 FAIL("Failed to read Entity.player property"); 217 if (!JS_GetProperty(cx, obj, "templateName", &templateName) || !FromJSVal(cx, templateName, out.templateName))247 if (!JS_GetProperty(cx, obj, "templateName", templateName.address()) || !FromJSVal(cx, templateName, out.templateName)) 218 248 FAIL("Failed to read Entity.templateName property"); 219 if (!JS_GetProperty(cx, obj, "id", &id) || !FromJSVal(cx, id, out.entityID))249 if (!JS_GetProperty(cx, obj, "id", id.address()) || !FromJSVal(cx, id, out.entityID)) 220 250 FAIL("Failed to read Entity.id property"); 221 if (!JS_GetProperty(cx, obj, "position", &position) || !FromJSVal(cx, position, out.position))251 if (!JS_GetProperty(cx, obj, "position", position.address()) || !FromJSVal(cx, position, out.position)) 222 252 FAIL("Failed to read Entity.position property"); 223 if (!JS_GetProperty(cx, obj, "rotation", &rotation) || !FromJSVal(cx, rotation, out.rotation))253 if (!JS_GetProperty(cx, obj, "rotation", rotation.address()) || !FromJSVal(cx, rotation, out.rotation)) 224 254 FAIL("Failed to read Entity.rotation property"); 225 255 226 256 return true; … … 234 264 return val ? JSVAL_TRUE : JSVAL_FALSE; 235 265 } 236 266 237 template<> jsval ScriptInterface::ToJSVal<float>(JSContext* cx, const float& val)267 template<> jsval ScriptInterface::ToJSVal<float>(JSContext* UNUSED(cx), const float& val) 238 268 { 239 jsval rval = JSVAL_VOID; 240 JS_NewNumberValue(cx, val, &rval); // ignore return value 269 jsval rval = JS_NumberValue(val); 241 270 return rval; 242 271 } 243 272 244 template<> jsval ScriptInterface::ToJSVal<double>(JSContext* cx, const double& val)273 template<> jsval ScriptInterface::ToJSVal<double>(JSContext* UNUSED(cx), const double& val) 245 274 { 246 jsval rval = JSVAL_VOID; 247 JS_NewNumberValue(cx, val, &rval); // ignore return value 275 jsval rval = JS_NumberValue(val); 248 276 return rval; 249 277 } 250 278 … … 264 292 return INT_TO_JSVAL(val); 265 293 } 266 294 267 template<> jsval ScriptInterface::ToJSVal<u32>(JSContext* cx, const u32& val)295 template<> jsval ScriptInterface::ToJSVal<u32>(JSContext* UNUSED(cx), const u32& val) 268 296 { 269 297 if (val <= JSVAL_INT_MAX) 270 298 return INT_TO_JSVAL(val); 271 jsval rval = JSVAL_VOID; 272 JS_NewNumberValue(cx, val, &rval); // ignore return value 299 jsval rval = JS_NumberValue(val); 273 300 return rval; 274 301 } 275 302 … … 315 342 316 343 template<> jsval ScriptInterface::ToJSVal<std::wstring>(JSContext* cx, const std::wstring& val) 317 344 { 345 JSAutoRequest rq(cx); 318 346 utf16string utf16(val.begin(), val.end()); 319 347 JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast<const jschar*> (utf16.c_str()), utf16.length()); 320 348 if (str) … … 329 357 330 358 template<> jsval ScriptInterface::ToJSVal<std::string>(JSContext* cx, const std::string& val) 331 359 { 360 JSAutoRequest rq(cx); 332 361 JSString* str = JS_NewStringCopyN(cx, val.c_str(), val.length()); 333 362 if (str) 334 363 return STRING_TO_JSVAL(str); … … 342 371 343 372 template<> jsval ScriptInterface::ToJSVal<const char*>(JSContext* cx, const char* const& val) 344 373 { 374 JSAutoRequest rq(cx); 345 375 JSString* str = JS_NewStringCopyZ(cx, val); 346 376 if (str) 347 377 return STRING_TO_JSVAL(str); … … 363 393 364 394 template<typename T> static jsval ToJSVal_vector(JSContext* cx, const std::vector<T>& val) 365 395 { 366 JSObject* obj = JS_NewArrayObject(cx, (jsint)val.size(), NULL); 396 JSAutoRequest rq(cx); 397 JSObject* obj = JS_NewArrayObject(cx, val.size(), NULL); 367 398 if (!obj) 368 399 return JSVAL_VOID; 369 for ( size_t i = 0; i < val.size(); ++i)400 for (uint32_t i = 0; i < val.size(); ++i) 370 401 { 371 jsval el = ScriptInterface::ToJSVal<T>(cx, val[i]);372 JS_SetElement(cx, obj, (jsint)i, &el);402 JS::RootedValue el(cx, ScriptInterface::ToJSVal<T>(cx, val[i])); 403 JS_SetElement(cx, obj, i, el.address()); 373 404 } 374 405 return OBJECT_TO_JSVAL(obj); 375 406 } 376 407 377 408 template<typename T> static bool FromJSVal_vector(JSContext* cx, jsval v, std::vector<T>& out) 378 409 { 410 JSAutoRequest rq(cx); 379 411 JSObject* obj; 380 if (!JS_ValueToObject(cx, v, &obj) || obj == NULL || !(JS_IsArrayObject(cx, obj) || js_IsTypedArray(obj)))412 if (!JS_ValueToObject(cx, v, &obj) || obj == NULL || !(JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj))) 381 413 FAIL("Argument must be an array"); 382 jsuint length;414 uint32_t length; 383 415 if (!JS_GetArrayLength(cx, obj, &length)) 384 416 FAIL("Failed to get array length"); 385 417 out.reserve(length); 386 for ( jsuint i = 0; i < length; ++i)418 for (uint32_t i = 0; i < length; ++i) 387 419 { 388 jsval el;389 if (!JS_GetElement(cx, obj, i, &el))420 JS::RootedValue el(cx); 421 if (!JS_GetElement(cx, obj, i, el.address())) 390 422 FAIL("Failed to read array element"); 391 423 T el2; 392 424 if (!ScriptInterface::FromJSVal<T>(cx, el, el2)) -
source/scriptinterface/ScriptExtraHeaders.h
25 25 #include "scriptinterface/ScriptTypes.h" 26 26 27 27 // Ignore some harmless warnings 28 #if GCC_VERSION >= 402 // (older GCCs don't support this pragma) 28 // Not all of these warnings can be disabled in older versions of GCC. 29 // The version checking was taken from the manual here: 30 // http://gcc.gnu.org/onlinedocs/ 31 // Choose the version and navigate to "Options to Request or Suppress Warnings" 32 // or for some flags "Options Controlling C++ Dialect". 33 #if GCC_VERSION >= 402 29 34 # if GCC_VERSION >= 406 // store user flags 30 35 # pragma GCC diagnostic push 31 36 # endif 32 37 # pragma GCC diagnostic ignored "-Wunused-parameter" 33 38 # pragma GCC diagnostic ignored "-Wredundant-decls" 34 # if GCC_VERSION >= 408 39 # pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 40 # if GCC_VERSION >= 407 35 41 # pragma GCC diagnostic ignored "-Wunused-local-typedefs" // caused by js/debug.h 36 42 # endif 37 43 #endif … … 46 52 # define signbit std::signbit 47 53 #endif 48 54 49 #include "js/jstypedarray.h" 50 #include "js/jsdbgapi.h" 55 #include "jsfriendapi.h" 56 #include "jsdbgapi.h" 57 #include "js/GCAPI.h" 51 58 52 59 #undef signbit 53 60 … … 57 64 #if GCC_VERSION >= 402 58 65 # pragma GCC diagnostic warning "-Wunused-parameter" 59 66 # pragma GCC diagnostic warning "-Wredundant-decls" 67 # pragma GCC diagnostic warning "-Wnon-virtual-dtor" 68 # if GCC_VERSION >= 407 69 # pragma GCC diagnostic warning "-Wunused-local-typedefs" // caused by js/debug.h 70 # endif 60 71 # if GCC_VERSION >= 406 61 72 # pragma GCC diagnostic pop // restore user flags 62 73 # endif -
source/scriptinterface/ScriptInterface.cpp
65 65 * (One means to share data between threads and runtimes is to create 66 66 * a ScriptInterface::StructuredClone.) 67 67 */ 68 69 70 void GCSliceCallbackHook(JSRuntime* UNUSED(rt), JS::GCProgress progress, const JS::GCDescription& UNUSED(desc)) 71 { 72 /* 73 * During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END 74 * callbacks. During an incremental GC, the sequence of callbacks is as 75 * follows: 76 * JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice) 77 * JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice) 78 * ... 79 * JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice) 80 */ 81 82 83 if (progress == JS::GC_SLICE_BEGIN) 84 { 85 if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread()) 86 g_Profiler.Start("GCSlice"); 87 g_Profiler2.RecordRegionEnter("GCSlice"); 88 } 89 else if (progress == JS::GC_SLICE_END) 90 { 91 if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread()) 92 g_Profiler.Stop(); 93 g_Profiler2.RecordRegionLeave("GCSlice"); 94 } 95 else if (progress == JS::GC_CYCLE_BEGIN) 96 { 97 if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread()) 98 g_Profiler.Start("GCSlice"); 99 g_Profiler2.RecordRegionEnter("GCSlice"); 100 } 101 else if (progress == JS::GC_CYCLE_END) 102 { 103 if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread()) 104 g_Profiler.Stop(); 105 g_Profiler2.RecordRegionLeave("GCSlice"); 106 } 107 108 // The following code can be used to print some information aobut garbage collection 109 // Search for "Nonincremental reason" if there are problems running GC incrementally. 110 /* 111 if (progress == JS::GCProgress::GC_CYCLE_BEGIN) 112 printf("starting cycle ===========================================\n"); 113 //{ 114 const jschar* str = desc.formatMessage(rt); 115 int len = 0; 116 117 for(int i = 0; i < 10000; i++) 118 { 119 len++; 120 if(!str[i]) 121 break; 122 } 123 124 wchar_t outstring[len]; 125 126 for(int i = 0; i < len; i++) 127 { 128 outstring[i] = (wchar_t)str[i]; 129 } 130 131 printf("---------------------------------------\n: %ls \n---------------------------------------\n", outstring); 132 //}*/ 133 } 134 68 135 class ScriptRuntime 69 136 { 70 137 public: 71 ScriptRuntime(int runtimeSize) : 72 m_rooter(NULL) 138 ScriptRuntime(int runtimeSize): 139 m_rooter(NULL), 140 m_LastGCBytes(0) 73 141 { 74 m_rt = JS_NewRuntime(runtimeSize); 142 m_rt = JS_NewRuntime(runtimeSize, JS_USE_HELPER_THREADS); 143 75 144 ENSURE(m_rt); // TODO: error handling 76 145 146 JS_SetNativeStackQuota(m_rt, 128 * sizeof(size_t) * 1024); 77 147 if (g_ScriptProfilingEnabled) 78 148 { 79 149 // Profiler isn't thread-safe, so only enable this on the main thread … … 86 156 } 87 157 } 88 158 } 89 90 JS_SetExtraGCRoots(m_rt, jshook_trace, this); 159 160 JS::SetGCSliceCallback(m_rt, GCSliceCallbackHook); 161 162 JS_SetGCParameter(m_rt, JSGC_MAX_MALLOC_BYTES, 384 * 1024 * 1024); 163 JS_SetGCParameter(m_rt, JSGC_MAX_BYTES, 384 * 1024 * 1024); 164 JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_INCREMENTAL); 165 //JS_SetGCParameter(m_rt, JSGC_SLICE_TIME_BUDGET, 5); 166 JS_SetGCParameter(m_rt, JSGC_ALLOCATION_THRESHOLD, 256); 167 168 // The whole heap-growth mechanism seems to work only for non-incremental GCs. 169 // We disable it to make it more clear if full GCs happen triggered by this JSAPI internal mechanism. 170 JS_SetGCParameter(m_rt, JSGC_DYNAMIC_HEAP_GROWTH, false); 171 172 JS_AddExtraGCRootsTracer(m_rt, jshook_trace, this); 173 174 m_dummyContext = JS_NewContext(m_rt, STACK_CHUNK_SIZE); 175 ENSURE(m_dummyContext); 91 176 } 177 178 void MaybeIncrementalGC() 179 { 180 PROFILE3("MaybeIncrementalGC"); 181 if (JS::IsIncrementalGCEnabled(m_rt)) 182 { 183 // The idea is to get the heap size after a completed GC and trigger the next GC when the heap size has 184 // reached m_LastGCBytes + X. 185 // In practice it doesn't quite work like that. When the incremental marking is completed, the sweeping kicks in. 186 // The sweeping actually frees memory and it does this in a background thread (if JS_USE_HELPER_THREADS is set). 187 // While the sweeping is happening we already run scripts again and produce new garbage. 188 int gcBytes = JS_GetGCParameter(m_rt, JSGC_BYTES); 189 //printf("gcBytes: %d \n", gcBytes); 190 if (m_LastGCBytes > gcBytes || m_LastGCBytes == 0) 191 { 192 //printf("Setting m_LastGCBytes: %d \n", gcBytes); // debugging 193 m_LastGCBytes = gcBytes; 194 } 195 196 // Run an additional incremental GC slice if the currently running incremental GC isn't over yet 197 // ... or 198 // start a new incremental GC if the JS heap size has grown enough for a GC to make sense 199 if (JS::IsIncrementalGCInProgress(m_rt) || (gcBytes - m_LastGCBytes > 20 * 1024 * 1024)) 200 { 201 /* Use for debugging 202 if (JS::IsIncrementalGCInProgress(m_rt)) 203 printf("Running incremental garbage collection because an incremental cycle is in progress. \n"); 204 else 205 printf("Running incremental garbage collection because JSGC_BYTES - m_LastGCBytes > X ---- JSGC_BYTES: %d m_LastGCBytes: %d", gcBytes, m_LastGCBytes); 206 */ 207 PrepareContextsForIncrementalGC(); 208 JS::IncrementalGC(m_rt, JS::gcreason::REFRESH_FRAME, 10); 209 m_LastGCBytes = gcBytes; 210 } 211 } 212 } 213 214 void RegisterContext(JSContext* cx) 215 { 216 m_Contexts.push_back(cx); 217 } 218 219 void UnRegisterContext(JSContext* cx) 220 { 221 m_Contexts.remove(cx); 222 } 92 223 93 224 ~ScriptRuntime() 94 225 { 226 JS_RemoveExtraGCRootsTracer(m_rt, jshook_trace, this); 227 JS_DestroyContext(m_dummyContext); 95 228 JS_DestroyRuntime(m_rt); 96 229 } 97 230 98 231 JSRuntime* m_rt; 99 232 AutoGCRooter* m_rooter; 100 233 101 234 private: 235 236 // Workaround for: https://bugzilla.mozilla.org/show_bug.cgi?id=890243 237 JSContext* m_dummyContext; 238 239 int m_LastGCBytes; 240 241 void PrepareContextsForIncrementalGC() 242 { 243 for (std::list<JSContext*>::iterator itr = m_Contexts.begin(); itr != m_Contexts.end(); itr++) 244 { 245 JS::PrepareZoneForGC(js::GetCompartmentZone(js::GetContextCompartment(*itr))); 246 } 247 } 248 249 std::list<JSContext*> m_Contexts; 102 250 103 251 104 static void* jshook_script(JSContext* UNUSED(cx), JS StackFrame* UNUSED(fp), JSBool before, JSBool* UNUSED(ok), void* closure)252 static void* jshook_script(JSContext* UNUSED(cx), JSAbstractFramePtr UNUSED(fp), bool UNUSED(isConstructing), JSBool before, JSBool* UNUSED(ok), void* closure) 105 253 { 106 254 if (before) 107 255 g_Profiler.StartScript("script invocation"); … … 154 302 if (slash != filename.npos) 155 303 filename = filename.substr(slash+1); 156 304 157 uint Nline = JS_PCToLineNumber(cx, script, pc);305 uint line = JS_PCToLineNumber(cx, script, pc); 158 306 159 307 std::stringstream ss; 160 308 ss << "(" << filename << ":" << line << ")"; … … 178 326 boost::flyweights::no_locking 179 327 > LocFlyweight; 180 328 181 static void* jshook_function(JSContext* cx, JS StackFrame* fp, JSBool before, JSBool* UNUSED(ok), void* closure)329 static void* jshook_function(JSContext* cx, JSAbstractFramePtr fp, bool UNUSED(isConstructing), JSBool before, JSBool* UNUSED(ok), void* closure) 182 330 { 183 331 if (!before) 184 332 { … … 186 334 return closure; 187 335 } 188 336 189 JSFunction* fn = JS_GetFrameFunction(cx, fp);337 JSFunction* fn = fp.maybeFun(); 190 338 if (!fn) 191 339 { 192 340 g_Profiler.StartScript("(function)"); … … 207 355 } 208 356 209 357 // No name - compute from the location instead 210 ScriptLocation loc = { cx, JS_GetFrameScript(cx, fp), JS_GetFramePC(cx, fp) }; 358 JSScript* script; 359 unsigned lineno; 360 JS_DescribeScriptedCaller(cx, &script, &lineno); 361 ENSURE(script == fp.script()); 362 ScriptLocation loc = { cx, fp.script(), JS_LineNumberToPC(cx, script, lineno) }; 211 363 g_Profiler.StartScript(LocFlyweight(loc).get().name.c_str()); 212 364 213 365 return closure; 214 366 } 215 367 216 368 static void jshook_trace(JSTracer* trc, void* data) 217 369 { 218 370 ScriptRuntime* m = static_cast<ScriptRuntime*>(data); 219 371 220 372 if (m->m_rooter) 221 373 m->m_rooter->Trace(trc); 222 374 } … … 233 385 { 234 386 ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime); 235 387 ~ScriptInterface_impl(); 236 void Register(const char* name, JSNative fptr, uint Nnargs);388 void Register(const char* name, JSNative fptr, uint nargs); 237 389 238 390 shared_ptr<ScriptRuntime> m_runtime; 239 391 JSContext* m_cx; 240 392 JSObject* m_glob; // global scope object 393 JSCompartment* m_comp; 394 boost::rand48* m_rng; 241 395 JSObject* m_nativeScope; // native function scope object 242 396 243 397 typedef std::map<ScriptInterface::CACHED_VAL, CScriptValRooted> ScriptValCache; … … 249 403 250 404 JSClass global_class = { 251 405 "global", JSCLASS_GLOBAL_FLAGS, 252 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, 253 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, 254 NULL, NULL, NULL, NULL, 406 JS_PropertyStub, JS_DeletePropertyStub, 407 JS_PropertyStub, JS_StrictPropertyStub, 408 JS_EnumerateStub, JS_ResolveStub, 409 JS_ConvertStub, NULL, 255 410 NULL, NULL, NULL, NULL 256 411 }; 257 412 258 413 void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report) 259 414 { 260 // XXX Ugly hack: we want to compile code with 'use strict' and with JSOPTION_STRICT,261 // but the latter causes the former to be reported as a useless expression, so262 // ignore that specific warning here263 if (report->flags == 5 && report->lineno == 0 && report->errorNumber == 163)264 return;265 415 266 416 std::stringstream msg; 267 417 bool isWarning = JSREPORT_IS_WARNING(report->flags); … … 276 426 277 427 // If there is an exception, then print its stack trace 278 428 jsval excn; 279 if (JS_GetPendingException(cx, &excn) && JSVAL_IS_OBJECT(excn))429 if (JS_GetPendingException(cx, &excn) && !JSVAL_IS_PRIMITIVE(excn)) 280 430 { 281 431 // TODO: this violates the docs ("The error reporter callback must not reenter the JSAPI.") 282 432 … … 312 462 313 463 // Functions in the global namespace: 314 464 315 JSBool print(JSContext* cx, uint Nargc, jsval* vp)465 JSBool print(JSContext* cx, uint argc, jsval* vp) 316 466 { 317 for (uint Ni = 0; i < argc; ++i)467 for (uint i = 0; i < argc; ++i) 318 468 { 319 469 std::wstring str; 320 470 if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[i], str)) … … 326 476 return JS_TRUE; 327 477 } 328 478 329 JSBool logmsg(JSContext* cx, uint Nargc, jsval* vp)479 JSBool logmsg(JSContext* cx, uint argc, jsval* vp) 330 480 { 331 481 if (argc < 1) 332 482 { … … 337 487 std::wstring str; 338 488 if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], str)) 339 489 return JS_FALSE; 340 LOGMESSAGE(L"%ls ", str.c_str());490 LOGMESSAGE(L"%ls%f", str.c_str(), timer_Time()); 341 491 JS_SET_RVAL(cx, vp, JSVAL_VOID); 342 492 return JS_TRUE; 343 493 } 344 494 345 JSBool warn(JSContext* cx, uint Nargc, jsval* vp)495 JSBool warn(JSContext* cx, uint argc, jsval* vp) 346 496 { 347 497 if (argc < 1) 348 498 { … … 358 508 return JS_TRUE; 359 509 } 360 510 361 JSBool error(JSContext* cx, uint Nargc, jsval* vp)511 JSBool error(JSContext* cx, uint argc, jsval* vp) 362 512 { 363 513 if (argc < 1) 364 514 { … … 374 524 return JS_TRUE; 375 525 } 376 526 377 JSBool deepcopy(JSContext* cx, uint Nargc, jsval* vp)527 JSBool deepcopy(JSContext* cx, uint argc, jsval* vp) 378 528 { 379 529 if (argc < 1) 380 530 { … … 384 534 385 535 jsval ret; 386 536 387 // We'd usually do: 388 // if (!JS_StructuredClone(cx, JS_ARGV(cx, vp)[0], &ret, NULL, NULL)) 389 // return JS_FALSE; 390 // but that function is broken in the 1.8.5 release 391 // (https://bugzilla.mozilla.org/show_bug.cgi?id=651510) 392 // so do an equivalent operation with a different API: 393 JSAutoStructuredCloneBuffer buf; 394 if (!buf.write(cx, JS_ARGV(cx, vp)[0]) || !buf.read(&ret, cx)) 537 if (!JS_StructuredClone(cx, JS_ARGV(cx, vp)[0], &ret, NULL, NULL)) 395 538 return JS_FALSE; 396 539 397 540 JS_SET_RVAL(cx, vp, ret); 398 541 return JS_TRUE; 399 542 } 400 543 401 JSBool ProfileStart(JSContext* cx, uint Nargc, jsval* vp)544 JSBool ProfileStart(JSContext* cx, uint argc, jsval* vp) 402 545 { 403 546 const char* name = "(ProfileStart)"; 404 547 … … 421 564 g_Profiler.StartScript(name); 422 565 423 566 g_Profiler2.RecordRegionEnter(name); 424 567 425 568 JS_SET_RVAL(cx, vp, JSVAL_VOID); 426 569 return JS_TRUE; 427 570 } 428 571 429 JSBool ProfileStop(JSContext* UNUSED(cx), uint NUNUSED(argc), jsval* vp)572 JSBool ProfileStop(JSContext* UNUSED(cx), uint UNUSED(argc), jsval* vp) 430 573 { 431 574 if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread()) 432 575 g_Profiler.Stop(); … … 455 598 } 456 599 } 457 600 458 JSBool Math_random(JSContext* cx, uint NUNUSED(argc), jsval* vp)601 JSBool Math_random(JSContext* cx, uint UNUSED(argc), jsval* vp) 459 602 { 460 // Grab the RNG that was hidden in our slot461 jsval rngp;462 if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0, &rngp))603 double r; 604 if(!ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->MathRandom(r)) 605 { 463 606 return JS_FALSE; 464 boost::rand48* rng = static_cast<boost::rand48*>(JSVAL_TO_PRIVATE(rngp)); 607 } 608 else 609 { 610 jsval rv = JS_NumberValue(r); 611 JS_SET_RVAL(cx, vp, rv); 612 return JS_TRUE; 613 } 614 } 465 615 466 double r = generate_uniform_real(*rng, 0.0, 1.0); 616 } // anonymous namespace 467 617 468 jsval rv; 469 if (!JS_NewNumberValue(cx, r, &rv)) 470 return JS_FALSE; 471 JS_SET_RVAL(cx, vp, rv); 472 return JS_TRUE; 618 bool ScriptInterface::MathRandom(double& nbr) 619 { 620 if (m->m_rng == NULL) 621 return false; 622 nbr = generate_uniform_real(*(m->m_rng), 0.0, 1.0); 623 return true; 473 624 } 474 625 475 } // anonymous namespace476 477 626 ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) : 478 627 m_runtime(runtime) 479 628 { 480 JSBool ok;629 bool ok; 481 630 482 631 m_cx = JS_NewContext(m_runtime->m_rt, STACK_CHUNK_SIZE); 483 632 ENSURE(m_cx); 484 633 634 JS_SetParallelCompilationEnabled(m_cx, true); 635 485 636 // For GC debugging: 486 637 // JS_SetGCZeal(m_cx, 2); 487 638 488 639 JS_SetContextPrivate(m_cx, NULL); 489 640 490 641 JS_SetErrorReporter(m_cx, ErrorReporter); 642 491 643 492 uint32 options = 0; 493 options |= JSOPTION_STRICT; // "warn on dubious practice" 494 options |= JSOPTION_XML; // "ECMAScript for XML support: parse <!-- --> as a token" 644 uint32_t options = 0; 645 options |= JSOPTION_EXTRA_WARNINGS; // "warn on dubious practice" 646 // We use strict mode to encourage better coding practices and 647 //to get code that can be optimized better by Spidermonkey's JIT compiler. 648 options |= JSOPTION_STRICT_MODE; 495 649 options |= JSOPTION_VAROBJFIX; // "recommended" (fixes variable scoping) 496 650 497 651 // Enable method JIT, unless script profiling/debugging is enabled (since profiling/debugging … … 499 653 // TODO: Verify what exactly is incompatible 500 654 if (!g_ScriptProfilingEnabled && !g_JSDebuggerEnabled) 501 655 { 502 options |= JSOPTION_METHODJIT; 656 options |= JSOPTION_BASELINE; 657 options |= JSOPTION_ION; 658 options |= JSOPTION_TYPE_INFERENCE; 659 options |= JSOPTION_COMPILE_N_GO; 503 660 504 661 // Some other JIT flags to experiment with: 505 options |= JSOPTION_JIT; 506 options |= JSOPTION_PROFILING; 662 //options |= JSOPTION_METHODJIT_ALWAYS; 507 663 } 508 664 509 665 JS_SetOptions(m_cx, options); 510 JS_SetVersion(m_cx, JSVERSION_LATEST); 666 667 JSAutoRequest rq(m_cx); 668 669 JS::CompartmentOptions opt; 670 opt.setVersion(JSVERSION_LATEST); 671 m_glob = JS_NewGlobalObject(m_cx, &global_class, NULL, opt); 672 m_comp = JS_EnterCompartment(m_cx, m_glob); 673 JS_SetGlobalObject(m_cx, m_glob); 511 674 512 m_glob = JS_NewCompartmentAndGlobalObject(m_cx, &global_class, NULL);513 514 675 ok = JS_InitStandardClasses(m_cx, m_glob); 515 676 ENSURE(ok); 516 677 678 517 679 JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY 518 680 | JSPROP_PERMANENT); 519 681 … … 528 690 529 691 Register("ProfileStart", ::ProfileStart, 1); 530 692 Register("ProfileStop", ::ProfileStop, 0); 693 694 runtime->RegisterContext(m_cx); 531 695 } 532 696 533 697 ScriptInterface_impl::~ScriptInterface_impl() 534 698 { 535 // Important: this must come before JS_DestroyContext because CScriptValRooted needs the context to unroot the values! 536 // TODO: Check again when SpiderMonkey is upgraded and when/if CScriptValRooted gets replaces by JS::Heap<T>. 537 m_ScriptValCache.clear(); 699 // Important: this must come before JS_DestroyContext because CScriptValRooted needs the context to unroot the values! 700 // TODO: Check again when SpiderMonkey is upgraded and when/if CScriptValRooted gets replaces by JS::Heap<T>. 701 m_ScriptValCache.clear(); 702 703 m_runtime->UnRegisterContext(m_cx); 704 { 705 JSAutoRequest rq(m_cx); 706 JS_LeaveCompartment(m_cx, m_comp); 707 } 538 708 JS_DestroyContext(m_cx); 539 709 } 540 710 541 void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint Nnargs)711 void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs) 542 712 { 713 JSAutoRequest rq(m_cx); 543 714 JSFunction* func = JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); 544 715 545 716 if (!func) … … 558 729 > LockedStringFlyweight; 559 730 560 731 LockedStringFlyweight fw(name); 561 JS_SetReservedSlot( m_cx,JS_GetFunctionObject(func), 0, PRIVATE_TO_JSVAL((void*)fw.get().c_str()));732 JS_SetReservedSlot(JS_GetFunctionObject(func), 0, PRIVATE_TO_JSVAL((void*)fw.get().c_str())); 562 733 } 563 734 } 564 735 … … 605 776 JS_ShutDown(); 606 777 } 607 778 779 void ScriptInterface::Tick() 780 { 781 js::NotifyAnimationActivity(m->m_glob); 782 } 783 608 784 void ScriptInterface::SetCallbackData(void* pCBData) 609 785 { 610 786 m_CxPrivate.pCBData = pCBData; … … 639 815 return false; 640 816 } 641 817 } 818 819 JSAutoRequest rq(m->m_cx); 642 820 jsval proto; 643 if (JS_GetProperty(m->m_cx, JS_GetGlobalObject(m->m_cx), "Vector2Dprototype", &proto))821 if (JS_GetProperty(m->m_cx, m->m_glob, "Vector2Dprototype", &proto)) 644 822 m->m_ScriptValCache[CACHE_VECTOR2DPROTO] = CScriptValRooted(m->m_cx, proto); 645 if (JS_GetProperty(m->m_cx, JS_GetGlobalObject(m->m_cx), "Vector3Dprototype", &proto))823 if (JS_GetProperty(m->m_cx, m->m_glob, "Vector3Dprototype", &proto)) 646 824 m->m_ScriptValCache[CACHE_VECTOR3DPROTO] = CScriptValRooted(m->m_cx, proto); 647 825 return true; 648 826 } 649 827 828 650 829 bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng) 651 830 { 652 jsval math; 653 if (JS_GetProperty(m->m_cx, m->m_glob, "Math", &math) && JSVAL_IS_OBJECT(math)) 831 JSAutoRequest rq(m->m_cx); 832 JS::RootedValue math(m->m_cx); 833 if (JS_GetProperty(m->m_cx, m->m_glob, "Math", math.address()) && !JSVAL_IS_PRIMITIVE(math.get())) 654 834 { 655 835 JSFunction* random = JS_DefineFunction(m->m_cx, JSVAL_TO_OBJECT(math), "random", Math_random, 0, 656 836 JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); 657 837 if (random) 658 838 { 659 // Store the RNG in a slot which is sort-of-guaranteed to be unused by the JS engine 660 if (JS_SetReservedSlot(m->m_cx, JS_GetFunctionObject(random), 0, PRIVATE_TO_JSVAL(&rng))) 661 return true; 839 m->m_rng = &rng; 840 return true; 662 841 } 663 842 } 664 843 … … 668 847 669 848 void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) 670 849 { 671 m->Register(name, fptr, (uint N)nargs);850 m->Register(name, fptr, (uint)nargs); 672 851 } 673 852 674 853 JSContext* ScriptInterface::GetContext() const … … 693 872 return ret; 694 873 } 695 874 696 697 jsval ScriptInterface::CallConstructor(jsval ctor, jsval arg) 875 jsval ScriptInterface::CallConstructor(jsval ctor, int argc, jsval argv) 698 876 { 699 if (!JSVAL_IS_OBJECT(ctor)) 877 JSAutoRequest rq(m->m_cx); 878 if (JSVAL_IS_PRIMITIVE(ctor)) 700 879 { 701 880 LOGERROR(L"CallConstructor: ctor is not an object"); 702 881 return JSVAL_VOID; 703 882 } 704 883 705 return OBJECT_TO_JSVAL(JS_New(m->m_cx, JSVAL_TO_OBJECT(ctor), 1, &arg)); 884 // Passing argc 0 and argv JSVAL_VOID causes a crash in mozjs24 885 if (argc == 0) 886 { 887 return OBJECT_TO_JSVAL(JS_New(m->m_cx, JSVAL_TO_OBJECT(ctor), 0, NULL)); 888 } 889 else 890 return OBJECT_TO_JSVAL(JS_New(m->m_cx, JSVAL_TO_OBJECT(ctor), argc, &argv)); 706 891 } 707 892 708 893 jsval ScriptInterface::NewObjectFromConstructor(jsval ctor) 709 894 { 895 JSAutoRequest rq(m->m_cx); 710 896 // Get the constructor's prototype 711 897 // (Can't use JS_GetPrototype, since we want .prototype not .__proto__) 712 jsval protoVal;713 if (!JS_GetProperty(m->m_cx, JSVAL_TO_OBJECT(ctor), "prototype", &protoVal))898 JS::RootedValue protoVal(m->m_cx); 899 if (!JS_GetProperty(m->m_cx, JSVAL_TO_OBJECT(ctor), "prototype", protoVal.address())) 714 900 { 715 901 LOGERROR(L"NewObjectFromConstructor: can't get prototype"); 716 902 return JSVAL_VOID; 717 903 } 718 904 719 if ( !JSVAL_IS_OBJECT(protoVal))905 if (JSVAL_IS_PRIMITIVE(protoVal.get())) 720 906 { 721 907 LOGERROR(L"NewObjectFromConstructor: prototype is not an object"); 722 908 return JSVAL_VOID; 723 909 } 724 910 725 JSObject* proto = JSVAL_TO_OBJECT(protoVal );726 JSObject* parent = JS_GetParent( m->m_cx,JSVAL_TO_OBJECT(ctor));911 JSObject* proto = JSVAL_TO_OBJECT(protoVal.get()); 912 JSObject* parent = JS_GetParent(JSVAL_TO_OBJECT(ctor)); 727 913 // TODO: rooting? 728 914 if (!proto || !parent) 729 915 { … … 743 929 744 930 void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) 745 931 { 932 JSAutoRequest rq(m->m_cx); 746 933 std::string typeName = clasp->name; 747 934 748 935 if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end()) … … 790 977 791 978 bool ScriptInterface::CallFunction_(jsval val, const char* name, size_t argc, jsval* argv, jsval& ret) 792 979 { 980 JSAutoRequest rq(m->m_cx); 793 981 JSObject* obj; 794 982 if (!JS_ValueToObject(m->m_cx, val, &obj) || obj == NULL) 795 983 return false; … … 798 986 // when calling an undefined value 799 987 JSBool found; 800 988 if (!JS_HasProperty(m->m_cx, obj, name, &found) || !found) 801 return false;989 return JS_FALSE; 802 990 803 JSBool ok = JS_CallFunctionName(m->m_cx, obj, name, (uintN)argc, argv, &ret);991 bool ok = JS_CallFunctionName(m->m_cx, obj, name, (uint)argc, argv, &ret); 804 992 805 return ok ? true : false;993 return ok ? JS_TRUE : JS_FALSE; 806 994 } 807 995 808 996 jsval ScriptInterface::GetGlobalObject() 809 997 { 810 return OBJECT_TO_JSVAL(JS_GetGlobalObject(m->m_cx)); 998 JSAutoRequest rq(m->m_cx); 999 return OBJECT_TO_JSVAL(JS_GetGlobalForScopeChain(m->m_cx)); 811 1000 } 812 1001 813 1002 JSClass* ScriptInterface::GetGlobalClass() … … 817 1006 818 1007 bool ScriptInterface::SetGlobal_(const char* name, jsval value, bool replace) 819 1008 { 1009 JSAutoRequest rq(m->m_cx); 820 1010 if (!replace) 821 1011 { 822 1012 JSBool found; 823 1013 if (!JS_HasProperty(m->m_cx, m->m_glob, name, &found)) 824 return false;1014 return JS_FALSE; 825 1015 if (found) 826 1016 { 827 1017 JS_ReportError(m->m_cx, "SetGlobal \"%s\" called multiple times", name); 828 return false;1018 return JS_FALSE; 829 1019 } 830 1020 } 831 1021 832 JSBool ok = JS_DefineProperty(m->m_cx, m->m_glob, name, value, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY833 | JSPROP_PERMANENT);834 return ok ? true : false;1022 bool ok = JS_DefineProperty(m->m_cx, m->m_glob, name, value, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY 1023 | JSPROP_PERMANENT); 1024 return ok ? JS_TRUE : JS_FALSE; 835 1025 } 836 1026 837 1027 bool ScriptInterface::SetProperty_(jsval obj, const char* name, jsval value, bool constant, bool enumerate) 838 1028 { 839 uintN attrs = 0; 1029 JSAutoRequest rq(m->m_cx); 1030 uint attrs = 0; 840 1031 if (constant) 841 1032 attrs |= JSPROP_READONLY | JSPROP_PERMANENT; 842 1033 if (enumerate) 843 1034 attrs |= JSPROP_ENUMERATE; 844 1035 845 if ( ! JSVAL_IS_OBJECT(obj))1036 if (JSVAL_IS_PRIMITIVE(obj)) 846 1037 return false; 847 1038 JSObject* object = JSVAL_TO_OBJECT(obj); 848 1039 … … 853 1044 854 1045 bool ScriptInterface::SetProperty_(jsval obj, const wchar_t* name, jsval value, bool constant, bool enumerate) 855 1046 { 856 uintN attrs = 0; 1047 JSAutoRequest rq(m->m_cx); 1048 uint attrs = 0; 857 1049 if (constant) 858 1050 attrs |= JSPROP_READONLY | JSPROP_PERMANENT; 859 1051 if (enumerate) 860 1052 attrs |= JSPROP_ENUMERATE; 861 1053 862 if ( ! JSVAL_IS_OBJECT(obj))1054 if ( JSVAL_IS_PRIMITIVE(obj)) 863 1055 return false; 864 1056 JSObject* object = JSVAL_TO_OBJECT(obj); 865 1057 … … 871 1063 872 1064 bool ScriptInterface::SetPropertyInt_(jsval obj, int name, jsval value, bool constant, bool enumerate) 873 1065 { 874 uintN attrs = 0; 1066 JSAutoRequest rq(m->m_cx); 1067 uint attrs = 0; 875 1068 if (constant) 876 1069 attrs |= JSPROP_READONLY | JSPROP_PERMANENT; 877 1070 if (enumerate) 878 1071 attrs |= JSPROP_ENUMERATE; 879 1072 880 if ( ! JSVAL_IS_OBJECT(obj))1073 if ( JSVAL_IS_PRIMITIVE(obj)) 881 1074 return false; 882 1075 JSObject* object = JSVAL_TO_OBJECT(obj); 883 1076 … … 886 1079 return true; 887 1080 } 888 1081 889 bool ScriptInterface::GetProperty_(jsval obj, const char* name, jsval&out)1082 bool ScriptInterface::GetProperty_(jsval obj, const char* name, JS::MutableHandleValue out) 890 1083 { 891 if (! JSVAL_IS_OBJECT(obj)) 1084 JSAutoRequest rq(m->m_cx); 1085 if ( JSVAL_IS_PRIMITIVE(obj)) 892 1086 return false; 893 1087 JSObject* object = JSVAL_TO_OBJECT(obj); 894 1088 895 if (!JS_GetProperty(m->m_cx, object, name, &out))1089 if (!JS_GetProperty(m->m_cx, object, name, out.address())) 896 1090 return false; 897 1091 return true; 898 1092 } 899 1093 900 bool ScriptInterface::GetPropertyInt_(jsval obj, int name, jsval&out)1094 bool ScriptInterface::GetPropertyInt_(jsval obj, int name, JS::MutableHandleValue out) 901 1095 { 902 if (! JSVAL_IS_OBJECT(obj)) 1096 JSAutoRequest rq(m->m_cx); 1097 if ( JSVAL_IS_PRIMITIVE(obj)) 903 1098 return false; 904 1099 JSObject* object = JSVAL_TO_OBJECT(obj); 905 1100 906 if (!JS_GetPropertyById(m->m_cx, object, INT_TO_JSID(name), &out))1101 if (!JS_GetPropertyById(m->m_cx, object, INT_TO_JSID(name), out.address())) 907 1102 return false; 908 1103 return true; 909 1104 } 910 1105 911 1106 bool ScriptInterface::HasProperty(jsval obj, const char* name) 912 1107 { 913 if (! JSVAL_IS_OBJECT(obj)) 914 return false; 1108 // TODO: proper errorhandling 1109 JSAutoRequest rq(m->m_cx); 1110 if ( JSVAL_IS_PRIMITIVE(obj)) 1111 return JS_FALSE; 915 1112 JSObject* object = JSVAL_TO_OBJECT(obj); 916 1113 917 1114 JSBool found; 918 1115 if (!JS_HasProperty(m->m_cx, object, name, &found)) 919 return false;920 return (found != JS_FALSE);1116 return JS_FALSE; 1117 return found; 921 1118 } 922 1119 923 bool ScriptInterface::EnumeratePropertyNamesWithPrefix( jsvalobj, const char* prefix, std::vector<std::string>& out)1120 bool ScriptInterface::EnumeratePropertyNamesWithPrefix(JS::HandleObject obj, const char* prefix, std::vector<std::string>& out) 924 1121 { 925 utf16string prefix16 (prefix, prefix+strlen(prefix)); 1122 JSAutoRequest rq(m->m_cx); 1123 if (obj.get() == 0x0) 1124 return true; 926 1125 927 if (! JSVAL_IS_OBJECT(obj))928 return false; // TODO: log error messages1126 // if ( obj.get().isPrimitive() ) 1127 // return false; // TODO: log error messages 929 1128 930 JSObject* it = JS_NewPropertyIterator(m->m_cx, JSVAL_TO_OBJECT(obj));1129 JSObject* it = JS_NewPropertyIterator(m->m_cx, obj.get()); 931 1130 if (!it) 932 1131 return false; 933 1132 … … 943 1142 continue; // ignore integer properties 944 1143 945 1144 JSString* name = JSVAL_TO_STRING(val); 946 size_t len; 947 const jschar* chars = JS_GetStringCharsAndLength(m->m_cx, name, &len); 948 if (chars && len >= prefix16.size() && memcmp(chars, prefix16.c_str(), prefix16.size()*2) == 0) 949 out.push_back(std::string(chars, chars+len)); // handles Unicode poorly 1145 size_t len = strlen(prefix)+1; 1146 char buf[len]; 1147 size_t prefixLen = strlen(prefix) * sizeof(char); 1148 JS_EncodeStringToBuffer(m->m_cx, name, buf, prefixLen); 1149 buf[len-1]= '\0'; 1150 if(0 == strcmp(buf, prefix)) 1151 { 1152 size_t len; 1153 const jschar* chars = JS_GetStringCharsAndLength(m->m_cx, name, &len); 1154 out.push_back(std::string(chars, chars+len)); 1155 } 950 1156 } 951 1157 952 1158 // Recurse up the prototype chain 953 JS Object* prototype = JS_GetPrototype(m->m_cx, JSVAL_TO_OBJECT(obj));954 if ( prototype)1159 JS::RootedObject prototype(m->m_cx); 1160 if (JS_GetPrototype(m->m_cx, obj, prototype.address())) 955 1161 { 956 if (! EnumeratePropertyNamesWithPrefix( OBJECT_TO_JSVAL(prototype), prefix, out))1162 if (! EnumeratePropertyNamesWithPrefix(prototype, prefix, out)) 957 1163 return false; 958 1164 } 959 1165 960 1166 return true; 961 1167 } 962 1168 963 bool ScriptInterface::SetPrototype( jsval obj, jsvalproto)1169 bool ScriptInterface::SetPrototype(JS::HandleObject obj, JS::HandleObject proto) 964 1170 { 965 if (!JSVAL_IS_OBJECT(obj) || !JSVAL_IS_OBJECT(proto)) 966 return false; 967 return JS_SetPrototype(m->m_cx, JSVAL_TO_OBJECT(obj), JSVAL_TO_OBJECT(proto)) ? true : false; 1171 JSAutoRequest rq(m->m_cx); 1172 //if (JSVAL_IS_PRIMITIVE(obj) || JSVAL_IS_PRIMITIVE(proto)) 1173 // return false; 1174 return JS_SetPrototype(m->m_cx, obj, proto); 968 1175 } 969 1176 970 1177 bool ScriptInterface::FreezeObject(jsval obj, bool deep) 971 1178 { 972 if (!JSVAL_IS_OBJECT(obj)) 1179 JSAutoRequest rq(m->m_cx); 1180 if (JSVAL_IS_PRIMITIVE(obj)) 973 1181 return false; 974 1182 975 1183 if (deep) … … 980 1188 981 1189 bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code) 982 1190 { 983 // Compile the code in strict mode, to encourage better coding practices and 984 // to possibly help SpiderMonkey with optimisations 985 std::wstring codeStrict = L"\"use strict\";\n" + wstring_from_utf8(code); 986 utf16string codeUtf16(codeStrict.begin(), codeStrict.end()); 987 uintN lineNo = 0; // put the automatic 'use strict' on line 0, so the real code starts at line 1 1191 JSAutoRequest rq(m->m_cx); 1192 utf16string codeUtf16(code.begin(), code.end()); 1193 uint lineNo = 1; 988 1194 989 JSFunction* func = JS_CompileUCFunction(m->m_cx, NULL, NULL, 0, NULL, 990 reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uintN)(codeUtf16.length()), 991 utf8_from_wstring(filename.string()).c_str(), lineNo); 992 1195 JS::Rooted<JSFunction*> func(m->m_cx, 1196 JS_CompileUCFunction(m->m_cx, m->m_glob, utf8_from_wstring(filename.string()).c_str(), 0, NULL, 1197 reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint)(codeUtf16.length()), 1198 utf8_from_wstring(filename.string()).c_str(), lineNo) 1199 ); 993 1200 if (!func) 994 1201 return false; 995 1202 996 jsval scriptRval;997 JSBool ok = JS_CallFunction(m->m_cx, NULL, func, 0, NULL, &scriptRval);1203 JS::RootedValue val(m->m_cx); 1204 bool ok = JS_CallFunction(m->m_cx, NULL, func, 0, NULL, val.address()); 998 1205 999 1206 return ok ? true : false; 1000 1207 } 1001 1208 1002 1209 bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code) 1003 1210 { 1004 // Compile the code in strict mode, to encourage better coding practices and 1005 // to possibly help SpiderMonkey with optimisations 1006 std::wstring codeStrict = L"\"use strict\";\n" + code; 1007 utf16string codeUtf16(codeStrict.begin(), codeStrict.end()); 1008 uintN lineNo = 0; // put the automatic 'use strict' on line 0, so the real code starts at line 1 1211 JSAutoRequest rq(m->m_cx); 1212 utf16string codeUtf16(code.begin(), code.end()); 1213 uint lineNo = 1; 1009 1214 1010 1215 jsval rval; 1011 JSBool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob,1012 reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint N)(codeUtf16.length()),1216 bool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob, 1217 reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint)(codeUtf16.length()), 1013 1218 utf8_from_wstring(filename.string()).c_str(), lineNo, &rval); 1014 1219 1015 return ok ? true : false;1220 return ok; 1016 1221 } 1017 1222 1018 1223 bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) 1019 1224 { 1225 JSAutoRequest rq(m->m_cx); 1020 1226 if (!VfsFileExists(path)) 1021 1227 { 1022 1228 LOGERROR(L"File '%ls' does not exist", path.string().c_str()); … … 1035 1241 1036 1242 std::wstring code = wstring_from_utf8(file.DecodeUTF8()); // assume it's UTF-8 1037 1243 1038 // Compile the code in strict mode, to encourage better coding practices and 1039 // to possibly help SpiderMonkey with optimisations 1040 std::wstring codeStrict = L"\"use strict\";\n" + code; 1041 utf16string codeUtf16(codeStrict.begin(), codeStrict.end()); 1042 uintN lineNo = 0; // put the automatic 'use strict' on line 0, so the real code starts at line 1 1244 utf16string codeUtf16(code.begin(), code.end()); 1245 uint lineNo = 1; 1043 1246 1044 1247 jsval rval; 1045 JSBool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob,1046 reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint N)(codeUtf16.length()),1248 bool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob, 1249 reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint)(codeUtf16.length()), 1047 1250 utf8_from_wstring(path.string()).c_str(), lineNo, &rval); 1048 1251 1049 return ok ? true : false;1252 return ok; 1050 1253 } 1051 1254 1052 1255 bool ScriptInterface::Eval(const char* code) … … 1057 1260 1058 1261 bool ScriptInterface::Eval_(const char* code, jsval& rval) 1059 1262 { 1263 JSAutoRequest rq(m->m_cx); 1060 1264 utf16string codeUtf16(code, code+strlen(code)); 1061 1265 1062 JSBool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob, (const jschar*)codeUtf16.c_str(), (uintN)codeUtf16.length(), "(eval)", 1, &rval);1063 return ok ? true : false;1266 bool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob, (const jschar*)codeUtf16.c_str(), (uint)codeUtf16.length(), "(eval)", 1, &rval); 1267 return ok; 1064 1268 } 1065 1269 1066 1270 bool ScriptInterface::Eval_(const wchar_t* code, jsval& rval) 1067 1271 { 1272 JSAutoRequest rq(m->m_cx); 1068 1273 utf16string codeUtf16(code, code+wcslen(code)); 1069 1274 1070 JSBool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob, (const jschar*)codeUtf16.c_str(), (uintN)codeUtf16.length(), "(eval)", 1, &rval);1071 return ok ? true : false;1275 bool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob, (const jschar*)codeUtf16.c_str(), (uint)codeUtf16.length(), "(eval)", 1, &rval); 1276 return ok; 1072 1277 } 1073 1278 1074 1279 CScriptValRooted ScriptInterface::ParseJSON(const std::string& string_utf8) 1075 1280 { 1281 JSAutoRequest rq(m->m_cx); 1076 1282 std::wstring attrsW = wstring_from_utf8(string_utf8); 1077 utf16string string(attrsW.begin(), attrsW.end()); 1078 1079 jsval vp; 1080 JSONParser* parser = JS_BeginJSONParse(m->m_cx, &vp); 1081 if (!parser) 1082 { 1083 LOGERROR(L"ParseJSON failed to begin"); 1084 return CScriptValRooted(); 1085 } 1086 1087 if (!JS_ConsumeJSONText(m->m_cx, parser, reinterpret_cast<const jschar*>(string.c_str()), (uint32)string.size())) 1088 { 1089 LOGERROR(L"ParseJSON failed to consume"); 1090 return CScriptValRooted(); 1091 } 1092 1093 if (!JS_FinishJSONParse(m->m_cx, parser, JSVAL_NULL)) 1094 { 1095 LOGERROR(L"ParseJSON failed to finish"); 1096 return CScriptValRooted(); 1097 } 1098 1283 utf16string string(attrsW.begin(), attrsW.end()); 1284 JS::Rooted<jsval> vp(m->m_cx); 1285 JS_ParseJSON(m->m_cx, reinterpret_cast<const jschar*>(string.c_str()), (uint32_t)string.size(), &vp); 1099 1286 return CScriptValRooted(m->m_cx, vp); 1100 1287 } 1101 1288 … … 1124 1311 1125 1312 struct Stringifier 1126 1313 { 1127 static JSBool callback(const jschar* buf, uint32 len, void* data)1314 static JSBool callback(const jschar* buf, uint32_t len, void* data) 1128 1315 { 1129 1316 utf16string str(buf, buf+len); 1130 1317 std::wstring strw(str.begin(), str.end()); … … 1139 1326 1140 1327 struct StringifierW 1141 1328 { 1142 static JSBool callback(const jschar* buf, uint32 len, void* data)1329 static JSBool callback(const jschar* buf, uint32_t len, void* data) 1143 1330 { 1144 1331 utf16string str(buf, buf+len); 1145 1332 static_cast<StringifierW*>(data)->stream << std::wstring(str.begin(), str.end()); … … 1151 1338 1152 1339 std::string ScriptInterface::StringifyJSON(jsval obj, bool indent) 1153 1340 { 1341 JSAutoRequest rq(m->m_cx); 1154 1342 Stringifier str; 1155 1343 if (!JS_Stringify(m->m_cx, &obj, NULL, indent ? INT_TO_JSVAL(2) : JSVAL_VOID, &Stringifier::callback, &str)) 1156 1344 { … … 1166 1354 1167 1355 std::wstring ScriptInterface::ToString(jsval obj, bool pretty) 1168 1356 { 1357 JSAutoRequest rq(m->m_cx); 1169 1358 if (JSVAL_IS_VOID(obj)) 1170 1359 return L"(void 0)"; 1171 1360 … … 1178 1367 // Temporary disable the error reporter, so we don't print complaints about cyclic values 1179 1368 JSErrorReporter er = JS_SetErrorReporter(m->m_cx, NULL); 1180 1369 1181 bool ok = JS_Stringify(m->m_cx, &obj, NULL, INT_TO_JSVAL(2), &StringifierW::callback, &str) == JS_TRUE;1370 JSBool ok = JS_Stringify(m->m_cx, &obj, NULL, INT_TO_JSVAL(2), &StringifierW::callback, &str); 1182 1371 1183 1372 // Restore error reporter 1184 1373 JS_SetErrorReporter(m->m_cx, er); … … 1200 1389 1201 1390 void ScriptInterface::ReportError(const char* msg) 1202 1391 { 1392 JSAutoRequest rq(m->m_cx); 1203 1393 // JS_ReportError by itself doesn't seem to set a JS-style exception, and so 1204 1394 // script callers will be unable to catch anything. So use JS_SetPendingException 1205 1395 // to make sure there really is a script-level exception. But just set it to undefined … … 1213 1403 1214 1404 bool ScriptInterface::IsExceptionPending(JSContext* cx) 1215 1405 { 1406 JSAutoRequest rq(cx); 1216 1407 return JS_IsExceptionPending(cx) ? true : false; 1217 1408 } 1218 1409 1219 JSClass* ScriptInterface::GetClass(JS Context* cx, JSObject* obj)1410 JSClass* ScriptInterface::GetClass(JSObject* obj) 1220 1411 { 1221 UNUSED2(cx); // unused if not JS_THREADSAFE 1222 1223 return JS_GET_CLASS(cx, obj); 1412 return JS_GetClass(obj); 1224 1413 } 1225 1414 1226 void* ScriptInterface::GetPrivate(JS Context* cx, JSObject* obj)1415 void* ScriptInterface::GetPrivate(JSObject* obj) 1227 1416 { 1228 1417 // TODO: use JS_GetInstancePrivate 1229 return JS_GetPrivate( cx,obj);1418 return JS_GetPrivate(obj); 1230 1419 } 1231 1420 1232 1421 void ScriptInterface::DumpHeap() 1233 1422 { 1234 1423 #if MOZJS_DEBUG_ABI 1235 JS_DumpHeap( m->m_cx, stderr, NULL, 0, NULL, (size_t)-1, NULL);1424 JS_DumpHeap(GetJSRuntime(), stderr, NULL, JSTRACE_OBJECT, NULL, (size_t)-1, NULL); 1236 1425 #endif 1237 1426 fprintf(stderr, "# Bytes allocated: %u\n", JS_GetGCParameter(GetJSRuntime(), JSGC_BYTES)); 1238 JS_GC( m->m_cx);1427 JS_GC(GetJSRuntime()); 1239 1428 fprintf(stderr, "# Bytes allocated after GC: %u\n", JS_GetGCParameter(GetJSRuntime(), JSGC_BYTES)); 1240 1429 } 1241 1430 1431 void ScriptInterface::MaybeIncrementalRuntimeGC() 1432 { 1433 m->m_runtime->MaybeIncrementalGC(); 1434 } 1435 1242 1436 void ScriptInterface::MaybeGC() 1243 1437 { 1244 1438 JS_MaybeGC(m->m_cx); 1245 1439 } 1246 1440 1247 class ValueCloner 1441 void ScriptInterface::ForceGC() 1248 1442 { 1249 public: 1250 ValueCloner(ScriptInterface& from, ScriptInterface& to) : 1251 scriptInterfaceFrom(from), cxFrom(from.GetContext()), cxTo(to.GetContext()), m_RooterFrom(from), m_RooterTo(to) 1252 { 1253 } 1443 PROFILE2("JS_GC"); 1444 JS_GC(this->GetJSRuntime()); 1445 } 1254 1446 1255 // Return the cloned object (or an already-computed object if we've cloned val before)1256 jsval GetOrClone(jsval val)1257 {1258 if (!JSVAL_IS_GCTHING(val) || JSVAL_IS_NULL(val))1259 return val;1260 1261 std::map<void*, jsval>::iterator it = m_Mapping.find(JSVAL_TO_GCTHING(val));1262 if (it != m_Mapping.end())1263 return it->second;1264 1265 m_RooterFrom.Push(val); // root it so our mapping doesn't get invalidated1266 1267 return Clone(val);1268 }1269 1270 private:1271 1272 #define CLONE_REQUIRE(expr, msg) if (!(expr)) { debug_warn(L"Internal error in CloneValueFromOtherContext: " msg); return JSVAL_VOID; }1273 1274 // Clone a new value (and root it and add it to the mapping)1275 jsval Clone(jsval val)1276 {1277 if (JSVAL_IS_DOUBLE(val))1278 {1279 jsval rval;1280 CLONE_REQUIRE(JS_NewNumberValue(cxTo, JSVAL_TO_DOUBLE(val), &rval), L"JS_NewNumberValue");1281 m_RooterTo.Push(rval);1282 return rval;1283 }1284 1285 if (JSVAL_IS_STRING(val))1286 {1287 size_t len;1288 const jschar* chars = JS_GetStringCharsAndLength(cxFrom, JSVAL_TO_STRING(val), &len);1289 CLONE_REQUIRE(chars, L"JS_GetStringCharsAndLength");1290 JSString* str = JS_NewUCStringCopyN(cxTo, chars, len);1291 CLONE_REQUIRE(str, L"JS_NewUCStringCopyN");1292 jsval rval = STRING_TO_JSVAL(str);1293 m_Mapping[JSVAL_TO_GCTHING(val)] = rval;1294 m_RooterTo.Push(rval);1295 return rval;1296 }1297 1298 ENSURE(JSVAL_IS_OBJECT(val));1299 1300 JSObject* newObj;1301 if (JS_IsArrayObject(cxFrom, JSVAL_TO_OBJECT(val)))1302 {1303 jsuint length;1304 CLONE_REQUIRE(JS_GetArrayLength(cxFrom, JSVAL_TO_OBJECT(val), &length), L"JS_GetArrayLength");1305 newObj = JS_NewArrayObject(cxTo, length, NULL);1306 CLONE_REQUIRE(newObj, L"JS_NewArrayObject");1307 }1308 else1309 {1310 newObj = JS_NewObject(cxTo, NULL, NULL, NULL);1311 CLONE_REQUIRE(newObj, L"JS_NewObject");1312 }1313 1314 m_Mapping[JSVAL_TO_GCTHING(val)] = OBJECT_TO_JSVAL(newObj);1315 m_RooterTo.Push(newObj);1316 1317 AutoJSIdArray ida (cxFrom, JS_Enumerate(cxFrom, JSVAL_TO_OBJECT(val)));1318 CLONE_REQUIRE(ida.get(), L"JS_Enumerate");1319 1320 AutoGCRooter idaRooter(scriptInterfaceFrom);1321 idaRooter.Push(ida.get());1322 1323 for (size_t i = 0; i < ida.length(); ++i)1324 {1325 jsid id = ida[i];1326 jsval idval, propval;1327 CLONE_REQUIRE(JS_IdToValue(cxFrom, id, &idval), L"JS_IdToValue");1328 CLONE_REQUIRE(JS_GetPropertyById(cxFrom, JSVAL_TO_OBJECT(val), id, &propval), L"JS_GetPropertyById");1329 jsval newPropval = GetOrClone(propval);1330 1331 if (JSVAL_IS_INT(idval))1332 {1333 // int jsids are portable across runtimes1334 CLONE_REQUIRE(JS_SetPropertyById(cxTo, newObj, id, &newPropval), L"JS_SetPropertyById");1335 }1336 else if (JSVAL_IS_STRING(idval))1337 {1338 // string jsids are runtime-specific, so we need to copy the string content1339 JSString* idstr = JS_ValueToString(cxFrom, idval);1340 CLONE_REQUIRE(idstr, L"JS_ValueToString (id)");1341 size_t len;1342 const jschar* chars = JS_GetStringCharsAndLength(cxFrom, idstr, &len);1343 CLONE_REQUIRE(idstr, L"JS_GetStringCharsAndLength (id)");1344 CLONE_REQUIRE(JS_SetUCProperty(cxTo, newObj, chars, len, &newPropval), L"JS_SetUCProperty");1345 }1346 else1347 {1348 // this apparently could be an XML object; ignore it1349 }1350 }1351 1352 return OBJECT_TO_JSVAL(newObj);1353 }1354 1355 ScriptInterface& scriptInterfaceFrom;1356 JSContext* cxFrom;1357 JSContext* cxTo;1358 std::map<void*, jsval> m_Mapping;1359 AutoGCRooter m_RooterFrom;1360 AutoGCRooter m_RooterTo;1361 };1362 1363 1447 jsval ScriptInterface::CloneValueFromOtherContext(ScriptInterface& otherContext, jsval val) 1364 1448 { 1365 1449 PROFILE("CloneValueFromOtherContext"); 1366 1367 ValueCloner cloner(otherContext, *this);1368 return clone r.GetOrClone(val);1450 shared_ptr<StructuredClone> structuredClone = otherContext.WriteStructuredClone(val); 1451 jsval clone = ReadStructuredClone(structuredClone); 1452 return clone; 1369 1453 } 1370 1454 1371 1455 ScriptInterface::StructuredClone::StructuredClone() : 1372 m_ Context(NULL), m_Data(NULL), m_Size(0)1456 m_Data(NULL), m_Size(0) 1373 1457 { 1374 1458 } 1375 1459 1376 1460 ScriptInterface::StructuredClone::~StructuredClone() 1377 1461 { 1378 1462 if (m_Data) 1379 JS_ free(m_Context, m_Data);1463 JS_ClearStructuredClone(m_Data, m_Size); 1380 1464 } 1381 1465 1382 1466 shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClone(jsval v) 1383 1467 { 1384 uint64* data = NULL; 1468 JSAutoRequest rq(m->m_cx); 1469 uint64_t* data = NULL; 1385 1470 size_t nbytes = 0; 1386 if (!JS_WriteStructuredClone(m->m_cx, v, &data, &nbytes, NULL, NULL ))1471 if (!JS_WriteStructuredClone(m->m_cx, v, &data, &nbytes, NULL, NULL, JSVAL_VOID)) 1387 1472 { 1388 1473 debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!"); 1389 1474 return shared_ptr<StructuredClone>(); 1390 1475 } 1391 1476 1392 1477 shared_ptr<StructuredClone> ret (new StructuredClone); 1393 ret->m_Context = m->m_cx;1394 1478 ret->m_Data = data; 1395 1479 ret->m_Size = nbytes; 1396 1480 return ret; … … 1398 1482 1399 1483 jsval ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& ptr) 1400 1484 { 1485 JSAutoRequest rq(m->m_cx); 1401 1486 jsval ret = JSVAL_VOID; 1402 1487 JS_ReadStructuredClone(m->m_cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, &ret, NULL, NULL); 1403 1488 return ret; -
source/scriptinterface/ScriptInterface.h
25 25 #include "ScriptTypes.h" 26 26 #include "ScriptVal.h" 27 27 28 #include "js/jsapi.h"29 30 28 #include "ps/Errors.h" 31 29 ERROR_GROUP(Scripting); 32 30 ERROR_TYPE(Scripting, SetupFailed); … … 115 113 void* pCBData; // meant to be used as the "this" object for callback functions 116 114 } m_CxPrivate; 117 115 116 void Tick(); 118 117 void SetCallbackData(void* pCBData); 119 118 static CxPrivate* GetScriptInterfaceAndCBData(JSContext* cx); 120 119 … … 140 139 * Call a constructor function, equivalent to JS "new ctor(arg)". 141 140 * @return The new object; or JSVAL_VOID on failure, and logs an error message 142 141 */ 143 jsval CallConstructor(jsval ctor, jsval arg);142 jsval CallConstructor(jsval ctor, int argc, jsval argv); 144 143 145 144 /** 146 145 * Create an object as with CallConstructor except don't actually execute the … … 255 254 */ 256 255 bool HasProperty(jsval obj, const char* name); 257 256 258 bool EnumeratePropertyNamesWithPrefix( jsvalobj, const char* prefix, std::vector<std::string>& out);257 bool EnumeratePropertyNamesWithPrefix(JS::HandleObject obj, const char* prefix, std::vector<std::string>& out); 259 258 260 bool SetPrototype( jsval obj, jsvalproto);259 bool SetPrototype(JS::HandleObject obj, JS::HandleObject proto); 261 260 262 261 bool FreezeObject(jsval obj, bool deep); 263 262 … … 341 340 * MaybeGC tries to determine whether garbage collection in cx's runtime would free up enough memory to be worth the amount of time it would take 342 341 */ 343 342 void MaybeGC(); 343 344 void MaybeIncrementalRuntimeGC(); 345 346 void ForceGC(); 344 347 348 bool MathRandom(double& nbr); 349 345 350 /** 346 351 * Structured clones are a way to serialize 'simple' JS values into a buffer 347 352 * that can safely be passed between contexts and runtimes and threads. … … 355 360 public: 356 361 StructuredClone(); 357 362 ~StructuredClone(); 358 JSContext* m_Context; 359 uint64* m_Data; 363 uint64_t* m_Data; 360 364 size_t m_Size; 361 365 }; 362 366 … … 371 375 bool SetProperty_(jsval obj, const char* name, jsval value, bool readonly, bool enumerate); 372 376 bool SetProperty_(jsval obj, const wchar_t* name, jsval value, bool readonly, bool enumerate); 373 377 bool SetPropertyInt_(jsval obj, int name, jsval value, bool readonly, bool enumerate); 374 bool GetProperty_(jsval obj, const char* name, jsval& value);375 bool GetPropertyInt_(jsval obj, int name, jsval&value);378 bool GetProperty_(jsval obj, const char* name, JS::MutableHandleValue out); 379 bool GetPropertyInt_(jsval obj, int name, JS::MutableHandleValue value); 376 380 static bool IsExceptionPending(JSContext* cx); 377 static JSClass* GetClass(JS Context* cx, JSObject* obj);378 static void* GetPrivate(JS Context* cx, JSObject* obj);381 static JSClass* GetClass(JSObject* obj); 382 static void* GetPrivate(JSObject* obj); 379 383 380 384 class CustomType 381 385 { … … 387 391 void Register(const char* name, JSNative fptr, size_t nargs); 388 392 std::auto_ptr<ScriptInterface_impl> m; 389 393 394 boost::rand48* m_rng; 390 395 std::map<std::string, CustomType> m_CustomObjectTypes; 391 396 392 397 // The nasty macro/template bits are split into a separate file so you don't have to look at them … … 531 536 template<typename T> 532 537 bool ScriptInterface::GetProperty(jsval obj, const char* name, T& out) 533 538 { 534 jsval val; 535 if (! GetProperty_(obj, name, val)) 539 JSContext* cx = GetContext(); 540 JSAutoRequest rq(cx); 541 JS::RootedValue val(cx); 542 if (! GetProperty_(obj, name, &val)) 536 543 return false; 537 return FromJSVal( GetContext(), val, out);544 return FromJSVal(cx, val, out); 538 545 } 539 546 540 547 template<typename T> 541 548 bool ScriptInterface::GetPropertyInt(jsval obj, int name, T& out) 542 549 { 543 jsval val; 544 if (! GetPropertyInt_(obj, name, val)) 550 JSAutoRequest rq(GetContext()); 551 JS::RootedValue val(GetContext()); 552 if (! GetPropertyInt_(obj, name, &val)) 545 553 return false; 546 554 return FromJSVal(GetContext(), val, out); 547 555 } -
source/scriptinterface/ScriptStats.cpp
21 21 22 22 #include "scriptinterface/ScriptInterface.h" 23 23 24 #include "js/jsapi.h"25 26 24 CScriptStatsTable* g_ScriptStatsTable; 27 25 28 26 enum -
source/scriptinterface/ScriptTypes.h
18 18 #ifndef INCLUDED_SCRIPTTYPES 19 19 #define INCLUDED_SCRIPTTYPES 20 20 21 #ifdef _WIN3222 # define XP_WIN23 # ifndef WIN3224 # define WIN32 // SpiderMonkey expects this25 # endif26 27 // The jsval struct type causes crashes due to weird miscompilation28 // issues in (at least) VC2008, so force it to be the less-type-safe29 // non-struct type instead30 # define JS_NO_JSVAL_JSID_STRUCT_TYPES31 32 // Make JS think the int8_t etc types are defined, since wposix_types.h emulates33 // the ones that are needed and this avoids conflicting definitions34 # define JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES35 36 #else // If not Windows, then Unix:37 38 # define XP_UNIX39 40 // In DEBUG mode, jsval defaults to struct types. Normally we build separate41 // debug/release mode versions of the library, but when using --with-system-mozjs18542 // it's always a release mode library, so we have to disable struct types for43 // ABI compatibility44 # if defined(DEBUG) && defined(WITH_SYSTEM_MOZJS185)45 # define JS_NO_JSVAL_JSID_STRUCT_TYPES46 # endif47 48 #endif49 // (we don't support XP_OS2 or XP_BEOS)50 51 52 21 // Guess whether the library was compiled with the release-mode or debug-mode ABI 53 22 // (for JS_DumpHeap etc) 54 #if defined(DEBUG) && !defined(WITH_SYSTEM_MOZJS 185)23 #if defined(DEBUG) && !defined(WITH_SYSTEM_MOZJS24) 55 24 # define MOZJS_DEBUG_ABI 1 56 25 #else 57 26 # define MOZJS_DEBUG_ABI 0 58 27 #endif 59 28 60 61 // SpiderMonkey wants the DEBUG flag62 #ifndef NDEBUG63 # ifndef DEBUG64 # define DEBUG65 # endif66 #endif67 68 29 // Ignore some harmless warnings triggered by jsapi.h 69 #if GCC_VERSION >= 402 // (older GCCs don't support this pragma) 30 // Not all of these warnings can be disabled in older versions of GCC. 31 // The version checking was taken from the manual here: 32 // http://gcc.gnu.org/onlinedocs/ 33 // Choose the version and navigate to "Options to Request or Suppress Warnings" 34 // or for some flags "Options Controlling C++ Dialect". 35 #if GCC_VERSION >= 402 70 36 # pragma GCC diagnostic ignored "-Wunused-parameter" 71 37 # pragma GCC diagnostic ignored "-Wredundant-decls" 38 # pragma GCC diagnostic ignored "-Wundef" // Some versions of GCC will still print warnings (see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431). 39 # pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 40 # if GCC_VERSION >= 403 41 # pragma GCC diagnostic ignored "-Wignored-qualifiers" 42 # endif 72 43 #endif 73 44 #if MSC_VERSION 74 45 # pragma warning(push) … … 76 47 # pragma warning(disable:4100) // "unreferenced formal parameter" 77 48 #endif 78 49 79 #include "js/jsapi.h" 50 #include "jspubtd.h" 51 #include "jsapi.h" 80 52 53 81 54 #if MSC_VERSION 82 55 # pragma warning(pop) 83 56 #endif 84 57 #if GCC_VERSION >= 402 85 58 # pragma GCC diagnostic warning "-Wunused-parameter" 86 59 # pragma GCC diagnostic warning "-Wredundant-decls" 60 # pragma GCC diagnostic warning "-Wundef" 61 # pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 62 # if GCC_VERSION >= 403 63 # pragma GCC diagnostic warning "-Wignored-qualifiers" 64 # endif 65 //# pragma GCC diagnostic warning "-Wnon-virtual-dtor" 87 66 #endif 88 67 89 #if JS_VERSION != 18590 #error Your compiler is trying to use an incorrect version of the SpiderMonkey library.68 #if MOZJS_MAJOR_VERSION != 24 69 #error Your compiler is trying to use an incorrect major version of the SpiderMonkey library. 91 70 #error The only version that works is the one in the libraries/spidermonkey/ directory, 92 71 #error and it will not work with a typical system-installed version. 93 72 #error Make sure you have got all the right files and include paths. 94 73 #endif 95 74 75 #if MOZJS_MINOR_VERSION != 2 76 #error Your compiler is trying to use an untested minor version of the SpiderMonkey library. 77 #error If you are a package maintainer, please make sure to check very carefully that this version does not change 78 #error the behaviour of the code executed by SpiderMonkey. 79 #error Different parts of the game (e.g. the multiplayer mode) rely on deterministic behaviour of the JavaScript engine. 80 #error A simple way for testing this would be playing a network game with one player using the old version and one player using the new version. 81 #error Another way for testing is running replays and comparing the final hash (check trac.wildfiregames.com/wiki/Debugging#Replaymode). 82 #error For more information check this link: trac.wildfiregames.com/wiki/Debugging#Outofsync 83 #endif 84 96 85 class ScriptInterface; 97 86 class CScriptVal; 98 87 class CScriptValRooted; -
source/scriptinterface/ScriptVal.cpp
17 17 18 18 #include "precompiled.h" 19 19 20 #include "ScriptInterface.h" 20 21 #include "ScriptVal.h" 21 22 22 #include "js/jsapi.h"23 23 24 24 struct Unrooter 25 25 { 26 26 Unrooter(JSContext* cx) : cx(cx) { } 27 void operator()(jsval* p) { JS_RemoveValueRoot(cx, p); delete p; } 27 void operator()(jsval* p) 28 { 29 JSAutoRequest rq(cx); 30 JS_RemoveValueRoot(cx, p); delete p; 31 } 28 32 JSContext* cx; 29 33 }; 30 34 31 35 CScriptValRooted::CScriptValRooted(JSContext* cx, jsval val) 32 36 { 37 JSAutoRequest rq(cx); 33 38 jsval* p = new jsval(val); 34 39 JS_AddNamedValueRoot(cx, p, "CScriptValRooted"); 35 40 m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx)); … … 37 42 38 43 CScriptValRooted::CScriptValRooted(JSContext* cx, CScriptVal val) 39 44 { 45 JSAutoRequest rq(cx); 40 46 jsval* p = new jsval(val.get()); 41 47 JS_AddNamedValueRoot(cx, p, "CScriptValRooted"); 42 48 m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx)); … … 64 70 { 65 71 return !m_Val; 66 72 } 67 68 AutoJSIdArray::AutoJSIdArray(JSContext* cx, JSIdArray* ida) :69 m_Context(cx), m_IdArray(ida)70 {71 }72 73 AutoJSIdArray::~AutoJSIdArray()74 {75 if (m_IdArray)76 JS_DestroyIdArray(m_Context, m_IdArray);77 }78 79 JSIdArray* AutoJSIdArray::get() const80 {81 return m_IdArray;82 }83 84 size_t AutoJSIdArray::length() const85 {86 if (!m_IdArray)87 return 0;88 return m_IdArray->length;89 }90 91 jsid AutoJSIdArray::operator[](size_t i) const92 {93 if (!(m_IdArray && i < (size_t)m_IdArray->length))94 return JSID_VOID;95 return m_IdArray->vector[i];96 } -
source/scriptinterface/ScriptVal.h
78 78 boost::shared_ptr<jsval> m_Val; 79 79 }; 80 80 81 /**82 * RAII wrapper for JSIdArray*83 */84 class AutoJSIdArray85 {86 NONCOPYABLE(AutoJSIdArray);87 public:88 AutoJSIdArray(JSContext* cx, JSIdArray* ida);89 ~AutoJSIdArray();90 91 JSIdArray* get() const;92 size_t length() const;93 jsid operator[](size_t i) const;94 95 private:96 JSContext* m_Context;97 JSIdArray* m_IdArray;98 };99 100 81 #endif // INCLUDED_SCRIPTVAL -
source/scriptinterface/tests/test_ScriptConversions.h
23 23 #include "maths/MathUtil.h" 24 24 #include "ps/CLogger.h" 25 25 26 #include "js /jsapi.h"26 #include "jsapi.h" 27 27 28 28 class TestScriptConversions : public CxxTest::TestSuite 29 29 { … … 32 32 { 33 33 ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime()); 34 34 JSContext* cx = script.GetContext(); 35 JSAutoRequest rq(cx); 35 36 36 37 jsval v1 = ScriptInterface::ToJSVal(cx, value); 37 38 38 39 // We want to convert values to strings, but can't just call toSource() on them 39 40 // since they might not be objects. So just use uneval. 40 41 std::string source; 41 TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobal Object(cx)), "uneval", CScriptVal(v1), source));42 TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalForScopeChain(cx)), "uneval", CScriptVal(v1), source)); 42 43 43 44 TS_ASSERT_STR_EQUALS(source, expected); 44 45 } … … 48 49 { 49 50 ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime()); 50 51 JSContext* cx = script.GetContext(); 52 JSAutoRequest rq(cx); 51 53 52 54 jsval v1 = ScriptInterface::ToJSVal(cx, value); 53 55 54 56 std::string source; 55 TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobal Object(cx)), "uneval", CScriptVal(v1), source));57 TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalForScopeChain(cx)), "uneval", CScriptVal(v1), source)); 56 58 57 59 if (expected) 58 60 TS_ASSERT_STR_EQUALS(source, expected); … … 101 103 102 104 roundtrip<std::string>("", "\"\""); 103 105 roundtrip<std::string>("test", "\"test\""); 104 roundtrip<std::string>(s1, "\"t\\ 0st\"");106 roundtrip<std::string>(s1, "\"t\\x00st\""); 105 107 // TODO: should test non-ASCII strings 106 108 107 109 roundtrip<std::wstring>(L"", "\"\""); 108 110 roundtrip<std::wstring>(L"test", "\"test\""); 109 roundtrip<std::wstring>(w1, "\"t\\ 0st\"");111 roundtrip<std::wstring>(w1, "\"t\\x00st\""); 110 112 // TODO: should test non-ASCII strings 111 113 112 114 convert_to<const char*>("", "\"\""); … … 123 125 { 124 126 ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime()); 125 127 JSContext* cx = script.GetContext(); 128 JSAutoRequest rq(cx); 126 129 127 130 TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 0))); 128 131 … … 146 149 147 150 ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime()); 148 151 JSContext* cx = script.GetContext(); 152 JSAutoRequest rq(cx); 149 153 150 154 float f = 0; 151 155 TS_ASSERT(ScriptInterface::FromJSVal(cx, ScriptInterface::ToJSVal(cx, NAN), f)); -
source/scriptinterface/tests/test_ScriptInterface.h
61 61 62 62 void test_clone_basic() 63 63 { 64 ScriptInterface script1("Test", "Test", ScriptInterface::CreateRuntime()); 65 ScriptInterface script2("Test", "Test", ScriptInterface::CreateRuntime()); 64 shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime(); 65 ScriptInterface script1("Test", "Test", runtime); 66 ScriptInterface script2("Test", "Test", runtime); 66 67 67 68 CScriptVal obj1; 68 69 TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", obj1)); … … 78 79 { 79 80 // The tests should be run with JS_SetGCZeal so this can try to find GC bugs 80 81 81 ScriptInterface script1("Test", "Test", ScriptInterface::CreateRuntime()); 82 ScriptInterface script2("Test", "Test", ScriptInterface::CreateRuntime()); 82 shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime(); 83 ScriptInterface script1("Test", "Test", runtime); 84 ScriptInterface script2("Test", "Test", runtime); 83 85 84 86 CScriptVal obj1; 85 87 TS_ASSERT(script1.Eval("var s = '?'; var v = ({get x() { return 123 }, 'y': {'w':{get z() { delete v.y; delete v.n; v = null; s += s; return 4 }}}, 'n': 100}); v", obj1)); … … 88 90 89 91 std::string source; 90 92 TS_ASSERT(script2.CallFunction(obj2.get(), "toSource", source)); 91 TS_ASSERT_STR_EQUALS(source, "({x:123, y:{w:{z:4}} , n:(void 0)})");93 TS_ASSERT_STR_EQUALS(source, "({x:123, y:{w:{z:4}}})"); 92 94 } 93 95 94 96 void test_clone_cyclic() 95 97 { 96 ScriptInterface script1("Test", "Test", ScriptInterface::CreateRuntime()); 97 ScriptInterface script2("Test", "Test", ScriptInterface::CreateRuntime()); 98 shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime(); 99 ScriptInterface script1("Test", "Test", runtime); 100 ScriptInterface script2("Test", "Test", runtime); 98 101 99 102 CScriptVal obj1; 100 103 TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", obj1)); 101 104 102 105 CScriptVal obj2 = script2.CloneValueFromOtherContext(script1, obj1.get()); 103 106 104 std::string source; 105 TS_ASSERT(script2.CallFunction(obj2.get(), "toSource", source)); 106 TS_ASSERT_STR_EQUALS(source, "({a:#1=[#1#], b:#1#})"); 107 // Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0] 108 JSContext* cx2 = script2.GetContext(); 109 JSAutoRequest rq(cx2); 110 JS::RootedValue prop_a(cx2); 111 JS::RootedValue prop_b(cx2); 112 JS::RootedValue prop_x1(cx2); 113 TS_ASSERT(JS_GetProperty(cx2, &(obj2.get().toObject()), "a", prop_a.address())); 114 TS_ASSERT(JS_GetProperty(cx2, &(obj2.get().toObject()), "b", prop_b.address())); 115 TS_ASSERT(prop_a.get().isObject()); 116 TS_ASSERT(prop_b.get().isObject()); 117 TS_ASSERT(JS_GetProperty(cx2, &(prop_a.get().toObject()), "0", prop_x1.address())); 118 TS_ASSERT_EQUALS(prop_x1.get(), prop_a.get()); 119 TS_ASSERT_EQUALS(prop_x1.get(), prop_b.get()); 107 120 } 108 121 109 122 void test_random() -
source/scriptinterface/tests/test_ScriptVal.h
20 20 #include "scriptinterface/ScriptInterface.h" 21 21 #include "scriptinterface/ScriptVal.h" 22 22 23 #include "js /jsapi.h"23 #include "jsapi.h" 24 24 25 25 class TestScriptVal : public CxxTest::TestSuite 26 26 { … … 29 29 { 30 30 ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime()); 31 31 JSContext* cx = script.GetContext(); 32 JSAutoRequest rq(cx); 32 33 33 34 JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL); 34 35 TS_ASSERT(obj); 35 36 36 37 CScriptValRooted root(cx, OBJECT_TO_JSVAL(obj)); 37 38 38 JS_GC( cx);39 JS_GC(script.GetJSRuntime()); 39 40 40 41 jsval val = INT_TO_JSVAL(123); 41 42 TS_ASSERT(JS_SetProperty(cx, obj, "test", &val)); 42 43 43 JS_GC( cx);44 JS_GC(script.GetJSRuntime()); 44 45 45 46 jsval rval; 46 47 TS_ASSERT(JS_GetProperty(cx, obj, "test", &rval)); -
source/simulation2/Simulation2.cpp
19 19 20 20 #include "Simulation2.h" 21 21 22 #include "scriptinterface/ScriptInterface.h" 23 22 24 #include "simulation2/MessageTypes.h" 23 25 #include "simulation2/system/ComponentManager.h" 24 26 #include "simulation2/system/ParamNode.h" … … 155 157 } 156 158 157 159 int ProgressiveLoad(); 160 161 void Tick(); 158 162 void Update(int turnLength, const std::vector<SimulationCommand>& commands); 159 163 static void UpdateComponents(CSimContext& simContext, fixed turnLengthFixed, const std::vector<SimulationCommand>& commands); 160 164 void Interpolate(float simFrameLength, float frameOffset, float realFrameLength); … … 336 340 debug_warn(L"Serialization test failure"); 337 341 } 338 342 343 void CSimulation2Impl::Tick() 344 { 345 m_ComponentManager.Tick(); 346 } 347 339 348 void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationCommand>& commands) 340 349 { 341 350 PROFILE3("sim update"); … … 451 460 // Run the GC occasionally 452 461 // (TODO: we ought to schedule this for a frame where we're not 453 462 // running the sim update, to spread the load) 454 if (m_TurnNumber % 1 0== 0)455 m_ComponentManager.GetScriptInterface().Maybe GC();463 if (m_TurnNumber % 1 == 0) 464 m_ComponentManager.GetScriptInterface().MaybeIncrementalRuntimeGC(); 456 465 457 466 if (m_EnableOOSLog) 458 467 DumpState(); … … 637 646 return m->m_ComponentManager.GetEntitiesWithInterfaceUnordered(iid); 638 647 } 639 648 649 void CSimulation2::Tick() 650 { 651 m->Tick(); 652 } 653 640 654 const CSimContext& CSimulation2::GetSimContext() const 641 655 { 642 656 return m->m_SimContext; -
source/simulation2/Simulation2.h
53 53 ~CSimulation2(); 54 54 55 55 void EnableOOSLog(); 56 void Tick(); 56 57 void EnableSerializationTest(); 57 58 58 59 /** -
source/simulation2/components/CCmpAIManager.cpp
152 152 ENSURE(m_Worker.m_HasLoadedEntityTemplates); 153 153 m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); 154 154 155 obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get()); 155 JS::AutoValueVector argv(m_ScriptInterface->GetContext()); 156 argv.append(settings.get()); 157 obj = m_ScriptInterface->CallConstructor(ctor.get(), argv.length(), argv.handleAt(0)); 156 158 } 157 159 else 158 160 { … … 209 211 }; 210 212 211 213 CAIWorker() : 212 // TODO: Passing a 32 MB argument to CreateRuntime() is a temporary fix 213 // to prevent frequent AI out-of-memory crashes. The argument should be 214 // removed as soon whenever the new pathfinder is committed 215 // And the AIs can stop relying on their own little hands. 216 m_ScriptRuntime(ScriptInterface::CreateRuntime(33554432)), 217 m_ScriptInterface(new ScriptInterface("Engine", "AI", m_ScriptRuntime)), 214 m_ScriptInterface(new ScriptInterface("Engine", "AI", g_ScriptRuntime)), 218 215 m_TurnNum(0), 219 216 m_CommandsComputed(true), 220 217 m_HasLoadedEntityTemplates(false), … … 305 302 static void ForceGC(ScriptInterface::CxPrivate* pCxPrivate) 306 303 { 307 304 PROFILE3("AI compute GC"); 308 JS_GC(pCxPrivate->pScriptInterface->Get Context());305 JS_GC(pCxPrivate->pScriptInterface->GetJSRuntime()); 309 306 } 310 307 311 308 /** … … 408 405 m_ScriptInterface->Eval("({})", fakeTech); 409 406 m_ScriptInterface->SetProperty(settings.get(), "techTemplates", fakeTech, false); 410 407 } 411 m_SharedAIObj = CScriptValRooted(m_ScriptInterface->GetContext(),m_ScriptInterface->CallConstructor(ctor.get(), settings.get())); 408 409 JS::AutoValueVector argv(m_ScriptInterface->GetContext()); 410 argv.append(settings.get()); 411 m_SharedAIObj = CScriptValRooted(m_ScriptInterface->GetContext(),m_ScriptInterface->CallConstructor(ctor.get(), argv.length(), argv.handleAt(0))); 412 412 413 413 414 414 if (m_SharedAIObj.undefined()) … … 430 430 if (!m_HasSharedComponent) 431 431 m_HasSharedComponent = ai->m_UseSharedComponent; 432 432 433 m_ScriptInterface->MaybeGC();434 435 433 m_Players.push_back(ai); 436 434 437 435 return true; … … 453 451 m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true); 454 452 455 453 m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "init", state); 456 m_ScriptInterface->MaybeGC();457 454 458 455 for (size_t i = 0; i < m_Players.size(); ++i) 459 456 { … … 706 703 } 707 704 708 705 void PerformComputation() 709 { 710 if (m_Players.size() == 0) 711 { 712 // Run the GC every so often. 713 // (This isn't particularly necessary, but it makes profiling clearer 714 // since it avoids random GC delays while running other scripts) 715 if (m_TurnNum++ % 50 == 0) 716 { 717 PROFILE3("AI compute GC"); 718 m_ScriptInterface->MaybeGC(); 719 } 720 return; 721 } 722 706 { 723 707 // Deserialize the game state, to pass to the AI's HandleMessage 724 708 CScriptVal state; 725 709 { … … 753 737 else 754 738 m_Players[i]->Run(state, m_Players[i]->m_Player); 755 739 } 756 757 // Run GC if we are about to overflow758 if (JS_GetGCParameter(m_ScriptInterface->GetJSRuntime(), JSGC_BYTES) > 33000000)759 {760 PROFILE3("AI compute GC");761 762 JS_GC(m_ScriptInterface->GetContext());763 }764 765 // Run the GC every so often.766 // (This isn't particularly necessary, but it makes profiling clearer767 // since it avoids random GC delays while running other scripts)768 /*if (m_TurnNum++ % 20 == 0)769 {770 PROFILE3("AI compute GC");771 m_ScriptInterface->MaybeGC();772 }*/773 740 } 774 741 775 742 shared_ptr<ScriptRuntime> m_ScriptRuntime; -
source/simulation2/components/ICmpFootprint.cpp
38 38 39 39 if (shape == CIRCLE) 40 40 { 41 jsval ptype = ScriptInterface::ToJSVal<std::string>(cx, "circle");42 jsval pradius = ScriptInterface::ToJSVal(cx, size0);43 jsval pheight = ScriptInterface::ToJSVal(cx, height);44 JS_SetProperty(cx, obj, "type", &ptype);45 JS_SetProperty(cx, obj, "radius", &pradius);46 JS_SetProperty(cx, obj, "height", &pheight);41 JS::RootedValue ptype(cx, ScriptInterface::ToJSVal<std::string>(cx, "circle")); 42 JS::RootedValue pradius(cx, ScriptInterface::ToJSVal(cx, size0)); 43 JS::RootedValue pheight(cx, ScriptInterface::ToJSVal(cx, height)); 44 JS_SetProperty(cx, obj, "type", ptype.address()); 45 JS_SetProperty(cx, obj, "radius", pradius.address()); 46 JS_SetProperty(cx, obj, "height", pheight.address()); 47 47 } 48 48 else 49 49 { 50 jsval ptype = ScriptInterface::ToJSVal<std::string>(cx, "square");51 jsval pwidth = ScriptInterface::ToJSVal(cx, size0);52 jsval pdepth = ScriptInterface::ToJSVal(cx, size1);53 jsval pheight = ScriptInterface::ToJSVal(cx, height);54 JS_SetProperty(cx, obj, "type", &ptype);55 JS_SetProperty(cx, obj, "width", &pwidth);56 JS_SetProperty(cx, obj, "depth", &pdepth);57 JS_SetProperty(cx, obj, "height", &pheight);50 JS::RootedValue ptype(cx, ScriptInterface::ToJSVal<std::string>(cx, "square")); 51 JS::RootedValue pwidth(cx, ScriptInterface::ToJSVal(cx, size0)); 52 JS::RootedValue pdepth(cx, ScriptInterface::ToJSVal(cx, size1)); 53 JS::RootedValue pheight(cx, ScriptInterface::ToJSVal(cx, height)); 54 JS_SetProperty(cx, obj, "type", ptype.address()); 55 JS_SetProperty(cx, obj, "width", pwidth.address()); 56 JS_SetProperty(cx, obj, "depth", pdepth.address()); 57 JS_SetProperty(cx, obj, "height", pheight.address()); 58 58 } 59 59 60 60 return OBJECT_TO_JSVAL(obj); -
source/simulation2/components/tests/test_CommandQueue.h
34 34 35 35 void test_basic() 36 36 { 37 ComponentTestHelper test ;37 ComponentTestHelper test(ScriptInterface::CreateRuntime()); 38 38 39 39 std::vector<SimulationCommand> empty; 40 40 -
source/simulation2/components/tests/test_ObstructionManager.h
68 68 ent3z = ent2z + ent2r + ent3r; // ensure it just touches the border of ent2 69 69 ent3g = ent3; 70 70 71 testHelper = new ComponentTestHelper ;71 testHelper = new ComponentTestHelper(ScriptInterface::CreateRuntime()); 72 72 cmp = testHelper->Add<ICmpObstructionManager>(CID_ObstructionManager, ""); 73 73 cmp->SetBounds(fixed::FromInt(0), fixed::FromInt(0), fixed::FromInt(1000), fixed::FromInt(1000)); 74 74 -
source/simulation2/components/tests/test_Position.h
39 39 40 40 void test_basic() 41 41 { 42 ComponentTestHelper test ;42 ComponentTestHelper test(ScriptInterface::CreateRuntime()); 43 43 44 44 MockTerrain terrain; 45 45 test.AddMock(SYSTEM_ENTITY, IID_Terrain, terrain); … … 111 111 112 112 void test_serialize() 113 113 { 114 ComponentTestHelper test ;114 ComponentTestHelper test(ScriptInterface::CreateRuntime()); 115 115 116 116 MockTerrain terrain; 117 117 test.AddMock(SYSTEM_ENTITY, IID_Terrain, terrain); -
source/simulation2/components/tests/test_RangeManager.h
77 77 78 78 void test_basic() 79 79 { 80 ComponentTestHelper test ;80 ComponentTestHelper test(ScriptInterface::CreateRuntime()); 81 81 82 82 ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, ""); 83 83 -
source/simulation2/scripting/EngineScriptConversions.cpp
34 34 35 35 template<> jsval ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, IComponent* const& val) 36 36 { 37 JSAutoRequest rq(cx); 37 38 if (val == NULL) 38 39 return JSVAL_NULL; 39 40 … … 58 59 LOGERROR(L"Failed to construct IComponent script object"); 59 60 return JSVAL_VOID; 60 61 } 61 JS_SetPrivate( cx,obj, static_cast<void*>(val));62 JS_SetPrivate(obj, static_cast<void*>(val)); 62 63 63 64 return OBJECT_TO_JSVAL(obj); 64 65 } 65 66 66 67 template<> jsval ScriptInterface::ToJSVal<CParamNode>(JSContext* cx, CParamNode const& val) 67 68 { 69 JSAutoRequest rq(cx); 68 70 jsval rval = val.ToJSVal(cx, true); 69 71 70 72 // Prevent modifications to the object, so that it's safe to share between 71 73 // components and to reconstruct on deserialization 72 if ( JSVAL_IS_OBJECT(rval))74 if (!JSVAL_IS_PRIMITIVE(rval)) 73 75 JS_DeepFreezeObject(cx, JSVAL_TO_OBJECT(rval)); 74 76 75 77 return rval; … … 85 87 86 88 template<> bool ScriptInterface::FromJSVal<CColor>(JSContext* cx, jsval v, CColor& out) 87 89 { 88 if ( !JSVAL_IS_OBJECT(v))90 if (JSVAL_IS_PRIMITIVE(v)) 89 91 FAIL("jsval not an object"); 90 92 93 JSAutoRequest rq(cx); 91 94 JSObject* obj = JSVAL_TO_OBJECT(v); 92 95 93 jsval r, g, b, a; 94 if (!JS_GetProperty(cx, obj, "r", &r) || !FromJSVal(cx, r, out.r)) 96 JS::RootedValue r(cx); 97 JS::RootedValue g(cx); 98 JS::RootedValue b(cx); 99 JS::RootedValue a(cx); 100 if (!JS_GetProperty(cx, obj, "r", r.address()) || !FromJSVal(cx, r, out.r)) 95 101 FAIL("Failed to get property CColor.r"); 96 if (!JS_GetProperty(cx, obj, "g", &g) || !FromJSVal(cx, g, out.g))102 if (!JS_GetProperty(cx, obj, "g", g.address()) || !FromJSVal(cx, g, out.g)) 97 103 FAIL("Failed to get property CColor.g"); 98 if (!JS_GetProperty(cx, obj, "b", &b) || !FromJSVal(cx, b, out.b))104 if (!JS_GetProperty(cx, obj, "b", b.address()) || !FromJSVal(cx, b, out.b)) 99 105 FAIL("Failed to get property CColor.b"); 100 if (!JS_GetProperty(cx, obj, "a", &a) || !FromJSVal(cx, a, out.a))106 if (!JS_GetProperty(cx, obj, "a", a.address()) || !FromJSVal(cx, a, out.a)) 101 107 FAIL("Failed to get property CColor.a"); 102 108 // TODO: this probably has GC bugs if a getter returns an unrooted value 103 109 … … 106 112 107 113 template<> jsval ScriptInterface::ToJSVal<CColor>(JSContext* cx, CColor const& val) 108 114 { 115 JSAutoRequest rq(cx); 109 116 JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL); 110 117 if (!obj) 111 118 return JSVAL_VOID; 112 119 113 jsval r = ToJSVal(cx, val.r);114 jsval g = ToJSVal(cx, val.g);115 jsval b = ToJSVal(cx, val.b);116 jsval a = ToJSVal(cx, val.a);120 JS::RootedValue r(cx, ToJSVal(cx, val.r)); 121 JS::RootedValue g(cx, ToJSVal(cx, val.g)); 122 JS::RootedValue b(cx, ToJSVal(cx, val.b)); 123 JS::RootedValue a(cx, ToJSVal(cx, val.a)); 117 124 118 JS_SetProperty(cx, obj, "r", &r);119 JS_SetProperty(cx, obj, "g", &g);120 JS_SetProperty(cx, obj, "b", &b);121 JS_SetProperty(cx, obj, "a", &a);125 JS_SetProperty(cx, obj, "r", r.address()); 126 JS_SetProperty(cx, obj, "g", g.address()); 127 JS_SetProperty(cx, obj, "b", b.address()); 128 JS_SetProperty(cx, obj, "a", a.address()); 122 129 123 130 return OBJECT_TO_JSVAL(obj); 124 131 } 125 132 126 133 template<> bool ScriptInterface::FromJSVal<fixed>(JSContext* cx, jsval v, fixed& out) 127 134 { 128 jsdouble ret; 135 JSAutoRequest rq(cx); 136 double ret; 129 137 if (!JS_ValueToNumber(cx, v, &ret)) 130 138 return false; 131 139 out = fixed::FromDouble(ret); … … 134 142 return true; 135 143 } 136 144 137 template<> jsval ScriptInterface::ToJSVal<fixed>(JSContext* cx, const fixed& val)145 template<> jsval ScriptInterface::ToJSVal<fixed>(JSContext* UNUSED(cx), const fixed& val) 138 146 { 139 jsval rval = JSVAL_VOID; 140 JS_NewNumberValue(cx, val.ToDouble(), &rval); // ignore return value 147 jsval rval = JS_NumberValue(val.ToDouble()); 141 148 return rval; 142 149 } 143 150 144 151 template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(JSContext* cx, jsval v, CFixedVector3D& out) 145 152 { 146 if ( !JSVAL_IS_OBJECT(v))153 if (JSVAL_IS_PRIMITIVE(v)) 147 154 return false; // TODO: report type error 155 156 JSAutoRequest rq(cx); 148 157 JSObject* obj = JSVAL_TO_OBJECT(v); 149 158 150 jsval p;159 JS::RootedValue p(cx); 151 160 152 if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors161 if (!JS_GetProperty(cx, obj, "x", p.address())) return false; // TODO: report type errors 153 162 if (!FromJSVal(cx, p, out.X)) return false; 154 163 155 if (!JS_GetProperty(cx, obj, "y", &p)) return false;164 if (!JS_GetProperty(cx, obj, "y", p.address())) return false; 156 165 if (!FromJSVal(cx, p, out.Y)) return false; 157 166 158 if (!JS_GetProperty(cx, obj, "z", &p)) return false;167 if (!JS_GetProperty(cx, obj, "z", p.address())) return false; 159 168 if (!FromJSVal(cx, p, out.Z)) return false; 160 169 161 170 return true; … … 163 172 164 173 template<> jsval ScriptInterface::ToJSVal<CFixedVector3D>(JSContext* cx, const CFixedVector3D& val) 165 174 { 175 JSAutoRequest rq(cx); 176 166 177 // apply the Vector3D prototype to the return value; 167 178 ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(cx); 168 179 JSObject* obj = JS_NewObject(cx, NULL, JSVAL_TO_OBJECT(pCxPrivate->pScriptInterface->GetCachedValue(ScriptInterface::CACHE_VECTOR3DPROTO).get()), NULL); … … 170 181 if (!obj) 171 182 return JSVAL_VOID; 172 183 173 jsval x = ToJSVal(cx, val.X);174 jsval y = ToJSVal(cx, val.Y);175 jsval z = ToJSVal(cx, val.Z);184 JS::RootedValue x(cx, ToJSVal(cx, val.X)); 185 JS::RootedValue y(cx, ToJSVal(cx, val.Y)); 186 JS::RootedValue z(cx, ToJSVal(cx, val.Z)); 176 187 177 JS_SetProperty(cx, obj, "x", &x);178 JS_SetProperty(cx, obj, "y", &y);179 JS_SetProperty(cx, obj, "z", &z);188 JS_SetProperty(cx, obj, "x", x.address()); 189 JS_SetProperty(cx, obj, "y", y.address()); 190 JS_SetProperty(cx, obj, "z", z.address()); 180 191 181 192 return OBJECT_TO_JSVAL(obj); 182 193 } 183 194 184 195 template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(JSContext* cx, jsval v, CFixedVector2D& out) 185 196 { 186 if (!JSVAL_IS_OBJECT(v)) 197 JSAutoRequest rq(cx); 198 if (JSVAL_IS_PRIMITIVE(v)) 187 199 return false; // TODO: report type error 188 200 JSObject* obj = JSVAL_TO_OBJECT(v); 189 201 190 jsval p;202 JS::RootedValue p(cx); 191 203 192 if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors204 if (!JS_GetProperty(cx, obj, "x", p.address())) return false; // TODO: report type errors 193 205 if (!FromJSVal(cx, p, out.X)) return false; 194 206 195 if (!JS_GetProperty(cx, obj, "y", &p)) return false;207 if (!JS_GetProperty(cx, obj, "y", p.address())) return false; 196 208 if (!FromJSVal(cx, p, out.Y)) return false; 197 209 198 210 return true; … … 200 212 201 213 template<> jsval ScriptInterface::ToJSVal<CFixedVector2D>(JSContext* cx, const CFixedVector2D& val) 202 214 { 215 JSAutoRequest rq(cx); 216 203 217 // apply the Vector2D prototype to the return value 204 218 ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(cx); 205 219 JSObject* obj = JS_NewObject(cx, NULL, JSVAL_TO_OBJECT(pCxPrivate->pScriptInterface->GetCachedValue(ScriptInterface::CACHE_VECTOR2DPROTO).get()), NULL); … … 207 221 if (!obj) 208 222 return JSVAL_VOID; 209 223 210 jsval x = ToJSVal(cx, val.X);211 jsval y = ToJSVal(cx, val.Y);224 JS::RootedValue x(cx, ToJSVal(cx, val.X)); 225 JS::RootedValue y(cx, ToJSVal(cx, val.Y)); 212 226 213 JS_SetProperty(cx, obj, "x", &x);214 JS_SetProperty(cx, obj, "y", &y);227 JS_SetProperty(cx, obj, "x", x.address()); 228 JS_SetProperty(cx, obj, "y", y.address()); 215 229 216 230 return OBJECT_TO_JSVAL(obj); 217 231 } 218 232 219 template< jsint atype, typename T> jsval ToJSVal_Grid(JSContext* cx, const Grid<T>& val)233 template<> jsval ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, const Grid<u8>& val) 220 234 { 221 JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL); 222 if (!obj) 223 return JSVAL_VOID; 235 JSAutoRequest rq(cx); 236 uint32_t length = (uint32_t)(val.m_W * val.m_H); 237 uint32_t nbytes = (uint32_t)(length * sizeof(uint8_t)); 238 JSObject* objArr = JS_NewUint8Array(cx, length); 239 memcpy((void*)JS_GetUint8ArrayData(objArr), val.m_Data, nbytes); 224 240 225 jsuint len = val.m_W * val.m_H; 226 JSObject *darray = js_CreateTypedArray(cx, atype, len); 227 if (!darray) 228 return JSVAL_VOID; 241 JS::RootedValue data(cx, OBJECT_TO_JSVAL(objArr)); 242 JS::RootedValue w(cx, ScriptInterface::ToJSVal(cx, val.m_W)); 243 JS::RootedValue h(cx, ScriptInterface::ToJSVal(cx, val.m_H)); 229 244 230 js::TypedArray *tdest = js::TypedArray::fromJSObject(darray);231 ENSURE(tdest->byteLength == len*sizeof(T));232 245 233 memcpy(tdest->data, val.m_Data, tdest->byteLength); 246 JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL); 247 JS_SetProperty(cx, obj, "width", w.address()); 248 JS_SetProperty(cx, obj, "height", h.address()); 249 JS_SetProperty(cx, obj, "data", data.address()); 234 250 235 jsval w = ScriptInterface::ToJSVal(cx, val.m_W);236 jsval h = ScriptInterface::ToJSVal(cx, val.m_H);237 jsval data = OBJECT_TO_JSVAL(darray);238 239 JS_SetProperty(cx, obj, "width", &w);240 JS_SetProperty(cx, obj, "height", &h);241 JS_SetProperty(cx, obj, "data", &data);242 243 251 return OBJECT_TO_JSVAL(obj); 244 252 } 253 254 template<> jsval ScriptInterface::ToJSVal<Grid<u16> >(JSContext* cx, const Grid<u16>& val) 255 { 256 JSAutoRequest rq(cx); 257 uint32_t length = (uint32_t)(val.m_W * val.m_H); 258 uint32_t nbytes = (uint32_t)(length * sizeof(uint16_t)); 259 JSObject* objArr = JS_NewUint16Array(cx, length); 260 memcpy((void*)JS_GetUint16ArrayData(objArr), val.m_Data, nbytes); 261 262 JS::RootedValue data(cx, OBJECT_TO_JSVAL(objArr)); 263 JS::RootedValue w(cx, ScriptInterface::ToJSVal(cx, val.m_W)); 264 JS::RootedValue h(cx, ScriptInterface::ToJSVal(cx, val.m_H)); 245 265 246 template<> jsval ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, const Grid<u8>& val) 247 { 248 return ToJSVal_Grid<js::TypedArray::TYPE_UINT8>(cx, val);249 } 266 JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL); 267 JS_SetProperty(cx, obj, "width", w.address()); 268 JS_SetProperty(cx, obj, "height", h.address()); 269 JS_SetProperty(cx, obj, "data", data.address()); 250 270 251 template<> jsval ScriptInterface::ToJSVal<Grid<u16> >(JSContext* cx, const Grid<u16>& val) 252 { 253 return ToJSVal_Grid<js::TypedArray::TYPE_UINT16>(cx, val); 271 return OBJECT_TO_JSVAL(obj); 254 272 } -
source/simulation2/scripting/MessageTypeConversions.cpp
21 21 #include "scriptinterface/ScriptInterface.h" 22 22 #include "simulation2/MessageTypes.h" 23 23 24 #include "js/jsapi.h"25 26 24 #define TOJSVAL_SETUP() \ 27 JSObject* obj = JS_NewObject(scriptInterface.GetContext(), NULL, NULL, NULL); \ 28 if (! obj) \ 29 return JSVAL_VOID; 25 JSObject* obj; \ 26 {\ 27 JSAutoRequest rq(scriptInterface.GetContext()); \ 28 obj = JS_NewObject(scriptInterface.GetContext(), NULL, NULL, NULL); \ 29 if (!obj) \ 30 return JSVAL_VOID; \ 31 } 30 32 31 33 #define SET_MSG_PROPERTY(name) \ 32 34 do { \ 33 jsval prop = ScriptInterface::ToJSVal(scriptInterface.GetContext(), this->name); \ 34 if (! JS_SetProperty(scriptInterface.GetContext(), obj, #name, &prop)) \ 35 JSAutoRequest rq(scriptInterface.GetContext()); \ 36 JSContext* cx = scriptInterface.GetContext(); \ 37 JS::RootedValue prop(cx, ScriptInterface::ToJSVal(cx, this->name)); \ 38 if (! JS_SetProperty(cx, obj, #name, prop.address())) \ 35 39 return JSVAL_VOID; \ 36 40 } while (0); 37 41 38 42 #define FROMJSVAL_SETUP() \ 39 if ( ! JSVAL_IS_OBJECT(val)) \43 if ( JSVAL_IS_PRIMITIVE(val)) \ 40 44 return NULL; \ 41 45 JSObject* obj = JSVAL_TO_OBJECT(val); \ 42 jsval prop;46 JS::RootedValue prop(scriptInterface.GetContext()); 43 47 44 48 #define GET_MSG_PROPERTY(type, name) \ 45 if (! JS_GetProperty(scriptInterface.GetContext(), obj, #name, &prop)) \ 49 type name; \ 50 { \ 51 JSAutoRequest rq(scriptInterface.GetContext()); \ 52 if (! JS_GetProperty(scriptInterface.GetContext(), obj, #name, prop.address())) \ 46 53 return NULL; \ 47 type name;\48 if (! ScriptInterface::FromJSVal(scriptInterface.GetContext(), prop, name))\49 return NULL;54 if (! ScriptInterface::FromJSVal(scriptInterface.GetContext(), prop.get(), name)) \ 55 return NULL; \ 56 } 50 57 51 58 jsval CMessage::ToJSValCached(ScriptInterface& scriptInterface) const 52 59 { -
source/simulation2/serialization/BinarySerializer.cpp
19 19 20 20 #include "BinarySerializer.h" 21 21 22 #include "SerializedScriptTypes.h"23 24 22 #include "lib/alignment.h" 25 23 #include "ps/CLogger.h" 26 24 27 25 #include "scriptinterface/ScriptInterface.h" 28 26 #include "scriptinterface/ScriptExtraHeaders.h" // for JSDOUBLE_IS_INT32, typed arrays 27 #include "SerializedScriptTypes.h" 29 28 30 static u8 GetArrayType( uint32arrayType)29 static u8 GetArrayType(JSArrayBufferViewType arrayType) 31 30 { 32 31 switch(arrayType) 33 32 { 34 case js:: TypedArray::TYPE_INT8:33 case js::ArrayBufferView::TYPE_INT8: 35 34 return SCRIPT_TYPED_ARRAY_INT8; 36 case js:: TypedArray::TYPE_UINT8:35 case js::ArrayBufferView::TYPE_UINT8: 37 36 return SCRIPT_TYPED_ARRAY_UINT8; 38 case js:: TypedArray::TYPE_INT16:37 case js::ArrayBufferView::TYPE_INT16: 39 38 return SCRIPT_TYPED_ARRAY_INT16; 40 case js:: TypedArray::TYPE_UINT16:39 case js::ArrayBufferView::TYPE_UINT16: 41 40 return SCRIPT_TYPED_ARRAY_UINT16; 42 case js:: TypedArray::TYPE_INT32:41 case js::ArrayBufferView::TYPE_INT32: 43 42 return SCRIPT_TYPED_ARRAY_INT32; 44 case js:: TypedArray::TYPE_UINT32:43 case js::ArrayBufferView::TYPE_UINT32: 45 44 return SCRIPT_TYPED_ARRAY_UINT32; 46 case js:: TypedArray::TYPE_FLOAT32:45 case js::ArrayBufferView::TYPE_FLOAT32: 47 46 return SCRIPT_TYPED_ARRAY_FLOAT32; 48 case js:: TypedArray::TYPE_FLOAT64:47 case js::ArrayBufferView::TYPE_FLOAT64: 49 48 return SCRIPT_TYPED_ARRAY_FLOAT64; 50 case js:: TypedArray::TYPE_UINT8_CLAMPED:49 case js::ArrayBufferView::TYPE_UINT8_CLAMPED: 51 50 return SCRIPT_TYPED_ARRAY_UINT8_CLAMPED; 52 51 default: 53 52 LOGERROR(L"Cannot serialize unrecognized typed array view: %d", arrayType); … … 64 63 void CBinarySerializerScriptImpl::HandleScriptVal(jsval val) 65 64 { 66 65 JSContext* cx = m_ScriptInterface.GetContext(); 66 JSAutoRequest rq(cx); 67 67 68 68 switch (JS_TypeOfValue(cx, val)) 69 69 { … … 85 85 break; 86 86 } 87 87 88 JS Object* obj = JSVAL_TO_OBJECT(val);88 JS::RootedObject obj(cx, JSVAL_TO_OBJECT(val)); 89 89 90 90 // If we've already serialized this object, just output a reference to it 91 91 u32 tag = GetScriptBackrefTag(obj); … … 104 104 105 105 // Arrays like [1, 2, ] have an 'undefined' at the end which is part of the 106 106 // length but seemingly isn't enumerated, so store the length explicitly 107 jsuint length = 0;107 uint length = 0; 108 108 if (!JS_GetArrayLength(cx, obj, &length)) 109 109 throw PSERROR_Serialize_ScriptError("JS_GetArrayLength failed"); 110 110 m_Serializer.NumberU32_Unbounded("array length", length); 111 111 } 112 else if ( js_IsTypedArray(obj))112 else if (JS_IsTypedArrayObject(obj)) 113 113 { 114 114 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_TYPED_ARRAY); 115 115 116 js::TypedArray* typedArray = js::TypedArray::fromJSObject(obj); 117 118 m_Serializer.NumberU8_Unbounded("array type", GetArrayType(typedArray->type)); 119 m_Serializer.NumberU32_Unbounded("byte offset", typedArray->byteOffset); 120 m_Serializer.NumberU32_Unbounded("length", typedArray->length); 116 m_Serializer.NumberU8_Unbounded("array type", GetArrayType(JS_GetArrayBufferViewType(obj))); 117 m_Serializer.NumberU32_Unbounded("byte offset", JS_GetTypedArrayByteOffset(obj)); 118 m_Serializer.NumberU32_Unbounded("length", JS_GetTypedArrayLength(obj)); 121 119 122 120 // Now handle its array buffer 123 121 // this may be a backref, since ArrayBuffers can be shared by multiple views 124 HandleScriptVal(OBJECT_TO_JSVAL( typedArray->bufferJS));122 HandleScriptVal(OBJECT_TO_JSVAL(JS_GetArrayBufferViewBuffer(obj))); 125 123 break; 126 124 } 127 else if ( js_IsArrayBuffer(obj))125 else if (JS_IsArrayBufferObject(obj)) 128 126 { 129 127 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY_BUFFER); 130 128 131 js::ArrayBuffer* arrayBuffer = js::ArrayBuffer::fromJSObject(obj);132 133 129 #if BYTE_ORDER != LITTLE_ENDIAN 134 130 #error TODO: need to convert JS ArrayBuffer data to little-endian 135 131 #endif 136 132 137 u32 length = arrayBuffer->byteLength;133 u32 length = JS_GetArrayBufferByteLength(obj); 138 134 m_Serializer.NumberU32_Unbounded("buffer length", length); 139 m_Serializer.RawBytes("buffer data", (const u8*) arrayBuffer->data, length);135 m_Serializer.RawBytes("buffer data", (const u8*)JS_GetArrayBufferData(obj), length); 140 136 break; 141 137 } 142 138 else 143 139 { 144 140 // Find type of object 145 JSClass* jsclass = JS_G ET_CLASS(cx,obj);141 JSClass* jsclass = JS_GetClass(obj); 146 142 if (!jsclass) 147 throw PSERROR_Serialize_ScriptError("JS_G ET_CLASSfailed");143 throw PSERROR_Serialize_ScriptError("JS_GetClass failed"); 148 144 JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass); 149 145 150 146 if (protokey == JSProto_Object) 151 147 { 152 148 // Object class - check for user-defined prototype 153 JSObject* proto = JS_GetPrototype(cx, obj); 149 JS::RootedObject proto(cx); 150 JS_GetPrototype(cx, obj, proto.address()); 154 151 if (!proto) 155 152 throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed"); 156 153 … … 175 172 JSBool hasCustomSerialize; 176 173 if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize)) 177 174 throw PSERROR_Serialize_ScriptError("JS_HasProperty failed"); 178 175 179 176 if (hasCustomSerialize) 180 177 { 181 jsval serialize;182 if (!JS_LookupProperty(cx, obj, "Serialize", &serialize))178 JS::RootedValue serialize(cx); 179 if (!JS_LookupProperty(cx, obj, "Serialize", serialize.address())) 183 180 throw PSERROR_Serialize_ScriptError("JS_LookupProperty failed"); 184 181 185 182 // If serialize is null, so don't serialize anything more … … 199 196 // Standard Number object 200 197 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_NUMBER); 201 198 // Get primitive value 202 jsdouble d;199 double d; 203 200 if (!JS_ValueToNumber(cx, val, &d)) 204 201 throw PSERROR_Serialize_ScriptError("JS_ValueToNumber failed"); 205 202 m_Serializer.NumberDouble_Unbounded("value", d); … … 224 221 JSBool b; 225 222 if (!JS_ValueToBoolean(cx, val, &b)) 226 223 throw PSERROR_Serialize_ScriptError("JS_ValueToBoolean failed"); 227 m_Serializer.Bool("value", b == JS_TRUE);224 m_Serializer.Bool("value", b); 228 225 break; 229 226 } 230 227 else … … 240 237 // (Note that we don't do any rooting, because we assume nothing is going to trigger GC. 241 238 // I'm not absolute certain that's necessarily a valid assumption.) 242 239 243 AutoJSIdArray ida (cx, JS_Enumerate(cx, obj));244 if (!ida .get())240 JS::AutoIdArray ida (cx, JS_Enumerate(cx, obj)); 241 if (!ida) 245 242 throw PSERROR_Serialize_ScriptError("JS_Enumerate failed"); 246 243 247 244 m_Serializer.NumberU32_Unbounded("num props", (uint32_t)ida.length()); … … 250 247 { 251 248 jsid id = ida[i]; 252 249 253 jsval idval, propval; 254 250 JS::RootedValue idval(cx); 251 JS::RootedValue propval(cx); 252 255 253 // Get the property name as a string 256 if (!JS_IdToValue(cx, id, &idval))254 if (!JS_IdToValue(cx, id, idval.address())) 257 255 throw PSERROR_Serialize_ScriptError("JS_IdToValue failed"); 258 JSString* idstr = JS_ValueToString(cx, idval );256 JSString* idstr = JS_ValueToString(cx, idval.get()); 259 257 if (!idstr) 260 258 throw PSERROR_Serialize_ScriptError("JS_ValueToString failed"); 261 259 … … 263 261 264 262 // Use LookupProperty instead of GetProperty to avoid the danger of getters 265 263 // (they might delete values and trigger GC) 266 if (!JS_LookupPropertyById(cx, obj, id, &propval))264 if (!JS_LookupPropertyById(cx, obj, id, propval.address())) 267 265 throw PSERROR_Serialize_ScriptError("JS_LookupPropertyById failed"); 268 266 269 267 HandleScriptVal(propval); … … 299 297 } 300 298 case JSTYPE_NUMBER: 301 299 { 302 // For efficiency, handle ints and doubles separately. 303 if (JSVAL_IS_INT(val)) 300 // To reduce the size of the serialized data, we handle integers and doubles separately. 301 // We can't check for val.isInt32 and val.isDouble directly, because integer numbers are not guaranteed 302 // to be represented as integers. A number like 33 could be stored as integer on the computer of one player 303 // and as double on the other player's computer. That would cause out of sync errors in multiplayer games because 304 // their binary representation and thus the hash would be different. 305 306 double d; 307 d = val.toNumber(); 308 int32_t integer; 309 310 if (JS_DoubleIsInt32(d, &integer)) 304 311 { 305 312 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_INT); 306 m_Serializer.NumberI32_Unbounded("value", (int32_t)JSVAL_TO_INT(val));313 m_Serializer.NumberI32_Unbounded("value", integer); 307 314 } 308 315 else 309 316 { 310 ENSURE(JSVAL_IS_DOUBLE(val)); 311 312 // If the value fits in an int, serialise as an int 313 jsdouble d = JSVAL_TO_DOUBLE(val); 314 int32_t i; 315 if (JSDOUBLE_IS_INT32(d, &i)) 316 { 317 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_INT); 318 m_Serializer.NumberI32_Unbounded("value", i); 319 } 320 // Otherwise serialise as a double 321 else 322 { 323 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE); 324 m_Serializer.NumberDouble_Unbounded("value", d); 325 } 317 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE); 318 m_Serializer.NumberDouble_Unbounded("value", d); 326 319 } 320 327 321 break; 328 322 } 329 323 case JSTYPE_BOOLEAN: 330 324 { 331 325 m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BOOLEAN); 332 JSBool b = JSVAL_TO_BOOLEAN(val);326 bool b = JSVAL_TO_BOOLEAN(val); 333 327 m_Serializer.NumberU8_Unbounded("value", b ? 1 : 0); 334 328 break; 335 329 } 336 case JSTYPE_XML:337 {338 LOGERROR(L"Cannot serialise JS objects of type 'xml'");339 throw PSERROR_Serialize_InvalidScriptValue();340 }341 330 default: 342 331 { 343 332 debug_warn(L"Invalid TypeOfValue"); … … 349 338 void CBinarySerializerScriptImpl::ScriptString(const char* name, JSString* string) 350 339 { 351 340 JSContext* cx = m_ScriptInterface.GetContext(); 341 JSAutoRequest rq(cx); 342 352 343 size_t length; 353 344 const jschar* chars = JS_GetStringCharsAndLength(cx, string, &length); 354 345 -
source/simulation2/serialization/StdDeserializer.cpp
25 25 #include "scriptinterface/ScriptInterface.h" 26 26 #include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays 27 27 28 #include "js/jsapi.h"29 30 28 #include "lib/byte_order.h" 31 29 32 static uint32 GetJSArrayType(u8 arrayType)33 {34 switch(arrayType)35 {36 case SCRIPT_TYPED_ARRAY_INT8:37 return js::TypedArray::TYPE_INT8;38 case SCRIPT_TYPED_ARRAY_UINT8:39 return js::TypedArray::TYPE_UINT8;40 case SCRIPT_TYPED_ARRAY_INT16:41 return js::TypedArray::TYPE_INT16;42 case SCRIPT_TYPED_ARRAY_UINT16:43 return js::TypedArray::TYPE_UINT16;44 case SCRIPT_TYPED_ARRAY_INT32:45 return js::TypedArray::TYPE_INT32;46 case SCRIPT_TYPED_ARRAY_UINT32:47 return js::TypedArray::TYPE_UINT32;48 case SCRIPT_TYPED_ARRAY_FLOAT32:49 return js::TypedArray::TYPE_FLOAT32;50 case SCRIPT_TYPED_ARRAY_FLOAT64:51 return js::TypedArray::TYPE_FLOAT64;52 case SCRIPT_TYPED_ARRAY_UINT8_CLAMPED:53 return js::TypedArray::TYPE_UINT8_CLAMPED;54 default:55 throw PSERROR_Deserialize_ScriptError("Failed to deserialize unrecognized typed array view");56 }57 }58 59 30 CStdDeserializer::CStdDeserializer(ScriptInterface& scriptInterface, std::istream& stream) : 60 31 m_ScriptInterface(scriptInterface), m_Stream(stream) 61 32 { … … 138 109 139 110 void CStdDeserializer::FreeScriptBackrefs() 140 111 { 112 JSContext* cx = m_ScriptInterface.GetContext(); 113 JSAutoRequest rq(cx); 114 141 115 std::map<u32, JSObject*>::iterator it = m_ScriptBackrefs.begin(); 142 116 for (; it != m_ScriptBackrefs.end(); ++it) 143 117 { 144 if (!JS_RemoveObjectRoot(m_ScriptInterface.GetContext(), &it->second)) 145 throw PSERROR_Deserialize_ScriptError("JS_RemoveRoot failed"); 118 JS_RemoveObjectRoot(m_ScriptInterface.GetContext(), &it->second); 146 119 } 147 120 m_ScriptBackrefs.clear(); 148 121 } … … 152 125 jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* appendParent) 153 126 { 154 127 JSContext* cx = m_ScriptInterface.GetContext(); 128 129 JSAutoRequest rq(cx); 155 130 156 131 uint8_t type; 157 132 NumberU8_Unbounded("type", type); … … 192 167 if (!proto) 193 168 throw PSERROR_Deserialize_ScriptError("Failed to find serializable prototype for object"); 194 169 195 JSObject* parent = JS_GetParent( cx,proto);170 JSObject* parent = JS_GetParent(proto); 196 171 if (!proto || !parent) 197 172 throw PSERROR_Deserialize_ScriptError(); 198 173 … … 206 181 JSBool hasCustomDeserialize, hasCustomSerialize; 207 182 if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize) || !JS_HasProperty(cx, obj, "Deserialize", &hasCustomDeserialize)) 208 183 throw PSERROR_Serialize_ScriptError("JS_HasProperty failed"); 209 184 210 185 if (hasCustomDeserialize) 211 186 { 212 jsval serialize;213 if (!JS_LookupProperty(cx, obj, "Serialize", &serialize))187 JS::RootedValue serialize(cx); 188 if (!JS_LookupProperty(cx, obj, "Serialize", serialize.address())) 214 189 throw PSERROR_Serialize_ScriptError("JS_LookupProperty failed"); 215 190 bool hasNullSerialize = hasCustomSerialize && JSVAL_IS_NULL(serialize); 216 191 … … 241 216 utf16string propname; 242 217 ReadStringUTF16("prop name", propname); 243 218 244 jsval propval = ReadScriptVal("prop value", NULL);219 JS::RootedValue propval(cx, ReadScriptVal("prop value", NULL)); 245 220 CScriptValRooted propvalRoot(cx, propval); 246 221 247 if (!JS_SetUCProperty(cx, obj, (const jschar*)propname.data(), propname.length(), &propval))222 if (!JS_SetUCProperty(cx, obj, (const jschar*)propname.data(), propname.length(), propval.address())) 248 223 throw PSERROR_Deserialize_ScriptError(); 249 224 } 250 225 … … 266 241 { 267 242 double value; 268 243 NumberDouble_Unbounded("value", value); 269 jsval rval ;270 if ( !JS_NewNumberValue(cx, value, &rval))244 jsval rval = JS_NumberValue(value); 245 if (JSVAL_IS_NULL(rval)) 271 246 throw PSERROR_Deserialize_ScriptError("JS_NewNumberValue failed"); 272 247 return rval; 273 248 } … … 275 250 { 276 251 uint8_t value; 277 252 NumberU8("value", value, 0, 1); 278 return BOOLEAN_TO_JSVAL(value ? JS_TRUE : JS_FALSE);253 return BOOLEAN_TO_JSVAL(value ? true : false); 279 254 } 280 255 case SCRIPT_TYPE_BACKREF: 281 256 { … … 290 265 { 291 266 double value; 292 267 NumberDouble_Unbounded("value", value); 293 jsval val; 294 if (!JS_NewNumberValue(cx, value, &val)) 295 throw PSERROR_Deserialize_ScriptError(); 268 JS::RootedValue val(cx, JS_NumberValue(value)); 296 269 CScriptValRooted objRoot(cx, val); 297 270 298 271 JSObject* ctorobj; 299 if (!JS_GetClassObject(cx, JS_GetGlobal Object(cx), JSProto_Number, &ctorobj))272 if (!JS_GetClassObject(cx, JS_GetGlobalForScopeChain(cx), JSProto_Number, &ctorobj)) 300 273 throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); 301 274 302 JSObject* obj = JS_New(cx, ctorobj, 1, &val);275 JSObject* obj = JS_New(cx, ctorobj, 1, val.address()); 303 276 if (!obj) 304 277 throw PSERROR_Deserialize_ScriptError("JS_New failed"); 305 278 AddScriptBackref(obj); … … 311 284 ScriptString("value", str); 312 285 if (!str) 313 286 throw PSERROR_Deserialize_ScriptError(); 314 jsval val = STRING_TO_JSVAL(str);287 JS::RootedValue val(cx, STRING_TO_JSVAL(str)); 315 288 CScriptValRooted valRoot(cx, val); 316 289 317 290 JSObject* ctorobj; 318 if (!JS_GetClassObject(cx, JS_GetGlobal Object(cx), JSProto_String, &ctorobj))291 if (!JS_GetClassObject(cx, JS_GetGlobalForScopeChain(cx), JSProto_String, &ctorobj)) 319 292 throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); 320 293 321 JSObject* obj = JS_New(cx, ctorobj, 1, &val);294 JSObject* obj = JS_New(cx, ctorobj, 1, val.address()); 322 295 if (!obj) 323 296 throw PSERROR_Deserialize_ScriptError("JS_New failed"); 324 297 AddScriptBackref(obj); … … 328 301 { 329 302 bool value; 330 303 Bool("value", value); 331 jsval val = BOOLEAN_TO_JSVAL(value ? JS_TRUE : JS_FALSE); 332 CScriptValRooted objRoot(cx, val); 304 JS::RootedValue val(cx, BOOLEAN_TO_JSVAL(value)); 333 305 334 306 JSObject* ctorobj; 335 if (!JS_GetClassObject(cx, JS_GetGlobal Object(cx), JSProto_Boolean, &ctorobj))307 if (!JS_GetClassObject(cx, JS_GetGlobalForScopeChain(cx), JSProto_Boolean, &ctorobj)) 336 308 throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed"); 337 309 338 JSObject* obj = JS_New(cx, ctorobj, 1, &val);310 JSObject* obj = JS_New(cx, ctorobj, 1, val.address()); 339 311 if (!obj) 340 312 throw PSERROR_Deserialize_ScriptError("JS_New failed"); 341 313 AddScriptBackref(obj); … … 354 326 355 327 // Get buffer object 356 328 jsval bufferVal = ReadScriptVal("buffer", NULL); 357 CScriptValRooted bufferValRoot(cx, bufferVal);358 329 359 if ( !JSVAL_IS_OBJECT(bufferVal))330 if (JSVAL_IS_PRIMITIVE(bufferVal)) 360 331 throw PSERROR_Deserialize_ScriptError(); 361 332 362 333 JSObject* bufferObj = JSVAL_TO_OBJECT(bufferVal); 363 if (! js_IsArrayBuffer(bufferObj))334 if (!JS_IsArrayBufferObject(bufferObj)) 364 335 throw PSERROR_Deserialize_ScriptError("js_IsArrayBuffer failed"); 365 336 366 JSObject* arrayObj = js_CreateTypedArrayWithBuffer(cx, GetJSArrayType(arrayType), bufferObj, byteOffset, length); 337 JSObject* arrayObj; 338 switch(arrayType) 339 { 340 case SCRIPT_TYPED_ARRAY_INT8: 341 arrayObj = JS_NewInt8ArrayWithBuffer(cx, bufferObj, byteOffset, length); 342 break; 343 case SCRIPT_TYPED_ARRAY_UINT8: 344 arrayObj = JS_NewUint8ArrayWithBuffer(cx, bufferObj, byteOffset, length); 345 break; 346 case SCRIPT_TYPED_ARRAY_INT16: 347 arrayObj = JS_NewInt16ArrayWithBuffer(cx, bufferObj, byteOffset, length); 348 break; 349 case SCRIPT_TYPED_ARRAY_UINT16: 350 arrayObj = JS_NewUint16ArrayWithBuffer(cx, bufferObj, byteOffset, length); 351 break; 352 case SCRIPT_TYPED_ARRAY_INT32: 353 arrayObj = JS_NewInt32ArrayWithBuffer(cx, bufferObj, byteOffset, length); 354 break; 355 case SCRIPT_TYPED_ARRAY_UINT32: 356 arrayObj = JS_NewUint32ArrayWithBuffer(cx, bufferObj, byteOffset, length); 357 break; 358 case SCRIPT_TYPED_ARRAY_FLOAT32: 359 arrayObj = JS_NewFloat32ArrayWithBuffer(cx, bufferObj, byteOffset, length); 360 break; 361 case SCRIPT_TYPED_ARRAY_FLOAT64: 362 arrayObj = JS_NewFloat64ArrayWithBuffer(cx, bufferObj, byteOffset, length); 363 break; 364 case SCRIPT_TYPED_ARRAY_UINT8_CLAMPED: 365 arrayObj = JS_NewUint8ClampedArrayWithBuffer(cx, bufferObj, byteOffset, length); 366 break; 367 default: 368 throw PSERROR_Deserialize_ScriptError("Failed to deserialize unrecognized typed array view"); 369 } 367 370 if (!arrayObj) 368 371 throw PSERROR_Deserialize_ScriptError("js_CreateTypedArrayWithBuffer failed"); 369 372 … … 375 378 { 376 379 u32 length; 377 380 NumberU32_Unbounded("buffer length", length); 381 u8* bufferData = NULL; 378 382 379 u8* bufferData = new u8[length];380 RawBytes("buffer data", bufferData, length);381 383 382 384 #if BYTE_ORDER != LITTLE_ENDIAN 383 385 #error TODO: need to convert JS ArrayBuffer data from little-endian 384 386 #endif 385 386 JSObject* bufferObj = js_CreateArrayBuffer(cx, length); 387 if (!bufferObj) 388 throw PSERROR_Deserialize_ScriptError("js_CreateArrayBuffer failed"); 389 387 void* contents = NULL; 388 JS_AllocateArrayBufferContents(cx, length, &contents, &bufferData); 389 RawBytes("buffer data", bufferData, length); 390 JSObject* bufferObj = JS_NewArrayBufferWithContents(cx, contents); 390 391 AddScriptBackref(bufferObj); 391 392 392 js::ArrayBuffer* buffer = js::ArrayBuffer::fromJSObject(bufferObj);393 memcpy(buffer->data, bufferData, length);394 delete[] bufferData;395 396 393 return OBJECT_TO_JSVAL(bufferObj); 397 394 } 398 395 default: … … 440 437 441 438 void CStdDeserializer::ScriptObjectAppend(const char* name, jsval& obj) 442 439 { 443 if ( !JSVAL_IS_OBJECT(obj))440 if (JSVAL_IS_PRIMITIVE(obj)) 444 441 throw PSERROR_Deserialize_ScriptError(); 445 442 446 443 ReadScriptVal(name, JSVAL_TO_OBJECT(obj)); -
source/simulation2/system/ComponentManager.cpp
243 243 244 244 // Find all the ctor prototype's On* methods, and subscribe to the appropriate messages: 245 245 246 CScriptVal proto;246 JS::RootedObject proto(componentManager->m_ScriptInterface.GetContext()); 247 247 if (!componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", proto)) 248 248 return; // error 249 249 250 250 std::vector<std::string> methods; 251 if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(proto .get(), "On", methods))251 if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(proto, "On", methods)) 252 252 return; // error 253 253 254 254 for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it) … … 289 289 { 290 290 jsval instance = eit->second->GetJSInstance(); 291 291 if (!JSVAL_IS_NULL(instance)) 292 componentManager->m_ScriptInterface.SetPrototype(instance, proto.get()); 292 { 293 JS::RootedObject instanceObj(componentManager->m_ScriptInterface.GetContext(),&instance.toObject()); 294 componentManager->m_ScriptInterface.SetPrototype(instanceObj, proto); 295 } 293 296 } 294 297 } 295 298 } … … 616 619 jsval obj = JSVAL_NULL; 617 620 if (ct.type == CT_Script) 618 621 { 619 obj = m_ScriptInterface.CallConstructor(ct.ctor.get(), JSVAL_VOID);622 obj = m_ScriptInterface.CallConstructor(ct.ctor.get(), 0, JSVAL_VOID); 620 623 if (JSVAL_IS_VOID(obj)) 621 624 { 622 625 LOGERROR(L"Script component constructor failed"); -
source/simulation2/system/ComponentManager.h
96 96 void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); 97 97 void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); 98 98 99 100 void Tick() { m_ScriptInterface.Tick(); }; 99 101 /** 100 102 * Subscribe the current component type to the given message type. 101 103 * Each component's HandleMessage will be called on any BroadcastMessage of this message type, -
source/simulation2/system/ComponentTest.h
52 52 EComponentTypeId m_Cid; 53 53 54 54 public: 55 ComponentTestHelper( ) :56 m_Context(), m_ComponentManager(m_Context, ScriptInterface::CreateRuntime()), m_Cmp(NULL)55 ComponentTestHelper(shared_ptr<ScriptRuntime> runtime) : 56 m_Context(), m_ComponentManager(m_Context, runtime), m_Cmp(NULL) 57 57 { 58 58 m_ComponentManager.LoadComponentTypes(); 59 59 } … … 135 135 CStdSerializer std1(GetScriptInterface(), stdstr1); 136 136 m_Cmp->Serialize(std1); 137 137 138 ComponentTestHelper test2 ;138 ComponentTestHelper test2(GetScriptInterface().GetRuntime()); 139 139 // (We should never need to add any mock objects etc to test2, since deserialization 140 140 // mustn't depend on other components already existing) 141 141 -
source/simulation2/system/InterfaceScripted.h
19 19 #define INCLUDED_INTERFACE_SCRIPTED 20 20 21 21 #include "scriptinterface/ScriptInterface.h" 22 #include "js/jsapi.h"23 22 24 23 #define BEGIN_INTERFACE_WRAPPER(iname) \ 25 24 JSClass class_ICmp##iname = { \ 26 25 "ICmp" #iname, JSCLASS_HAS_PRIVATE, \ 27 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ 28 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, \ 29 JSCLASS_NO_OPTIONAL_MEMBERS \ 26 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ 27 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub \ 30 28 }; \ 31 29 static JSFunctionSpec methods_ICmp##iname[] = { 32 30 … … 35 33 }; \ 36 34 void ICmp##iname::InterfaceInit(ScriptInterface& scriptInterface) { \ 37 35 JSContext* cx = scriptInterface.GetContext(); \ 38 JSObject* global = JS_GetGlobalObject(cx); \ 36 JSAutoRequest rq(cx); \ 37 JSObject* global = JS_GetGlobalForScopeChain(cx); \ 39 38 JS_InitClass(cx, global, NULL, &class_ICmp##iname, NULL, 0, NULL, methods_ICmp##iname, NULL, NULL); \ 40 39 } \ 41 40 JSClass* ICmp##iname::GetJSClass() const { return &class_ICmp##iname; } \ … … 45 44 46 45 #define DEFINE_INTERFACE_METHOD_0(scriptname, rettype, classname, methodname) \ 47 46 { scriptname, \ 48 ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>, \47 { ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>, NULL }, \ 49 48 0, \ 50 49 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 51 50 52 51 #define DEFINE_INTERFACE_METHOD_1(scriptname, rettype, classname, methodname, arg1) \ 53 52 { scriptname, \ 54 ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>, \53 { ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>, NULL}, \ 55 54 1, \ 56 55 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 57 56 58 57 #define DEFINE_INTERFACE_METHOD_2(scriptname, rettype, classname, methodname, arg1, arg2) \ 59 58 { scriptname, \ 60 ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>, \59 { ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>, NULL }, \ 61 60 2, \ 62 61 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 63 62 64 63 #define DEFINE_INTERFACE_METHOD_3(scriptname, rettype, classname, methodname, arg1, arg2, arg3) \ 65 64 { scriptname, \ 66 ScriptInterface::callMethod<rettype, arg1, arg2, arg3, &class_##classname, classname, &classname::methodname>, \65 { ScriptInterface::callMethod<rettype, arg1, arg2, arg3, &class_##classname, classname, &classname::methodname>, NULL }, \ 67 66 3, \ 68 67 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 69 68 70 69 #define DEFINE_INTERFACE_METHOD_4(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4) \ 71 70 { scriptname, \ 72 ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, &class_##classname, classname, &classname::methodname>, \71 { ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, &class_##classname, classname, &classname::methodname>, NULL }, \ 73 72 4, \ 74 73 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 75 74 76 75 #define DEFINE_INTERFACE_METHOD_5(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5) \ 77 76 { scriptname, \ 78 ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, &class_##classname, classname, &classname::methodname>, \77 { ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, &class_##classname, classname, &classname::methodname>, NULL }, \ 79 78 5, \ 80 79 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 81 80 82 81 #define DEFINE_INTERFACE_METHOD_6(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5, arg6) \ 83 82 { scriptname, \ 84 ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, arg6, &class_##classname, classname, &classname::methodname>, \83 { ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, arg6, &class_##classname, classname, &classname::methodname>, NULL }, \ 85 84 6, \ 86 85 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 87 86 88 87 #define DEFINE_INTERFACE_METHOD_7(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 89 88 { scriptname, \ 90 ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, arg6, arg7, &class_##classname, classname, &classname::methodname>, \89 { ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, arg6, arg7, &class_##classname, classname, &classname::methodname>, NULL }, \ 91 90 7, \ 92 91 JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, 93 92 -
source/simulation2/system/ParamNode.cpp
25 25 #include "ps/Filesystem.h" 26 26 #include "ps/XML/Xeromyces.h" 27 27 28 #include "js/jsapi.h"29 30 28 #include <sstream> 31 29 32 30 // Disable "'boost::algorithm::detail::is_classifiedF' : assignment operator could not be generated" … … 328 326 329 327 jsval CParamNode::ConstructJSVal(JSContext* cx) const 330 328 { 329 JSAutoRequest rq(cx); 331 330 if (m_Childs.empty()) 332 331 { 333 332 // Empty node - map to undefined … … 351 350 352 351 for (std::map<std::string, CParamNode>::const_iterator it = m_Childs.begin(); it != m_Childs.end(); ++it) 353 352 { 354 jsval childVal = it->second.ConstructJSVal(cx);355 if (!JS_SetProperty(cx, obj, it->first.c_str(), &childVal))353 JS::RootedValue childVal(cx, it->second.ConstructJSVal(cx)); 354 if (!JS_SetProperty(cx, obj, it->first.c_str(), childVal.address())) 356 355 return JSVAL_VOID; // TODO: report error 357 356 } 358 357 … … 363 362 JSString* str = JS_InternUCStringN(cx, reinterpret_cast<const jschar*>(text.data()), text.length()); 364 363 if (!str) 365 364 return JSVAL_VOID; // TODO: report error 366 jsval childVal = STRING_TO_JSVAL(str);367 if (!JS_SetProperty(cx, obj, "_string", &childVal))365 JS::RootedValue childVal(cx, STRING_TO_JSVAL(str)); 366 if (!JS_SetProperty(cx, obj, "_string", childVal.address())) 368 367 return JSVAL_VOID; // TODO: report error 369 368 } 370 369 -
source/simulation2/tests/test_ComponentManager.h
594 594 void test_serialization() 595 595 { 596 596 CSimContext context; 597 CComponentManager man(context, ScriptInterface::CreateRuntime()); 597 shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime(); 598 CComponentManager man(context, runtime); 598 599 man.LoadComponentTypes(); 599 600 600 601 entity_id_t ent1 = 1, ent2 = 2, ent3 = FIRST_LOCAL_ENTITY; … … 664 665 ); 665 666 666 667 CSimContext context2; 667 CComponentManager man2(context2, ScriptInterface::CreateRuntime());668 CComponentManager man2(context2, runtime); 668 669 man2.LoadComponentTypes(); 669 670 670 671 TS_ASSERT(man2.QueryInterface(ent1, IID_Test1) == NULL); … … 683 684 void test_script_serialization() 684 685 { 685 686 CSimContext context; 686 CComponentManager man(context, ScriptInterface::CreateRuntime()); 687 shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime(); 688 689 CComponentManager man(context, runtime); 687 690 ScriptTestSetup(man.m_ScriptInterface); 688 691 man.LoadComponentTypes(); 689 692 TS_ASSERT(man.LoadScript(L"simulation/components/test-serialize.js")); … … 700 703 701 704 man.AddComponent(hnd1, man.LookupCID("TestScript1_values"), testParam); 702 705 man.AddComponent(hnd2, man.LookupCID("TestScript1_entity"), testParam); 706 707 // TODO: Since the upgrade to SpiderMonkey v24 this test won't be able to correctly represent 708 // non-tree structures because sharp variables were removed (bug 566700). 709 // This also affects the debug serializer and it could make sense to implement correct serialization again. 703 710 man.AddComponent(hnd3, man.LookupCID("TestScript1_nontree"), testParam); 711 704 712 man.AddComponent(hnd4, man.LookupCID("TestScript1_custom"), testParam); 705 713 706 714 TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 1234); … … 713 721 std::stringstream debugStream; 714 722 TS_ASSERT(man.DumpDebugState(debugStream, true)); 715 723 TS_ASSERT_STR_EQUALS(debugStream.str(), 716 "rng: \"78606\"\n "717 "entities:\n" 718 "- id: 1\n" 719 " TestScript1_values:\n" 720 " object: {\n" 721 " \"x\": 1234,\n" 722 " \"str\": \"this is a string\",\n" 723 " \"things\": {\n" 724 " \"a\": 1,\n" 725 " \"b\": \"2\",\n" 726 " \"c\": [\n" 727 " 3,\n" 728 " \"4\",\n" 729 " [\n" 730 " 5,\n" 731 " []\n" 732 " ]\n" 733 " ]\n" 734 " }\n" 735 "}\n" 736 "\n" 737 "- id: 2\n" 738 " TestScript1_entity:\n" 739 " object: {}\n" 740 "\n" 741 "- id: 3\n" 742 " TestScript1_nontree:\n" 743 " object: ({x:#2=[#1=[2], #1#, #2#, {y:#1#}]})\n" 744 "\n" 745 "- id: 4\n" 746 " TestScript1_custom:\n" 747 " object: {\n" 748 " \"c\": 1\n" 749 "}\n" 750 "\n"724 "rng: \"78606\"\n\ 725 entities:\n\ 726 - id: 1\n\ 727 TestScript1_values:\n\ 728 object: {\n\ 729 \"x\": 1234,\n\ 730 \"str\": \"this is a string\",\n\ 731 \"things\": {\n\ 732 \"a\": 1,\n\ 733 \"b\": \"2\",\n\ 734 \"c\": [\n\ 735 3,\n\ 736 \"4\",\n\ 737 [\n\ 738 5,\n\ 739 []\n\ 740 ]\n\ 741 ]\n\ 742 }\n\ 743 }\n\ 744 \n\ 745 - id: 2\n\ 746 TestScript1_entity:\n\ 747 object: {}\n\ 748 \n\ 749 - id: 3\n\ 750 TestScript1_nontree:\n\ 751 object: ({x:[[2], [2], [], {y:[2]}]})\n\ 752 \n\ 753 - id: 4\n\ 754 TestScript1_custom:\n\ 755 object: {\n\ 756 \"c\": 1\n\ 757 }\n\ 758 \n" 751 759 ); 752 760 753 761 std::stringstream stateStream; 754 762 TS_ASSERT(man.SerializeState(stateStream)); 755 763 756 764 CSimContext context2; 757 CComponentManager man2(context2, ScriptInterface::CreateRuntime());765 CComponentManager man2(context2, runtime); 758 766 man2.LoadComponentTypes(); 759 767 TS_ASSERT(man2.LoadScript(L"simulation/components/test-serialize.js")); 760 768 … … 789 797 void test_script_serialization_template() 790 798 { 791 799 CSimContext context; 792 CComponentManager man(context, ScriptInterface::CreateRuntime()); 800 shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime(); 801 802 CComponentManager man(context, runtime); 793 803 man.LoadComponentTypes(); 794 804 TS_ASSERT(man.LoadScript(L"simulation/components/test-serialize.js")); 795 805 man.InitSystemEntity(); … … 813 823 TS_ASSERT(man.SerializeState(stateStream)); 814 824 815 825 CSimContext context2; 816 CComponentManager man2(context2, ScriptInterface::CreateRuntime());826 CComponentManager man2(context2, runtime); 817 827 man2.LoadComponentTypes(); 818 828 TS_ASSERT(man2.LoadScript(L"simulation/components/test-serialize.js")); 819 829 -
source/simulation2/tests/test_Serializer.h
574 574 575 575 TestLogger logger; 576 576 577 TS_ASSERT(script.Eval("({x:1, y:<x/>})", obj));578 TS_ASSERT_THROWS(serialize.ScriptVal("script", obj), PSERROR_Serialize_InvalidScriptValue);579 580 577 TS_ASSERT(script.Eval("([1, 2, function () { }])", obj)); 581 578 TS_ASSERT_THROWS(serialize.ScriptVal("script", obj), PSERROR_Serialize_InvalidScriptValue); 582 579 }