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