Ticket #1886: SpiderMonkeyESR24_v0.11.diff

File SpiderMonkeyESR24_v0.11.diff, 184.6 KB (added by Yves, 10 years ago)

Tested on r14775. Remaining todos: Test on Windows, Test on Mac OS X, Fix related tickets linked in the description, Review.

  • 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
     
    562562    },
    563563    spidermonkey = {
    564564        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" }
    570571            else
    571572                if os.is("windows") then
    572573                    include_dir = "include-win32"
    573574                elseif os.is("macosx") then
    574                     include_dir = "include"
     575                    include_dir = "include-unix"
    575576                else
    576577                    include_dir = "include-unix"
    577578                end
    578579                configuration "Debug"
    579                     includedirs { libraries_source_dir.."spidermonkey/"..include_dir }
     580                    includedirs { libraries_source_dir.."spidermonkey/"..include_dir.."-debug" }
     581                    defines { "DEBUG" }
    580582                configuration "Release"
    581                     includedirs { libraries_source_dir.."spidermonkey/"..include_dir }
     583                    includedirs { libraries_source_dir.."spidermonkey/"..include_dir.."-release" }
    582584                configuration { }
    583585            end
    584586        end,
    585587        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
    592595            else
    593596                configuration "Debug"
    594                     links { "mozjs185-ps-debug" }
     597                    links { "mozjs24-ps-debug" }
    595598                configuration "Release"
    596                     links { "mozjs185-ps-release" }
     599                    links { "mozjs24-ps-release" }
    597600                configuration { }
    598601                add_source_lib_paths("spidermonkey")
    599602            end
  • build/premake/premake4.lua

     
    1515newoption { trigger = "with-system-nvtt", description = "Search standard paths for nvidia-texture-tools library, instead of using bundled copy" }
    1616newoption { trigger = "with-system-enet", description = "Search standard paths for libenet, instead of using bundled copy" }
    1717newoption { trigger = "with-system-miniupnpc", description = "Search standard paths for libminiupnpc, instead of using bundled copy" }
    18 newoption { trigger = "with-system-mozjs185", description = "Search standard paths for libmozjs185, instead of using bundled copy" }
     18newoption { trigger = "with-system-mozjs24", description = "Search standard paths for libmozjs24, instead of using bundled copy" }
    1919newoption { trigger = "with-c++11", description = "Enable C++11 on GCC" }
    2020newoption { trigger = "sysroot", description = "Set compiler system root path, used for building against a non-system SDK. For example /usr/local becomes SYSROOT/user/local" }
    2121newoption { 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

     
    3737with_system_nvtt=false
    3838with_system_enet=false
    3939with_system_miniupnpc=false
    40 with_system_mozjs185=false
     40with_system_mozjs24=false
    4141enable_atlas=true
    4242
    4343for i in "$@"
     
    4747    --with-system-nvtt ) with_system_nvtt=true; premake_args="${premake_args} --with-system-nvtt" ;;
    4848    --with-system-enet ) with_system_enet=true; premake_args="${premake_args} --with-system-enet" ;;
    4949    --with-system-miniupnpc ) with_system_miniupnpc=true; premake_args="${premake_args} --with-system-miniupnpc" ;;
    50     --with-system-mozjs185 ) 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" ;;
    5151    --enable-atlas ) enable_atlas=true ;;
    5252    --disable-atlas ) enable_atlas=false ;;
    5353    -j* ) JOBS=$i ;;
     
    8181  # Build/update bundled external libraries
    8282  (cd ../../libraries/source/fcollada/src && ${MAKE} ${JOBS}) || die "FCollada build failed"
    8383  echo
    84   if [ "$with_system_mozjs185" = "false" ]; then
     84  if [ "$with_system_mozjs24" = "false" ]; then
    8585    (cd ../../libraries/source/spidermonkey && MAKE=${MAKE} JOBS=${JOBS} ./build.sh) || die "SpiderMonkey build failed"
    8686  fi
    8787  echo
  • libraries/source/spidermonkey/README.txt

     
    55then run start-msvc8.bat and run ./build.sh here.
    66
    77This 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)
     8https://ftp.mozilla.org/pub/mozilla.org/js/mozjs-24.2.0.tar.bz2
    109
    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.
     10The game must be compiled with precisely this version since SpiderMonkey
     11does not guarantee API stability and may have behavioural changes that
     12cause subtle bugs or network out-of-sync errors.
     13A standard system-provided version of the library may only be used if it's
     14exactly the same version or if it's another minor release that does not
     15change the behaviour of the scripts executed by SpiderMonkey.
  • libraries/source/spidermonkey/build.sh

     
    1717echo "Building SpiderMonkey..."
    1818echo
    1919
    20 JOBS=${JOBS:="-j2"}
    2120MAKE=${MAKE:="make"}
    2221
    2322MAKE_OPTS="${JOBS}"
     23NSPR_INCLUDES="`pkg-config nspr --cflags`"
     24NSPR_LIBS="`pkg-config nspr --libs`"
    2425
    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)
     26CONF_OPTS="--enable-threadsafe --enable-shared-js --disable-tests" # --enable-trace-logging"
    2827
    2928# If Valgrind looks like it's installed, then set up SM to support it
    3029# (else the JITs will interact poorly with it)
     
    3332  CONF_OPTS="${CONF_OPTS} --enable-valgrind"
    3433fi
    3534
    36 #CONF_OPTS="${CONF_OPTS} --enable-threadsafe --with-system-nspr"
    37 #CONF_OPTS="${CONF_OPTS} --enable-trace-jscalls"
    38 
    3935# We need to be able to override CHOST in case it is 32bit userland on 64bit kernel
    4036CONF_OPTS="${CONF_OPTS} \
    4137  ${CBUILD:+--build=${CBUILD}} \
     
    4339  ${CTARGET:+--target=${CTARGET}}"
    4440
    4541echo "SpiderMonkey build options: ${CONF_OPTS}"
     42echo ${CONF_OPTS}
    4643
    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
     45rm -rf mozjs24
     46tar xjf mozjs-24.2.0.tar.bz2
    4947
    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
    5350
    54 cd js-1.8.5/js/src
     51# rename the extracted directory to something shorter
     52mv mozjs-24.2.0 mozjs24
    5553
     54cd mozjs24/js/src
     55
    5656# We want separate debug/release versions of the library, so we have to change
    5757# the LIBRARY_NAME for each build.
    5858# (We use perl instead of sed so that it works with MozillaBuild on Windows,
    5959# which has an ancient sed.)
    60 perl -i.bak -pe 's/^(LIBRARY_NAME\s+= mozjs185)(-ps-debug|-ps-release)?/$1-ps-debug/' Makefile.in
     60perl -i.bak -pe 's/(^LIBRARY_NAME\s+=).*/$1mozjs24-ps-debug/' Makefile.in
    6161mkdir -p build-debug
    6262cd build-debug
    63 ../configure ${CONF_OPTS} --enable-debug --disable-optimize
     63../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
    6464${MAKE} ${MAKE_OPTS}
    6565cd ..
    6666
    67 perl -i.bak -pe 's/^(LIBRARY_NAME\s+= mozjs185)(-ps-debug|-ps-release)?/$1-ps-release/' Makefile.in
     67perl -i.bak -pe 's/(^LIBRARY_NAME\s+=).*/$1mozjs24-ps-release/' Makefile.in
    6868mkdir -p build-release
    6969cd build-release
    70 ../configure ${CONF_OPTS} # --enable-gczeal --enable-debug-symbols
     70../configure ${CONF_OPTS} --with-nspr-libs="$NSPR_LIBS" --with-nspr-cflags="$NSPR_INCLUDES" --enable-optimize  # --enable-gczeal --enable-debug-symbols
    7171${MAKE} ${MAKE_OPTS}
    7272cd ..
    7373
    74 # Remove the library suffixes to avoid spurious SVN diffs
    75 perl -i.bak -pe 's/^(LIBRARY_NAME\s+= mozjs185)(-ps-debug|-ps-release)?/$1/' Makefile.in
    76 
    7774cd ../../..
    7875
    7976if [ "${OS}" = "Windows_NT" ]
    8077then
    81   INCLUDE_DIR=include-win32
     78  INCLUDE_DIR_DEBUG=include-win32-debug
     79  INCLUDE_DIR_RELEASE=include-win32-release
    8280  DLL_SRC_SUFFIX=-1.0.dll
    8381  DLL_DST_SUFFIX=-1.0.dll
    8482  LIB_PREFIX=
    8583  LIB_SRC_SUFFIX=-1.0.lib
    8684  LIB_DST_SUFFIX=.lib
    8785else
    88   INCLUDE_DIR=include-unix
     86  INCLUDE_DIR_DEBUG=include-unix-debug
     87  INCLUDE_DIR_RELEASE=include-unix-release
    8988  DLL_SRC_SUFFIX=.so
    90   DLL_DST_SUFFIX=.so.1.0
     89  DLL_DST_SUFFIX=.so
    9190  LIB_PREFIX=lib
    9291  LIB_SRC_SUFFIX=.so
    9392  LIB_DST_SUFFIX=.so
     
    102101
    103102# Copy files into the necessary locations for building and running the game
    104103
    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
     105mkdir -p ${INCLUDE_DIR_DEBUG}
     106mkdir -p ${INCLUDE_DIR_RELEASE}
     107cp -R -L mozjs24/js/src/build-release/dist/include/* ${INCLUDE_DIR_RELEASE}/
     108cp -R -L mozjs24/js/src/build-debug/dist/include/* ${INCLUDE_DIR_DEBUG}/
    108109
    109110mkdir -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}
     111cp -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}
     112cp -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}
     113cp -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}
     114cp -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}
    114115
    115116# Flag that it's already been built successfully so we can skip it next time
    116117touch .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.cpp
    2 +++ js-1.8.5/js/src/jsnativestack.cpp
    3 @@ -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  # endif
    11  
    12 @@ -196,7 +196,9 @@
    13  # else
    14      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  #  else
    23 @@ -212,7 +214,13 @@
    24  #  ifdef DEBUG
    25      int rc =
    26  #  endif
    27 +# 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 +# else
    32          pthread_attr_getstack(&sattr, &stackBase, &stackSize);
    33 +# endif
    34      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.in
    2 +++ js-1.8.5/js/src/configure.in
    3 @@ -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/configure
    14 +++ js-1.8.5/js/src/configure
    15 @@ -8093,6 +8093,12 @@
    16  EOF
    17  
    18      ;;
    19 +*-openbsd*)
    20 +    cat >> confdefs.h <<\EOF
    21 +#define AVMPLUS_UNIX 1
    22 +EOF
    23 +
    24 +    ;;
    25  *-gnu*)
    26      cat >> confdefs.h <<\EOF
    27  #define AVMPLUS_UNIX 1
  • source/gui/GUIManager.cpp

     
    7171    shared_ptr<ScriptInterface::StructuredClone> initDataClone;
    7272    if (initData.get() != JSVAL_VOID)
    7373    {
    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());
    9275    }
    9376    m_PageStack.clear();
    9477    PushPage(pageName, initDataClone);
  • source/gui/IGUIObject.cpp

     
    422422        throw PSERROR_GUI_OperationNeedsGUIObject();
    423423       
    424424    JSContext* cx = pGUI->GetScriptInterface()->GetContext();
     425    JSAutoRequest rq(cx);
    425426   
    426427    const int paramCount = 1;
    427428    const char* paramNames[paramCount] = { "mouse" };
     
    469470        return;
    470471
    471472    JSContext* cx = m_pGUI->GetScriptInterface()->GetContext();
    472 
     473    JSAutoRequest rq(cx);
     474   
    473475    // Set up the 'mouse' parameter
    474476    CScriptVal mouse;
    475477    m_pGUI->GetScriptInterface()->Eval("({})", mouse);
     
    480482    jsval paramData[] = { mouse.get() };
    481483
    482484    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);
    484486    if (!ok)
    485487    {
    486488        // We have no way to propagate the script exception, so just ignore it
     
    490492
    491493void IGUIObject::ScriptEvent(const CStr& Action, const CScriptValRooted& Argument)
    492494{
    493     JSContext* cx = m_pGUI->GetScriptInterface()->GetContext();
    494495    std::map<CStr, CScriptValRooted>::iterator it = m_ScriptHandlers.find(Action);
    495496    if (it == m_ScriptHandlers.end())
    496497        return;
    497 
     498       
     499    JSContext* cx = m_pGUI->GetScriptInterface()->GetContext();
     500    JSAutoRequest rq(cx);
     501   
    498502    JSObject* object = GetJSObject();
    499503
    500504    jsval arg = Argument.get();
    501505
    502506    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);
    504508    if (!ok)
    505509    {
    506510        JS_ReportError(cx, "Errors executing script action \"%s\"", Action.c_str());
     
    510514JSObject* IGUIObject::GetJSObject()
    511515{
    512516    JSContext* cx = m_pGUI->GetScriptInterface()->GetContext();
     517    JSAutoRequest rq(cx);
    513518    // Cache the object when somebody first asks for it, because otherwise
    514519    // we end up doing far too much object allocation. TODO: Would be nice to
    515520    // not have these objects hang around forever using up memory, though.
     
    517522    {
    518523        JSObject* obj = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL);
    519524        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);
    521526    }
    522527    return JSVAL_TO_OBJECT(m_JSObject.get());;
    523528}
  • source/gui/IGUIObject.h

     
    142142    friend class GUITooltip;
    143143
    144144    // Allow getProperty to access things like GetParent()
    145     friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
    146     friend JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, JSBool strict, jsval* vp);
    147     friend JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uintN argc, 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);
    148148
    149149public:
    150150    IGUIObject();
  • source/gui/scripting/GuiScriptConversions.cpp

     
    2323#include "lib/external_libraries/libsdl.h"
    2424#include "ps/Hotkey.h"
    2525
    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()))
    2927    // ignore JS_SetProperty return value, because errors should be impossible
    3028    // and we can't do anything useful in the case of errors anyway
    3129
    3230template<> jsval ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, SDL_Event_ const& val)
    3331{
     32    JSAutoRequest rq(cx);
    3433    const char* typeName;
    3534
    3635    switch (val.ev.type)
     
    7877        JSObject* keysym = JS_NewObject(cx, NULL, NULL, NULL);
    7978        if (! keysym)
    8079            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());
    8382
    8483        // SET(keysym, "scancode", (int)val.ev.key.keysym.scancode); // (not in wsdl.h)
    8584        SET(keysym, "sym", (int)val.ev.key.keysym.sym);
  • source/gui/scripting/JSInterface_GUITypes.cpp

     
    2323/**** GUISize ****/
    2424JSClass JSI_GUISize::JSI_class = {
    2525    "GUISize", 0,
    26         JS_PropertyStub, JS_PropertyStub,
     26        JS_PropertyStub, JS_DeletePropertyStub,
    2727        JS_PropertyStub, JS_StrictPropertyStub,
    2828        JS_EnumerateStub, JS_ResolveStub,
    29         JS_ConvertStub, JS_FinalizeStub,
     29        JS_ConvertStub, NULL,
    3030        NULL, NULL, NULL, JSI_GUISize::construct
    3131};
    3232
     
    4545
    4646JSFunctionSpec JSI_GUISize::JSI_methods[] =
    4747{
    48     { "toString", JSI_GUISize::toString, 0, 0 },
    49     { 0 }
     48    JS_FS("toString", JSI_GUISize::toString, 0, 0),
     49    JS_FS_END
    5050};
    5151
    52 JSBool JSI_GUISize::construct(JSContext* cx, uintN argc, jsval* vp)
     52JSBool JSI_GUISize::construct(JSContext* cx, uint argc, jsval* vp)
    5353{
    5454    JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL);
    5555
     56    // TODO: ugly with so much repetition...?
    5657    if (argc == 8)
    5758    {
    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());
    6675    }
    6776    else if (argc == 4)
    6877    {
    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());
    7891    }
    7992    else
    8093    {
    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());
    90103    }
    91104
    92105    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
     
    102115        return CStr::FromDouble(per)+"%"+( pix == 0.0 ? CStr() : pix > 0.0 ? CStr("+")+CStr::FromDouble(pix) : CStr::FromDouble(pix) );
    103116}
    104117
    105 JSBool JSI_GUISize::toString(JSContext* cx, uintN argc, jsval* vp)
     118JSBool JSI_GUISize::toString(JSContext* cx, uint argc, jsval* vp)
    106119{
    107120    UNUSED2(argc);
    108121
     
    141154
    142155JSClass JSI_GUIColor::JSI_class = {
    143156    "GUIColor", 0,
    144         JS_PropertyStub, JS_PropertyStub,
     157        JS_PropertyStub, JS_DeletePropertyStub,
    145158        JS_PropertyStub, JS_StrictPropertyStub,
    146159        JS_EnumerateStub, JS_ResolveStub,
    147         JS_ConvertStub, JS_FinalizeStub,
     160        JS_ConvertStub, NULL,
    148161        NULL, NULL, NULL, JSI_GUIColor::construct
    149162};
    150163
     
    159172
    160173JSFunctionSpec JSI_GUIColor::JSI_methods[] =
    161174{
    162     { "toString", JSI_GUIColor::toString, 0, 0 },
    163     { 0 }
     175    JS_FS("toString", JSI_GUIColor::toString, 0, 0),
     176    JS_FS_END
    164177};
    165178
    166 JSBool JSI_GUIColor::construct(JSContext* cx, uintN argc, jsval* vp)
     179JSBool JSI_GUIColor::construct(JSContext* cx, uint argc, jsval* vp)
    167180{
    168181    JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL);
    169182
     
    177190    else
    178191    {
    179192        // 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))
    182195            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))
    187201            return JS_FALSE;
    188         JS_SetProperty(cx, obj, "g", &c);
     202        JS_SetProperty(cx, obj, "g", c.address());
    189203    }
    190204
    191205    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
    192206    return JS_TRUE;
    193207}
    194208
    195 JSBool JSI_GUIColor::toString(JSContext* cx, uintN argc, jsval* vp)
     209JSBool JSI_GUIColor::toString(JSContext* cx, uint argc, jsval* vp)
    196210{
    197211    UNUSED2(argc);
    198212
     
    218232
    219233JSClass JSI_GUIMouse::JSI_class = {
    220234    "GUIMouse", 0,
    221         JS_PropertyStub, JS_PropertyStub,
     235        JS_PropertyStub, JS_DeletePropertyStub,
    222236        JS_PropertyStub, JS_StrictPropertyStub,
    223237        JS_EnumerateStub, JS_ResolveStub,
    224         JS_ConvertStub, JS_FinalizeStub,
     238        JS_ConvertStub, NULL,
    225239        NULL, NULL, NULL, JSI_GUIMouse::construct
    226240};
    227241
     
    235249
    236250JSFunctionSpec JSI_GUIMouse::JSI_methods[] =
    237251{
    238     { "toString", JSI_GUIMouse::toString, 0, 0 },
    239     { 0 }
     252    JS_FS("toString", JSI_GUIMouse::toString, 0, 0),
     253    JS_FS_END
    240254};
    241255
    242 JSBool JSI_GUIMouse::construct(JSContext* cx, uintN argc, jsval* vp)
     256JSBool JSI_GUIMouse::construct(JSContext* cx, uint argc, jsval* vp)
    243257{
    244258    JSObject* obj = JS_NewObject(cx, &JSI_GUIMouse::JSI_class, NULL, NULL);
    245259
    246260    if (argc == 3)
    247261    {
    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());
    251268    }
    252269    else
    253270    {
    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());
    258275    }
    259276
    260277    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
    261278    return JS_TRUE;
    262279}
    263280
    264 JSBool JSI_GUIMouse::toString(JSContext* cx, uintN argc, jsval* vp)
     281JSBool JSI_GUIMouse::toString(JSContext* cx, uint argc, jsval* vp)
    265282{
    266283    UNUSED2(argc);
    267284
    268     int32 x, y, buttons;
     285    int32_t x, y, buttons;
    269286    ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
    270287    pScriptInterface->GetProperty(JS_THIS_VALUE(cx, vp), "x", x);
    271288    pScriptInterface->GetProperty(JS_THIS_VALUE(cx, vp), "y", y);
  • source/gui/scripting/JSInterface_GUITypes.h

     
    2626        extern JSClass JSI_class;               \
    2727        extern JSPropertySpec JSI_props[];      \
    2828        extern JSFunctionSpec JSI_methods[];    \
    29         JSBool construct(JSContext* cx, uintN argc, jsval* vp); \
    30         JSBool toString(JSContext* cx, uintN argc, jsval* vp);  \
     29        JSBool construct(JSContext* cx, uint argc, jsval* vp);  \
     30        JSBool toString(JSContext* cx, uint argc, jsval* vp);   \
    3131    }
    3232
    3333GUISTDTYPE(Size)
  • source/gui/scripting/JSInterface_IGUIObject.cpp

     
    3232
    3333JSClass JSI_IGUIObject::JSI_class = {
    3434    "GUIObject", JSCLASS_HAS_PRIVATE,
    35     JS_PropertyStub, JS_PropertyStub,
     35    JS_PropertyStub, JS_DeletePropertyStub,
    3636    JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty,
    3737    JS_EnumerateStub, JS_ResolveStub,
    38     JS_ConvertStub, JS_FinalizeStub,
     38    JS_ConvertStub, NULL,
    3939    NULL, NULL, NULL, JSI_IGUIObject::construct
    4040};
    4141
    42 JSPropertySpec JSI_IGUIObject::JSI_props[] = 
     42JSPropertySpec JSI_IGUIObject::JSI_props[] =
    4343{
    4444    { 0 }
    4545};
    4646
    47 JSFunctionSpec JSI_IGUIObject::JSI_methods[] = 
     47JSFunctionSpec JSI_IGUIObject::JSI_methods[] =
    4848{
    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
    5454};
    5555
    56 JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
     56JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<jsval> vp)
    5757{
    5858    IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
    5959    if (!e)
     
    8888        CStr eventName (CStr(propName.substr(2)).LowerCase());
    8989        std::map<CStr, CScriptValRooted>::iterator it = e->m_ScriptHandlers.find(eventName);
    9090        if (it == e->m_ScriptHandlers.end())
    91             *vp = JSVAL_NULL;
     91            vp.set(JSVAL_NULL);
    9292        else
    93             *vp = it->second.get();
     93            vp.set((*it).second.get());
    9494        return JS_TRUE;
    9595    }
    9696
     
    102102        if (parent)
    103103        {
    104104            // 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()));
    106106        }
    107107        else
    108108        {
    109109            // Return null if there's no parent
    110             *vp = JSVAL_NULL;
     110            vp.set(JSVAL_NULL);
    111111        }
    112112        return JS_TRUE;
    113113    }
    114114    // Also handle "name" specially
    115115    else if (propName == "name")
    116116    {
    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())));
    118118        return JS_TRUE;
    119119    }
    120120    // Handle all other properties
     
    135135            {
    136136                bool value;
    137137                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;
    139140                break;
    140141            }
    141142
     
    143144            {
    144145                int value;
    145146                GUI<int>::GetSetting(e, propName, value);
    146                 *vp = INT_TO_JSVAL(value);
     147                vp.set(INT_TO_JSVAL(value));
    147148                break;
    148149            }
    149150
     
    152153                float value;
    153154                GUI<float>::GetSetting(e, propName, value);
    154155                // 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());
    156158            }
    157159
    158160        case GUIST_CColor:
     
    160162                CColor colour;
    161163                GUI<CColor>::GetSetting(e, propName, colour);
    162164                JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL);
    163                 *vp = OBJECT_TO_JSVAL(obj); // root it
     165                vp.set(OBJECT_TO_JSVAL(obj)); // root it
    164166
    165                 jsval c;
     167                JS::RootedValue c(cx);
    166168                // 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())
    168171                    P(r);
    169172                    P(g);
    170173                    P(b);
     
    179182                CClientArea area;
    180183                GUI<CClientArea>::GetSetting(e, propName, area);
    181184                JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL);
    182                 *vp = OBJECT_TO_JSVAL(obj); // root it
     185                vp.set(OBJECT_TO_JSVAL(obj)); // root it
    183186                try
    184187                {
    185188                    ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
     
    207210            {
    208211                CGUIString value;
    209212                GUI<CGUIString>::GetSetting(e, propName, value);
    210                 *vp = ScriptInterface::ToJSVal(cx, value.GetOriginalString());
     213                vp.set(ScriptInterface::ToJSVal(cx, value.GetOriginalString()));
    211214                break;
    212215            }
    213216
     
    215218            {
    216219                CStr value;
    217220                GUI<CStr>::GetSetting(e, propName, value);
    218                 *vp = ScriptInterface::ToJSVal(cx, value);
     221                vp.set(ScriptInterface::ToJSVal(cx, value));
    219222                break;
    220223            }
    221224
     
    223226            {
    224227                CStrW value;
    225228                GUI<CStrW>::GetSetting(e, propName, value);
    226                 *vp = ScriptInterface::ToJSVal(cx, value);
     229                vp.set(ScriptInterface::ToJSVal(cx, value));
    227230                break;
    228231            }
    229232
     
    231234            {
    232235                CGUISpriteInstance *value;
    233236                GUI<CGUISpriteInstance>::GetSettingPointer(e, propName, value);
    234                 *vp = ScriptInterface::ToJSVal(cx, value->GetName());
     237                vp.set(ScriptInterface::ToJSVal(cx, value->GetName()));
    235238                break;
    236239            }
    237240
     
    247250                case EAlign_Center: word = "center"; break;
    248251                default: debug_warn(L"Invalid EAlign!"); word = "error"; break;
    249252                }
    250                 *vp = ScriptInterface::ToJSVal(cx, word);
     253                vp.set(ScriptInterface::ToJSVal(cx, word));
    251254                break;
    252255            }
    253256
     
    263266                case EVAlign_Center: word = "center"; break;
    264267                default: debug_warn(L"Invalid EVAlign!"); word = "error"; break;
    265268                }
    266                 *vp = ScriptInterface::ToJSVal(cx, word);
     269                vp.set(ScriptInterface::ToJSVal(cx, word));
    267270                break;
    268271            }
    269272
     
    273276                GUI<CGUIList>::GetSetting(e, propName, value);
    274277
    275278                JSObject *obj = JS_NewArrayObject(cx, 0, NULL);
    276                 *vp = OBJECT_TO_JSVAL(obj); // root it
    277                
     279                vp.set(OBJECT_TO_JSVAL(obj)); // root it
     280
    278281                for (size_t i = 0; i < value.m_Items.size(); ++i)
    279282                {
    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());
    282285                }
    283286
    284287                break;
     
    294297    }
    295298}
    296299
    297 JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, JSBool UNUSED(strict), jsval* vp)
     300JSBool JSI_IGUIObject::setProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JSBool UNUSED(strict), JS::MutableHandle<jsval> vp)
    298301{
    299302    IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
    300303    if (!e)
     
    311314    if (propName == "name")
    312315    {
    313316        std::string value;
    314         if (!ScriptInterface::FromJSVal(cx, *vp, value))
     317        if (!ScriptInterface::FromJSVal(cx, vp.get(), value))
    315318            return JS_FALSE;
    316319        e->SetName(value);
    317320        return JS_TRUE;
     
    320323    // Use onWhatever to set event handlers
    321324    if (propName.substr(0, 2) == "on")
    322325    {
    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())))
    324327        {
    325328            JS_ReportError(cx, "on- event-handlers must be functions");
    326329            return JS_FALSE;
    327330        }
    328331
    329332        CStr eventName (CStr(propName.substr(2)).LowerCase());
    330         e->SetScriptHandler(eventName, JSVAL_TO_OBJECT(*vp));
     333        e->SetScriptHandler(eventName, JSVAL_TO_OBJECT(vp.get()));
    331334
    332335        return JS_TRUE;
    333336    }
     
    346349    case GUIST_CStr:
    347350        {
    348351            std::string value;
    349             if (!ScriptInterface::FromJSVal(cx, *vp, value))
     352            if (!ScriptInterface::FromJSVal(cx, vp.get(), value))
    350353                return JS_FALSE;
    351354
    352355            GUI<CStr>::SetSetting(e, propName, value);
     
    356359    case GUIST_CStrW:
    357360        {
    358361            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;
    361364
    362365            GUI<CStrW>::SetSetting(e, propName, value);
    363366            break;
     
    366369    case GUIST_CGUISpriteInstance:
    367370        {
    368371            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;
    371374
    372375            GUI<CGUISpriteInstance>::SetSetting(e, propName, CGUISpriteInstance(value));
    373376            break;
     
    376379    case GUIST_CGUIString:
    377380        {
    378381            std::wstring value;
    379             if (!ScriptInterface::FromJSVal(cx, *vp, value))
     382            if (!ScriptInterface::FromJSVal(cx, vp.get(), value))
    380383                return JS_FALSE;
    381384
    382385            CGUIString str;
     
    388391    case GUIST_EAlign:
    389392        {
    390393            std::string value;
    391             if (!ScriptInterface::FromJSVal(cx, *vp, value))
     394            if (!ScriptInterface::FromJSVal(cx, vp.get(), value))
    392395                return JS_FALSE;
    393396
    394397            EAlign a;
     
    407410    case GUIST_EVAlign:
    408411        {
    409412            std::string value;
    410             if (!ScriptInterface::FromJSVal(cx, *vp, value))
     413            if (!ScriptInterface::FromJSVal(cx, vp.get(), value))
    411414                return JS_FALSE;
    412415
    413416            EVAlign a;
     
    425428
    426429    case GUIST_int:
    427430        {
    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)
    430433                GUI<int>::SetSetting(e, propName, value);
    431434            else
    432435            {
     
    438441
    439442    case GUIST_float:
    440443        {
    441             jsdouble value;
    442             if (JS_ValueToNumber(cx, *vp, &value) == JS_TRUE)
     444            double value;
     445            if (JS_ValueToNumber(cx, vp.get(), &value) == true)
    443446                GUI<float>::SetSetting(e, propName, (float)value);
    444447            else
    445448            {
     
    452455    case GUIST_bool:
    453456        {
    454457            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);
    457460            else
    458461            {
    459462                JS_ReportError(cx, "Cannot convert value to bool");
     
    464467
    465468    case GUIST_CClientArea:
    466469        {
    467             if (JSVAL_IS_STRING(*vp))
     470            if (JSVAL_IS_STRING(vp.get()))
    468471            {
    469472                std::wstring value;
    470                 if (!ScriptInterface::FromJSVal(cx, *vp, value))
     473                if (!ScriptInterface::FromJSVal(cx, vp.get(), value))
    471474                    return JS_FALSE;
    472475
    473476                if (e->SetSetting(propName, value) != PSRETURN_OK)
     
    476479                    return JS_FALSE;
    477480                }
    478481            }
    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))
    480483            {
    481484                CClientArea area;
    482485                GUI<CClientArea>::GetSetting(e, propName, area);
    483486
    484                 JSObject* obj = JSVAL_TO_OBJECT(*vp);
     487                JSObject* obj = JSVAL_TO_OBJECT(vp.get());
    485488                ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
    486489                #define P(x, y, z) pScriptInterface->GetProperty(OBJECT_TO_JSVAL(obj), #z, area.x.y)
    487490                    P(pixel,    left,   left);
     
    506509
    507510    case GUIST_CColor:
    508511        {
    509             if (JSVAL_IS_STRING(*vp))
     512            if (JSVAL_IS_STRING(vp.get()))
    510513            {
    511514                std::wstring value;
    512                 if (!ScriptInterface::FromJSVal(cx, *vp, value))
     515                if (!ScriptInterface::FromJSVal(cx, vp.get(), value))
    513516                    return JS_FALSE;
    514517
    515518                if (e->SetSetting(propName, value) != PSRETURN_OK)
     
    518521                    return JS_FALSE;
    519522                }
    520523            }
    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))
    522525            {
    523526                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()); \
    527531                                JS_ValueToNumber(cx, t, &s); \
    528532                                colour.x = (float)s
    529533                PROP(r); PROP(g); PROP(b); PROP(a);
     
    541545
    542546    case GUIST_CGUIList:
    543547        {
    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)
    547551            {
    548552                CGUIList list;
    549553
    550554                for (int i=0; i<(int)length; ++i)
    551555                {
    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()))
    554558                    {
    555559                        JS_ReportError(cx, "Failed to get list element");
    556560                        return JS_FALSE;
     
    562566
    563567                    CGUIString str;
    564568                    str.SetValue(value);
    565                    
     569
    566570                    list.m_Items.push_back(str);
    567571                }
    568572
     
    587591}
    588592
    589593
    590 JSBool JSI_IGUIObject::construct(JSContext* cx, uintN argc, jsval* vp)
     594JSBool JSI_IGUIObject::construct(JSContext* cx, uint argc, jsval* vp)
    591595{
    592596    if (argc == 0)
    593597    {
     
    599603
    600604    // Store the IGUIObject in the JS object's 'private' area
    601605    IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(JS_ARGV(cx, vp)[0]);
    602     JS_SetPrivate(cx, obj, guiObject);
     606    JS_SetPrivate(obj, guiObject);
    603607
    604608    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
    605609    return JS_TRUE;
     
    610614    scriptInterface.DefineCustomObjectType(&JSI_class, construct, 1, JSI_props, JSI_methods, NULL, NULL);
    611615}
    612616
    613 JSBool JSI_IGUIObject::toString(JSContext* cx, uintN argc, jsval* vp)
     617JSBool JSI_IGUIObject::toString(JSContext* cx, uint argc, jsval* vp)
    614618{
    615619    UNUSED2(argc);
    616620
     
    625629    return JS_TRUE;
    626630}
    627631
    628 JSBool JSI_IGUIObject::focus(JSContext* cx, uintN argc, jsval* vp)
     632JSBool JSI_IGUIObject::focus(JSContext* cx, uint argc, jsval* vp)
    629633{
    630634    UNUSED2(argc);
    631635
     
    639643    return JS_TRUE;
    640644}
    641645
    642 JSBool JSI_IGUIObject::blur(JSContext* cx, uintN argc, jsval* vp)
     646JSBool JSI_IGUIObject::blur(JSContext* cx, uint argc, jsval* vp)
    643647{
    644648    UNUSED2(argc);
    645649
     
    653657    return JS_TRUE;
    654658}
    655659
    656 JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uintN argc, jsval* vp)
     660JSBool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, jsval* vp)
    657661{
    658662    UNUSED2(argc);
    659663    IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
  • source/gui/scripting/JSInterface_IGUIObject.h

     
    2525    extern JSClass JSI_class;
    2626    extern JSPropertySpec JSI_props[];
    2727    extern JSFunctionSpec JSI_methods[];
    28     JSBool getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
    29     JSBool setProperty(JSContext* cx, JSObject* obj, jsid id, JSBool strict, jsval* vp);
    30     JSBool construct(JSContext* cx, uintN argc, jsval* vp);
    31     JSBool toString(JSContext* cx, uintN argc, jsval* vp);
    32     JSBool focus(JSContext* cx, uintN argc, jsval* vp);
    33     JSBool blur(JSContext* cx, uintN argc, jsval* vp);
    34     JSBool getComputedSize(JSContext* cx, uintN argc, 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);
    3535    void init(ScriptInterface& scriptInterface);
    3636}
    3737
  • source/gui/scripting/ScriptFunctions.cpp

     
    6969#include "soundmanager/SoundManager.h"
    7070#include "soundmanager/scripting/JSInterface_Sound.h"
    7171
    72 #include "js/jsapi.h"
    7372/*
    7473 * This file defines a set of functions that are available to GUI scripts, to allow
    7574 * interaction with the rest of the engine.
     
    8887// TODO: Use LOGERROR to print a friendly error message when the requirements aren't met instead of failing with debug_warn when cloning.
    8988void PushGuiPage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring name, CScriptVal initData)
    9089{
    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()));
    9591}
    9692
    9793void SwitchGuiPage(ScriptInterface::CxPrivate* pCxPrivate, std::wstring name, CScriptVal initData)
     
    557553void ForceGC(ScriptInterface::CxPrivate* pCxPrivate)
    558554{
    559555    double time = timer_Time();
    560     JS_GC(pCxPrivate->pScriptInterface->GetContext());
     556    JS_GC(pCxPrivate->pScriptInterface->GetJSRuntime());
    561557    time = timer_Time() - time;
    562558    g_Console->InsertMessage(L"Garbage collection completed in: %f", time);
    563559}
  • source/lib/types.h

     
    2929
    3030#include "lib/posix/posix_types.h"
    3131
    32 // defines instead of typedefs so we can #undef in case of conflicts
     32typedef int8_t i8;
     33typedef int16_t i16;
     34typedef int32_t i32;
     35typedef int64_t i64;
    3336
    34 #define i8 int8_t
    35 #define i16 int16_t
    36 #define i32 int32_t
    37 #define i64 int64_t
     37typedef uint8_t u8;
     38typedef uint16_t u16;
     39typedef uint32_t u32;
     40typedef uint64_t u64;
    3841
    39 #define u8  uint8_t
    40 #define u16 uint16_t
    41 #define u32 uint32_t
    42 #define u64 uint64_t
    43 
    4442#endif // #ifndef INCLUDED_TYPES
  • source/lobby/XmppClient.cpp

     
    309309void XmppClient::SendIqGameReport(ScriptInterface& scriptInterface, CScriptVal data)
    310310{
    311311    glooxwrapper::JID xpartamuppJid(m_xpartamuppId);
    312     jsval dataval = data.get();
     312    JS::RootedValue dataval(scriptInterface.GetContext(), data.get());
    313313
    314314    // Setup some base stanza attributes
    315315    GameReport* game = new GameReport();
     
    317317
    318318    // Iterate through all the properties reported and add them to the stanza.
    319319    std::vector<std::string> properties;
    320     scriptInterface.EnumeratePropertyNamesWithPrefix(dataval, "", properties);
     320    scriptInterface.EnumeratePropertyNamesWithPrefix(JS::RootedObject(scriptInterface.GetContext(), JSVAL_TO_OBJECT(dataval)), "", properties);
    321321    for (std::vector<int>::size_type i = 0; i != properties.size(); i++)
    322322    {
    323323        std::wstring value;
     
    343343void XmppClient::SendIqRegisterGame(ScriptInterface& scriptInterface, CScriptVal data)
    344344{
    345345    glooxwrapper::JID xpartamuppJid(m_xpartamuppId);
    346     jsval dataval = data.get();
     346    JS::RootedValue dataval(scriptInterface.GetContext(), data.get());
    347347
    348348    // Setup some base stanza attributes
    349349    GameListQuery* g = new GameListQuery();
     
    354354
    355355    // Iterate through all the properties reported and add them to the stanza.
    356356    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);
    358359    for (std::vector<int>::size_type i = 0; i != properties.size(); i++)
    359360    {
    360361        std::wstring value;
  • source/network/NetServer.cpp

     
    342342
    343343void CNetServerWorker::Run()
    344344{
     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   
    345348    // To avoid the need for JS_SetContextThread, we create and use and destroy
    346349    // the script interface entirely within this network thread
    347350    m_ScriptInterface = new ScriptInterface("Engine", "Net server", ScriptInterface::CreateRuntime());
  • source/ps/Errors.h

     
    7272
    7373#include <exception>
    7474
    75 typedef u32 PSRETURN;
     75typedef uint32_t PSRETURN;
    7676
    7777class PSERROR : public std::exception
    7878{
  • source/ps/GameSetup/GameSetup.cpp

     
    560560    SAFE_DELETE(g_GUI);
    561561
    562562    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();
    563567
    564568    // disable the special Windows cursor, or free textures for OGL cursors
    565569    cursor_draw(g_VFS, 0, g_mouse_x, g_yres-g_mouse_y, false);
     
    858862    g_Logger = new CLogger;
    859863   
    860864    // 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);
    862866
    863867    // Special command-line mode to dump the entity schemas instead of running the game.
    864868    // (This must be done after loading VFS etc, but should be done before wasting time
     
    11041108        CStr seedArg = args.Get("autostart-random");
    11051109
    11061110        // Default seed is 0
    1107         uint32 seed = 0;
     1111        uint32_t seed = 0;
    11081112        if (!seedArg.empty())
    11091113        {
    11101114            if (seedArg.compare("-1") == 0)
  • source/ps/Profile.cpp

     
    2929# define USE_CRT_SET_ALLOC_HOOK
    3030#endif
    3131
    32 #if defined(__GLIBC__) && !defined(NDEBUG)
    33 //# define USE_GLIBC_MALLOC_HOOK
    34 # define USE_GLIBC_MALLOC_OVERRIDE
    35 # include <dlfcn.h>
    36 # include <malloc.h>
    37 # include "lib/sysdep/cpu.h"
    38 #endif
    39 
    4032#include <numeric>
    4133
    4234///////////////////////////////////////////////////////////////////////////////////////////////
  • source/ps/Replay.cpp

     
    127127    new CProfileManager;
    128128    g_ScriptStatsTable = new CScriptStatsTable;
    129129    g_ProfileViewer.AddRootTable(g_ScriptStatsTable);
    130     g_ScriptRuntime = ScriptInterface::CreateRuntime(128 * 1024 * 1024);
     130    g_ScriptRuntime = ScriptInterface::CreateRuntime(384 * 1024 * 1024);
    131131
    132132    CGame game(true);
    133133    g_Game = &game;
     
    210210                g_Profiler2.IncrementFrameNumber();
    211211                PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber());
    212212
     213                game.GetSimulation2()->Tick();
    213214                game.GetSimulation2()->Update(turnLength, commands);
    214215                commands.clear();
    215216            }
     
    217218//          std::string hash;
    218219//          bool ok = game.GetSimulation2()->ComputeStateHash(hash, true);
    219220//          ENSURE(ok);
    220 //          debug_printf(L"%hs", Hexify(hash).c_str());
     221//          debug_printf(L"turn hash (%u) : %hs", turn, Hexify(hash).c_str());
    221222
    222223            debug_printf(L"\n");
    223224
     
    244245
    245246    timer_DisplayClientTotals();
    246247
     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   
    247252    // Clean up
    248253    delete &g_TexMan;
    249254    tex_codec_unregister_all();
  • source/ps/scripting/JSInterface_VFS.cpp

     
    6868{
    6969    BuildDirEntListState* s = (BuildDirEntListState*)cbData;
    7070
    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());
    7373    return INFO::OK;
    7474}
    7575
     
    191191    while (std::getline(ss, line))
    192192    {
    193193        // 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());
    196196    }
    197197
    198198    return OBJECT_TO_JSVAL( line_array );
  • source/scriptinterface/AutoRooters.cpp

     
    4040
    4141    for (size_t i = 0; i < m_Objects.size(); ++i)
    4242    {
    43         JS_CALL_OBJECT_TRACER(trc, m_Objects[i], "AutoGCRooter object");
     43        JS_CallObjectTracer(trc, &m_Objects[i], "AutoGCRooter object");
    4444    }
    4545
    4646    for (size_t i = 0; i < m_Vals.size(); ++i)
    4747    {
    48         JS_CALL_VALUE_TRACER(trc, m_Vals[i], "AutoGCRooter val");
     48        JS_CallValueTracer(trc, &m_Vals[i], "AutoGCRooter val");
    4949    }
    5050
    5151    for (size_t i = 0; i < m_IdArrays.size(); ++i)
    5252    {
    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)
    5454        {
    5555            jsval val = JSVAL_VOID;
    56             JS_IdToValue(m_ScriptInterface.GetContext(), m_IdArrays[i]->vector[j], &val);
    57             JS_CALL_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");
    5858        }
    5959    }
    6060
  • source/scriptinterface/AutoRooters.h

     
    2020
    2121#include "scriptinterface/ScriptTypes.h"
    2222
    23 #include "js/jsapi.h"
    2423
    2524/**
    2625 * Helper for rooting large groups of script values.
  • source/scriptinterface/NativeWrapperDecls.h

     
    2626#define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i
    2727// Some other things
    2828#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;
    3030
    3131// List-generating macros, named roughly after their first list item
    3232#define TYPENAME_T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, typename T) // "typename T0, typename T1, "
     
    5151// (Definition comes later, since it depends on some things we haven't defined yet)
    5252#define OVERLOADS(z, i, data) \
    5353    template <typename R, TYPENAME_T0_HEAD(z,i)  R (*fptr) ( ScriptInterface::CxPrivate* T0_TAIL(z,i) )> \
    54     static JSBool call(JSContext* cx, uintN argc, jsval* vp);
     54    static JSBool call(JSContext* cx, uint32_t argc, jsval* vp);
    5555BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
    5656#undef OVERLOADS
    5757
    5858// Similar, for class methods
    5959#define OVERLOADS(z, i, data) \
    6060    template <typename R, TYPENAME_T0_HEAD(z,i)  JSClass* CLS, typename TC, R (TC::*fptr) ( T0(z,i) )> \
    61     static JSBool callMethod(JSContext* cx, uintN argc, jsval* vp);
     61    static JSBool callMethod(JSContext* cx, uint32_t argc, jsval* vp);
    6262BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
    6363#undef OVERLOADS
    6464
  • source/scriptinterface/NativeWrapperDefns.h

     
    7979#define SCRIPT_PROFILE \
    8080    if (g_ScriptProfilingEnabled) \
    8181    { \
    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)))); \
    8383        const char* name = "(unknown)"; \
    8484        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)) \
    8787            name = static_cast<const char*>(JSVAL_TO_PRIVATE(nameval)); \
    8888        CProfileSampleScript profile(name); \
    8989    }
     
    9191// JSFastNative-compatible function that wraps the function identified in the template argument list
    9292#define OVERLOADS(z, i, data) \
    9393    template <typename R, TYPENAME_T0_HEAD(z,i)  R (*fptr) ( ScriptInterface::CxPrivate* T0_TAIL(z,i) )> \
    94     JSBool ScriptInterface::call(JSContext* cx, uintN argc, jsval* vp) { \
     94    JSBool ScriptInterface::call(JSContext* cx, uint32_t argc, jsval* vp) { \
    9595        UNUSED2(argc); \
    9696        SCRIPT_PROFILE \
    9797        BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
    9898        jsval rval = JSVAL_VOID; \
    9999        ScriptInterface_NativeWrapper<R>::call(cx, rval, fptr  A0_TAIL(z,i)); \
    100100        JS_SET_RVAL(cx, vp, rval); \
    101         return (ScriptInterface::IsExceptionPending(cx) ? JS_FALSE : JS_TRUE); \
     101        return !ScriptInterface::IsExceptionPending(cx); \
    102102    }
    103103BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
    104104#undef OVERLOADS
     
    106106// Same idea but for methods
    107107#define OVERLOADS(z, i, data) \
    108108    template <typename R, TYPENAME_T0_HEAD(z,i)  JSClass* CLS, typename TC, R (TC::*fptr) ( T0(z,i) )> \
    109     JSBool ScriptInterface::callMethod(JSContext* cx, uintN argc, jsval* vp) { \
     109    JSBool ScriptInterface::callMethod(JSContext* cx, uint32_t argc, jsval* vp) { \
    110110        UNUSED2(argc); \
    111111        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; \
    115115        BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
    116116        jsval rval = JSVAL_VOID; \
    117117        ScriptInterface_NativeMethodWrapper<R, TC>::call(cx, rval, c, fptr  A0_TAIL(z,i)); \
    118118        JS_SET_RVAL(cx, vp, rval); \
    119         return (ScriptInterface::IsExceptionPending(cx) ? JS_FALSE : JS_TRUE); \
     119        return !ScriptInterface::IsExceptionPending(cx); \
    120120    }
    121121BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
    122122#undef OVERLOADS
  • source/scriptinterface/ScriptConversions.cpp

     
    3232
    3333template<> bool ScriptInterface::FromJSVal<bool>(JSContext* cx, jsval v, bool& out)
    3434{
     35    JSAutoRequest rq(cx);
    3536    JSBool ret;
    3637    WARN_IF_NOT(JSVAL_IS_BOOLEAN(v), v);
    3738    if (!JS_ValueToBoolean(cx, v, &ret))
     
    4243
    4344template<> bool ScriptInterface::FromJSVal<float>(JSContext* cx, jsval v, float& out)
    4445{
    45     jsdouble ret;
     46    JSAutoRequest rq(cx);
     47    double ret;
    4648    WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
    4749    if (!JS_ValueToNumber(cx, v, &ret))
    4850        return false;
     
    5254
    5355template<> bool ScriptInterface::FromJSVal<double>(JSContext* cx, jsval v, double& out)
    5456{
    55     jsdouble ret;
     57    JSAutoRequest rq(cx);
     58    double ret;
    5659    WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
    5760    if (!JS_ValueToNumber(cx, v, &ret))
    5861        return false;
     
    6265
    6366template<> bool ScriptInterface::FromJSVal<i32>(JSContext* cx, jsval v, i32& out)
    6467{
    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;
    6672    WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
    67     if (!JS_ValueToECMAInt32(cx, v, &ret))
     73    if (!JS::ToInt32(cx, v1, &ret))
    6874        return false;
    6975    out = ret;
    7076    return true;
     
    7278
    7379template<> bool ScriptInterface::FromJSVal<u32>(JSContext* cx, jsval v, u32& out)
    7480{
    75     uint32 ret;
     81    JSAutoRequest rq(cx);
     82    uint32_t ret;
    7683    WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
    7784    if (!JS_ValueToECMAUint32(cx, v, &ret))
    7885        return false;
     
    8289
    8390template<> bool ScriptInterface::FromJSVal<u16>(JSContext* cx, jsval v, u16& out)
    8491{
    85     uint16 ret;
     92    JSAutoRequest rq(cx);
     93    uint16_t ret;
    8694    WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
    8795    if (!JS_ValueToUint16(cx, v, &ret))
    8896        return false;
     
    92100
    93101template<> bool ScriptInterface::FromJSVal<u8>(JSContext* cx, jsval v, u8& out)
    94102{
    95     uint16 ret;
     103    JSAutoRequest rq(cx);
     104    uint16_t ret;
    96105    WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
    97106    if (!JS_ValueToUint16(cx, v, &ret))
    98107        return false;
     
    102111
    103112template<> bool ScriptInterface::FromJSVal<long>(JSContext* cx, jsval v, long& out)
    104113{
    105     int32 tmp;
    106     JSBool ok = JS_ValueToInt32(cx, v, &tmp);
     114    int32_t tmp;
     115    bool ok = JS_ValueToInt32(cx, v, &tmp);
    107116    out = (long)tmp;
    108     return ok == JS_TRUE;
     117    return ok;
    109118}
    110119
    111120template<> bool ScriptInterface::FromJSVal<unsigned long>(JSContext* cx, jsval v, unsigned long& out)
    112121{
    113     int32 tmp;
    114     JSBool ok = JS_ValueToInt32(cx, v, &tmp);
     122    int32_t tmp;
     123    bool ok = JS_ValueToInt32(cx, v, &tmp);
    115124    out = (unsigned long)tmp;
    116     return ok == JS_TRUE;
     125    return ok;
    117126}
    118127
    119128// see comment below (where the same preprocessor condition is used)
     
    143152
    144153#endif
    145154
    146 // NOTE: we can't define a jsval specialisation, because that conflicts with integer types
     155template<> jsval ScriptInterface::ToJSVal<JS::Value>(JSContext* UNUSED(cx), const JS::Value& val)
     156{
     157    return val;
     158}
     159
    147160template<> bool ScriptInterface::FromJSVal<CScriptVal>(JSContext* UNUSED(cx), jsval v, CScriptVal& out)
    148161{
    149162    out = v;
    150163    return true;
    151164}
    152165
     166template<> 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
    153176template<> bool ScriptInterface::FromJSVal<CScriptValRooted>(JSContext* cx, jsval v, CScriptValRooted& out)
    154177{
    155178    out = CScriptValRooted(cx, v);
     
    158181
    159182template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, jsval v, std::wstring& out)
    160183{
     184    JSAutoRequest rq(cx);
    161185    WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions
    162186    JSString* ret = JS_ValueToString(cx, v);
    163187    if (!ret)
     
    181205
    182206template<> bool ScriptInterface::FromJSVal<std::string>(JSContext* cx, jsval v, std::string& out)
    183207{
     208    JSAutoRequest rq(cx);
    184209    WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions
    185210    JSString* ret = JS_ValueToString(cx, v);
    186211    if (!ret)
     
    205230
    206231template<> bool ScriptInterface::FromJSVal<Entity>(JSContext* cx, jsval v, Entity& out)
    207232{
     233    JSAutoRequest rq(cx);
    208234    JSObject* obj;
    209235    if (!JS_ValueToObject(cx, v, &obj) || obj == NULL)
    210236        FAIL("Argument must be an object");
    211237
    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);
    213243
    214244    // 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))
    216246        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))
    218248        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))
    220250        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))
    222252        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))
    224254        FAIL("Failed to read Entity.rotation property");
    225255
    226256    return true;
     
    234264    return val ? JSVAL_TRUE : JSVAL_FALSE;
    235265}
    236266
    237 template<> jsval ScriptInterface::ToJSVal<float>(JSContext* cx, const float& val)
     267template<> jsval ScriptInterface::ToJSVal<float>(JSContext* UNUSED(cx), const float& val)
    238268{
    239     jsval rval = JSVAL_VOID;
    240     JS_NewNumberValue(cx, val, &rval); // ignore return value
     269    jsval rval = JS_NumberValue(val);
    241270    return rval;
    242271}
    243272
    244 template<> jsval ScriptInterface::ToJSVal<double>(JSContext* cx, const double& val)
     273template<> jsval ScriptInterface::ToJSVal<double>(JSContext* UNUSED(cx), const double& val)
    245274{
    246     jsval rval = JSVAL_VOID;
    247     JS_NewNumberValue(cx, val, &rval); // ignore return value
     275    jsval rval = JS_NumberValue(val);
    248276    return rval;
    249277}
    250278
     
    264292    return INT_TO_JSVAL(val);
    265293}
    266294
    267 template<> jsval ScriptInterface::ToJSVal<u32>(JSContext* cx, const u32& val)
     295template<> jsval ScriptInterface::ToJSVal<u32>(JSContext* UNUSED(cx), const u32& val)
    268296{
    269297    if (val <= JSVAL_INT_MAX)
    270298        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);
    273300    return rval;
    274301}
    275302
     
    315342
    316343template<> jsval ScriptInterface::ToJSVal<std::wstring>(JSContext* cx, const std::wstring& val)
    317344{
     345    JSAutoRequest rq(cx);
    318346    utf16string utf16(val.begin(), val.end());
    319347    JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast<const jschar*> (utf16.c_str()), utf16.length());
    320348    if (str)
     
    329357
    330358template<> jsval ScriptInterface::ToJSVal<std::string>(JSContext* cx, const std::string& val)
    331359{
     360    JSAutoRequest rq(cx);
    332361    JSString* str = JS_NewStringCopyN(cx, val.c_str(), val.length());
    333362    if (str)
    334363        return STRING_TO_JSVAL(str);
     
    342371
    343372template<> jsval ScriptInterface::ToJSVal<const char*>(JSContext* cx, const char* const& val)
    344373{
     374    JSAutoRequest rq(cx);
    345375    JSString* str = JS_NewStringCopyZ(cx, val);
    346376    if (str)
    347377        return STRING_TO_JSVAL(str);
     
    363393
    364394template<typename T> static jsval ToJSVal_vector(JSContext* cx, const std::vector<T>& val)
    365395{
    366     JSObject* obj = JS_NewArrayObject(cx, (jsint)val.size(), NULL);
     396    JSAutoRequest rq(cx);
     397    JSObject* obj = JS_NewArrayObject(cx, val.size(), NULL);
    367398    if (!obj)
    368399        return JSVAL_VOID;
    369     for (size_t i = 0; i < val.size(); ++i)
     400    for (uint32_t i = 0; i < val.size(); ++i)
    370401    {
    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());
    373404    }
    374405    return OBJECT_TO_JSVAL(obj);
    375406}
    376407
    377408template<typename T> static bool FromJSVal_vector(JSContext* cx, jsval v, std::vector<T>& out)
    378409{
     410    JSAutoRequest rq(cx);
    379411    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)))
    381413        FAIL("Argument must be an array");
    382     jsuint length;
     414    uint32_t length;
    383415    if (!JS_GetArrayLength(cx, obj, &length))
    384416        FAIL("Failed to get array length");
    385417    out.reserve(length);
    386     for (jsuint i = 0; i < length; ++i)
     418    for (uint32_t i = 0; i < length; ++i)
    387419    {
    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()))
    390422            FAIL("Failed to read array element");
    391423        T el2;
    392424        if (!ScriptInterface::FromJSVal<T>(cx, el, el2))
  • source/scriptinterface/ScriptExtraHeaders.h

     
    2525#include "scriptinterface/ScriptTypes.h"
    2626
    2727// 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
    2934# if GCC_VERSION >= 406 // store user flags
    3035#  pragma GCC diagnostic push
    3136# endif
    3237# pragma GCC diagnostic ignored "-Wunused-parameter"
    3338# pragma GCC diagnostic ignored "-Wredundant-decls"
    34 # if GCC_VERSION >= 408
     39# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
     40# if GCC_VERSION >= 407
    3541#  pragma GCC diagnostic ignored "-Wunused-local-typedefs" // caused by js/debug.h
    3642# endif
    3743#endif
     
    4652# define signbit std::signbit
    4753#endif
    4854
    49 #include "js/jstypedarray.h"
    50 #include "js/jsdbgapi.h"
     55#include "jsfriendapi.h"
     56#include "jsdbgapi.h"
     57#include "js/GCAPI.h"
    5158
    5259#undef signbit
    5360
     
    5764#if GCC_VERSION >= 402
    5865# pragma GCC diagnostic warning "-Wunused-parameter"
    5966# 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
    6071# if GCC_VERSION >= 406
    6172#  pragma GCC diagnostic pop // restore user flags
    6273# endif
  • source/scriptinterface/ScriptInterface.cpp

     
    6565 * (One means to share data between threads and runtimes is to create
    6666 * a ScriptInterface::StructuredClone.)
    6767 */
     68
     69
     70void 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 
    68135class ScriptRuntime
    69136{
    70137public:
    71     ScriptRuntime(int runtimeSize) :
    72         m_rooter(NULL)
     138    ScriptRuntime(int runtimeSize):
     139        m_rooter(NULL),
     140        m_LastGCBytes(0)
    73141    {
    74         m_rt = JS_NewRuntime(runtimeSize);
     142        m_rt = JS_NewRuntime(runtimeSize, JS_USE_HELPER_THREADS);
     143
    75144        ENSURE(m_rt); // TODO: error handling
    76145
     146        JS_SetNativeStackQuota(m_rt, 128 * sizeof(size_t) * 1024);
    77147        if (g_ScriptProfilingEnabled)
    78148        {
    79149            // Profiler isn't thread-safe, so only enable this on the main thread
     
    86156                }
    87157            }
    88158        }
    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);
    91176    }
     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    }
    92223
    93224    ~ScriptRuntime()
    94225    {
     226        JS_RemoveExtraGCRootsTracer(m_rt, jshook_trace, this);
     227        JS_DestroyContext(m_dummyContext);
    95228        JS_DestroyRuntime(m_rt);
    96229    }
    97 
     230   
    98231    JSRuntime* m_rt;
    99232    AutoGCRooter* m_rooter;
    100233
    101234private:
     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;
    102250
    103251
    104     static void* jshook_script(JSContext* UNUSED(cx), JSStackFrame* 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)
    105253    {
    106254        if (before)
    107255            g_Profiler.StartScript("script invocation");
     
    154302            if (slash != filename.npos)
    155303                filename = filename.substr(slash+1);
    156304
    157             uintN line = JS_PCToLineNumber(cx, script, pc);
     305            uint line = JS_PCToLineNumber(cx, script, pc);
    158306
    159307            std::stringstream ss;
    160308            ss << "(" << filename << ":" << line << ")";
     
    178326        boost::flyweights::no_locking
    179327    > LocFlyweight;
    180328
    181     static void* jshook_function(JSContext* cx, JSStackFrame* 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)
    182330    {
    183331        if (!before)
    184332        {
     
    186334            return closure;
    187335        }
    188336
    189         JSFunction* fn = JS_GetFrameFunction(cx, fp);
     337        JSFunction* fn = fp.maybeFun();
    190338        if (!fn)
    191339        {
    192340            g_Profiler.StartScript("(function)");
     
    207355        }
    208356
    209357        // 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) };
    211363        g_Profiler.StartScript(LocFlyweight(loc).get().name.c_str());
    212364
    213365        return closure;
    214366    }
    215 
     367   
    216368    static void jshook_trace(JSTracer* trc, void* data)
    217369    {
    218370        ScriptRuntime* m = static_cast<ScriptRuntime*>(data);
    219 
     371   
    220372        if (m->m_rooter)
    221373            m->m_rooter->Trace(trc);
    222374    }
     
    233385{
    234386    ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime);
    235387    ~ScriptInterface_impl();
    236     void Register(const char* name, JSNative fptr, uintN nargs);
     388    void Register(const char* name, JSNative fptr, uint nargs);
    237389
    238390    shared_ptr<ScriptRuntime> m_runtime;
    239391    JSContext* m_cx;
    240392    JSObject* m_glob; // global scope object
     393    JSCompartment* m_comp;
     394    boost::rand48* m_rng;
    241395    JSObject* m_nativeScope; // native function scope object
    242396
    243397    typedef std::map<ScriptInterface::CACHED_VAL, CScriptValRooted> ScriptValCache;
     
    249403
    250404JSClass global_class = {
    251405    "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,
    255410    NULL, NULL, NULL, NULL
    256411};
    257412
    258413void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
    259414{
    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, so
    262     // ignore that specific warning here
    263     if (report->flags == 5 && report->lineno == 0 && report->errorNumber == 163)
    264         return;
    265415
    266416    std::stringstream msg;
    267417    bool isWarning = JSREPORT_IS_WARNING(report->flags);
     
    276426
    277427    // If there is an exception, then print its stack trace
    278428    jsval excn;
    279     if (JS_GetPendingException(cx, &excn) && JSVAL_IS_OBJECT(excn))
     429    if (JS_GetPendingException(cx, &excn) && !JSVAL_IS_PRIMITIVE(excn))
    280430    {
    281431        // TODO: this violates the docs ("The error reporter callback must not reenter the JSAPI.")
    282432
     
    312462
    313463// Functions in the global namespace:
    314464
    315 JSBool print(JSContext* cx, uintN argc, jsval* vp)
     465JSBool print(JSContext* cx, uint argc, jsval* vp)
    316466{
    317     for (uintN i = 0; i < argc; ++i)
     467    for (uint i = 0; i < argc; ++i)
    318468    {
    319469        std::wstring str;
    320470        if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[i], str))
     
    326476    return JS_TRUE;
    327477}
    328478
    329 JSBool logmsg(JSContext* cx, uintN argc, jsval* vp)
     479JSBool logmsg(JSContext* cx, uint argc, jsval* vp)
    330480{
    331481    if (argc < 1)
    332482    {
     
    337487    std::wstring str;
    338488    if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], str))
    339489        return JS_FALSE;
    340     LOGMESSAGE(L"%ls", str.c_str());
     490    LOGMESSAGE(L"%ls%f", str.c_str(), timer_Time());
    341491    JS_SET_RVAL(cx, vp, JSVAL_VOID);
    342492    return JS_TRUE;
    343493}
    344494
    345 JSBool warn(JSContext* cx, uintN argc, jsval* vp)
     495JSBool warn(JSContext* cx, uint argc, jsval* vp)
    346496{
    347497    if (argc < 1)
    348498    {
     
    358508    return JS_TRUE;
    359509}
    360510
    361 JSBool error(JSContext* cx, uintN argc, jsval* vp)
     511JSBool error(JSContext* cx, uint argc, jsval* vp)
    362512{
    363513    if (argc < 1)
    364514    {
     
    374524    return JS_TRUE;
    375525}
    376526
    377 JSBool deepcopy(JSContext* cx, uintN argc, jsval* vp)
     527JSBool deepcopy(JSContext* cx, uint argc, jsval* vp)
    378528{
    379529    if (argc < 1)
    380530    {
     
    384534
    385535    jsval ret;
    386536
    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))
    395538        return JS_FALSE;
    396539
    397540    JS_SET_RVAL(cx, vp, ret);
    398541    return JS_TRUE;
    399542}
    400543
    401 JSBool ProfileStart(JSContext* cx, uintN argc, jsval* vp)
     544JSBool ProfileStart(JSContext* cx, uint argc, jsval* vp)
    402545{
    403546    const char* name = "(ProfileStart)";
    404547
     
    421564        g_Profiler.StartScript(name);
    422565
    423566    g_Profiler2.RecordRegionEnter(name);
    424 
     567   
    425568    JS_SET_RVAL(cx, vp, JSVAL_VOID);
    426569    return JS_TRUE;
    427570}
    428571
    429 JSBool ProfileStop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* vp)
     572JSBool ProfileStop(JSContext* UNUSED(cx), uint UNUSED(argc), jsval* vp)
    430573{
    431574    if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread())
    432575        g_Profiler.Stop();
     
    455598    }
    456599}
    457600
    458 JSBool Math_random(JSContext* cx, uintN UNUSED(argc), jsval* vp)
     601JSBool Math_random(JSContext* cx, uint UNUSED(argc), jsval* vp)
    459602{
    460     // Grab the RNG that was hidden in our slot
    461     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    {
    463606        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}
    465615
    466     double r = generate_uniform_real(*rng, 0.0, 1.0);
     616} // anonymous namespace
    467617
    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;
     618bool 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;
    473624}
    474625
    475 } // anonymous namespace
    476 
    477626ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) :
    478627    m_runtime(runtime)
    479628{
    480     JSBool ok;
     629    bool ok;
    481630
    482631    m_cx = JS_NewContext(m_runtime->m_rt, STACK_CHUNK_SIZE);
    483632    ENSURE(m_cx);
    484633
     634    JS_SetParallelCompilationEnabled(m_cx, true);
     635
    485636    // For GC debugging:
    486637    // JS_SetGCZeal(m_cx, 2);
    487638
    488639    JS_SetContextPrivate(m_cx, NULL);
    489640
    490641    JS_SetErrorReporter(m_cx, ErrorReporter);
     642   
    491643
    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;
    495649    options |= JSOPTION_VAROBJFIX; // "recommended" (fixes variable scoping)
    496650
    497651    // Enable method JIT, unless script profiling/debugging is enabled (since profiling/debugging
     
    499653    // TODO: Verify what exactly is incompatible
    500654    if (!g_ScriptProfilingEnabled && !g_JSDebuggerEnabled)
    501655    {
    502         options |= JSOPTION_METHODJIT;
     656        options |= JSOPTION_BASELINE;
     657        options |= JSOPTION_ION;
     658        options |= JSOPTION_TYPE_INFERENCE;
     659        options |= JSOPTION_COMPILE_N_GO;
    503660
    504661        // Some other JIT flags to experiment with:
    505         options |= JSOPTION_JIT;
    506         options |= JSOPTION_PROFILING;
     662        //options |= JSOPTION_METHODJIT_ALWAYS;
    507663    }
    508664
    509665    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);
    511674
    512     m_glob = JS_NewCompartmentAndGlobalObject(m_cx, &global_class, NULL);
    513 
    514675    ok = JS_InitStandardClasses(m_cx, m_glob);
    515676    ENSURE(ok);
    516677
     678
    517679    JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
    518680            | JSPROP_PERMANENT);
    519681
     
    528690
    529691    Register("ProfileStart", ::ProfileStart, 1);
    530692    Register("ProfileStop", ::ProfileStop, 0);
     693   
     694    runtime->RegisterContext(m_cx);
    531695}
    532696
    533697ScriptInterface_impl::~ScriptInterface_impl()
    534698{
    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    }
    538708    JS_DestroyContext(m_cx);
    539709}
    540710
    541 void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs)
     711void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs)
    542712{
     713    JSAutoRequest rq(m_cx);
    543714    JSFunction* func = JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
    544715
    545716    if (!func)
     
    558729        > LockedStringFlyweight;
    559730
    560731        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()));
    562733    }
    563734}
    564735
     
    605776    JS_ShutDown();
    606777}
    607778
     779void ScriptInterface::Tick()
     780{
     781    js::NotifyAnimationActivity(m->m_glob);
     782}
     783
    608784void ScriptInterface::SetCallbackData(void* pCBData)
    609785{
    610786    m_CxPrivate.pCBData = pCBData;
     
    639815            return false;
    640816        }
    641817    }
     818   
     819    JSAutoRequest rq(m->m_cx);
    642820    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))
    644822        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))
    646824        m->m_ScriptValCache[CACHE_VECTOR3DPROTO] = CScriptValRooted(m->m_cx, proto);
    647825    return true;
    648826}
    649827
     828
    650829bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng)
    651830{
    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()))
    654834    {
    655835        JSFunction* random = JS_DefineFunction(m->m_cx, JSVAL_TO_OBJECT(math), "random", Math_random, 0,
    656836            JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
    657837        if (random)
    658838        {
    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;
    662841        }
    663842    }
    664843
     
    668847
    669848void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs)
    670849{
    671     m->Register(name, fptr, (uintN)nargs);
     850    m->Register(name, fptr, (uint)nargs);
    672851}
    673852
    674853JSContext* ScriptInterface::GetContext() const
     
    693872    return ret;
    694873}
    695874
    696 
    697 jsval ScriptInterface::CallConstructor(jsval ctor, jsval arg)
     875jsval ScriptInterface::CallConstructor(jsval ctor, int argc, jsval argv)
    698876{
    699     if (!JSVAL_IS_OBJECT(ctor))
     877    JSAutoRequest rq(m->m_cx);
     878    if (JSVAL_IS_PRIMITIVE(ctor))
    700879    {
    701880        LOGERROR(L"CallConstructor: ctor is not an object");
    702881        return JSVAL_VOID;
    703882    }
    704883
    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));
    706891}
    707892
    708893jsval ScriptInterface::NewObjectFromConstructor(jsval ctor)
    709894{
     895    JSAutoRequest rq(m->m_cx);
    710896    // Get the constructor's prototype
    711897    // (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()))
    714900    {
    715901        LOGERROR(L"NewObjectFromConstructor: can't get prototype");
    716902        return JSVAL_VOID;
    717903    }
    718904
    719     if (!JSVAL_IS_OBJECT(protoVal))
     905    if (JSVAL_IS_PRIMITIVE(protoVal.get()))
    720906    {
    721907        LOGERROR(L"NewObjectFromConstructor: prototype is not an object");
    722908        return JSVAL_VOID;
    723909    }
    724910
    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));
    727913    // TODO: rooting?
    728914    if (!proto || !parent)
    729915    {
     
    743929
    744930void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
    745931{
     932    JSAutoRequest rq(m->m_cx);
    746933    std::string typeName = clasp->name;
    747934
    748935    if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end())
     
    790977
    791978bool ScriptInterface::CallFunction_(jsval val, const char* name, size_t argc, jsval* argv, jsval& ret)
    792979{
     980    JSAutoRequest rq(m->m_cx);
    793981    JSObject* obj;
    794982    if (!JS_ValueToObject(m->m_cx, val, &obj) || obj == NULL)
    795983        return false;
     
    798986    // when calling an undefined value
    799987    JSBool found;
    800988    if (!JS_HasProperty(m->m_cx, obj, name, &found) || !found)
    801         return false;
     989        return JS_FALSE;
    802990
    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);
    804992
    805     return ok ? true : false;
     993    return ok ? JS_TRUE : JS_FALSE;
    806994}
    807995
    808996jsval ScriptInterface::GetGlobalObject()
    809997{
    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));
    8111000}
    8121001
    8131002JSClass* ScriptInterface::GetGlobalClass()
     
    8171006
    8181007bool ScriptInterface::SetGlobal_(const char* name, jsval value, bool replace)
    8191008{
     1009    JSAutoRequest rq(m->m_cx);
    8201010    if (!replace)
    8211011    {
    8221012        JSBool found;
    8231013        if (!JS_HasProperty(m->m_cx, m->m_glob, name, &found))
    824             return false;
     1014            return JS_FALSE;
    8251015        if (found)
    8261016        {
    8271017            JS_ReportError(m->m_cx, "SetGlobal \"%s\" called multiple times", name);
    828             return false;
     1018            return JS_FALSE;
    8291019        }
    8301020    }
    8311021
    832     JSBool ok = JS_DefineProperty(m->m_cx, m->m_glob, name, value, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
    833             | 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;
    8351025}
    8361026
    8371027bool ScriptInterface::SetProperty_(jsval obj, const char* name, jsval value, bool constant, bool enumerate)
    8381028{
    839     uintN attrs = 0;
     1029    JSAutoRequest rq(m->m_cx);
     1030    uint attrs = 0;
    8401031    if (constant)
    8411032        attrs |= JSPROP_READONLY | JSPROP_PERMANENT;
    8421033    if (enumerate)
    8431034        attrs |= JSPROP_ENUMERATE;
    8441035
    845     if (! JSVAL_IS_OBJECT(obj))
     1036    if (JSVAL_IS_PRIMITIVE(obj))
    8461037        return false;
    8471038    JSObject* object = JSVAL_TO_OBJECT(obj);
    8481039
     
    8531044
    8541045bool ScriptInterface::SetProperty_(jsval obj, const wchar_t* name, jsval value, bool constant, bool enumerate)
    8551046{
    856     uintN attrs = 0;
     1047    JSAutoRequest rq(m->m_cx);
     1048    uint attrs = 0;
    8571049    if (constant)
    8581050        attrs |= JSPROP_READONLY | JSPROP_PERMANENT;
    8591051    if (enumerate)
    8601052        attrs |= JSPROP_ENUMERATE;
    8611053
    862     if (! JSVAL_IS_OBJECT(obj))
     1054    if ( JSVAL_IS_PRIMITIVE(obj))
    8631055        return false;
    8641056    JSObject* object = JSVAL_TO_OBJECT(obj);
    8651057
     
    8711063
    8721064bool ScriptInterface::SetPropertyInt_(jsval obj, int name, jsval value, bool constant, bool enumerate)
    8731065{
    874     uintN attrs = 0;
     1066    JSAutoRequest rq(m->m_cx);
     1067    uint attrs = 0;
    8751068    if (constant)
    8761069        attrs |= JSPROP_READONLY | JSPROP_PERMANENT;
    8771070    if (enumerate)
    8781071        attrs |= JSPROP_ENUMERATE;
    8791072
    880     if (! JSVAL_IS_OBJECT(obj))
     1073    if ( JSVAL_IS_PRIMITIVE(obj))
    8811074        return false;
    8821075    JSObject* object = JSVAL_TO_OBJECT(obj);
    8831076
     
    8861079    return true;
    8871080}
    8881081
    889 bool ScriptInterface::GetProperty_(jsval obj, const char* name, jsval& out)
     1082bool ScriptInterface::GetProperty_(jsval obj, const char* name, JS::MutableHandleValue out)
    8901083{
    891     if (! JSVAL_IS_OBJECT(obj))
     1084    JSAutoRequest rq(m->m_cx);
     1085    if ( JSVAL_IS_PRIMITIVE(obj))
    8921086        return false;
    8931087    JSObject* object = JSVAL_TO_OBJECT(obj);
    8941088
    895     if (!JS_GetProperty(m->m_cx, object, name, &out))
     1089    if (!JS_GetProperty(m->m_cx, object, name, out.address()))
    8961090        return false;
    8971091    return true;
    8981092}
    8991093
    900 bool ScriptInterface::GetPropertyInt_(jsval obj, int name, jsval& out)
     1094bool ScriptInterface::GetPropertyInt_(jsval obj, int name, JS::MutableHandleValue out)
    9011095{
    902     if (! JSVAL_IS_OBJECT(obj))
     1096    JSAutoRequest rq(m->m_cx);
     1097    if ( JSVAL_IS_PRIMITIVE(obj))
    9031098        return false;
    9041099    JSObject* object = JSVAL_TO_OBJECT(obj);
    9051100
    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()))
    9071102        return false;
    9081103    return true;
    9091104}
    9101105
    9111106bool ScriptInterface::HasProperty(jsval obj, const char* name)
    9121107{
    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;
    9151112    JSObject* object = JSVAL_TO_OBJECT(obj);
    9161113
    9171114    JSBool found;
    9181115    if (!JS_HasProperty(m->m_cx, object, name, &found))
    919         return false;
    920     return (found != JS_FALSE);
     1116        return JS_FALSE;
     1117    return found;
    9211118}
    9221119
    923 bool ScriptInterface::EnumeratePropertyNamesWithPrefix(jsval obj, const char* prefix, std::vector<std::string>& out)
     1120bool ScriptInterface::EnumeratePropertyNamesWithPrefix(JS::HandleObject obj, const char* prefix, std::vector<std::string>& out)
    9241121{
    925     utf16string prefix16 (prefix, prefix+strlen(prefix));
     1122    JSAutoRequest rq(m->m_cx);
     1123    if (obj.get() == 0x0)
     1124        return true;
    9261125
    927     if (! JSVAL_IS_OBJECT(obj))
    928         return false; // TODO: log error messages
     1126//  if ( obj.get().isPrimitive() )
     1127//      return false; // TODO: log error messages
    9291128
    930     JSObject* it = JS_NewPropertyIterator(m->m_cx, JSVAL_TO_OBJECT(obj));
     1129    JSObject* it = JS_NewPropertyIterator(m->m_cx, obj.get());
    9311130    if (!it)
    9321131        return false;
    9331132
     
    9431142            continue; // ignore integer properties
    9441143
    9451144        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        }
    9501156    }
    9511157
    9521158    // Recurse up the prototype chain
    953     JSObject* 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()))
    9551161    {
    956         if (! EnumeratePropertyNamesWithPrefix(OBJECT_TO_JSVAL(prototype), prefix, out))
     1162        if (! EnumeratePropertyNamesWithPrefix(prototype, prefix, out))
    9571163            return false;
    9581164    }
    9591165
    9601166    return true;
    9611167}
    9621168
    963 bool ScriptInterface::SetPrototype(jsval obj, jsval proto)
     1169bool ScriptInterface::SetPrototype(JS::HandleObject obj, JS::HandleObject proto)
    9641170{
    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);
    9681175}
    9691176
    9701177bool ScriptInterface::FreezeObject(jsval obj, bool deep)
    9711178{
    972     if (!JSVAL_IS_OBJECT(obj))
     1179    JSAutoRequest rq(m->m_cx);
     1180    if (JSVAL_IS_PRIMITIVE(obj))
    9731181        return false;
    9741182
    9751183    if (deep)
     
    9801188
    9811189bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code)
    9821190{
    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;
    9881194
    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    );
    9931200    if (!func)
    9941201        return false;
    9951202
    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());
    9981205
    9991206    return ok ? true : false;
    10001207}
    10011208
    10021209bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code)
    10031210{
    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;
    10091214
    10101215    jsval rval;
    1011     JSBool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob,
    1012             reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uintN)(codeUtf16.length()),
     1216    bool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob,
     1217            reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint)(codeUtf16.length()),
    10131218            utf8_from_wstring(filename.string()).c_str(), lineNo, &rval);
    10141219
    1015     return ok ? true : false;
     1220    return ok;
    10161221}
    10171222
    10181223bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path)
    10191224{
     1225    JSAutoRequest rq(m->m_cx);
    10201226    if (!VfsFileExists(path))
    10211227    {
    10221228        LOGERROR(L"File '%ls' does not exist", path.string().c_str());
     
    10351241
    10361242    std::wstring code = wstring_from_utf8(file.DecodeUTF8()); // assume it's UTF-8
    10371243
    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;
    10431246
    10441247    jsval rval;
    1045     JSBool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob,
    1046             reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uintN)(codeUtf16.length()),
     1248    bool ok = JS_EvaluateUCScript(m->m_cx, m->m_glob,
     1249            reinterpret_cast<const jschar*> (codeUtf16.c_str()), (uint)(codeUtf16.length()),
    10471250            utf8_from_wstring(path.string()).c_str(), lineNo, &rval);
    10481251
    1049     return ok ? true : false;
     1252    return ok;
    10501253}
    10511254
    10521255bool ScriptInterface::Eval(const char* code)
     
    10571260
    10581261bool ScriptInterface::Eval_(const char* code, jsval& rval)
    10591262{
     1263    JSAutoRequest rq(m->m_cx);
    10601264    utf16string codeUtf16(code, code+strlen(code));
    10611265
    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;
    10641268}
    10651269
    10661270bool ScriptInterface::Eval_(const wchar_t* code, jsval& rval)
    10671271{
     1272    JSAutoRequest rq(m->m_cx);
    10681273    utf16string codeUtf16(code, code+wcslen(code));
    10691274
    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;
    10721277}
    10731278
    10741279CScriptValRooted ScriptInterface::ParseJSON(const std::string& string_utf8)
    10751280{
     1281    JSAutoRequest rq(m->m_cx);
    10761282    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);
    10991286    return CScriptValRooted(m->m_cx, vp);
    11001287}
    11011288
     
    11241311
    11251312struct Stringifier
    11261313{
    1127     static JSBool callback(const jschar* buf, uint32 len, void* data)
     1314    static JSBool callback(const jschar* buf, uint32_t len, void* data)
    11281315    {
    11291316        utf16string str(buf, buf+len);
    11301317        std::wstring strw(str.begin(), str.end());
     
    11391326
    11401327struct StringifierW
    11411328{
    1142     static JSBool callback(const jschar* buf, uint32 len, void* data)
     1329    static JSBool callback(const jschar* buf, uint32_t len, void* data)
    11431330    {
    11441331        utf16string str(buf, buf+len);
    11451332        static_cast<StringifierW*>(data)->stream << std::wstring(str.begin(), str.end());
     
    11511338
    11521339std::string ScriptInterface::StringifyJSON(jsval obj, bool indent)
    11531340{
     1341    JSAutoRequest rq(m->m_cx);
    11541342    Stringifier str;
    11551343    if (!JS_Stringify(m->m_cx, &obj, NULL, indent ? INT_TO_JSVAL(2) : JSVAL_VOID, &Stringifier::callback, &str))
    11561344    {
     
    11661354
    11671355std::wstring ScriptInterface::ToString(jsval obj, bool pretty)
    11681356{
     1357    JSAutoRequest rq(m->m_cx);
    11691358    if (JSVAL_IS_VOID(obj))
    11701359        return L"(void 0)";
    11711360
     
    11781367        // Temporary disable the error reporter, so we don't print complaints about cyclic values
    11791368        JSErrorReporter er = JS_SetErrorReporter(m->m_cx, NULL);
    11801369
    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);
    11821371
    11831372        // Restore error reporter
    11841373        JS_SetErrorReporter(m->m_cx, er);
     
    12001389
    12011390void ScriptInterface::ReportError(const char* msg)
    12021391{
     1392    JSAutoRequest rq(m->m_cx);
    12031393    // JS_ReportError by itself doesn't seem to set a JS-style exception, and so
    12041394    // script callers will be unable to catch anything. So use JS_SetPendingException
    12051395    // to make sure there really is a script-level exception. But just set it to undefined
     
    12131403
    12141404bool ScriptInterface::IsExceptionPending(JSContext* cx)
    12151405{
     1406    JSAutoRequest rq(cx);
    12161407    return JS_IsExceptionPending(cx) ? true : false;
    12171408}
    12181409
    1219 JSClass* ScriptInterface::GetClass(JSContext* cx, JSObject* obj)
     1410JSClass* ScriptInterface::GetClass(JSObject* obj)
    12201411{
    1221     UNUSED2(cx); // unused if not JS_THREADSAFE
    1222 
    1223     return JS_GET_CLASS(cx, obj);
     1412    return JS_GetClass(obj);
    12241413}
    12251414
    1226 void* ScriptInterface::GetPrivate(JSContext* cx, JSObject* obj)
     1415void* ScriptInterface::GetPrivate(JSObject* obj)
    12271416{
    12281417    // TODO: use JS_GetInstancePrivate
    1229     return JS_GetPrivate(cx, obj);
     1418    return JS_GetPrivate(obj);
    12301419}
    12311420
    12321421void ScriptInterface::DumpHeap()
    12331422{
    12341423#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);
    12361425#endif
    12371426    fprintf(stderr, "# Bytes allocated: %u\n", JS_GetGCParameter(GetJSRuntime(), JSGC_BYTES));
    1238     JS_GC(m->m_cx);
     1427    JS_GC(GetJSRuntime());
    12391428    fprintf(stderr, "# Bytes allocated after GC: %u\n", JS_GetGCParameter(GetJSRuntime(), JSGC_BYTES));
    12401429}
    12411430
     1431void ScriptInterface::MaybeIncrementalRuntimeGC()
     1432{
     1433    m->m_runtime->MaybeIncrementalGC();
     1434}
     1435
    12421436void ScriptInterface::MaybeGC()
    12431437{
    12441438    JS_MaybeGC(m->m_cx);
    12451439}
    12461440
    1247 class ValueCloner
     1441void ScriptInterface::ForceGC()
    12481442{
    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}
    12541446
    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 invalidated
    1266 
    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         else
    1309         {
    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 runtimes
    1334                 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 content
    1339                 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             else
    1347             {
    1348                 // this apparently could be an XML object; ignore it
    1349             }
    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 
    13631447jsval ScriptInterface::CloneValueFromOtherContext(ScriptInterface& otherContext, jsval val)
    13641448{
    13651449    PROFILE("CloneValueFromOtherContext");
    1366 
    1367     ValueCloner cloner(otherContext, *this);
    1368     return cloner.GetOrClone(val);
     1450    shared_ptr<StructuredClone> structuredClone = otherContext.WriteStructuredClone(val);
     1451    jsval clone = ReadStructuredClone(structuredClone);
     1452    return clone;
    13691453}
    13701454
    13711455ScriptInterface::StructuredClone::StructuredClone() :
    1372     m_Context(NULL), m_Data(NULL), m_Size(0)
     1456    m_Data(NULL), m_Size(0)
    13731457{
    13741458}
    13751459
    13761460ScriptInterface::StructuredClone::~StructuredClone()
    13771461{
    13781462    if (m_Data)
    1379         JS_free(m_Context, m_Data);
     1463        JS_ClearStructuredClone(m_Data, m_Size);
    13801464}
    13811465
    13821466shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClone(jsval v)
    13831467{
    1384     uint64* data = NULL;
     1468    JSAutoRequest rq(m->m_cx);
     1469    uint64_t* data = NULL;
    13851470    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))
    13871472    {
    13881473        debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!");
    13891474        return shared_ptr<StructuredClone>();
    13901475    }
    13911476
    13921477    shared_ptr<StructuredClone> ret (new StructuredClone);
    1393     ret->m_Context = m->m_cx;
    13941478    ret->m_Data = data;
    13951479    ret->m_Size = nbytes;
    13961480    return ret;
     
    13981482
    13991483jsval ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& ptr)
    14001484{
     1485    JSAutoRequest rq(m->m_cx);
    14011486    jsval ret = JSVAL_VOID;
    14021487    JS_ReadStructuredClone(m->m_cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, &ret, NULL, NULL);
    14031488    return ret;
  • source/scriptinterface/ScriptInterface.h

     
    2525#include "ScriptTypes.h"
    2626#include "ScriptVal.h"
    2727
    28 #include "js/jsapi.h"
    29 
    3028#include "ps/Errors.h"
    3129ERROR_GROUP(Scripting);
    3230ERROR_TYPE(Scripting, SetupFailed);
     
    115113        void* pCBData; // meant to be used as the "this" object for callback functions
    116114    } m_CxPrivate;
    117115
     116    void Tick();
    118117    void SetCallbackData(void* pCBData);
    119118    static CxPrivate* GetScriptInterfaceAndCBData(JSContext* cx);
    120119
     
    140139     * Call a constructor function, equivalent to JS "new ctor(arg)".
    141140     * @return The new object; or JSVAL_VOID on failure, and logs an error message
    142141     */
    143     jsval CallConstructor(jsval ctor, jsval arg);
     142    jsval CallConstructor(jsval ctor, int argc, jsval argv);
    144143
    145144    /**
    146145     * Create an object as with CallConstructor except don't actually execute the
     
    255254     */
    256255    bool HasProperty(jsval obj, const char* name);
    257256
    258     bool EnumeratePropertyNamesWithPrefix(jsval obj, const char* prefix, std::vector<std::string>& out);
     257    bool EnumeratePropertyNamesWithPrefix(JS::HandleObject obj, const char* prefix, std::vector<std::string>& out);
    259258
    260     bool SetPrototype(jsval obj, jsval proto);
     259    bool SetPrototype(JS::HandleObject obj, JS::HandleObject proto);
    261260
    262261    bool FreezeObject(jsval obj, bool deep);
    263262
     
    341340     * 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
    342341     */
    343342    void MaybeGC();
     343   
     344    void MaybeIncrementalRuntimeGC();
     345   
     346    void ForceGC();
    344347
     348    bool MathRandom(double& nbr);
     349
    345350    /**
    346351     * Structured clones are a way to serialize 'simple' JS values into a buffer
    347352     * that can safely be passed between contexts and runtimes and threads.
     
    355360    public:
    356361        StructuredClone();
    357362        ~StructuredClone();
    358         JSContext* m_Context;
    359         uint64* m_Data;
     363        uint64_t* m_Data;
    360364        size_t m_Size;
    361365    };
    362366
     
    371375    bool SetProperty_(jsval obj, const char* name, jsval value, bool readonly, bool enumerate);
    372376    bool SetProperty_(jsval obj, const wchar_t* name, jsval value, bool readonly, bool enumerate);
    373377    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);
    376380    static bool IsExceptionPending(JSContext* cx);
    377     static JSClass* GetClass(JSContext* cx, JSObject* obj);
    378     static void* GetPrivate(JSContext* cx, JSObject* obj);
     381    static JSClass* GetClass(JSObject* obj);
     382    static void* GetPrivate(JSObject* obj);
    379383
    380384    class CustomType
    381385    {
     
    387391    void Register(const char* name, JSNative fptr, size_t nargs);
    388392    std::auto_ptr<ScriptInterface_impl> m;
    389393   
     394    boost::rand48* m_rng;
    390395    std::map<std::string, CustomType> m_CustomObjectTypes;
    391396
    392397// The nasty macro/template bits are split into a separate file so you don't have to look at them
     
    531536template<typename T>
    532537bool ScriptInterface::GetProperty(jsval obj, const char* name, T& out)
    533538{
    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))
    536543        return false;
    537     return FromJSVal(GetContext(), val, out);
     544    return FromJSVal(cx, val, out);
    538545}
    539546
    540547template<typename T>
    541548bool ScriptInterface::GetPropertyInt(jsval obj, int name, T& out)
    542549{
    543     jsval val;
    544     if (! GetPropertyInt_(obj, name, val))
     550    JSAutoRequest rq(GetContext());
     551    JS::RootedValue val(GetContext());
     552    if (! GetPropertyInt_(obj, name, &val))
    545553        return false;
    546554    return FromJSVal(GetContext(), val, out);
    547555}
  • source/scriptinterface/ScriptStats.cpp

     
    2121
    2222#include "scriptinterface/ScriptInterface.h"
    2323
    24 #include "js/jsapi.h"
    25 
    2624CScriptStatsTable* g_ScriptStatsTable;
    2725
    2826enum
  • source/scriptinterface/ScriptTypes.h

     
    1818#ifndef INCLUDED_SCRIPTTYPES
    1919#define INCLUDED_SCRIPTTYPES
    2020
    21 #ifdef _WIN32
    22 # define XP_WIN
    23 # ifndef WIN32
    24 #  define WIN32 // SpiderMonkey expects this
    25 # endif
    26 
    27 // The jsval struct type causes crashes due to weird miscompilation
    28 // issues in (at least) VC2008, so force it to be the less-type-safe
    29 // non-struct type instead
    30 # define JS_NO_JSVAL_JSID_STRUCT_TYPES
    31 
    32 // Make JS think the int8_t etc types are defined, since wposix_types.h emulates
    33 // the ones that are needed and this avoids conflicting definitions
    34 # define JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES
    35 
    36 #else // If not Windows, then Unix:
    37 
    38 # define XP_UNIX
    39 
    40 // In DEBUG mode, jsval defaults to struct types. Normally we build separate
    41 // debug/release mode versions of the library, but when using --with-system-mozjs185
    42 // it's always a release mode library, so we have to disable struct types for
    43 // ABI compatibility
    44 # if defined(DEBUG) && defined(WITH_SYSTEM_MOZJS185)
    45 #  define JS_NO_JSVAL_JSID_STRUCT_TYPES
    46 # endif
    47 
    48 #endif
    49 // (we don't support XP_OS2 or XP_BEOS)
    50 
    51 
    5221// Guess whether the library was compiled with the release-mode or debug-mode ABI
    5322// (for JS_DumpHeap etc)
    54 #if defined(DEBUG) && !defined(WITH_SYSTEM_MOZJS185)
     23#if defined(DEBUG) && !defined(WITH_SYSTEM_MOZJS24)
    5524# define MOZJS_DEBUG_ABI 1
    5625#else
    5726# define MOZJS_DEBUG_ABI 0
    5827#endif
    5928
    60 
    61 // SpiderMonkey wants the DEBUG flag
    62 #ifndef NDEBUG
    63 # ifndef DEBUG
    64 #  define DEBUG
    65 # endif
    66 #endif
    67 
    6829// 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
    7036# pragma GCC diagnostic ignored "-Wunused-parameter"
    7137# 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
    7243#endif
    7344#if MSC_VERSION
    7445# pragma warning(push)
     
    7647# pragma warning(disable:4100) // "unreferenced formal parameter"
    7748#endif
    7849
    79 #include "js/jsapi.h"
     50#include "jspubtd.h"
     51#include "jsapi.h"
    8052
     53
    8154#if MSC_VERSION
    8255# pragma warning(pop)
    8356#endif
    8457#if GCC_VERSION >= 402
    8558# pragma GCC diagnostic warning "-Wunused-parameter"
    8659# 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"
    8766#endif
    8867
    89 #if JS_VERSION != 185
    90 #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.
    9170#error The only version that works is the one in the libraries/spidermonkey/ directory,
    9271#error and it will not work with a typical system-installed version.
    9372#error Make sure you have got all the right files and include paths.
    9473#endif
    9574
     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
    9685class ScriptInterface;
    9786class CScriptVal;
    9887class CScriptValRooted;
  • source/scriptinterface/ScriptVal.cpp

     
    1717
    1818#include "precompiled.h"
    1919
     20#include "ScriptInterface.h"
    2021#include "ScriptVal.h"
    2122
    22 #include "js/jsapi.h"
    2323
    2424struct Unrooter
    2525{
    2626    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    }
    2832    JSContext* cx;
    2933};
    3034
    3135CScriptValRooted::CScriptValRooted(JSContext* cx, jsval val)
    3236{
     37    JSAutoRequest rq(cx);
    3338    jsval* p = new jsval(val);
    3439    JS_AddNamedValueRoot(cx, p, "CScriptValRooted");
    3540    m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx));
     
    3742
    3843CScriptValRooted::CScriptValRooted(JSContext* cx, CScriptVal val)
    3944{
     45    JSAutoRequest rq(cx);
    4046    jsval* p = new jsval(val.get());
    4147    JS_AddNamedValueRoot(cx, p, "CScriptValRooted");
    4248    m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx));
     
    6470{
    6571    return !m_Val;
    6672}
    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() const
    80 {
    81     return m_IdArray;
    82 }
    83 
    84 size_t AutoJSIdArray::length() const
    85 {
    86     if (!m_IdArray)
    87         return 0;
    88     return m_IdArray->length;
    89 }
    90 
    91 jsid AutoJSIdArray::operator[](size_t i) const
    92 {
    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

     
    7878    boost::shared_ptr<jsval> m_Val;
    7979};
    8080
    81 /**
    82  * RAII wrapper for JSIdArray*
    83  */
    84 class AutoJSIdArray
    85 {
    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 
    10081#endif // INCLUDED_SCRIPTVAL
  • source/scriptinterface/tests/test_ScriptConversions.h

     
    2323#include "maths/MathUtil.h"
    2424#include "ps/CLogger.h"
    2525
    26 #include "js/jsapi.h"
     26#include "jsapi.h"
    2727
    2828class TestScriptConversions : public CxxTest::TestSuite
    2929{
     
    3232    {
    3333        ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime());
    3434        JSContext* cx = script.GetContext();
     35        JSAutoRequest rq(cx);
    3536
    3637        jsval v1 = ScriptInterface::ToJSVal(cx, value);
    3738
    3839        // We want to convert values to strings, but can't just call toSource() on them
    3940        // since they might not be objects. So just use uneval.
    4041        std::string source;
    41         TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalObject(cx)), "uneval", CScriptVal(v1), source));
     42        TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalForScopeChain(cx)), "uneval", CScriptVal(v1), source));
    4243
    4344        TS_ASSERT_STR_EQUALS(source, expected);
    4445    }
     
    4849    {
    4950        ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime());
    5051        JSContext* cx = script.GetContext();
     52        JSAutoRequest rq(cx);
    5153
    5254        jsval v1 = ScriptInterface::ToJSVal(cx, value);
    5355
    5456        std::string source;
    55         TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalObject(cx)), "uneval", CScriptVal(v1), source));
     57        TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalForScopeChain(cx)), "uneval", CScriptVal(v1), source));
    5658
    5759        if (expected)
    5860            TS_ASSERT_STR_EQUALS(source, expected);
     
    101103
    102104        roundtrip<std::string>("", "\"\"");
    103105        roundtrip<std::string>("test", "\"test\"");
    104         roundtrip<std::string>(s1, "\"t\\0st\"");
     106        roundtrip<std::string>(s1, "\"t\\x00st\"");
    105107        // TODO: should test non-ASCII strings
    106108
    107109        roundtrip<std::wstring>(L"", "\"\"");
    108110        roundtrip<std::wstring>(L"test", "\"test\"");
    109         roundtrip<std::wstring>(w1, "\"t\\0st\"");
     111        roundtrip<std::wstring>(w1, "\"t\\x00st\"");
    110112        // TODO: should test non-ASCII strings
    111113
    112114        convert_to<const char*>("", "\"\"");
     
    123125    {
    124126        ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime());
    125127        JSContext* cx = script.GetContext();
     128        JSAutoRequest rq(cx);
    126129
    127130        TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 0)));
    128131
     
    146149
    147150        ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime());
    148151        JSContext* cx = script.GetContext();
     152        JSAutoRequest rq(cx);
    149153
    150154        float f = 0;
    151155        TS_ASSERT(ScriptInterface::FromJSVal(cx, ScriptInterface::ToJSVal(cx, NAN), f));
  • source/scriptinterface/tests/test_ScriptInterface.h

     
    6161
    6262    void test_clone_basic()
    6363    {
    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);
    6667
    6768        CScriptVal obj1;
    6869        TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", obj1));
     
    7879    {
    7980        // The tests should be run with JS_SetGCZeal so this can try to find GC bugs
    8081
    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);
    8385
    8486        CScriptVal obj1;
    8587        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));
     
    8890
    8991        std::string source;
    9092        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}}})");
    9294    }
    9395
    9496    void test_clone_cyclic()
    9597    {
    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);
    98101
    99102        CScriptVal obj1;
    100103        TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", obj1));
    101104
    102105        CScriptVal obj2 = script2.CloneValueFromOtherContext(script1, obj1.get());
    103106
    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());
    107120    }
    108121
    109122    void test_random()
  • source/scriptinterface/tests/test_ScriptVal.h

     
    2020#include "scriptinterface/ScriptInterface.h"
    2121#include "scriptinterface/ScriptVal.h"
    2222
    23 #include "js/jsapi.h"
     23#include "jsapi.h"
    2424
    2525class TestScriptVal : public CxxTest::TestSuite
    2626{
     
    2929    {
    3030        ScriptInterface script("Test", "Test", ScriptInterface::CreateRuntime());
    3131        JSContext* cx = script.GetContext();
     32        JSAutoRequest rq(cx);
    3233
    3334        JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
    3435        TS_ASSERT(obj);
    3536
    3637        CScriptValRooted root(cx, OBJECT_TO_JSVAL(obj));
    3738
    38         JS_GC(cx);
     39        JS_GC(script.GetJSRuntime());
    3940
    4041        jsval val = INT_TO_JSVAL(123);
    4142        TS_ASSERT(JS_SetProperty(cx, obj, "test", &val));
    4243
    43         JS_GC(cx);
     44        JS_GC(script.GetJSRuntime());
    4445
    4546        jsval rval;
    4647        TS_ASSERT(JS_GetProperty(cx, obj, "test", &rval));
  • source/simulation2/Simulation2.cpp

     
    1919
    2020#include "Simulation2.h"
    2121
     22#include "scriptinterface/ScriptInterface.h"
     23
    2224#include "simulation2/MessageTypes.h"
    2325#include "simulation2/system/ComponentManager.h"
    2426#include "simulation2/system/ParamNode.h"
     
    155157    }
    156158
    157159    int ProgressiveLoad();
     160
     161    void Tick();
    158162    void Update(int turnLength, const std::vector<SimulationCommand>& commands);
    159163    static void UpdateComponents(CSimContext& simContext, fixed turnLengthFixed, const std::vector<SimulationCommand>& commands);
    160164    void Interpolate(float simFrameLength, float frameOffset, float realFrameLength);
     
    336340    debug_warn(L"Serialization test failure");
    337341}
    338342
     343void CSimulation2Impl::Tick()
     344{
     345    m_ComponentManager.Tick();
     346}
     347
    339348void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationCommand>& commands)
    340349{
    341350    PROFILE3("sim update");
     
    451460    // Run the GC occasionally
    452461    // (TODO: we ought to schedule this for a frame where we're not
    453462    // running the sim update, to spread the load)
    454     if (m_TurnNumber % 10 == 0)
    455         m_ComponentManager.GetScriptInterface().MaybeGC();
     463    if (m_TurnNumber % 1 == 0)
     464        m_ComponentManager.GetScriptInterface().MaybeIncrementalRuntimeGC();
    456465
    457466    if (m_EnableOOSLog)
    458467        DumpState();
     
    637646    return m->m_ComponentManager.GetEntitiesWithInterfaceUnordered(iid);
    638647}
    639648
     649void CSimulation2::Tick()
     650{
     651    m->Tick();
     652}
     653
    640654const CSimContext& CSimulation2::GetSimContext() const
    641655{
    642656    return m->m_SimContext;
  • source/simulation2/Simulation2.h

     
    5353    ~CSimulation2();
    5454
    5555    void EnableOOSLog();
     56    void Tick();
    5657    void EnableSerializationTest();
    5758
    5859    /**
  • source/simulation2/components/CCmpAIManager.cpp

     
    152152                ENSURE(m_Worker.m_HasLoadedEntityTemplates);
    153153                m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false);
    154154
    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));
    156158            }
    157159            else
    158160            {
     
    209211    };
    210212
    211213    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)),
    218215        m_TurnNum(0),
    219216        m_CommandsComputed(true),
    220217        m_HasLoadedEntityTemplates(false),
     
    305302    static void ForceGC(ScriptInterface::CxPrivate* pCxPrivate)
    306303    {
    307304        PROFILE3("AI compute GC");
    308         JS_GC(pCxPrivate->pScriptInterface->GetContext());
     305        JS_GC(pCxPrivate->pScriptInterface->GetJSRuntime());
    309306    }
    310307   
    311308    /**
     
    408405            m_ScriptInterface->Eval("({})", fakeTech);
    409406            m_ScriptInterface->SetProperty(settings.get(), "techTemplates", fakeTech, false);
    410407        }
    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)));
    412412   
    413413       
    414414        if (m_SharedAIObj.undefined())
     
    430430        if (!m_HasSharedComponent)
    431431            m_HasSharedComponent = ai->m_UseSharedComponent;
    432432
    433         m_ScriptInterface->MaybeGC();
    434 
    435433        m_Players.push_back(ai);
    436434
    437435        return true;
     
    453451            m_ScriptInterface->SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);
    454452
    455453            m_ScriptInterface->CallFunctionVoid(m_SharedAIObj.get(), "init", state);
    456             m_ScriptInterface->MaybeGC();
    457454           
    458455            for (size_t i = 0; i < m_Players.size(); ++i)
    459456            {
     
    706703    }
    707704
    708705    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    {           
    723707        // Deserialize the game state, to pass to the AI's HandleMessage
    724708        CScriptVal state;
    725709        {
     
    753737            else
    754738                m_Players[i]->Run(state, m_Players[i]->m_Player);
    755739        }
    756 
    757         // Run GC if we are about to overflow
    758         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 clearer
    767         // 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         }*/
    773740    }
    774741
    775742    shared_ptr<ScriptRuntime> m_ScriptRuntime;
  • source/simulation2/components/ICmpFootprint.cpp

     
    3838
    3939    if (shape == CIRCLE)
    4040    {
    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());
    4747    }
    4848    else
    4949    {
    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());
    5858    }
    5959
    6060    return OBJECT_TO_JSVAL(obj);
  • source/simulation2/components/tests/test_CommandQueue.h

     
    3434
    3535    void test_basic()
    3636    {
    37         ComponentTestHelper test;
     37        ComponentTestHelper test(ScriptInterface::CreateRuntime());
    3838
    3939        std::vector<SimulationCommand> empty;
    4040
  • source/simulation2/components/tests/test_ObstructionManager.h

     
    6868        ent3z = ent2z + ent2r + ent3r; // ensure it just touches the border of ent2
    6969        ent3g = ent3;
    7070
    71         testHelper = new ComponentTestHelper;
     71        testHelper = new ComponentTestHelper(ScriptInterface::CreateRuntime());
    7272        cmp = testHelper->Add<ICmpObstructionManager>(CID_ObstructionManager, "");
    7373        cmp->SetBounds(fixed::FromInt(0), fixed::FromInt(0), fixed::FromInt(1000), fixed::FromInt(1000));
    7474
  • source/simulation2/components/tests/test_Position.h

     
    3939
    4040    void test_basic()
    4141    {
    42         ComponentTestHelper test;
     42        ComponentTestHelper test(ScriptInterface::CreateRuntime());
    4343
    4444        MockTerrain terrain;
    4545        test.AddMock(SYSTEM_ENTITY, IID_Terrain, terrain);
     
    111111
    112112    void test_serialize()
    113113    {
    114         ComponentTestHelper test;
     114        ComponentTestHelper test(ScriptInterface::CreateRuntime());
    115115
    116116        MockTerrain terrain;
    117117        test.AddMock(SYSTEM_ENTITY, IID_Terrain, terrain);
  • source/simulation2/components/tests/test_RangeManager.h

     
    7777
    7878    void test_basic()
    7979    {
    80         ComponentTestHelper test;
     80        ComponentTestHelper test(ScriptInterface::CreateRuntime());
    8181
    8282        ICmpRangeManager* cmp = test.Add<ICmpRangeManager>(CID_RangeManager, "");
    8383
  • source/simulation2/scripting/EngineScriptConversions.cpp

     
    3434
    3535template<> jsval ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, IComponent* const& val)
    3636{
     37    JSAutoRequest rq(cx);
    3738    if (val == NULL)
    3839        return JSVAL_NULL;
    3940
     
    5859        LOGERROR(L"Failed to construct IComponent script object");
    5960        return JSVAL_VOID;
    6061    }
    61     JS_SetPrivate(cx, obj, static_cast<void*>(val));
     62    JS_SetPrivate(obj, static_cast<void*>(val));
    6263
    6364    return OBJECT_TO_JSVAL(obj);
    6465}
    6566
    6667template<> jsval ScriptInterface::ToJSVal<CParamNode>(JSContext* cx, CParamNode const& val)
    6768{
     69    JSAutoRequest rq(cx);
    6870    jsval rval = val.ToJSVal(cx, true);
    6971
    7072    // Prevent modifications to the object, so that it's safe to share between
    7173    // components and to reconstruct on deserialization
    72     if (JSVAL_IS_OBJECT(rval))
     74    if (!JSVAL_IS_PRIMITIVE(rval))
    7375        JS_DeepFreezeObject(cx, JSVAL_TO_OBJECT(rval));
    7476
    7577    return rval;
     
    8587
    8688template<> bool ScriptInterface::FromJSVal<CColor>(JSContext* cx, jsval v, CColor& out)
    8789{
    88     if (!JSVAL_IS_OBJECT(v))
     90    if (JSVAL_IS_PRIMITIVE(v))
    8991        FAIL("jsval not an object");
    9092
     93    JSAutoRequest rq(cx);
    9194    JSObject* obj = JSVAL_TO_OBJECT(v);
    9295
    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))
    95101        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))
    97103        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))
    99105        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))
    101107        FAIL("Failed to get property CColor.a");
    102108    // TODO: this probably has GC bugs if a getter returns an unrooted value
    103109
     
    106112
    107113template<> jsval ScriptInterface::ToJSVal<CColor>(JSContext* cx, CColor const& val)
    108114{
     115    JSAutoRequest rq(cx);
    109116    JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
    110117    if (!obj)
    111118        return JSVAL_VOID;
    112119
    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));
    117124
    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());
    122129
    123130    return OBJECT_TO_JSVAL(obj);
    124131}
    125132
    126133template<> bool ScriptInterface::FromJSVal<fixed>(JSContext* cx, jsval v, fixed& out)
    127134{
    128     jsdouble ret;
     135    JSAutoRequest rq(cx);
     136    double ret;
    129137    if (!JS_ValueToNumber(cx, v, &ret))
    130138        return false;
    131139    out = fixed::FromDouble(ret);
     
    134142    return true;
    135143}
    136144
    137 template<> jsval ScriptInterface::ToJSVal<fixed>(JSContext* cx, const fixed& val)
     145template<> jsval ScriptInterface::ToJSVal<fixed>(JSContext* UNUSED(cx), const fixed& val)
    138146{
    139     jsval rval = JSVAL_VOID;
    140     JS_NewNumberValue(cx, val.ToDouble(), &rval); // ignore return value
     147    jsval rval = JS_NumberValue(val.ToDouble());
    141148    return rval;
    142149}
    143150
    144151template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(JSContext* cx, jsval v, CFixedVector3D& out)
    145152{
    146     if (!JSVAL_IS_OBJECT(v))
     153    if (JSVAL_IS_PRIMITIVE(v))
    147154        return false; // TODO: report type error
     155
     156    JSAutoRequest rq(cx);
    148157    JSObject* obj = JSVAL_TO_OBJECT(v);
    149158
    150     jsval p;
     159    JS::RootedValue p(cx);
    151160
    152     if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors
     161    if (!JS_GetProperty(cx, obj, "x", p.address())) return false; // TODO: report type errors
    153162    if (!FromJSVal(cx, p, out.X)) return false;
    154163
    155     if (!JS_GetProperty(cx, obj, "y", &p)) return false;
     164    if (!JS_GetProperty(cx, obj, "y", p.address())) return false;
    156165    if (!FromJSVal(cx, p, out.Y)) return false;
    157166
    158     if (!JS_GetProperty(cx, obj, "z", &p)) return false;
     167    if (!JS_GetProperty(cx, obj, "z", p.address())) return false;
    159168    if (!FromJSVal(cx, p, out.Z)) return false;
    160169
    161170    return true;
     
    163172
    164173template<> jsval ScriptInterface::ToJSVal<CFixedVector3D>(JSContext* cx, const CFixedVector3D& val)
    165174{
     175    JSAutoRequest rq(cx);
     176
    166177    // apply the Vector3D prototype to the return value;
    167178    ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(cx);
    168179    JSObject* obj = JS_NewObject(cx, NULL, JSVAL_TO_OBJECT(pCxPrivate->pScriptInterface->GetCachedValue(ScriptInterface::CACHE_VECTOR3DPROTO).get()), NULL);
     
    170181    if (!obj)
    171182        return JSVAL_VOID;
    172183
    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));
    176187
    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());
    180191
    181192    return OBJECT_TO_JSVAL(obj);
    182193}
    183194
    184195template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(JSContext* cx, jsval v, CFixedVector2D& out)
    185196{
    186     if (!JSVAL_IS_OBJECT(v))
     197    JSAutoRequest rq(cx);
     198    if (JSVAL_IS_PRIMITIVE(v))
    187199        return false; // TODO: report type error
    188200    JSObject* obj = JSVAL_TO_OBJECT(v);
    189201
    190     jsval p;
     202    JS::RootedValue p(cx);
    191203
    192     if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors
     204    if (!JS_GetProperty(cx, obj, "x", p.address())) return false; // TODO: report type errors
    193205    if (!FromJSVal(cx, p, out.X)) return false;
    194206
    195     if (!JS_GetProperty(cx, obj, "y", &p)) return false;
     207    if (!JS_GetProperty(cx, obj, "y", p.address())) return false;
    196208    if (!FromJSVal(cx, p, out.Y)) return false;
    197209
    198210    return true;
     
    200212
    201213template<> jsval ScriptInterface::ToJSVal<CFixedVector2D>(JSContext* cx, const CFixedVector2D& val)
    202214{
     215    JSAutoRequest rq(cx);
     216
    203217    // apply the Vector2D prototype to the return value
    204218    ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(cx);
    205219    JSObject* obj = JS_NewObject(cx, NULL, JSVAL_TO_OBJECT(pCxPrivate->pScriptInterface->GetCachedValue(ScriptInterface::CACHE_VECTOR2DPROTO).get()), NULL);
     
    207221    if (!obj)
    208222        return JSVAL_VOID;
    209223
    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));
    212226
    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());
    215229
    216230    return OBJECT_TO_JSVAL(obj);
    217231}
    218232
    219 template<jsint atype, typename T> jsval ToJSVal_Grid(JSContext* cx, const Grid<T>& val)
     233template<> jsval ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, const Grid<u8>& val)
    220234{
    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);
    224240
    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));
    229244
    230     js::TypedArray *tdest = js::TypedArray::fromJSObject(darray);
    231     ENSURE(tdest->byteLength == len*sizeof(T));
    232245
    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());
    234250
    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 
    243251    return OBJECT_TO_JSVAL(obj);
    244252}
     253 
     254template<> 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));
    245265
    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());
    250270
    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);
    254272}
  • source/simulation2/scripting/MessageTypeConversions.cpp

     
    2121#include "scriptinterface/ScriptInterface.h"
    2222#include "simulation2/MessageTypes.h"
    2323
    24 #include "js/jsapi.h"
    25 
    2624#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    }
    3032
    3133#define SET_MSG_PROPERTY(name) \
    3234    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())) \
    3539            return JSVAL_VOID; \
    3640    } while (0);
    3741
    3842#define FROMJSVAL_SETUP() \
    39     if (! JSVAL_IS_OBJECT(val)) \
     43    if ( JSVAL_IS_PRIMITIVE(val)) \
    4044        return NULL; \
    4145    JSObject* obj = JSVAL_TO_OBJECT(val); \
    42     jsval prop;
     46    JS::RootedValue prop(scriptInterface.GetContext());
    4347
    4448#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())) \
    4653        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    }
    5057
    5158jsval CMessage::ToJSValCached(ScriptInterface& scriptInterface) const
    5259{
  • source/simulation2/serialization/BinarySerializer.cpp

     
    1919
    2020#include "BinarySerializer.h"
    2121
    22 #include "SerializedScriptTypes.h"
    23 
    2422#include "lib/alignment.h"
    2523#include "ps/CLogger.h"
    2624
    2725#include "scriptinterface/ScriptInterface.h"
    2826#include "scriptinterface/ScriptExtraHeaders.h" // for JSDOUBLE_IS_INT32, typed arrays
     27#include "SerializedScriptTypes.h"
    2928
    30 static u8 GetArrayType(uint32 arrayType)
     29static u8 GetArrayType(JSArrayBufferViewType arrayType)
    3130{
    3231    switch(arrayType)
    3332    {
    34     case js::TypedArray::TYPE_INT8:
     33    case js::ArrayBufferView::TYPE_INT8:
    3534        return SCRIPT_TYPED_ARRAY_INT8;
    36     case js::TypedArray::TYPE_UINT8:
     35    case js::ArrayBufferView::TYPE_UINT8:
    3736        return SCRIPT_TYPED_ARRAY_UINT8;
    38     case js::TypedArray::TYPE_INT16:
     37    case js::ArrayBufferView::TYPE_INT16:
    3938        return SCRIPT_TYPED_ARRAY_INT16;
    40     case js::TypedArray::TYPE_UINT16:
     39    case js::ArrayBufferView::TYPE_UINT16:
    4140        return SCRIPT_TYPED_ARRAY_UINT16;
    42     case js::TypedArray::TYPE_INT32:
     41    case js::ArrayBufferView::TYPE_INT32:
    4342        return SCRIPT_TYPED_ARRAY_INT32;
    44     case js::TypedArray::TYPE_UINT32:
     43    case js::ArrayBufferView::TYPE_UINT32:
    4544        return SCRIPT_TYPED_ARRAY_UINT32;
    46     case js::TypedArray::TYPE_FLOAT32:
     45    case js::ArrayBufferView::TYPE_FLOAT32:
    4746        return SCRIPT_TYPED_ARRAY_FLOAT32;
    48     case js::TypedArray::TYPE_FLOAT64:
     47    case js::ArrayBufferView::TYPE_FLOAT64:
    4948        return SCRIPT_TYPED_ARRAY_FLOAT64;
    50     case js::TypedArray::TYPE_UINT8_CLAMPED:
     49    case js::ArrayBufferView::TYPE_UINT8_CLAMPED:
    5150        return SCRIPT_TYPED_ARRAY_UINT8_CLAMPED;
    5251    default:
    5352        LOGERROR(L"Cannot serialize unrecognized typed array view: %d", arrayType);
     
    6463void CBinarySerializerScriptImpl::HandleScriptVal(jsval val)
    6564{
    6665    JSContext* cx = m_ScriptInterface.GetContext();
     66    JSAutoRequest rq(cx);
    6767
    6868    switch (JS_TypeOfValue(cx, val))
    6969    {
     
    8585            break;
    8686        }
    8787
    88         JSObject* obj = JSVAL_TO_OBJECT(val);
     88        JS::RootedObject obj(cx, JSVAL_TO_OBJECT(val));
    8989
    9090        // If we've already serialized this object, just output a reference to it
    9191        u32 tag = GetScriptBackrefTag(obj);
     
    104104
    105105            // Arrays like [1, 2, ] have an 'undefined' at the end which is part of the
    106106            // length but seemingly isn't enumerated, so store the length explicitly
    107             jsuint length = 0;
     107            uint length = 0;
    108108            if (!JS_GetArrayLength(cx, obj, &length))
    109109                throw PSERROR_Serialize_ScriptError("JS_GetArrayLength failed");
    110110            m_Serializer.NumberU32_Unbounded("array length", length);
    111111        }
    112         else if (js_IsTypedArray(obj))
     112        else if (JS_IsTypedArrayObject(obj))
    113113        {
    114114            m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_TYPED_ARRAY);
    115115
    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));
    121119
    122120            // Now handle its array buffer
    123121            // 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)));
    125123            break;
    126124        }
    127         else if (js_IsArrayBuffer(obj))
     125        else if (JS_IsArrayBufferObject(obj))
    128126        {
    129127            m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY_BUFFER);
    130128
    131             js::ArrayBuffer* arrayBuffer = js::ArrayBuffer::fromJSObject(obj);
    132 
    133129#if BYTE_ORDER != LITTLE_ENDIAN
    134130#error TODO: need to convert JS ArrayBuffer data to little-endian
    135131#endif
    136132
    137             u32 length = arrayBuffer->byteLength;
     133            u32 length = JS_GetArrayBufferByteLength(obj);
    138134            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);
    140136            break;
    141137        }
    142138        else
    143139        {
    144140            // Find type of object
    145             JSClass* jsclass = JS_GET_CLASS(cx, obj);
     141            JSClass* jsclass = JS_GetClass(obj);
    146142            if (!jsclass)
    147                 throw PSERROR_Serialize_ScriptError("JS_GET_CLASS failed");
     143                throw PSERROR_Serialize_ScriptError("JS_GetClass failed");
    148144            JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass);
    149145
    150146            if (protokey == JSProto_Object)
    151147            {
    152148                // 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());
    154151                if (!proto)
    155152                    throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed");
    156153
     
    175172                    JSBool hasCustomSerialize;
    176173                    if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize))
    177174                        throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
    178                    
     175
    179176                    if (hasCustomSerialize)
    180177                    {
    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()))
    183180                            throw PSERROR_Serialize_ScriptError("JS_LookupProperty failed");
    184181
    185182                        // If serialize is null, so don't serialize anything more
     
    199196                // Standard Number object
    200197                m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_NUMBER);
    201198                // Get primitive value
    202                 jsdouble d;
     199                double d;
    203200                if (!JS_ValueToNumber(cx, val, &d))
    204201                    throw PSERROR_Serialize_ScriptError("JS_ValueToNumber failed");
    205202                m_Serializer.NumberDouble_Unbounded("value", d);
     
    224221                JSBool b;
    225222                if (!JS_ValueToBoolean(cx, val, &b))
    226223                    throw PSERROR_Serialize_ScriptError("JS_ValueToBoolean failed");
    227                 m_Serializer.Bool("value", b == JS_TRUE);
     224                m_Serializer.Bool("value", b);
    228225                break;
    229226            }
    230227            else
     
    240237        // (Note that we don't do any rooting, because we assume nothing is going to trigger GC.
    241238        // I'm not absolute certain that's necessarily a valid assumption.)
    242239
    243         AutoJSIdArray ida (cx, JS_Enumerate(cx, obj));
    244         if (!ida.get())
     240        JS::AutoIdArray ida (cx, JS_Enumerate(cx, obj));
     241        if (!ida)
    245242            throw PSERROR_Serialize_ScriptError("JS_Enumerate failed");
    246243
    247244        m_Serializer.NumberU32_Unbounded("num props", (uint32_t)ida.length());
     
    250247        {
    251248            jsid id = ida[i];
    252249
    253             jsval idval, propval;
    254 
     250            JS::RootedValue idval(cx);
     251            JS::RootedValue propval(cx);
     252           
    255253            // Get the property name as a string
    256             if (!JS_IdToValue(cx, id, &idval))
     254            if (!JS_IdToValue(cx, id, idval.address()))
    257255                throw PSERROR_Serialize_ScriptError("JS_IdToValue failed");
    258             JSString* idstr = JS_ValueToString(cx, idval);
     256            JSString* idstr = JS_ValueToString(cx, idval.get());
    259257            if (!idstr)
    260258                throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
    261259
     
    263261
    264262            // Use LookupProperty instead of GetProperty to avoid the danger of getters
    265263            // (they might delete values and trigger GC)
    266             if (!JS_LookupPropertyById(cx, obj, id, &propval))
     264            if (!JS_LookupPropertyById(cx, obj, id, propval.address()))
    267265                throw PSERROR_Serialize_ScriptError("JS_LookupPropertyById failed");
    268266
    269267            HandleScriptVal(propval);
     
    299297    }
    300298    case JSTYPE_NUMBER:
    301299    {
    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))
    304311        {
    305312            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);
    307314        }
    308315        else
    309316        {
    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);
    326319        }
     320       
    327321        break;
    328322    }
    329323    case JSTYPE_BOOLEAN:
    330324    {
    331325        m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_BOOLEAN);
    332         JSBool b = JSVAL_TO_BOOLEAN(val);
     326        bool b = JSVAL_TO_BOOLEAN(val);
    333327        m_Serializer.NumberU8_Unbounded("value", b ? 1 : 0);
    334328        break;
    335329    }
    336     case JSTYPE_XML:
    337     {
    338         LOGERROR(L"Cannot serialise JS objects of type 'xml'");
    339         throw PSERROR_Serialize_InvalidScriptValue();
    340     }
    341330    default:
    342331    {
    343332        debug_warn(L"Invalid TypeOfValue");
     
    349338void CBinarySerializerScriptImpl::ScriptString(const char* name, JSString* string)
    350339{
    351340    JSContext* cx = m_ScriptInterface.GetContext();
     341    JSAutoRequest rq(cx);
     342
    352343    size_t length;
    353344    const jschar* chars = JS_GetStringCharsAndLength(cx, string, &length);
    354345
  • source/simulation2/serialization/StdDeserializer.cpp

     
    2525#include "scriptinterface/ScriptInterface.h"
    2626#include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays
    2727
    28 #include "js/jsapi.h"
    29 
    3028#include "lib/byte_order.h"
    3129
    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 
    5930CStdDeserializer::CStdDeserializer(ScriptInterface& scriptInterface, std::istream& stream) :
    6031    m_ScriptInterface(scriptInterface), m_Stream(stream)
    6132{
     
    138109
    139110void CStdDeserializer::FreeScriptBackrefs()
    140111{
     112    JSContext* cx = m_ScriptInterface.GetContext();
     113    JSAutoRequest rq(cx);
     114   
    141115    std::map<u32, JSObject*>::iterator it = m_ScriptBackrefs.begin();
    142116    for (; it != m_ScriptBackrefs.end(); ++it)
    143117    {
    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);
    146119    }
    147120    m_ScriptBackrefs.clear();
    148121}
     
    152125jsval CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JSObject* appendParent)
    153126{
    154127    JSContext* cx = m_ScriptInterface.GetContext();
     128   
     129    JSAutoRequest rq(cx);
    155130
    156131    uint8_t type;
    157132    NumberU8_Unbounded("type", type);
     
    192167            if (!proto)
    193168                throw PSERROR_Deserialize_ScriptError("Failed to find serializable prototype for object");
    194169
    195             JSObject* parent = JS_GetParent(cx, proto);
     170            JSObject* parent = JS_GetParent(proto);
    196171            if (!proto || !parent)
    197172                throw PSERROR_Deserialize_ScriptError();
    198173
     
    206181            JSBool hasCustomDeserialize, hasCustomSerialize;
    207182            if (!JS_HasProperty(cx, obj, "Serialize", &hasCustomSerialize) || !JS_HasProperty(cx, obj, "Deserialize", &hasCustomDeserialize))
    208183                throw PSERROR_Serialize_ScriptError("JS_HasProperty failed");
    209            
     184
    210185            if (hasCustomDeserialize)
    211186            {
    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()))
    214189                    throw PSERROR_Serialize_ScriptError("JS_LookupProperty failed");
    215190                bool hasNullSerialize = hasCustomSerialize && JSVAL_IS_NULL(serialize);
    216191
     
    241216            utf16string propname;
    242217            ReadStringUTF16("prop name", propname);
    243218
    244             jsval propval = ReadScriptVal("prop value", NULL);
     219            JS::RootedValue propval(cx, ReadScriptVal("prop value", NULL));
    245220            CScriptValRooted propvalRoot(cx, propval);
    246221
    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()))
    248223                throw PSERROR_Deserialize_ScriptError();
    249224        }
    250225
     
    266241    {
    267242        double value;
    268243        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))
    271246            throw PSERROR_Deserialize_ScriptError("JS_NewNumberValue failed");
    272247        return rval;
    273248    }
     
    275250    {
    276251        uint8_t value;
    277252        NumberU8("value", value, 0, 1);
    278         return BOOLEAN_TO_JSVAL(value ? JS_TRUE : JS_FALSE);
     253        return BOOLEAN_TO_JSVAL(value ? true : false);
    279254    }
    280255    case SCRIPT_TYPE_BACKREF:
    281256    {
     
    290265    {
    291266        double value;
    292267        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));
    296269        CScriptValRooted objRoot(cx, val);
    297270
    298271        JSObject* ctorobj;
    299         if (!JS_GetClassObject(cx, JS_GetGlobalObject(cx), JSProto_Number, &ctorobj))
     272        if (!JS_GetClassObject(cx, JS_GetGlobalForScopeChain(cx), JSProto_Number, &ctorobj))
    300273            throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
    301274
    302         JSObject* obj = JS_New(cx, ctorobj, 1, &val);
     275        JSObject* obj = JS_New(cx, ctorobj, 1, val.address());
    303276        if (!obj)
    304277            throw PSERROR_Deserialize_ScriptError("JS_New failed");
    305278        AddScriptBackref(obj);
     
    311284        ScriptString("value", str);
    312285        if (!str)
    313286            throw PSERROR_Deserialize_ScriptError();
    314         jsval val = STRING_TO_JSVAL(str);
     287        JS::RootedValue val(cx, STRING_TO_JSVAL(str));
    315288        CScriptValRooted valRoot(cx, val);
    316289
    317290        JSObject* ctorobj;
    318         if (!JS_GetClassObject(cx, JS_GetGlobalObject(cx), JSProto_String, &ctorobj))
     291        if (!JS_GetClassObject(cx, JS_GetGlobalForScopeChain(cx), JSProto_String, &ctorobj))
    319292            throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
    320293
    321         JSObject* obj = JS_New(cx, ctorobj, 1, &val);
     294        JSObject* obj = JS_New(cx, ctorobj, 1, val.address());
    322295        if (!obj)
    323296            throw PSERROR_Deserialize_ScriptError("JS_New failed");
    324297        AddScriptBackref(obj);
     
    328301    {
    329302        bool value;
    330303        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));
    333305
    334306        JSObject* ctorobj;
    335         if (!JS_GetClassObject(cx, JS_GetGlobalObject(cx), JSProto_Boolean, &ctorobj))
     307        if (!JS_GetClassObject(cx, JS_GetGlobalForScopeChain(cx), JSProto_Boolean, &ctorobj))
    336308            throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
    337309
    338         JSObject* obj = JS_New(cx, ctorobj, 1, &val);
     310        JSObject* obj = JS_New(cx, ctorobj, 1, val.address());
    339311        if (!obj)
    340312            throw PSERROR_Deserialize_ScriptError("JS_New failed");
    341313        AddScriptBackref(obj);
     
    354326
    355327        // Get buffer object
    356328        jsval bufferVal = ReadScriptVal("buffer", NULL);
    357         CScriptValRooted bufferValRoot(cx, bufferVal);
    358329
    359         if (!JSVAL_IS_OBJECT(bufferVal))
     330        if (JSVAL_IS_PRIMITIVE(bufferVal))
    360331            throw PSERROR_Deserialize_ScriptError();
    361332
    362333        JSObject* bufferObj = JSVAL_TO_OBJECT(bufferVal);
    363         if (!js_IsArrayBuffer(bufferObj))
     334        if (!JS_IsArrayBufferObject(bufferObj))
    364335            throw PSERROR_Deserialize_ScriptError("js_IsArrayBuffer failed");
    365336
    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        }
    367370        if (!arrayObj)
    368371            throw PSERROR_Deserialize_ScriptError("js_CreateTypedArrayWithBuffer failed");
    369372
     
    375378    {
    376379        u32 length;
    377380        NumberU32_Unbounded("buffer length", length);
     381        u8* bufferData = NULL;
    378382       
    379         u8* bufferData = new u8[length];
    380         RawBytes("buffer data", bufferData, length);
    381383
    382384#if BYTE_ORDER != LITTLE_ENDIAN
    383385#error TODO: need to convert JS ArrayBuffer data from little-endian
    384386#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);
    390391        AddScriptBackref(bufferObj);
    391392
    392         js::ArrayBuffer* buffer = js::ArrayBuffer::fromJSObject(bufferObj);
    393         memcpy(buffer->data, bufferData, length);
    394         delete[] bufferData;
    395 
    396393        return OBJECT_TO_JSVAL(bufferObj);
    397394    }
    398395    default:
     
    440437
    441438void CStdDeserializer::ScriptObjectAppend(const char* name, jsval& obj)
    442439{
    443     if (!JSVAL_IS_OBJECT(obj))
     440    if (JSVAL_IS_PRIMITIVE(obj))
    444441        throw PSERROR_Deserialize_ScriptError();
    445442
    446443    ReadScriptVal(name, JSVAL_TO_OBJECT(obj));
  • source/simulation2/system/ComponentManager.cpp

     
    243243
    244244    // Find all the ctor prototype's On* methods, and subscribe to the appropriate messages:
    245245
    246     CScriptVal proto;
     246    JS::RootedObject proto(componentManager->m_ScriptInterface.GetContext());
    247247    if (!componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", proto))
    248248        return; // error
    249249
    250250    std::vector<std::string> methods;
    251     if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(proto.get(), "On", methods))
     251    if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(proto, "On", methods))
    252252        return; // error
    253253
    254254    for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it)
     
    289289        {
    290290            jsval instance = eit->second->GetJSInstance();
    291291            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            }
    293296        }
    294297    }
    295298}
     
    616619    jsval obj = JSVAL_NULL;
    617620    if (ct.type == CT_Script)
    618621    {
    619         obj = m_ScriptInterface.CallConstructor(ct.ctor.get(), JSVAL_VOID);
     622        obj = m_ScriptInterface.CallConstructor(ct.ctor.get(), 0, JSVAL_VOID);
    620623        if (JSVAL_IS_VOID(obj))
    621624        {
    622625            LOGERROR(L"Script component constructor failed");
  • source/simulation2/system/ComponentManager.h

     
    9696    void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema);
    9797    void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema);
    9898
     99
     100    void Tick() { m_ScriptInterface.Tick(); };
    99101    /**
    100102     * Subscribe the current component type to the given message type.
    101103     * Each component's HandleMessage will be called on any BroadcastMessage of this message type,
  • source/simulation2/system/ComponentTest.h

     
    5252    EComponentTypeId m_Cid;
    5353
    5454public:
    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)
    5757    {
    5858        m_ComponentManager.LoadComponentTypes();
    5959    }
     
    135135        CStdSerializer std1(GetScriptInterface(), stdstr1);
    136136        m_Cmp->Serialize(std1);
    137137
    138         ComponentTestHelper test2;
     138        ComponentTestHelper test2(GetScriptInterface().GetRuntime());
    139139        // (We should never need to add any mock objects etc to test2, since deserialization
    140140        // mustn't depend on other components already existing)
    141141
  • source/simulation2/system/InterfaceScripted.h

     
    1919#define INCLUDED_INTERFACE_SCRIPTED
    2020
    2121#include "scriptinterface/ScriptInterface.h"
    22 #include "js/jsapi.h"
    2322
    2423#define BEGIN_INTERFACE_WRAPPER(iname) \
    2524    JSClass class_ICmp##iname = { \
    2625        "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 \
    3028    }; \
    3129    static JSFunctionSpec methods_ICmp##iname[] = {
    3230
     
    3533    }; \
    3634    void ICmp##iname::InterfaceInit(ScriptInterface& scriptInterface) { \
    3735        JSContext* cx = scriptInterface.GetContext(); \
    38         JSObject* global = JS_GetGlobalObject(cx); \
     36        JSAutoRequest rq(cx); \
     37        JSObject* global = JS_GetGlobalForScopeChain(cx); \
    3938        JS_InitClass(cx, global, NULL, &class_ICmp##iname, NULL, 0, NULL, methods_ICmp##iname, NULL, NULL); \
    4039    } \
    4140    JSClass* ICmp##iname::GetJSClass() const { return &class_ICmp##iname; } \
     
    4544
    4645#define DEFINE_INTERFACE_METHOD_0(scriptname, rettype, classname, methodname) \
    4746    { scriptname, \
    48         ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>, \
     47        { ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>, NULL }, \
    4948        0, \
    5049        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    5150
    5251#define DEFINE_INTERFACE_METHOD_1(scriptname, rettype, classname, methodname, arg1) \
    5352    { scriptname, \
    54         ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>, \
     53        { ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>, NULL}, \
    5554        1, \
    5655        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    5756
    5857#define DEFINE_INTERFACE_METHOD_2(scriptname, rettype, classname, methodname, arg1, arg2) \
    5958    { scriptname, \
    60         ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>, \
     59        { ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>, NULL }, \
    6160        2, \
    6261        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    6362
    6463#define DEFINE_INTERFACE_METHOD_3(scriptname, rettype, classname, methodname, arg1, arg2, arg3) \
    6564    { 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 }, \
    6766        3, \
    6867        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    6968
    7069#define DEFINE_INTERFACE_METHOD_4(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4) \
    7170    { 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 }, \
    7372        4, \
    7473        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    7574
    7675#define DEFINE_INTERFACE_METHOD_5(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5) \
    7776    { 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 }, \
    7978        5, \
    8079        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    8180
    8281#define DEFINE_INTERFACE_METHOD_6(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5, arg6) \
    8382    { 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 }, \
    8584        6, \
    8685        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    8786
    8887#define DEFINE_INTERFACE_METHOD_7(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
    8988    { 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 }, \
    9190        7, \
    9291        JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
    9392
  • source/simulation2/system/ParamNode.cpp

     
    2525#include "ps/Filesystem.h"
    2626#include "ps/XML/Xeromyces.h"
    2727
    28 #include "js/jsapi.h"
    29 
    3028#include <sstream>
    3129
    3230// Disable "'boost::algorithm::detail::is_classifiedF' : assignment operator could not be generated"
     
    328326
    329327jsval CParamNode::ConstructJSVal(JSContext* cx) const
    330328{
     329    JSAutoRequest rq(cx);
    331330    if (m_Childs.empty())
    332331    {
    333332        // Empty node - map to undefined
     
    351350
    352351    for (std::map<std::string, CParamNode>::const_iterator it = m_Childs.begin(); it != m_Childs.end(); ++it)
    353352    {
    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()))
    356355            return JSVAL_VOID; // TODO: report error
    357356    }
    358357
     
    363362        JSString* str = JS_InternUCStringN(cx, reinterpret_cast<const jschar*>(text.data()), text.length());
    364363        if (!str)
    365364            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()))
    368367            return JSVAL_VOID; // TODO: report error
    369368    }
    370369
  • source/simulation2/tests/test_ComponentManager.h

     
    594594    void test_serialization()
    595595    {
    596596        CSimContext context;
    597         CComponentManager man(context, ScriptInterface::CreateRuntime());
     597        shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime();
     598        CComponentManager man(context, runtime);
    598599        man.LoadComponentTypes();
    599600
    600601        entity_id_t ent1 = 1, ent2 = 2, ent3 = FIRST_LOCAL_ENTITY;
     
    664665        );
    665666
    666667        CSimContext context2;
    667         CComponentManager man2(context2, ScriptInterface::CreateRuntime());
     668        CComponentManager man2(context2, runtime);
    668669        man2.LoadComponentTypes();
    669670
    670671        TS_ASSERT(man2.QueryInterface(ent1, IID_Test1) == NULL);
     
    683684    void test_script_serialization()
    684685    {
    685686        CSimContext context;
    686         CComponentManager man(context, ScriptInterface::CreateRuntime());
     687        shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime();
     688       
     689        CComponentManager man(context, runtime);
    687690        ScriptTestSetup(man.m_ScriptInterface);
    688691        man.LoadComponentTypes();
    689692        TS_ASSERT(man.LoadScript(L"simulation/components/test-serialize.js"));
     
    700703
    701704        man.AddComponent(hnd1, man.LookupCID("TestScript1_values"), testParam);
    702705        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.
    703710        man.AddComponent(hnd3, man.LookupCID("TestScript1_nontree"), testParam);
     711       
    704712        man.AddComponent(hnd4, man.LookupCID("TestScript1_custom"), testParam);
    705713
    706714        TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 1234);
     
    713721        std::stringstream debugStream;
    714722        TS_ASSERT(man.DumpDebugState(debugStream, true));
    715723        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\
     725entities:\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"
    751759        );
    752760
    753761        std::stringstream stateStream;
    754762        TS_ASSERT(man.SerializeState(stateStream));
    755763
    756764        CSimContext context2;
    757         CComponentManager man2(context2, ScriptInterface::CreateRuntime());
     765        CComponentManager man2(context2, runtime);
    758766        man2.LoadComponentTypes();
    759767        TS_ASSERT(man2.LoadScript(L"simulation/components/test-serialize.js"));
    760768
     
    789797    void test_script_serialization_template()
    790798    {
    791799        CSimContext context;
    792         CComponentManager man(context, ScriptInterface::CreateRuntime());
     800        shared_ptr<ScriptRuntime> runtime = ScriptInterface::CreateRuntime();
     801       
     802        CComponentManager man(context, runtime);
    793803        man.LoadComponentTypes();
    794804        TS_ASSERT(man.LoadScript(L"simulation/components/test-serialize.js"));
    795805        man.InitSystemEntity();
     
    813823        TS_ASSERT(man.SerializeState(stateStream));
    814824
    815825        CSimContext context2;
    816         CComponentManager man2(context2, ScriptInterface::CreateRuntime());
     826        CComponentManager man2(context2, runtime);
    817827        man2.LoadComponentTypes();
    818828        TS_ASSERT(man2.LoadScript(L"simulation/components/test-serialize.js"));
    819829
  • source/simulation2/tests/test_Serializer.h

     
    574574
    575575        TestLogger logger;
    576576
    577         TS_ASSERT(script.Eval("({x:1, y:<x/>})", obj));
    578         TS_ASSERT_THROWS(serialize.ScriptVal("script", obj), PSERROR_Serialize_InvalidScriptValue);
    579 
    580577        TS_ASSERT(script.Eval("([1, 2, function () { }])", obj));
    581578        TS_ASSERT_THROWS(serialize.ScriptVal("script", obj), PSERROR_Serialize_InvalidScriptValue);
    582579    }