зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1288104 part 1 - Move XDR buffer to the caller. r=luke
Add a typedef on top of mozilla::Vector to define the TranscodeBuffer which owns the encoded content of a Script / Function. This modification renames JS_EncodeScript, into JS::EncodeScript, and change its prototype to have a JSContext, a TranscodeBuffer, and a Handle on a script that we want to encode. Similar modifications are made to JS_EncodeInterpretedFunction, and the Decode variant of these.
This commit is contained in:
Родитель
41f4e7423a
Коммит
b3e4b94e1e
|
@ -25,17 +25,15 @@ FreezeThaw(JSContext* cx, JS::HandleScript script)
|
|||
JS::SetBuildIdOp(cx, GetBuildId);
|
||||
|
||||
// freeze
|
||||
uint32_t nbytes;
|
||||
void* memory = nullptr;
|
||||
TranscodeResult rs = JS_EncodeScript(cx, script, &nbytes, &memory);
|
||||
if (rs != TranscodeResult_Ok)
|
||||
JS::TranscodeBuffer buffer;
|
||||
JS::TranscodeResult rs = JS::EncodeScript(cx, buffer, script);
|
||||
if (rs != JS::TranscodeResult_Ok)
|
||||
return nullptr;
|
||||
|
||||
// thaw
|
||||
JS::RootedScript script2(cx);
|
||||
rs = JS_DecodeScript(cx, memory, nbytes, &script2);
|
||||
js_free(memory);
|
||||
if (rs != TranscodeResult_Ok)
|
||||
rs = JS::DecodeScript(cx, buffer, &script2);
|
||||
if (rs != JS::TranscodeResult_Ok)
|
||||
return nullptr;
|
||||
return script2;
|
||||
}
|
||||
|
|
|
@ -6592,47 +6592,42 @@ JS::detail::AssertArgumentsAreSane(JSContext* cx, HandleValue value)
|
|||
}
|
||||
#endif /* JS_DEBUG */
|
||||
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeScript(JSContext* cx, HandleScript scriptArg,
|
||||
uint32_t* lengthp, void** buffer)
|
||||
JS_PUBLIC_API(JS::TranscodeResult)
|
||||
JS::EncodeScript(JSContext* cx, TranscodeBuffer& buffer, HandleScript scriptArg)
|
||||
{
|
||||
XDREncoder encoder(cx);
|
||||
XDREncoder encoder(cx, buffer);
|
||||
RootedScript script(cx, scriptArg);
|
||||
*buffer = nullptr;
|
||||
if (encoder.codeScript(&script))
|
||||
*buffer = encoder.forgetData(lengthp);
|
||||
MOZ_ASSERT(bool(*buffer) == (encoder.resultCode() == TranscodeResult_Ok));
|
||||
if (!encoder.codeScript(&script))
|
||||
buffer.clearAndFree();
|
||||
MOZ_ASSERT(!buffer.empty() == (encoder.resultCode() == TranscodeResult_Ok));
|
||||
return encoder.resultCode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeInterpretedFunction(JSContext* cx, HandleObject funobjArg,
|
||||
uint32_t* lengthp, void** buffer)
|
||||
JS_PUBLIC_API(JS::TranscodeResult)
|
||||
JS::EncodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, HandleObject funobjArg)
|
||||
{
|
||||
XDREncoder encoder(cx);
|
||||
XDREncoder encoder(cx, buffer);
|
||||
RootedFunction funobj(cx, &funobjArg->as<JSFunction>());
|
||||
*buffer = nullptr;
|
||||
if (encoder.codeFunction(&funobj))
|
||||
*buffer = encoder.forgetData(lengthp);
|
||||
MOZ_ASSERT(bool(*buffer) == (encoder.resultCode() == TranscodeResult_Ok));
|
||||
if (!encoder.codeFunction(&funobj))
|
||||
buffer.clearAndFree();
|
||||
MOZ_ASSERT(!buffer.empty() == (encoder.resultCode() == TranscodeResult_Ok));
|
||||
return encoder.resultCode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeScript(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleScript scriptp)
|
||||
JS_PUBLIC_API(JS::TranscodeResult)
|
||||
JS::DecodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleScript scriptp)
|
||||
{
|
||||
XDRDecoder decoder(cx, data, length);
|
||||
XDRDecoder decoder(cx, buffer);
|
||||
decoder.codeScript(scriptp);
|
||||
MOZ_ASSERT(bool(scriptp) == (decoder.resultCode() == TranscodeResult_Ok));
|
||||
return decoder.resultCode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleFunction funp)
|
||||
JS_PUBLIC_API(JS::TranscodeResult)
|
||||
JS::DecodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer,
|
||||
JS::MutableHandleFunction funp)
|
||||
{
|
||||
XDRDecoder decoder(cx, data, length);
|
||||
XDRDecoder decoder(cx, buffer);
|
||||
decoder.codeFunction(funp);
|
||||
MOZ_ASSERT(bool(funp) == (decoder.resultCode() == TranscodeResult_Ok));
|
||||
return decoder.resultCode();
|
||||
|
|
|
@ -5830,12 +5830,12 @@ class MOZ_RAII AutoHideScriptedCaller
|
|||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/*
|
||||
* Encode/Decode interpreted scripts and functions to/from memory.
|
||||
*/
|
||||
|
||||
typedef mozilla::Vector<uint8_t> TranscodeBuffer;
|
||||
|
||||
enum TranscodeResult
|
||||
{
|
||||
// Successful encoding / decoding.
|
||||
|
@ -5853,21 +5853,18 @@ enum TranscodeResult
|
|||
};
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeScript(JSContext* cx, JS::HandleScript script,
|
||||
uint32_t* lengthp, void** buffer);
|
||||
EncodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::HandleScript script);
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeInterpretedFunction(JSContext* cx, JS::HandleObject funobj,
|
||||
uint32_t* lengthp, void** buffer);
|
||||
EncodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::HandleObject funobj);
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeScript(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleScript scriptp);
|
||||
DecodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleScript scriptp);
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleFunction funp);
|
||||
DecodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleFunction funp);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -565,12 +565,16 @@ js::XDRAtom(XDRState<mode>* xdr, MutableHandleAtom atomp)
|
|||
JSContext* cx = xdr->cx();
|
||||
JSAtom* atom;
|
||||
if (latin1) {
|
||||
const Latin1Char* chars = reinterpret_cast<const Latin1Char*>(xdr->buf.read(length));
|
||||
const Latin1Char* chars = nullptr;
|
||||
if (length)
|
||||
chars = reinterpret_cast<const Latin1Char*>(xdr->buf.read(length));
|
||||
atom = AtomizeChars(cx, chars, length);
|
||||
} else {
|
||||
#if MOZ_LITTLE_ENDIAN
|
||||
/* Directly access the little endian chars in the XDR buffer. */
|
||||
const char16_t* chars = reinterpret_cast<const char16_t*>(xdr->buf.read(length * sizeof(char16_t)));
|
||||
const char16_t* chars = nullptr;
|
||||
if (length)
|
||||
chars = reinterpret_cast<const char16_t*>(xdr->buf.read(length * sizeof(char16_t)));
|
||||
atom = AtomizeChars(cx, chars, length);
|
||||
#else
|
||||
/*
|
||||
|
|
|
@ -358,7 +358,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
if (!comp->creationOptions().cloneSingletons() ||
|
||||
!comp->behaviors().getSingletonsAsTemplates())
|
||||
{
|
||||
return xdr->fail(TranscodeResult_Failure_RunOnceNotSupported);
|
||||
return xdr->fail(JS::TranscodeResult_Failure_RunOnceNotSupported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -792,7 +792,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
funEnclosingScope = function->nonLazyScript()->enclosingScope();
|
||||
} else {
|
||||
MOZ_ASSERT(function->isAsmJSNative());
|
||||
return xdr->fail(TranscodeResult_Failure_AsmJSNotSupported);
|
||||
return xdr->fail(JS::TranscodeResult_Failure_AsmJSNotSupported);
|
||||
}
|
||||
|
||||
funEnclosingScopeIndex = FindScopeIndex(script, *funEnclosingScope);
|
||||
|
@ -827,7 +827,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
|
||||
default: {
|
||||
MOZ_ASSERT(false, "Unknown class kind.");
|
||||
return xdr->fail(TranscodeResult_Failure_UnknownClassKind);
|
||||
return xdr->fail(JS::TranscodeResult_Failure_UnknownClassKind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1511,36 +1511,36 @@ CacheEntry_setBytecode(JSContext* cx, HandleObject cache, uint8_t* buffer, uint3
|
|||
}
|
||||
|
||||
static bool
|
||||
ConvertTranscodeResultToJSException(JSContext* cx, TranscodeResult rv)
|
||||
ConvertTranscodeResultToJSException(JSContext* cx, JS::TranscodeResult rv)
|
||||
{
|
||||
switch (rv) {
|
||||
case TranscodeResult_Ok:
|
||||
case JS::TranscodeResult_Ok:
|
||||
return true;
|
||||
|
||||
default:
|
||||
MOZ_FALLTHROUGH;
|
||||
case TranscodeResult_Failure:
|
||||
case JS::TranscodeResult_Failure:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "generic warning");
|
||||
return false;
|
||||
case TranscodeResult_Failure_BadBuildId:
|
||||
case JS::TranscodeResult_Failure_BadBuildId:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "the build-id does not match");
|
||||
return false;
|
||||
case TranscodeResult_Failure_RunOnceNotSupported:
|
||||
case JS::TranscodeResult_Failure_RunOnceNotSupported:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "run-once script are not supported by XDR");
|
||||
return false;
|
||||
case TranscodeResult_Failure_AsmJSNotSupported:
|
||||
case JS::TranscodeResult_Failure_AsmJSNotSupported:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "Asm.js is not supported by XDR");
|
||||
return false;
|
||||
case TranscodeResult_Failure_UnknownClassKind:
|
||||
case JS::TranscodeResult_Failure_UnknownClassKind:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "Unknown class kind, go fix it.");
|
||||
return false;
|
||||
|
||||
case TranscodeResult_Throw:
|
||||
case JS::TranscodeResult_Throw:
|
||||
MOZ_ASSERT(cx->isExceptionPending());
|
||||
return false;
|
||||
}
|
||||
|
@ -1663,15 +1663,19 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!codeChars.initTwoByte(cx, code))
|
||||
return false;
|
||||
|
||||
uint32_t loadLength = 0;
|
||||
uint8_t* loadBuffer = nullptr;
|
||||
uint32_t saveLength = 0;
|
||||
ScopedJSFreePtr<uint8_t> saveBuffer;
|
||||
JS::TranscodeBuffer loadBuffer;
|
||||
JS::TranscodeBuffer saveBuffer;
|
||||
|
||||
if (loadBytecode) {
|
||||
loadBuffer = CacheEntry_getBytecode(cacheEntry, &loadLength);
|
||||
if (!loadBuffer)
|
||||
uint32_t loadLength = 0;
|
||||
uint8_t* loadData = nullptr;
|
||||
loadData = CacheEntry_getBytecode(cacheEntry, &loadLength);
|
||||
if (!loadData)
|
||||
return false;
|
||||
if (!loadBuffer.append(loadData, loadLength)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1691,7 +1695,7 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
if (loadBytecode) {
|
||||
TranscodeResult rv = JS_DecodeScript(cx, loadBuffer, loadLength, &script);
|
||||
JS::TranscodeResult rv = JS::DecodeScript(cx, loadBuffer, &script);
|
||||
if (!ConvertTranscodeResultToJSException(cx, rv))
|
||||
return false;
|
||||
} else {
|
||||
|
@ -1742,8 +1746,7 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
if (saveBytecode) {
|
||||
TranscodeResult rv = JS_EncodeScript(cx, script, &saveLength,
|
||||
reinterpret_cast<void**>(&saveBuffer.rwget()));
|
||||
JS::TranscodeResult rv = JS::EncodeScript(cx, saveBuffer, script);
|
||||
if (!ConvertTranscodeResultToJSException(cx, rv))
|
||||
return false;
|
||||
}
|
||||
|
@ -1753,28 +1756,34 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
|||
// If we are both loading and saving, we assert that we are going to
|
||||
// replace the current bytecode by the same stream of bytes.
|
||||
if (loadBytecode && assertEqBytecode) {
|
||||
if (saveLength != loadLength) {
|
||||
if (saveBuffer.length() != loadBuffer.length()) {
|
||||
char loadLengthStr[16];
|
||||
SprintfLiteral(loadLengthStr, "%" PRIu32, loadLength);
|
||||
SprintfLiteral(loadLengthStr, "%" PRIuSIZE, loadBuffer.length());
|
||||
char saveLengthStr[16];
|
||||
SprintfLiteral(saveLengthStr,"%" PRIu32, saveLength);
|
||||
SprintfLiteral(saveLengthStr,"%" PRIuSIZE, saveBuffer.length());
|
||||
|
||||
JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_CACHE_EQ_SIZE_FAILED,
|
||||
loadLengthStr, saveLengthStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PodEqual(loadBuffer, saveBuffer.get(), loadLength)) {
|
||||
if (!PodEqual(loadBuffer.begin(), saveBuffer.begin(), loadBuffer.length())) {
|
||||
JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr,
|
||||
JSSMSG_CACHE_EQ_CONTENT_FAILED);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CacheEntry_setBytecode(cx, cacheEntry, saveBuffer, saveLength))
|
||||
size_t saveLength = saveBuffer.length();
|
||||
if (saveLength >= INT32_MAX) {
|
||||
JS_ReportErrorASCII(cx, "Cannot save large cache entry content");
|
||||
return false;
|
||||
|
||||
saveBuffer.forget();
|
||||
}
|
||||
uint8_t* saveData = saveBuffer.extractOrCopyRawBuffer();
|
||||
if (!CacheEntry_setBytecode(cx, cacheEntry, saveData, saveLength)) {
|
||||
js_free(saveData);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_WrapValue(cx, args.rval());
|
||||
|
|
|
@ -19,52 +19,13 @@
|
|||
using namespace js;
|
||||
using mozilla::PodEqual;
|
||||
|
||||
void
|
||||
XDRBuffer::freeBuffer()
|
||||
{
|
||||
js_free(base);
|
||||
#ifdef DEBUG
|
||||
memset(this, 0xe2, sizeof *this);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
XDRBuffer::grow(size_t n)
|
||||
{
|
||||
MOZ_ASSERT(n > size_t(limit - cursor));
|
||||
|
||||
const size_t MIN_CAPACITY = 8192;
|
||||
const size_t MAX_CAPACITY = size_t(INT32_MAX) + 1;
|
||||
size_t offset = cursor - base;
|
||||
MOZ_ASSERT(offset <= MAX_CAPACITY);
|
||||
if (n > MAX_CAPACITY - offset) {
|
||||
js::gc::AutoSuppressGC suppressGC(cx());
|
||||
JS_ReportErrorNumberASCII(cx(), GetErrorMessage, nullptr, JSMSG_TOO_BIG_TO_ENCODE);
|
||||
return false;
|
||||
}
|
||||
size_t newCapacity = mozilla::RoundUpPow2(offset + n);
|
||||
if (newCapacity < MIN_CAPACITY)
|
||||
newCapacity = MIN_CAPACITY;
|
||||
|
||||
MOZ_ASSERT(newCapacity <= MAX_CAPACITY);
|
||||
void* data = js_realloc(base, newCapacity);
|
||||
if (!data) {
|
||||
ReportOutOfMemory(cx());
|
||||
return false;
|
||||
}
|
||||
base = static_cast<uint8_t*>(data);
|
||||
cursor = base + offset;
|
||||
limit = base + newCapacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<XDRMode mode>
|
||||
void
|
||||
XDRState<mode>::postProcessContextErrors(JSContext* cx)
|
||||
{
|
||||
if (cx->isExceptionPending()) {
|
||||
MOZ_ASSERT(resultCode_ == TranscodeResult_Ok);
|
||||
resultCode_ = TranscodeResult_Throw;
|
||||
MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok);
|
||||
resultCode_ = JS::TranscodeResult_Throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,6 +37,8 @@ XDRState<mode>::codeChars(const Latin1Char* chars, size_t nchars)
|
|||
|
||||
MOZ_ASSERT(mode == XDR_ENCODE);
|
||||
|
||||
if (nchars == 0)
|
||||
return true;
|
||||
uint8_t* ptr = buf.write(nchars);
|
||||
if (!ptr)
|
||||
return false;
|
||||
|
@ -88,6 +51,8 @@ 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);
|
||||
|
@ -121,7 +86,7 @@ VersionCheck(XDRState<mode>* xdr)
|
|||
return false;
|
||||
|
||||
if (mode == XDR_DECODE && buildIdLength != buildId.length())
|
||||
return xdr->fail(TranscodeResult_Failure_BadBuildId);
|
||||
return xdr->fail(JS::TranscodeResult_Failure_BadBuildId);
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
if (!xdr->codeBytes(buildId.begin(), buildIdLength))
|
||||
|
@ -141,7 +106,7 @@ VersionCheck(XDRState<mode>* xdr)
|
|||
|
||||
// We do not provide binary compatibility with older scripts.
|
||||
if (!PodEqual(decodedBuildId.begin(), buildId.begin(), buildIdLength))
|
||||
return xdr->fail(TranscodeResult_Failure_BadBuildId);
|
||||
return xdr->fail(JS::TranscodeResult_Failure_BadBuildId);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -201,11 +166,5 @@ XDRState<mode>::codeConstValue(MutableHandleValue vp)
|
|||
return XDRScriptConst(this, vp);
|
||||
}
|
||||
|
||||
XDRDecoder::XDRDecoder(JSContext* cx, const void* data, uint32_t length)
|
||||
: XDRState<XDR_DECODE>(cx)
|
||||
{
|
||||
buf.setData(data, length);
|
||||
}
|
||||
|
||||
template class js::XDRState<XDR_ENCODE>;
|
||||
template class js::XDRState<XDR_DECODE>;
|
||||
|
|
111
js/src/vm/Xdr.h
111
js/src/vm/Xdr.h
|
@ -17,59 +17,44 @@ namespace js {
|
|||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
explicit XDRBuffer(JSContext* cx)
|
||||
: context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
|
||||
XDRBuffer(JSContext* cx, JS::TranscodeBuffer& buffer)
|
||||
: context_(cx), buffer_(buffer), cursor_(0) { }
|
||||
|
||||
JSContext* cx() const {
|
||||
return context;
|
||||
}
|
||||
|
||||
void* getData(uint32_t* lengthp) const {
|
||||
MOZ_ASSERT(size_t(cursor - base) <= size_t(UINT32_MAX));
|
||||
*lengthp = uint32_t(cursor - base);
|
||||
return base;
|
||||
}
|
||||
|
||||
void setData(const void* data, uint32_t length) {
|
||||
base = static_cast<uint8_t*>(const_cast<void*>(data));
|
||||
cursor = base;
|
||||
limit = base + length;
|
||||
return context_;
|
||||
}
|
||||
|
||||
const uint8_t* read(size_t n) {
|
||||
MOZ_ASSERT(n <= size_t(limit - cursor));
|
||||
uint8_t* ptr = cursor;
|
||||
cursor += n;
|
||||
MOZ_ASSERT(cursor_ < buffer_.length());
|
||||
uint8_t* ptr = &buffer_[cursor_];
|
||||
cursor_ += n;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const char* readCString() {
|
||||
char* ptr = reinterpret_cast<char*>(cursor);
|
||||
cursor = reinterpret_cast<uint8_t*>(strchr(ptr, '\0')) + 1;
|
||||
MOZ_ASSERT(base < cursor);
|
||||
MOZ_ASSERT(cursor <= limit);
|
||||
char* ptr = reinterpret_cast<char*>(&buffer_[cursor_]);
|
||||
uint8_t* end = reinterpret_cast<uint8_t*>(strchr(ptr, '\0')) + 1;
|
||||
MOZ_ASSERT(buffer_.begin() < end);
|
||||
MOZ_ASSERT(end <= buffer_.end());
|
||||
cursor_ = end - buffer_.begin();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t* write(size_t n) {
|
||||
if (n > size_t(limit - cursor)) {
|
||||
if (!grow(n))
|
||||
return nullptr;
|
||||
MOZ_ASSERT(n != 0);
|
||||
if (!buffer_.growByUninitialized(n)) {
|
||||
JS_ReportOutOfMemory(cx());
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* ptr = cursor;
|
||||
cursor += n;
|
||||
uint8_t* ptr = &buffer_[cursor_];
|
||||
cursor_ += n;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void freeBuffer();
|
||||
|
||||
private:
|
||||
bool grow(size_t n);
|
||||
|
||||
JSContext* const context;
|
||||
uint8_t* base;
|
||||
uint8_t* cursor;
|
||||
uint8_t* limit;
|
||||
JSContext* const context_;
|
||||
JS::TranscodeBuffer& buffer_;
|
||||
size_t cursor_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -79,48 +64,46 @@ template <XDRMode mode>
|
|||
class XDRState {
|
||||
public:
|
||||
XDRBuffer buf;
|
||||
TranscodeResult resultCode_;
|
||||
JS::TranscodeResult resultCode_;
|
||||
|
||||
protected:
|
||||
explicit XDRState(JSContext* cx)
|
||||
: buf(cx), resultCode_(TranscodeResult_Ok) { }
|
||||
XDRState(JSContext* cx, JS::TranscodeBuffer& buffer)
|
||||
: buf(cx, buffer), resultCode_(JS::TranscodeResult_Ok) { }
|
||||
|
||||
public:
|
||||
JSContext* cx() const {
|
||||
return buf.cx();
|
||||
}
|
||||
|
||||
// Record logical failures of XDR.
|
||||
void postProcessContextErrors(JSContext* cx);
|
||||
TranscodeResult resultCode() const {
|
||||
JS::TranscodeResult resultCode() const {
|
||||
return resultCode_;
|
||||
}
|
||||
bool fail(TranscodeResult code) {
|
||||
MOZ_ASSERT(resultCode_ == TranscodeResult_Ok);
|
||||
bool fail(JS::TranscodeResult code) {
|
||||
MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok);
|
||||
resultCode_ = code;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool codeUint8(uint8_t* n) {
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof *n);
|
||||
uint8_t* ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
*ptr = *n;
|
||||
} else {
|
||||
*n = *buf.read(sizeof *n);
|
||||
*n = *buf.read(sizeof(*n));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool codeUint16(uint16_t* n) {
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof *n);
|
||||
uint8_t* ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
mozilla::LittleEndian::writeUint16(ptr, *n);
|
||||
} else {
|
||||
const uint8_t* ptr = buf.read(sizeof *n);
|
||||
const uint8_t* ptr = buf.read(sizeof(*n));
|
||||
*n = mozilla::LittleEndian::readUint16(ptr);
|
||||
}
|
||||
return true;
|
||||
|
@ -128,12 +111,12 @@ class XDRState {
|
|||
|
||||
bool codeUint32(uint32_t* n) {
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof *n);
|
||||
uint8_t* ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
mozilla::LittleEndian::writeUint32(ptr, *n);
|
||||
} else {
|
||||
const uint8_t* ptr = buf.read(sizeof *n);
|
||||
const uint8_t* ptr = buf.read(sizeof(*n));
|
||||
*n = mozilla::LittleEndian::readUint32(ptr);
|
||||
}
|
||||
return true;
|
||||
|
@ -185,6 +168,8 @@ class XDRState {
|
|||
}
|
||||
|
||||
bool codeBytes(void* bytes, size_t len) {
|
||||
if (len == 0)
|
||||
return true;
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(len);
|
||||
if (!ptr)
|
||||
|
@ -223,32 +208,8 @@ class XDRState {
|
|||
bool codeConstValue(MutableHandleValue vp);
|
||||
};
|
||||
|
||||
class XDREncoder : public XDRState<XDR_ENCODE> {
|
||||
public:
|
||||
explicit XDREncoder(JSContext* cx)
|
||||
: XDRState<XDR_ENCODE>(cx) {
|
||||
}
|
||||
|
||||
~XDREncoder() {
|
||||
buf.freeBuffer();
|
||||
}
|
||||
|
||||
const void* getData(uint32_t* lengthp) const {
|
||||
return buf.getData(lengthp);
|
||||
}
|
||||
|
||||
void* forgetData(uint32_t* lengthp) {
|
||||
void* data = buf.getData(lengthp);
|
||||
buf.setData(nullptr, 0);
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
class XDRDecoder : public XDRState<XDR_DECODE> {
|
||||
public:
|
||||
XDRDecoder(JSContext* cx, const void* data, uint32_t length);
|
||||
|
||||
};
|
||||
using XDREncoder = XDRState<XDR_ENCODE>;
|
||||
using XDRDecoder = XDRState<XDR_DECODE>;
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
|
||||
using namespace JS;
|
||||
using namespace mozilla::scache;
|
||||
using mozilla::UniquePtr;
|
||||
|
@ -29,14 +29,16 @@ ReadCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
|||
if (NS_FAILED(rv))
|
||||
return rv; // don't warn since NOT_AVAILABLE is an ok error
|
||||
|
||||
TranscodeResult code = JS_DecodeScript(cx, buf.get(), len, scriptp);
|
||||
if (code == TranscodeResult_Ok)
|
||||
JS::TranscodeBuffer buffer;
|
||||
buffer.replaceRawBuffer(reinterpret_cast<uint8_t*>(buf.release()), len);
|
||||
JS::TranscodeResult code = JS::DecodeScript(cx, buffer, scriptp);
|
||||
if (code == JS::TranscodeResult_Ok)
|
||||
return NS_OK;
|
||||
|
||||
if ((code & TranscodeResult_Failure) != 0)
|
||||
if ((code & JS::TranscodeResult_Failure) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
|
||||
MOZ_ASSERT((code & JS::TranscodeResult_Throw) != 0);
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -55,20 +57,22 @@ WriteCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
|||
{
|
||||
MOZ_ASSERT(JS_GetScriptPrincipals(script) == nsJSPrincipals::get(systemPrincipal));
|
||||
|
||||
uint32_t size;
|
||||
void* data = nullptr;
|
||||
TranscodeResult code = JS_EncodeScript(cx, script, &size, &data);
|
||||
if (code != TranscodeResult_Ok) {
|
||||
if ((code & TranscodeResult_Failure) != 0)
|
||||
JS::TranscodeBuffer buffer;
|
||||
JS::TranscodeResult code = JS::EncodeScript(cx, buffer, script);
|
||||
if (code != JS::TranscodeResult_Ok) {
|
||||
if ((code & JS::TranscodeResult_Failure) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
|
||||
MOZ_ASSERT((code & JS::TranscodeResult_Throw) != 0);
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(size && data);
|
||||
nsresult rv = cache->PutBuffer(PromiseFlatCString(uri).get(), static_cast<char*>(data), size);
|
||||
js_free(data);
|
||||
size_t size = buffer.length();
|
||||
if (size > UINT32_MAX)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = cache->PutBuffer(PromiseFlatCString(uri).get(),
|
||||
reinterpret_cast<char*>(buffer.begin()),
|
||||
size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -1090,14 +1090,13 @@ WriteScriptOrFunction(nsIObjectOutputStream* stream, JSContext* cx,
|
|||
return rv;
|
||||
|
||||
|
||||
uint32_t size;
|
||||
void* data = nullptr;
|
||||
TranscodeBuffer buffer;
|
||||
TranscodeResult code;
|
||||
{
|
||||
if (functionObj)
|
||||
code = JS_EncodeInterpretedFunction(cx, functionObj, &size, &data);
|
||||
code = EncodeInterpretedFunction(cx, buffer, functionObj);
|
||||
else
|
||||
code = JS_EncodeScript(cx, script, &size, &data);
|
||||
code = EncodeScript(cx, buffer, script);
|
||||
}
|
||||
|
||||
if (code != TranscodeResult_Ok) {
|
||||
|
@ -1108,11 +1107,12 @@ WriteScriptOrFunction(nsIObjectOutputStream* stream, JSContext* cx,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(size && data);
|
||||
size_t size = buffer.length();
|
||||
if (size > UINT32_MAX)
|
||||
return NS_ERROR_FAILURE;
|
||||
rv = stream->Write32(size);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = stream->WriteBytes(static_cast<char*>(data), size);
|
||||
js_free(data);
|
||||
rv = stream->WriteBytes(reinterpret_cast<char*>(buffer.begin()), size);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -1145,16 +1145,19 @@ ReadScriptOrFunction(nsIObjectInputStream* stream, JSContext* cx,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
TranscodeBuffer buffer;
|
||||
buffer.replaceRawBuffer(reinterpret_cast<uint8_t*>(data), size);
|
||||
|
||||
{
|
||||
TranscodeResult code;
|
||||
if (scriptp) {
|
||||
Rooted<JSScript*> script(cx);
|
||||
code = JS_DecodeScript(cx, data, size, &script);
|
||||
code = DecodeScript(cx, buffer, &script);
|
||||
if (code == TranscodeResult_Ok)
|
||||
*scriptp = script.get();
|
||||
} else {
|
||||
Rooted<JSFunction*> funobj(cx);
|
||||
code = JS_DecodeInterpretedFunction(cx, data, size, &funobj);
|
||||
code = DecodeInterpretedFunction(cx, buffer, &funobj);
|
||||
if (code == TranscodeResult_Ok)
|
||||
*functionObjp = JS_GetFunctionObject(funobj.get());
|
||||
}
|
||||
|
@ -1168,7 +1171,6 @@ ReadScriptOrFunction(nsIObjectInputStream* stream, JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
free(data);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче