Bug 960367 - OdinMonkey: compress source stored in in cache file (r=sstangl)
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/Compression.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
#include "jslibmath.h"
|
||||
@@ -32,6 +33,7 @@ using namespace js;
|
||||
using namespace jit;
|
||||
using namespace frontend;
|
||||
using mozilla::PodEqual;
|
||||
using mozilla::Compression::LZ4;
|
||||
|
||||
void
|
||||
AsmJSModule::initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx)
|
||||
@@ -814,8 +816,7 @@ struct PropertyNameWrapper
|
||||
|
||||
class ModuleChars
|
||||
{
|
||||
uint32_t length_;
|
||||
const jschar *begin_;
|
||||
protected:
|
||||
uint32_t isFunCtor_;
|
||||
js::Vector<PropertyNameWrapper, 0, SystemAllocPolicy> funCtorArgs_;
|
||||
|
||||
@@ -827,8 +828,34 @@ class ModuleChars
|
||||
static uint32_t endOffset(AsmJSParser &parser) {
|
||||
return parser.tokenStream.peekTokenPos().end;
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleCharsForStore : ModuleChars
|
||||
{
|
||||
uint32_t uncompressedSize_;
|
||||
uint32_t compressedSize_;
|
||||
js::Vector<char, 0, SystemAllocPolicy> compressedBuffer_;
|
||||
|
||||
public:
|
||||
bool init(AsmJSParser &parser, const AsmJSModule &module) {
|
||||
JS_ASSERT(beginOffset(parser) < endOffset(parser));
|
||||
|
||||
uncompressedSize_ = (endOffset(parser) - beginOffset(parser)) * sizeof(jschar);
|
||||
size_t maxCompressedSize = LZ4::maxCompressedSize(uncompressedSize_);
|
||||
if (maxCompressedSize < uncompressedSize_)
|
||||
return false;
|
||||
|
||||
if (!compressedBuffer_.resize(maxCompressedSize))
|
||||
return false;
|
||||
|
||||
const jschar *chars = parser.tokenStream.rawBase() + beginOffset(parser);
|
||||
const char *source = reinterpret_cast<const char*>(chars);
|
||||
size_t compressedSize = LZ4::compress(source, uncompressedSize_, compressedBuffer_.begin());
|
||||
if (!compressedSize || compressedSize > UINT32_MAX)
|
||||
return false;
|
||||
|
||||
compressedSize_ = compressedSize;
|
||||
|
||||
bool initFromParsedModule(AsmJSParser &parser, const AsmJSModule &module) {
|
||||
// For a function statement or named function expression:
|
||||
// function f(x,y,z) { abc }
|
||||
// the range [beginOffset, endOffset) captures the source:
|
||||
@@ -841,9 +868,6 @@ class ModuleChars
|
||||
// For functions created with 'new Function', function arguments are
|
||||
// not present in the source so we must manually explicitly serialize
|
||||
// and match the formals as a Vector of PropertyName.
|
||||
JS_ASSERT(beginOffset(parser) < endOffset(parser));
|
||||
begin_ = parser.tokenStream.rawBase() + beginOffset(parser);
|
||||
length_ = endOffset(parser) - beginOffset(parser);
|
||||
isFunCtor_ = parser.pc->isFunctionConstructorBody();
|
||||
if (isFunCtor_) {
|
||||
unsigned numArgs;
|
||||
@@ -853,42 +877,65 @@ class ModuleChars
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t serializedSize() const {
|
||||
return sizeof(uint32_t) +
|
||||
length_ * sizeof(jschar) +
|
||||
sizeof(uint32_t) +
|
||||
compressedSize_ +
|
||||
sizeof(uint32_t) +
|
||||
(isFunCtor_ ? SerializedVectorSize(funCtorArgs_) : 0);
|
||||
}
|
||||
|
||||
uint8_t *serialize(uint8_t *cursor) const {
|
||||
cursor = WriteScalar<uint32_t>(cursor, length_);
|
||||
cursor = WriteBytes(cursor, begin_, length_ * sizeof(jschar));
|
||||
cursor = WriteScalar<uint32_t>(cursor, uncompressedSize_);
|
||||
cursor = WriteScalar<uint32_t>(cursor, compressedSize_);
|
||||
cursor = WriteBytes(cursor, compressedBuffer_.begin(), compressedSize_);
|
||||
cursor = WriteScalar<uint32_t>(cursor, isFunCtor_);
|
||||
if (isFunCtor_)
|
||||
cursor = SerializeVector(cursor, funCtorArgs_);
|
||||
return cursor;
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleCharsForLookup : ModuleChars
|
||||
{
|
||||
js::Vector<jschar, 0, SystemAllocPolicy> chars_;
|
||||
|
||||
public:
|
||||
const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor) {
|
||||
cursor = ReadScalar<uint32_t>(cursor, &length_);
|
||||
begin_ = reinterpret_cast<const jschar *>(cursor);
|
||||
cursor += length_ * sizeof(jschar);
|
||||
uint32_t uncompressedSize;
|
||||
cursor = ReadScalar<uint32_t>(cursor, &uncompressedSize);
|
||||
|
||||
uint32_t compressedSize;
|
||||
cursor = ReadScalar<uint32_t>(cursor, &compressedSize);
|
||||
|
||||
if (!chars_.resize(uncompressedSize / sizeof(jschar)))
|
||||
return nullptr;
|
||||
|
||||
const char *source = reinterpret_cast<const char*>(cursor);
|
||||
char *dest = reinterpret_cast<char*>(chars_.begin());
|
||||
if (!LZ4::decompress(source, dest, uncompressedSize))
|
||||
return nullptr;
|
||||
|
||||
cursor += compressedSize;
|
||||
|
||||
cursor = ReadScalar<uint32_t>(cursor, &isFunCtor_);
|
||||
if (isFunCtor_)
|
||||
cursor = DeserializeVector(cx, cursor, &funCtorArgs_);
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
bool matchUnparsedModule(AsmJSParser &parser) const {
|
||||
bool match(AsmJSParser &parser) const {
|
||||
const jschar *parseBegin = parser.tokenStream.rawBase() + beginOffset(parser);
|
||||
const jschar *parseLimit = parser.tokenStream.rawLimit();
|
||||
JS_ASSERT(parseLimit >= parseBegin);
|
||||
if (uint32_t(parseLimit - parseBegin) < length_)
|
||||
if (uint32_t(parseLimit - parseBegin) < chars_.length())
|
||||
return false;
|
||||
if (!PodEqual(begin_, parseBegin, length_))
|
||||
if (!PodEqual(chars_.begin(), parseBegin, chars_.length()))
|
||||
return false;
|
||||
if (isFunCtor_ != parser.pc->isFunctionConstructorBody())
|
||||
return false;
|
||||
@@ -900,7 +947,7 @@ class ModuleChars
|
||||
// new Function('"use asm"; function f() {} return f')
|
||||
// from incorrectly matching
|
||||
// new Function('"use asm"; function f() {} return ff')
|
||||
if (parseBegin + length_ != parseLimit)
|
||||
if (parseBegin + chars_.length() != parseLimit)
|
||||
return false;
|
||||
unsigned numArgs;
|
||||
ParseNode *arg = FunctionArgsList(parser.pc->maybeFunction, &numArgs);
|
||||
@@ -942,8 +989,8 @@ js::StoreAsmJSModuleInCache(AsmJSParser &parser,
|
||||
if (!machineId.extractCurrentState(cx))
|
||||
return false;
|
||||
|
||||
ModuleChars moduleChars;
|
||||
if (!moduleChars.initFromParsedModule(parser, module))
|
||||
ModuleCharsForStore moduleChars;
|
||||
if (!moduleChars.init(parser, module))
|
||||
return false;
|
||||
|
||||
size_t serializedSize = machineId.serializedSize() +
|
||||
@@ -1021,9 +1068,9 @@ js::LookupAsmJSModuleInCache(ExclusiveContext *cx,
|
||||
if (machineId != cachedMachineId)
|
||||
return true;
|
||||
|
||||
ModuleChars moduleChars;
|
||||
ModuleCharsForLookup moduleChars;
|
||||
cursor = moduleChars.deserialize(cx, cursor);
|
||||
if (!moduleChars.matchUnparsedModule(parser))
|
||||
if (!moduleChars.match(parser))
|
||||
return true;
|
||||
|
||||
ScopedJSDeletePtr<AsmJSModule> module(
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
* Compresses 'inputSize' bytes from 'source' into 'dest'.
|
||||
* Destination buffer must be already allocated,
|
||||
* and must be sized to handle worst cases situations (input data not compressible)
|
||||
* Worst case size evaluation is provided by function LZ4_compressBound()
|
||||
* Worst case size evaluation is provided by function maxCompressedSize()
|
||||
*
|
||||
* @param inputSize is the input size. Max supported value is ~1.9GB
|
||||
* @param return the number of bytes written in buffer dest
|
||||
|
||||
Reference in New Issue
Block a user