1
0
forked from 0ad/0ad

Upgrade SpiderMonkey to version 45.0.2, refs #4893.

- Various build changes, in particular NSPR is not needed on Unix
anymore
- Add js/Initialization.h to source/scriptinterface/ScriptEngine.h
- Use nullptr instead of JS::NullPtr(), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1164602
- Remove `JS::RuntimeOptionsRef.varObjFix`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1171177
- Remove uses of `AutoIdArray`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1191529
- `JS_InternUCStringN` has been renamed, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1178581
- `JS::Evaluate` now takes scope chains explicitly, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1097987
- Array functions (such as `JS_IsArrayObject`) are fallible and output
to params, see https://bugzilla.mozilla.org/show_bug.cgi?id=f3d35d8
- Remove `JSCLASS_CACHED_PROTO_WIDTH` workaround in our code, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1236373
- Remove compile'n go (`setCompileAndGo`) and replace it by
`setIsRunOnce` which will become the default in the future, see
https://bugzilla.mozilla.org/show_bug.cgi?id=679939
- Mark shared memory in direct access operations
(`JS_GetUint16ArrayData` and `JS_GetUint8ArrayData`), see
https://bugzilla.mozilla.org/show_bug.cgi?id=1176214
- Use new `JS::ObjectOpResult`, see
https://bugzilla.mozilla.org/show_bug.cgi?id=1113369

Thanks to wraitii, elexis, Krinkle and historic_bruno for contributions
and comments, and to gentz, madpilot, s0600204 and Stan for testing and
indirect contributions.

Differential Revision: https://code.wildfiregames.com/D1510
This was SVN commit r22627.
This commit is contained in:
Nicolas Auvray 2019-08-07 22:37:43 +00:00
parent 7876ca7acb
commit 64b477625d
18 changed files with 99 additions and 135 deletions

View File

@ -533,9 +533,9 @@ extern_lib_defs = {
}, },
spidermonkey = { spidermonkey = {
compile_settings = function() compile_settings = function()
if _OPTIONS["with-system-mozjs38"] then if _OPTIONS["with-system-mozjs45"] then
if not _OPTIONS["android"] then if not _OPTIONS["android"] then
pkgconfig.add_includes("mozjs-38") pkgconfig.add_includes("mozjs-45")
end end
else else
if os.istarget("windows") then if os.istarget("windows") then
@ -553,31 +553,25 @@ extern_lib_defs = {
end end
end, end,
link_settings = function() link_settings = function()
if _OPTIONS["with-system-mozjs38"] then if _OPTIONS["with-system-mozjs45"] then
if _OPTIONS["android"] then if _OPTIONS["android"] then
links { "mozjs-38" } links { "mozjs-45" }
else else
pkgconfig.add_links("nspr") pkgconfig.add_links("mozjs-45")
pkgconfig.add_links("mozjs-38")
end end
else else
if os.istarget("macosx") then
add_default_lib_paths("nspr")
links { "nspr4", "plc4", "plds4" }
end
filter { "Debug", "action:vs2013" } filter { "Debug", "action:vs2013" }
links { "mozjs38-ps-debug-vc120" } links { "mozjs45-ps-debug-vc120" }
filter { "Release", "action:vs2013" } filter { "Release", "action:vs2013" }
links { "mozjs38-ps-release-vc120" } links { "mozjs45-ps-release-vc120" }
filter { "Debug", "action:vs2015" } filter { "Debug", "action:vs2015" }
links { "mozjs38-ps-debug-vc140" } links { "mozjs45-ps-debug-vc140" }
filter { "Release", "action:vs2015" } filter { "Release", "action:vs2015" }
links { "mozjs38-ps-release-vc140" } links { "mozjs45-ps-release-vc140" }
filter { "Debug", "action:not vs*" } filter { "Debug", "action:not vs*" }
links { "mozjs38-ps-debug" } links { "mozjs45-ps-debug" }
filter { "Release", "action:not vs*" } filter { "Release", "action:not vs*" }
links { "mozjs38-ps-release" } links { "mozjs45-ps-release" }
filter { } filter { }
add_source_lib_paths("spidermonkey") add_source_lib_paths("spidermonkey")
end end

View File

@ -33,11 +33,12 @@ if [ "$preserve_libs" != "true" ]; then
(cd ../../libraries/source/fcollada/src && rm -rf ./output) (cd ../../libraries/source/fcollada/src && rm -rf ./output)
(cd ../../libraries/source/nvtt/src && rm -rf ./build) (cd ../../libraries/source/nvtt/src && rm -rf ./build)
(cd ../../libraries/source/spidermonkey && rm -f .already-built) (cd ../../libraries/source/spidermonkey && rm -f .already-built)
(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-38.0.0) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-45.0.2)
fi fi
# Still delete the directory of previous SpiderMonkey versions to # Still delete the directory of previous SpiderMonkey versions to
# avoid wasting disk space if people clean workspaces after updating. # avoid wasting disk space if people clean workspaces after updating.
(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-38.0.0)
(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs31) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs31)
(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs24) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs24)

View File

