Bug 960367 - OdinMonkey: compress source stored in in cache file (r=sstangl)

This commit is contained in:
Luke Wagner
2014-01-17 17:34:33 -06:00
parent d0b53ae3e5
commit 1a0b0ef75b
2 changed files with 68 additions and 21 deletions

View File

@@ -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(

View File

@@ -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