diff options
Diffstat (limited to 'js/src/vm/Xdr.cpp')
-rw-r--r-- | js/src/vm/Xdr.cpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp new file mode 100644 index 000000000..7f1012d86 --- /dev/null +++ b/js/src/vm/Xdr.cpp @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "vm/Xdr.h" + +#include "mozilla/PodOperations.h" + +#include <string.h> + +#include "jsapi.h" +#include "jsscript.h" + +#include "vm/Debugger.h" +#include "vm/EnvironmentObject.h" + +using namespace js; +using mozilla::PodEqual; + +template<XDRMode mode> +void +XDRState<mode>::postProcessContextErrors(JSContext* cx) +{ + if (cx->isExceptionPending()) { + MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok); + resultCode_ = JS::TranscodeResult_Throw; + } +} + +template<XDRMode mode> +bool +XDRState<mode>::codeChars(const Latin1Char* chars, size_t nchars) +{ + static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte"); + + MOZ_ASSERT(mode == XDR_ENCODE); + + if (nchars == 0) + return true; + uint8_t* ptr = buf.write(nchars); + if (!ptr) + return false; + + mozilla::PodCopy(ptr, chars, nchars); + return true; +} + +template<XDRMode mode> +bool +XDRState<mode>::codeChars(char16_t* chars, size_t nchars) +{ + if (nchars == 0) + return true; + size_t nbytes = nchars * sizeof(char16_t); + if (mode == XDR_ENCODE) { + uint8_t* ptr = buf.write(nbytes); + if (!ptr) + return false; + mozilla::NativeEndian::copyAndSwapToLittleEndian(ptr, chars, nchars); + } else { + const uint8_t* ptr = buf.read(nbytes); + mozilla::NativeEndian::copyAndSwapFromLittleEndian(chars, ptr, nchars); + } + return true; +} + +template<XDRMode mode> +static bool +VersionCheck(XDRState<mode>* xdr) +{ + JS::BuildIdCharVector buildId; + if (!xdr->cx()->buildIdOp() || !xdr->cx()->buildIdOp()(&buildId)) { + JS_ReportErrorNumberASCII(xdr->cx(), GetErrorMessage, nullptr, + JSMSG_BUILD_ID_NOT_AVAILABLE); + return false; + } + MOZ_ASSERT(!buildId.empty()); + + uint32_t buildIdLength; + if (mode == XDR_ENCODE) + buildIdLength = buildId.length(); + + if (!xdr->codeUint32(&buildIdLength)) + return false; + + if (mode == XDR_DECODE && buildIdLength != buildId.length()) + return xdr->fail(JS::TranscodeResult_Failure_BadBuildId); + + if (mode == XDR_ENCODE) { + if (!xdr->codeBytes(buildId.begin(), buildIdLength)) + return false; + } else { + JS::BuildIdCharVector decodedBuildId; + + // buildIdLength is already checked against the length of current + // buildId. + if (!decodedBuildId.resize(buildIdLength)) { + ReportOutOfMemory(xdr->cx()); + return false; + } + + if (!xdr->codeBytes(decodedBuildId.begin(), buildIdLength)) + return false; + + // We do not provide binary compatibility with older scripts. + if (!PodEqual(decodedBuildId.begin(), buildId.begin(), buildIdLength)) + return xdr->fail(JS::TranscodeResult_Failure_BadBuildId); + } + + return true; +} + +template<XDRMode mode> +bool +XDRState<mode>::codeFunction(MutableHandleFunction funp) +{ + if (mode == XDR_DECODE) + funp.set(nullptr); + else + MOZ_ASSERT(funp->nonLazyScript()->enclosingScope()->is<GlobalScope>()); + + if (!VersionCheck(this)) { + postProcessContextErrors(cx()); + return false; + } + + RootedScope scope(cx(), &cx()->global()->emptyGlobalScope()); + if (!XDRInterpretedFunction(this, scope, nullptr, funp)) { + postProcessContextErrors(cx()); + funp.set(nullptr); + return false; + } + + return true; +} + +template<XDRMode mode> +bool +XDRState<mode>::codeScript(MutableHandleScript scriptp) +{ + if (mode == XDR_DECODE) + scriptp.set(nullptr); + else + MOZ_ASSERT(!scriptp->enclosingScope()); + + if (!VersionCheck(this)) { + postProcessContextErrors(cx()); + return false; + } + + if (!XDRScript(this, nullptr, nullptr, nullptr, scriptp)) { + postProcessContextErrors(cx()); + scriptp.set(nullptr); + return false; + } + + return true; +} + +template<XDRMode mode> +bool +XDRState<mode>::codeConstValue(MutableHandleValue vp) +{ + return XDRScriptConst(this, vp); +} + +template class js::XDRState<XDR_ENCODE>; +template class js::XDRState<XDR_DECODE>; |