@ -39,8 +39,6 @@ NETTLE_VERSION="nettle-3.5.1"
# NOTE: remember to also update LIB_URL below when changing version # NOTE: remember to also update LIB_URL below when changing version
GNUTLS_VERSION="gnutls-3.6.8" GNUTLS_VERSION="gnutls-3.6.8"
GLOOX_VERSION="gloox-1.0.22" GLOOX_VERSION="gloox-1.0.22"
# NSPR is necessary for threadsafe Spidermonkey
NSPR_VERSION="4.15"
# OS X only includes part of ICU, and only the dylib # OS X only includes part of ICU, and only the dylib
# NOTE: remember to also update LIB_URL below when changing version # NOTE: remember to also update LIB_URL below when changing version
ICU_VERSION="icu4c-59_1" ICU_VERSION="icu4c-59_1"
@ -49,7 +47,7 @@ MINIUPNPC_VERSION="miniupnpc-2.0.20180222"
SODIUM_VERSION="libsodium-1.0.16" SODIUM_VERSION="libsodium-1.0.16"
# -------------------------------------------------------------- # --------------------------------------------------------------
# Bundled with the game: # Bundled with the game:
# * SpiderMonkey 38 # * SpiderMonkey 45
# * NVTT # * NVTT
# * FCollada # * FCollada
# -------------------------------------------------------------- # --------------------------------------------------------------
@ -750,41 +748,6 @@ else
fi fi
popd > /dev/null popd > /dev/null
# --------------------------------------------------------------
echo -e "Building NSPR..."
LIB_VERSION="${NSPR_VERSION}"
LIB_ARCHIVE="nspr-$LIB_VERSION.tar.gz"
LIB_DIRECTORY="nspr-$LIB_VERSION"
LIB_URL="https://ftp.mozilla.org/pub/mozilla.org/nspr/releases/v$LIB_VERSION/src/"
mkdir -p nspr
pushd nspr > /dev/null
NSPR_DIR="$(pwd)"
if [[ "$force_rebuild" = "true" ]] || [[ ! -e .already-built ]] || [[ .already-built -ot $LIB_DIRECTORY ]]
then
rm -f .already-built
download_lib $LIB_URL $LIB_ARCHIVE
rm -rf $LIB_DIRECTORY bin include lib share
tar -xf $LIB_ARCHIVE
pushd $LIB_DIRECTORY/nspr
(CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \
./configure --prefix="$NSPR_DIR" \
--enable-64bit \
&& make ${JOBS} && make install) || die "NSPR build failed"
popd
# TODO: how can we not build the dylibs?
rm -f lib/*.dylib
touch .already-built
else
already_built
fi
popd > /dev/null
# -------------------------------------------------------------- # --------------------------------------------------------------
echo -e "Building ICU..." echo -e "Building ICU..."
@ -940,9 +903,9 @@ popd > /dev/null
# be customized, so we build and install them from bundled sources # be customized, so we build and install them from bundled sources
# -------------------------------------------------------------------- # --------------------------------------------------------------------
echo -e "Building Spidermonkey..." echo -e "Building Spidermonkey..."
LIB_VERSION="mozjs-38.2.1" LIB_VERSION="mozjs-45.0.2"
LIB_ARCHIVE="$LIB_VERSION.rc0.tar.bz2" LIB_ARCHIVE="$LIB_VERSION.tar.bz2"
LIB_DIRECTORY="mozjs-38.0.0" LIB_DIRECTORY="mozjs-45.0.2"
pushd ../source/spidermonkey/ > /dev/null pushd ../source/spidermonkey/ > /dev/null
@ -963,20 +926,17 @@ then
popd popd
pushd $LIB_DIRECTORY/js/src pushd $LIB_DIRECTORY/js/src
# We want separate debug/release versions of the library, so change their install name in the Makefile
perl -i.bak -pe 's/(^STATIC_LIBRARY_NAME\s+=).*/$1'\''mozjs38-ps-debug'\''/' moz.build
CONF_OPTS="--target=$ARCH-apple-darwin CONF_OPTS="--target=$ARCH-apple-darwin
--prefix=${INSTALL_DIR} --prefix=${INSTALL_DIR}
--with-system-nspr --enable-posix-nspr-emulation
--with-nspr-prefix=${NSPR_DIR}
--with-system-zlib=${ZLIB_DIR} --with-system-zlib=${ZLIB_DIR}
--disable-tests --disable-tests
--disable-shared-js" --disable-shared-js
--disable-jemalloc
--without-intl-api"
# Change the default location where the tracelogger should store its output, which is /tmp/ on OSX. # Change the default location where the tracelogger should store its output, which is /tmp/ on OSX.
TLCXXFLAGS='-DTRACE_LOG_DIR="\"../../source/tools/tracelogger/\""' TLCXXFLAGS='-DTRACE_LOG_DIR="\"../../source/tools/tracelogger/\""'
# Uncomment this line for 32-bit 10.5 cross compile:
#CONF_OPTS="$CONF_OPTS --target=i386-apple-darwin9.0.0"
if [[ $MIN_OSX_VERSION && ${MIN_OSX_VERSION-_} ]]; then if [[ $MIN_OSX_VERSION && ${MIN_OSX_VERSION-_} ]]; then
CONF_OPTS="$CONF_OPTS --enable-macos-target=$MIN_OSX_VERSION" CONF_OPTS="$CONF_OPTS --enable-macos-target=$MIN_OSX_VERSION"
fi fi
@ -984,6 +944,8 @@ then
CONF_OPTS="$CONF_OPTS --with-macosx-sdk=$SYSROOT" CONF_OPTS="$CONF_OPTS --with-macosx-sdk=$SYSROOT"
fi fi
# We want separate debug/release versions of the library, so change their install name in the Makefile
perl -i.bak -pe 's/(^STATIC_LIBRARY_NAME\s+=).*/$1'\''mozjs45-ps-debug'\''/' moz.build
mkdir -p build-debug mkdir -p build-debug
pushd build-debug pushd build-debug
(CC="clang" CXX="clang++" CXXFLAGS="${TLCXXFLAGS}" AR=ar CROSS_COMPILE=1 \ (CC="clang" CXX="clang++" CXXFLAGS="${TLCXXFLAGS}" AR=ar CROSS_COMPILE=1 \
@ -996,11 +958,11 @@ then
# js-config.h is different for debug and release builds, so we need different include directories for both # js-config.h is different for debug and release builds, so we need different include directories for both
mkdir -p $INCLUDE_DIR_DEBUG mkdir -p $INCLUDE_DIR_DEBUG
cp -R -L dist/include/* $INCLUDE_DIR_DEBUG/ cp -R -L dist/include/* $INCLUDE_DIR_DEBUG/
cp dist/lib/*.a $INSTALL_DIR/lib cp dist/sdk/lib/*.a $INSTALL_DIR/lib
popd popd
mv moz.build.bak moz.build mv moz.build.bak moz.build
perl -i.bak -pe 's/(^STATIC_LIBRARY_NAME\s+=).*/$1'\''mozjs38-ps-release'\''/' moz.build perl -i.bak -pe 's/(^STATIC_LIBRARY_NAME\s+=).*/$1'\''mozjs45-ps-release'\''/' moz.build
mkdir -p build-release mkdir -p build-release
pushd build-release pushd build-release
(CC="clang" CXX="clang++" CXXFLAGS="${TLCXXFLAGS}" AR=ar CROSS_COMPILE=1 \ (CC="clang" CXX="clang++" CXXFLAGS="${TLCXXFLAGS}" AR=ar CROSS_COMPILE=1 \
@ -1010,7 +972,8 @@ then
# js-config.h is different for debug and release builds, so we need different include directories for both # js-config.h is different for debug and release builds, so we need different include directories for both
mkdir -p $INCLUDE_DIR_RELEASE mkdir -p $INCLUDE_DIR_RELEASE
cp -R -L dist/include/* $INCLUDE_DIR_RELEASE/ cp -R -L dist/include/* $INCLUDE_DIR_RELEASE/
cp dist/lib/*.a $INSTALL_DIR/lib cp dist/sdk/lib/*.a $INSTALL_DIR/lib
cp js/src/*.a $INSTALL_DIR/lib
popd popd
mv moz.build.bak moz.build mv moz.build.bak moz.build

View File

@ -346,7 +346,7 @@ void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGU
JS::CompileOptions options(cx); JS::CompileOptions options(cx);
options.setFileAndLine(CodeName.c_str(), 0); options.setFileAndLine(CodeName.c_str(), 0);
options.setCompileAndGo(true); options.setIsRunOnce(true);
JS::RootedFunction func(cx); JS::RootedFunction func(cx);
JS::AutoObjectVector emptyScopeChain(cx); JS::AutoObjectVector emptyScopeChain(cx);

View File

@ -56,7 +56,7 @@ class IGUIObject
// Allow getProperty to access things like GetParent() // Allow getProperty to access things like GetParent()
friend bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); friend bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp);
friend bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp); friend bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result);
friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp); friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp);
public: public:

View File

@ -124,28 +124,28 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
return false; return false;
} }
bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp) bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result)
{ {
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
if (!e) if (!e)
return false; return result.fail(JSMSG_NOT_NONNULL_OBJECT);
JSAutoRequest rq(cx); JSAutoRequest rq(cx);
JS::RootedValue idval(cx); JS::RootedValue idval(cx);
if (!JS_IdToValue(cx, id, &idval)) if (!JS_IdToValue(cx, id, &idval))
return false; return result.fail(JSMSG_NOT_NONNULL_OBJECT);
std::string propName; std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName)) if (!ScriptInterface::FromJSVal(cx, idval, propName))
return false; return result.fail(JSMSG_UNDEFINED_PROP);
if (propName == "name") if (propName == "name")
{ {
std::string value; std::string value;
if (!ScriptInterface::FromJSVal(cx, vp, value)) if (!ScriptInterface::FromJSVal(cx, vp, value))
return false; return result.fail(JSMSG_UNDEFINED_PROP);
e->SetName(value); e->SetName(value);
return true; return result.succeed();
} }
JS::RootedObject vpObj(cx); JS::RootedObject vpObj(cx);
@ -158,20 +158,20 @@ bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject())) if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject()))
{ {
JS_ReportError(cx, "on- event-handlers must be functions"); JS_ReportError(cx, "on- event-handlers must be functions");
return false; return result.fail(JSMSG_NOT_FUNCTION);
} }
CStr eventName(CStr(propName.substr(2)).LowerCase()); CStr eventName(CStr(propName.substr(2)).LowerCase());
e->SetScriptHandler(eventName, vpObj); e->SetScriptHandler(eventName, vpObj);
return true; return result.succeed();
} }
if (e->SettingExists(propName)) if (e->SettingExists(propName))
return e->m_Settings[propName]->FromJSVal(cx, vp); return e->m_Settings[propName]->FromJSVal(cx, vp) ? result.succeed() : result.fail(JSMSG_TYPE_ERR_BAD_ARGS);
JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str());
return false; return result.fail(JSMSG_UNDEFINED_PROP);
} }
void JSI_IGUIObject::init(ScriptInterface& scriptInterface) void JSI_IGUIObject::init(ScriptInterface& scriptInterface)

View File

@ -25,7 +25,7 @@ namespace JSI_IGUIObject
extern JSClass JSI_class; extern JSClass JSI_class;
extern JSFunctionSpec JSI_methods[]; extern JSFunctionSpec JSI_methods[];
bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp);
bool setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp); bool setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result);
bool toString(JSContext* cx, uint argc, JS::Value* vp); bool toString(JSContext* cx, uint argc, JS::Value* vp);
bool focus(JSContext* cx, uint argc, JS::Value* vp); bool focus(JSContext* cx, uint argc, JS::Value* vp);
bool blur(JSContext* cx, uint argc, JS::Value* vp); bool blur(JSContext* cx, uint argc, JS::Value* vp);

View File

@ -608,7 +608,8 @@ bool ModIo::ParseGameIdResponse(const ScriptInterface& scriptInterface, const st
JS::RootedObject data(cx, dataVal.toObjectOrNull()); JS::RootedObject data(cx, dataVal.toObjectOrNull());
u32 length; u32 length;
if (!JS_IsArrayObject(cx, data) || !JS_GetArrayLength(cx, data, &length) || !length) bool isArray;
if (!JS_IsArrayObject(cx, data, &isArray) || !isArray || !JS_GetArrayLength(cx, data, &length) || !length)
FAIL("data property not an array with at least one element."); FAIL("data property not an array with at least one element.");
// {"id": 42, ...} // {"id": 42, ...}
@ -679,7 +680,8 @@ bool ModIo::ParseModsResponse(const ScriptInterface& scriptInterface, const std:
JS::RootedObject data(cx, dataVal.toObjectOrNull()); JS::RootedObject data(cx, dataVal.toObjectOrNull());
u32 length; u32 length;
if (!JS_IsArrayObject(cx, data) || !JS_GetArrayLength(cx, data, &length) || !length) bool isArray;
if (!JS_IsArrayObject(cx, data, &isArray) || !isArray || !JS_GetArrayLength(cx, data, &length) || !length)
FAIL("data property not an array with at least one element."); FAIL("data property not an array with at least one element.");
modData.clear(); modData.clear();

View File

@ -86,7 +86,8 @@ bool VisualReplay::ReadCacheFile(const ScriptInterface& scriptInterface, JS::Mut
if (scriptInterface.ParseJSON(cacheStr, &cachedReplays)) if (scriptInterface.ParseJSON(cacheStr, &cachedReplays))
{ {
cachedReplaysObject.set(&cachedReplays.toObject()); cachedReplaysObject.set(&cachedReplays.toObject());
if (JS_IsArrayObject(cx, cachedReplaysObject)) bool isArray;
if (JS_IsArrayObject(cx, cachedReplaysObject, &isArray) && isArray)
return true; return true;
} }

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games. /* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -52,8 +52,9 @@ template<typename T> static bool FromJSVal_vector(JSContext* cx, JS::HandleValue
if (!v.isObject()) if (!v.isObject())
FAIL("Argument must be an array"); FAIL("Argument must be an array");
bool isArray;
obj = &v.toObject(); obj = &v.toObject();
if (!(JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj))) if ((!JS_IsArrayObject(cx, obj, &isArray) || !isArray) && !JS_IsTypedArrayObject(obj))
FAIL("Argument must be an array"); FAIL("Argument must be an array");
u32 length; u32 length;

View File

@ -21,6 +21,8 @@
#include "ScriptTypes.h" #include "ScriptTypes.h"
#include "ps/Singleton.h" #include "ps/Singleton.h"
#include "js/Initialization.h"
/** /**
* A class using the RAII (Resource Acquisition Is Initialization) idiom to manage initialization * A class using the RAII (Resource Acquisition Is Initialization) idiom to manage initialization
* and shutdown of the SpiderMonkey script engine. It also keeps a count of active script runtimes * and shutdown of the SpiderMonkey script engine. It also keeps a count of active script runtimes

View File

@ -352,7 +352,6 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const sh
JS::RuntimeOptionsRef(m_cx) JS::RuntimeOptionsRef(m_cx)
.setExtraWarnings(true) .setExtraWarnings(true)
.setWerror(false) .setWerror(false)
.setVarObjFix(true)
.setStrictMode(true); .setStrictMode(true);
JS::CompartmentOptions opt; JS::CompartmentOptions opt;
@ -523,11 +522,11 @@ void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructo
} }
JS::RootedObject global(m->m_cx, m->m_glob); JS::RootedObject global(m->m_cx, m->m_glob);
JS::RootedObject obj(m->m_cx, JS_InitClass(m->m_cx, global, JS::NullPtr(), JS::RootedObject obj(m->m_cx, JS_InitClass(m->m_cx, global, nullptr,
clasp, clasp,
constructor, minArgs, // Constructor, min args constructor, minArgs, // Constructor, min args
ps, fs, // Properties, methods ps, fs, // Properties, methods
static_ps, static_fs)); // Constructor properties, methods static_ps, static_fs)); // Constructor properties, methods
if (obj == NULL) if (obj == NULL)
throw PSERROR_Scripting_DefineType_CreationFailed(); throw PSERROR_Scripting_DefineType_CreationFailed();
@ -610,7 +609,7 @@ bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool r
if (!JS_GetOwnPropertyDescriptor(m->m_cx, global, name, &desc)) if (!JS_GetOwnPropertyDescriptor(m->m_cx, global, name, &desc))
return false; return false;
if (desc.isReadonly()) if (!desc.writable())
{ {
if (!replace) if (!replace)
{ {
@ -620,7 +619,7 @@ bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool r
// This is not supposed to happen, unless the user has called SetProperty with constant = true on the global object // This is not supposed to happen, unless the user has called SetProperty with constant = true on the global object
// instead of using SetGlobal. // instead of using SetGlobal.
if (desc.isPermanent()) if (!desc.configurable())
{ {
JS_ReportError(m->m_cx, "The global \"%s\" is permanent and cannot be hotloaded", name); JS_ReportError(m->m_cx, "The global \"%s\" is permanent and cannot be hotloaded", name);
return false; return false;
@ -776,8 +775,8 @@ bool ScriptInterface::EnumeratePropertyNamesWithPrefix(JS::HandleValue objVal, c
return true; // reached the end of the prototype chain return true; // reached the end of the prototype chain
JS::RootedObject obj(m->m_cx, &objVal.toObject()); JS::RootedObject obj(m->m_cx, &objVal.toObject());
JS::AutoIdArray props(m->m_cx, JS_Enumerate(m->m_cx, obj)); JS::Rooted<JS::IdVector> props(m->m_cx, JS::IdVector(m->m_cx));
if (!props) if (!JS_Enumerate(m->m_cx, obj, &props))
return false; return false;
for (size_t i = 0; i < props.length(); ++i) for (size_t i = 0; i < props.length(); ++i)
@ -865,7 +864,7 @@ bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& cod
JS::CompileOptions options(m->m_cx); JS::CompileOptions options(m->m_cx);
options.setFileAndLine(filenameStr.c_str(), lineNo); options.setFileAndLine(filenameStr.c_str(), lineNo);
options.setCompileAndGo(true); options.setIsRunOnce(true);
JS::RootedFunction func(m->m_cx); JS::RootedFunction func(m->m_cx);
JS::AutoObjectVector emptyScopeChain(m->m_cx); JS::AutoObjectVector emptyScopeChain(m->m_cx);
@ -874,7 +873,7 @@ bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& cod
return false; return false;
JS::RootedValue rval(m->m_cx); JS::RootedValue rval(m->m_cx);
return JS_CallFunction(m->m_cx, JS::NullPtr(), func, JS::HandleValueArray::empty(), &rval); return JS_CallFunction(m->m_cx, nullptr, func, JS::HandleValueArray::empty(), &rval);
} }
shared_ptr<ScriptRuntime> ScriptInterface::CreateRuntime(shared_ptr<ScriptRuntime> parentRuntime, int runtimeSize, int heapGrowthBytesGCTrigger) shared_ptr<ScriptRuntime> ScriptInterface::CreateRuntime(shared_ptr<ScriptRuntime> parentRuntime, int runtimeSize, int heapGrowthBytesGCTrigger)
@ -885,7 +884,6 @@ shared_ptr<ScriptRuntime> ScriptInterface::CreateRuntime(shared_ptr<ScriptRuntim
bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code) const bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code) const
{ {
JSAutoRequest rq(m->m_cx); JSAutoRequest rq(m->m_cx);
JS::RootedObject global(m->m_cx, m->m_glob);
utf16string codeUtf16(code.begin(), code.end()); utf16string codeUtf16(code.begin(), code.end());
uint lineNo = 1; uint lineNo = 1;
// CompileOptions does not copy the contents of the filename string pointer. // CompileOptions does not copy the contents of the filename string pointer.
@ -895,14 +893,13 @@ bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstri
JS::RootedValue rval(m->m_cx); JS::RootedValue rval(m->m_cx);
JS::CompileOptions opts(m->m_cx); JS::CompileOptions opts(m->m_cx);
opts.setFileAndLine(filenameStr.c_str(), lineNo); opts.setFileAndLine(filenameStr.c_str(), lineNo);
return JS::Evaluate(m->m_cx, global, opts, return JS::Evaluate(m->m_cx, opts,
reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval); reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval);
} }
bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const
{ {
JSAutoRequest rq(m->m_cx); JSAutoRequest rq(m->m_cx);
JS::RootedObject global(m->m_cx, m->m_glob);
if (!VfsFileExists(path)) if (!VfsFileExists(path))
{ {
LOGERROR("File '%s' does not exist", path.string8()); LOGERROR("File '%s' does not exist", path.string8());
@ -930,7 +927,7 @@ bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const
JS::RootedValue rval(m->m_cx); JS::RootedValue rval(m->m_cx);
JS::CompileOptions opts(m->m_cx); JS::CompileOptions opts(m->m_cx);
opts.setFileAndLine(filenameStr.c_str(), lineNo); opts.setFileAndLine(filenameStr.c_str(), lineNo);
return JS::Evaluate(m->m_cx, global, opts, return JS::Evaluate(m->m_cx, opts,
reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval); reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval);
} }
@ -944,23 +941,21 @@ bool ScriptInterface::Eval(const char* code) const
bool ScriptInterface::Eval_(const char* code, JS::MutableHandleValue rval) const bool ScriptInterface::Eval_(const char* code, JS::MutableHandleValue rval) const
{ {
JSAutoRequest rq(m->m_cx); JSAutoRequest rq(m->m_cx);
JS::RootedObject global(m->m_cx, m->m_glob);
utf16string codeUtf16(code, code+strlen(code)); utf16string codeUtf16(code, code+strlen(code));
JS::CompileOptions opts(m->m_cx); JS::CompileOptions opts(m->m_cx);
opts.setFileAndLine("(eval)", 1); opts.setFileAndLine("(eval)", 1);
return JS::Evaluate(m->m_cx, global, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval); return JS::Evaluate(m->m_cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval);
} }
bool ScriptInterface::Eval_(const wchar_t* code, JS::MutableHandleValue rval) const bool ScriptInterface::Eval_(const wchar_t* code, JS::MutableHandleValue rval) const
{ {
JSAutoRequest rq(m->m_cx); JSAutoRequest rq(m->m_cx);
JS::RootedObject global(m->m_cx, m->m_glob);
utf16string codeUtf16(code, code+wcslen(code)); utf16string codeUtf16(code, code+wcslen(code));
JS::CompileOptions opts(m->m_cx); JS::CompileOptions opts(m->m_cx);
opts.setFileAndLine("(eval)", 1); opts.setFileAndLine("(eval)", 1);
return JS::Evaluate(m->m_cx, global, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval); return JS::Evaluate(m->m_cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval);
} }
bool ScriptInterface::ParseJSON(const std::string& string_utf8, JS::MutableHandleValue out) const bool ScriptInterface::ParseJSON(const std::string& string_utf8, JS::MutableHandleValue out) const
@ -1041,7 +1036,7 @@ std::string ScriptInterface::StringifyJSON(JS::MutableHandleValue obj, bool inde
JSAutoRequest rq(m->m_cx); JSAutoRequest rq(m->m_cx);
Stringifier str; Stringifier str;
JS::RootedValue indentVal(m->m_cx, indent ? JS::Int32Value(2) : JS::UndefinedValue()); JS::RootedValue indentVal(m->m_cx, indent ? JS::Int32Value(2) : JS::UndefinedValue());
if (!JS_Stringify(m->m_cx, obj, JS::NullPtr(), indentVal, &Stringifier::callback, &str)) if (!JS_Stringify(m->m_cx, obj, nullptr, indentVal, &Stringifier::callback, &str))
{ {
JS_ClearPendingException(m->m_cx); JS_ClearPendingException(m->m_cx);
LOGERROR("StringifyJSON failed"); LOGERROR("StringifyJSON failed");
@ -1069,7 +1064,7 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
// Temporary disable the error reporter, so we don't print complaints about cyclic values // Temporary disable the error reporter, so we don't print complaints about cyclic values
JSErrorReporter er = JS_SetErrorReporter(m->m_runtime->m_rt, NULL); JSErrorReporter er = JS_SetErrorReporter(m->m_runtime->m_rt, NULL);
bool ok = JS_Stringify(m->m_cx, obj, JS::NullPtr(), indentVal, &Stringifier::callback, &str); bool ok = JS_Stringify(m->m_cx, obj, nullptr, indentVal, &Stringifier::callback, &str);
// Restore error reporter // Restore error reporter
JS_SetErrorReporter(m->m_runtime->m_rt, er); JS_SetErrorReporter(m->m_runtime->m_rt, er);

View File

@ -71,7 +71,7 @@
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
#if MOZJS_MAJOR_VERSION != 38 #if MOZJS_MAJOR_VERSION != 45
#error Your compiler is trying to use an incorrect major version of the \ #error Your compiler is trying to use an incorrect major version of the \
SpiderMonkey library. The only version that works is the one in the \ SpiderMonkey library. The only version that works is the one in the \
libraries/spidermonkey/ directory, and it will not work with a typical \ libraries/spidermonkey/ directory, and it will not work with a typical \
@ -79,7 +79,7 @@ system-installed version. Make sure you have got all the right files and \
include paths. include paths.
#endif #endif
#if MOZJS_MINOR_VERSION != 3 #if MOZJS_MINOR_VERSION != 0
#error Your compiler is trying to use an untested minor version of the \ #error Your compiler is trying to use an untested minor version of the \
SpiderMonkey library. If you are a package maintainer, please make sure \ SpiderMonkey library. If you are a package maintainer, please make sure \
to check very carefully that this version does not change the behaviour \ to check very carefully that this version does not change the behaviour \

View File

@ -562,8 +562,9 @@ public:
ENSURE(JS_GetArrayLength(cx, dataObj, &length)); ENSURE(JS_GetArrayLength(cx, dataObj, &length));
u32 nbytes = (u32)(length * sizeof(NavcellData)); u32 nbytes = (u32)(length * sizeof(NavcellData));
bool sharedMemory;
JS::AutoCheckCannotGC nogc; JS::AutoCheckCannotGC nogc;
memcpy((void*)JS_GetUint16ArrayData(dataObj, nogc), m_PassabilityMap.m_Data, nbytes); memcpy((void*)JS_GetUint16ArrayData(dataObj, &sharedMemory, nogc), m_PassabilityMap.m_Data, nbytes);
} }
} }
@ -591,8 +592,9 @@ public:
ENSURE(JS_GetArrayLength(cx, dataObj, &length)); ENSURE(JS_GetArrayLength(cx, dataObj, &length));
u32 nbytes = (u32)(length * sizeof(u8)); u32 nbytes = (u32)(length * sizeof(u8));
bool sharedMemory;
JS::AutoCheckCannotGC nogc; JS::AutoCheckCannotGC nogc;
memcpy((void*)JS_GetUint8ArrayData(dataObj, nogc), m_TerritoryMap.m_Data, nbytes); memcpy((void*)JS_GetUint8ArrayData(dataObj, &sharedMemory, nogc), m_TerritoryMap.m_Data, nbytes);
} }
} }

View File

@ -241,7 +241,8 @@ template<> void ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, JS::MutableHa
// Copy the array data and then remove the no-GC check to allow further changes to the JS data // Copy the array data and then remove the no-GC check to allow further changes to the JS data
{ {
JS::AutoCheckCannotGC nogc; JS::AutoCheckCannotGC nogc;
memcpy((void*)JS_GetUint8ArrayData(objArr, nogc), val.m_Data, nbytes); bool sharedMemory;
memcpy((void*)JS_GetUint8ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes);
} }
JS::RootedValue data(cx, JS::ObjectValue(*objArr)); JS::RootedValue data(cx, JS::ObjectValue(*objArr));
@ -267,7 +268,8 @@ template<> void ScriptInterface::ToJSVal<Grid<u16> >(JSContext* cx, JS::MutableH
// Copy the array data and then remove the no-GC check to allow further changes to the JS data // Copy the array data and then remove the no-GC check to allow further changes to the JS data
{ {
JS::AutoCheckCannotGC nogc; JS::AutoCheckCannotGC nogc;
memcpy((void*)JS_GetUint16ArrayData(objArr, nogc), val.m_Data, nbytes); bool sharedMemory;
memcpy((void*)JS_GetUint16ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes);
} }
JS::RootedValue data(cx, JS::ObjectValue(*objArr)); JS::RootedValue data(cx, JS::ObjectValue(*objArr));
@ -291,7 +293,8 @@ template<> bool ScriptInterface::FromJSVal<TNSpline>(JSContext* cx, JS::HandleVa
JSAutoRequest rq(cx); JSAutoRequest rq(cx);
JS::RootedObject obj(cx, &v.toObject()); JS::RootedObject obj(cx, &v.toObject());
if (!JS_IsArrayObject(cx, obj)) bool isArray;
if (!JS_IsArrayObject(cx, obj, &isArray) || !isArray)
FAIL("Argument must be an array"); FAIL("Argument must be an array");
u32 numberOfNodes = 0; u32 numberOfNodes = 0;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games. /* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -99,7 +99,8 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
} }
// Arrays are special cases of Object // Arrays are special cases of Object
if (JS_IsArrayObject(cx, obj)) bool isArray;
if (JS_IsArrayObject(cx, obj, &isArray) && isArray)
{ {
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY); m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY);
// TODO: probably should have a more efficient storage format // TODO: probably should have a more efficient storage format
@ -119,9 +120,10 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
m_Serializer.NumberU32_Unbounded("byte offset", JS_GetTypedArrayByteOffset(obj)); m_Serializer.NumberU32_Unbounded("byte offset", JS_GetTypedArrayByteOffset(obj));
m_Serializer.NumberU32_Unbounded("length", JS_GetTypedArrayLength(obj)); m_Serializer.NumberU32_Unbounded("length", JS_GetTypedArrayLength(obj));
bool sharedMemory;
// Now handle its array buffer // Now handle its array buffer
// this may be a backref, since ArrayBuffers can be shared by multiple views // this may be a backref, since ArrayBuffers can be shared by multiple views
JS::RootedValue bufferVal(cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(cx, obj))); JS::RootedValue bufferVal(cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(cx, obj, &sharedMemory)));
HandleScriptVal(bufferVal); HandleScriptVal(bufferVal);
break; break;
} }
@ -136,7 +138,8 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
u32 length = JS_GetArrayBufferByteLength(obj); u32 length = JS_GetArrayBufferByteLength(obj);
m_Serializer.NumberU32_Unbounded("buffer length", length); m_Serializer.NumberU32_Unbounded("buffer length", length);
JS::AutoCheckCannotGC nogc; JS::AutoCheckCannotGC nogc;
m_Serializer.RawBytes("buffer data", (const u8*)JS_GetArrayBufferData(obj, nogc), length); bool sharedMemory;
m_Serializer.RawBytes("buffer data", (const u8*)JS_GetArrayBufferData(obj, &sharedMemory, nogc), length);
break; break;
} }
else else
@ -145,11 +148,8 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
const JSClass* jsclass = JS_GetClass(obj); const JSClass* jsclass = JS_GetClass(obj);
if (!jsclass) if (!jsclass)
throw PSERROR_Serialize_ScriptError("JS_GetClass failed"); throw PSERROR_Serialize_ScriptError("JS_GetClass failed");
// TODO: Remove this workaround for upstream API breakage when updating SpiderMonkey
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1236373
#define JSCLASS_CACHED_PROTO_WIDTH js::JSCLASS_CACHED_PROTO_WIDTH
JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass); JSProtoKey protokey = JSCLASS_CACHED_PROTO_KEY(jsclass);
#undef JSCLASS_CACHED_PROTO_WIDTH
if (protokey == JSProto_Object) if (protokey == JSProto_Object)
{ {
@ -302,8 +302,8 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
} }
// Find all properties (ordered by insertion time) // Find all properties (ordered by insertion time)
JS::AutoIdArray ida (cx, JS_Enumerate(cx, obj)); JS::Rooted<JS::IdVector> ida(cx, JS::IdVector(cx));
if (!ida) if (!JS_Enumerate(cx, obj, &ida))
throw PSERROR_Serialize_ScriptError("JS_Enumerate failed"); throw PSERROR_Serialize_ScriptError("JS_Enumerate failed");
m_Serializer.NumberU32_Unbounded("num props", (u32)ida.length()); m_Serializer.NumberU32_Unbounded("num props", (u32)ida.length());

View File

@ -213,7 +213,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{ {
std::vector<JS::Latin1Char> propname; std::vector<JS::Latin1Char> propname;
ReadStringLatin1("prop name", propname); ReadStringLatin1("prop name", propname);
JS::RootedValue propval(cx, ReadScriptVal("prop value", JS::NullPtr())); JS::RootedValue propval(cx, ReadScriptVal("prop value", nullptr));
utf16string prp(propname.begin(), propname.end());; utf16string prp(propname.begin(), propname.end());;
// TODO: Should ask upstream about getting a variant of JS_SetProperty with a length param. // TODO: Should ask upstream about getting a variant of JS_SetProperty with a length param.
@ -224,7 +224,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{ {
utf16string propname; utf16string propname;
ReadStringUTF16("prop name", propname); ReadStringUTF16("prop name", propname);
JS::RootedValue propval(cx, ReadScriptVal("prop value", JS::NullPtr())); JS::RootedValue propval(cx, ReadScriptVal("prop value", nullptr));
if (!JS_SetUCProperty(cx, obj, (const char16_t*)propname.data(), propname.length(), propval)) if (!JS_SetUCProperty(cx, obj, (const char16_t*)propname.data(), propname.length(), propval))
throw PSERROR_Deserialize_ScriptError(); throw PSERROR_Deserialize_ScriptError();
@ -333,7 +333,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
AddScriptBackref(arrayObj); AddScriptBackref(arrayObj);
// Get buffer object // Get buffer object
JS::RootedValue bufferVal(cx, ReadScriptVal("buffer", JS::NullPtr())); JS::RootedValue bufferVal(cx, ReadScriptVal("buffer", nullptr));
if (!bufferVal.isObject()) if (!bufferVal.isObject())
throw PSERROR_Deserialize_ScriptError(); throw PSERROR_Deserialize_ScriptError();
@ -405,8 +405,8 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
for (u32 i=0; i<mapSize; ++i) for (u32 i=0; i<mapSize; ++i)
{ {
JS::RootedValue key(cx, ReadScriptVal("map key", JS::NullPtr())); JS::RootedValue key(cx, ReadScriptVal("map key", nullptr));
JS::RootedValue value(cx, ReadScriptVal("map value", JS::NullPtr())); JS::RootedValue value(cx, ReadScriptVal("map value", nullptr));
JS::MapSet(cx, obj, key, value); JS::MapSet(cx, obj, key, value);
} }
@ -425,7 +425,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
for (u32 i=0; i<setSize; ++i) for (u32 i=0; i<setSize; ++i)
{ {
JS::RootedValue value(cx, ReadScriptVal("set value", JS::NullPtr())); JS::RootedValue value(cx, ReadScriptVal("set value", nullptr));
m_ScriptInterface.CallFunctionVoid(setVal, "add", value); m_ScriptInterface.CallFunctionVoid(setVal, "add", value);
} }
@ -487,7 +487,7 @@ void CStdDeserializer::ScriptString(const char* name, JS::MutableHandleString ou
void CStdDeserializer::ScriptVal(const char* name, JS::MutableHandleValue out) void CStdDeserializer::ScriptVal(const char* name, JS::MutableHandleValue out)
{ {
out.set(ReadScriptVal(name, JS::NullPtr())); out.set(ReadScriptVal(name, nullptr));
} }
void CStdDeserializer::ScriptObjectAppend(const char* name, JS::HandleValue objVal) void CStdDeserializer::ScriptObjectAppend(const char* name, JS::HandleValue objVal)

View File

@ -386,7 +386,7 @@ void CParamNode::ConstructJSVal(JSContext* cx, JS::MutableHandleValue ret) const
// Just a string // Just a string
utf16string text(m_Value.begin(), m_Value.end()); utf16string text(m_Value.begin(), m_Value.end());
JS::RootedString str(cx, JS_InternUCStringN(cx, reinterpret_cast<const char16_t*>(text.data()), text.length())); JS::RootedString str(cx, JS_AtomizeAndPinUCStringN(cx, reinterpret_cast<const char16_t*>(text.data()), text.length()));
if (str) if (str)
{ {
ret.setString(str); ret.setString(str);
@ -421,7 +421,7 @@ void CParamNode::ConstructJSVal(JSContext* cx, JS::MutableHandleValue ret) const
if (!m_Value.empty()) if (!m_Value.empty())
{ {
utf16string text(m_Value.begin(), m_Value.end()); utf16string text(m_Value.begin(), m_Value.end());
JS::RootedString str(cx, JS_InternUCStringN(cx, reinterpret_cast<const char16_t*>(text.data()), text.length())); JS::RootedString str(cx, JS_AtomizeAndPinUCStringN(cx, reinterpret_cast<const char16_t*>(text.data()), text.length()));
if (!str) if (!str)
{ {
ret.setUndefined(); ret.setUndefined();