Bug 929236 - Don't waste time caching small asm.js modules (r=sstangl)

--HG--
extra : rebase_source : 03c1f15c9ad89e0cae2e53a633ab743656380bf5
This commit is contained in:
Luke Wagner 2013-11-18 16:02:05 -06:00
parent 5ed834b091
commit 3d01d25dc6
7 changed files with 96 additions and 51 deletions

View File

@ -1023,12 +1023,22 @@ OpenFile(JS::Handle<JSObject*> aGlobal,
typedef uint32_t AsmJSCookieType;
static const uint32_t sAsmJSCookie = 0x600d600d;
// Anything smaller should compile fast enough that caching will just add
// overhead.
static const size_t sMinCachedModuleLength = 10000;
bool
OpenEntryForRead(JS::Handle<JSObject*> aGlobal,
const jschar* aBegin,
const jschar* aLimit,
size_t* aSize,
const uint8_t** aMemory,
intptr_t* aFile)
{
if (size_t(aLimit - aBegin) < sMinCachedModuleLength) {
return false;
}
File::AutoClose file;
if (!OpenFile(aGlobal, eOpenForRead, 0, &file)) {
return false;
@ -1073,10 +1083,16 @@ CloseEntryForRead(JS::Handle<JSObject*> global,
bool
OpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
const jschar* aBegin,
const jschar* aEnd,
size_t aSize,
uint8_t** aMemory,
intptr_t* aFile)
{
if (size_t(aEnd - aBegin) < sMinCachedModuleLength) {
return false;
}
// Add extra space for the AsmJSCookieType (see OpenEntryForRead).
aSize += sizeof(AsmJSCookieType);

View File

@ -35,17 +35,29 @@ enum OpenMode
// Implementation of AsmJSCacheOps, installed by nsJSEnvironment:
bool
OpenEntryForRead(JS::Handle<JSObject*> aGlobal, size_t* aSize,
const uint8_t** aMemory, intptr_t *aHandle);
OpenEntryForRead(JS::Handle<JSObject*> aGlobal,
const jschar* aBegin,
const jschar* aLimit,
size_t* aSize,
const uint8_t** aMemory,
intptr_t *aHandle);
void
CloseEntryForRead(JS::Handle<JSObject*> aGlobal, size_t aSize,
const uint8_t* aMemory, intptr_t aHandle);
CloseEntryForRead(JS::Handle<JSObject*> aGlobal,
size_t aSize,
const uint8_t* aMemory,
intptr_t aHandle);
bool
OpenEntryForWrite(JS::Handle<JSObject*> aGlobal, size_t aSize,
uint8_t** aMemory, intptr_t* aHandle);
OpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
const jschar* aBegin,
const jschar* aEnd,
size_t aSize,
uint8_t** aMemory,
intptr_t* aHandle);
void
CloseEntryForWrite(JS::Handle<JSObject*> aGlobal, size_t aSize,
uint8_t* aMemory, intptr_t aHandle);
CloseEntryForWrite(JS::Handle<JSObject*> aGlobal,
size_t aSize,
uint8_t* aMemory,
intptr_t aHandle);
bool
GetBuildId(js::Vector<char>* aBuildId);

View File

@ -1632,7 +1632,7 @@ class MOZ_STACK_CLASS ModuleCompiler
module_->exportedFunction(exportIndex).initCodeOffset(masm_.size());
}
void buildCompilationTimeReport(ScopedJSFreePtr<char> *out) {
void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr<char> *out) {
ScopedJSFreePtr<char> slowFuns;
#ifndef JS_MORE_DETERMINISTIC
int64_t usecAfter = PRMJ_Now();
@ -1653,8 +1653,10 @@ class MOZ_STACK_CLASS ModuleCompiler
return;
}
}
out->reset(JS_smprintf("total compilation time %dms%s",
msTotal, slowFuns ? slowFuns.get() : ""));
out->reset(JS_smprintf("total compilation time %dms%s%s",
msTotal,
storedInCache ? "; stored in cache" : "",
slowFuns ? slowFuns.get() : ""));
#endif
}
@ -6462,10 +6464,10 @@ CheckModule(ExclusiveContext *cx, AsmJSParser &parser, ParseNode *stmtList,
if (!FinishModule(m, &module, &linkData))
return false;
StoreAsmJSModuleInCache(parser, *module, linkData, cx);
bool storedInCache = StoreAsmJSModuleInCache(parser, *module, linkData, cx);
module->staticallyLink(linkData, cx);
m.buildCompilationTimeReport(compilationTimeReport);
m.buildCompilationTimeReport(storedInCache, compilationTimeReport);
*moduleOut = module.forget();
return true;
}

View File

@ -802,6 +802,14 @@ class ModuleChars
Vector<PropertyNameWrapper, 0, SystemAllocPolicy> funCtorArgs_;
public:
static uint32_t beginOffset(AsmJSParser &parser) {
return parser.pc->maybeFunction->pn_pos.begin;
}
static uint32_t endOffset(AsmJSParser &parser) {
return parser.tokenStream.peekTokenPos().end;
}
bool initFromParsedModule(AsmJSParser &parser, const AsmJSModule &module) {
// For a function statement or named function expression:
// function f(x,y,z) { abc }
@ -815,11 +823,9 @@ 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.
uint32_t beginOffset = parser.pc->maybeFunction->pn_pos.begin;
uint32_t endOffset = parser.tokenStream.peekTokenPos().end;
JS_ASSERT(beginOffset < endOffset);
begin_ = parser.tokenStream.rawBase() + beginOffset;
length_ = endOffset - beginOffset;
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;
@ -858,9 +864,8 @@ class ModuleChars
return cursor;
}
bool matchUnparsedModule(const AsmJSParser &parser) const {
uint32_t parseBeginOffset = parser.pc->maybeFunction->pn_pos.begin;
const jschar *parseBegin = parser.tokenStream.rawBase() + parseBeginOffset;
bool matchUnparsedModule(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_)
@ -909,7 +914,7 @@ struct ScopedCacheEntryOpenedForWrite
}
};
void
bool
js::StoreAsmJSModuleInCache(AsmJSParser &parser,
const AsmJSModule &module,
const AsmJSStaticLinkData &linkData,
@ -917,24 +922,27 @@ js::StoreAsmJSModuleInCache(AsmJSParser &parser,
{
MachineId machineId(cx);
if (!machineId.extractCurrentState(cx))
return;
return false;
ModuleChars moduleChars;
if (!moduleChars.initFromParsedModule(parser, module))
return;
return false;
size_t serializedSize = machineId.serializedSize() +
moduleChars.serializedSize() +
module.serializedSize() +
linkData.serializedSize();
JS::OpenAsmJSCacheEntryForWriteOp openEntryForWrite = cx->asmJSCacheOps().openEntryForWrite;
if (!openEntryForWrite)
return;
JS::OpenAsmJSCacheEntryForWriteOp open = cx->asmJSCacheOps().openEntryForWrite;
if (!open)
return false;
const jschar *begin = parser.tokenStream.rawBase() + ModuleChars::beginOffset(parser);
const jschar *end = parser.tokenStream.rawBase() + ModuleChars::endOffset(parser);
ScopedCacheEntryOpenedForWrite entry(cx, serializedSize);
if (!openEntryForWrite(cx->global(), entry.serializedSize, &entry.memory, &entry.handle))
return;
if (!open(cx->global(), begin, end, entry.serializedSize, &entry.memory, &entry.handle))
return false;
uint8_t *cursor = entry.memory;
cursor = machineId.serialize(cursor);
@ -943,6 +951,7 @@ js::StoreAsmJSModuleInCache(AsmJSParser &parser,
cursor = linkData.serialize(cursor);
JS_ASSERT(cursor == entry.memory + serializedSize);
return true;
}
struct ScopedCacheEntryOpenedForRead
@ -974,12 +983,15 @@ js::LookupAsmJSModuleInCache(ExclusiveContext *cx,
if (!machineId.extractCurrentState(cx))
return true;
JS::OpenAsmJSCacheEntryForReadOp openEntryForRead = cx->asmJSCacheOps().openEntryForRead;
if (!openEntryForRead)
JS::OpenAsmJSCacheEntryForReadOp open = cx->asmJSCacheOps().openEntryForRead;
if (!open)
return true;
const jschar *begin = parser.tokenStream.rawBase() + ModuleChars::beginOffset(parser);
const jschar *limit = parser.tokenStream.rawLimit();
ScopedCacheEntryOpenedForRead entry(cx);
if (!openEntryForRead(cx->global(), &entry.serializedSize, &entry.memory, &entry.handle))
if (!open(cx->global(), begin, limit, &entry.serializedSize, &entry.memory, &entry.handle))
return true;
const uint8_t *cursor = entry.memory;

View File

@ -776,7 +776,7 @@ class AsmJSModule
};
// Store the just-parsed module in the cache using AsmJSCacheOps.
extern void
extern bool
StoreAsmJSModuleInCache(AsmJSParser &parser,
const AsmJSModule &module,
const AsmJSStaticLinkData &linkData,

View File

@ -4605,30 +4605,32 @@ namespace JS {
/*
* This callback represents a request by the JS engine to open for reading the
* existing cache entry for the given global. If a cache entry exists, the
* callback shall return 'true' and return the size, base address and an opaque
* file handle as outparams. If the callback returns 'true', the JS engine
* guarantees a call to CloseAsmJSCacheEntryForReadOp, passing the same base
* address, size and handle.
* existing cache entry for the given global and char range that may contain a
* module. If a cache entry exists, the callback shall return 'true' and return
* the size, base address and an opaque file handle as outparams. If the
* callback returns 'true', the JS engine guarantees a call to
* CloseAsmJSCacheEntryForReadOp, passing the same base address, size and
* handle.
*/
typedef bool
(* OpenAsmJSCacheEntryForReadOp)(HandleObject global, size_t *size, const uint8_t **memory,
intptr_t *handle);
(* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const jschar *begin, const jschar *limit,
size_t *size, const uint8_t **memory, intptr_t *handle);
typedef void
(* CloseAsmJSCacheEntryForReadOp)(HandleObject global, size_t size, const uint8_t *memory,
intptr_t handle);
/*
* This callback represents a request by the JS engine to open for writing a
* cache entry of the given size for the given global. If cache entry space is
* available, the callback shall return 'true' and return the base address and
* an opaque file handle as outparams. If the callback returns 'true', the JS
* engine guarantees a call to CloseAsmJSCacheEntryForWriteOp passing the same
* base address, size and handle.
* cache entry of the given size for the given global and char range containing
* the just-compiled module. If cache entry space is available, the callback
* shall return 'true' and return the base address and an opaque file handle as
* outparams. If the callback returns 'true', the JS engine guarantees a call
* to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and
* handle.
*/
typedef bool
(* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t **memory,
intptr_t *handle);
(* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, const jschar *begin, const jschar *end,
size_t size, uint8_t **memory, intptr_t *handle);
typedef void
(* CloseAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t *memory,
intptr_t handle);

View File

@ -5015,8 +5015,9 @@ class ScopedFileDesc
static const uint32_t asmJSCacheCookie = 0xabbadaba;
static bool
ShellOpenAsmJSCacheEntryForRead(HandleObject global, size_t *serializedSizeOut,
const uint8_t **memoryOut, intptr_t *handleOut)
ShellOpenAsmJSCacheEntryForRead(HandleObject global, const jschar *begin, const jschar *limit,
size_t *serializedSizeOut, const uint8_t **memoryOut,
intptr_t *handleOut)
{
if (!jsCacheAsmJSPath)
return false;
@ -5087,8 +5088,8 @@ ShellCloseAsmJSCacheEntryForRead(HandleObject global, size_t serializedSize, con
}
static bool
ShellOpenAsmJSCacheEntryForWrite(HandleObject global, size_t serializedSize,
uint8_t **memoryOut, intptr_t *handleOut)
ShellOpenAsmJSCacheEntryForWrite(HandleObject global, const jschar *begin, const jschar *end,
size_t serializedSize, uint8_t **memoryOut, intptr_t *handleOut)
{
if (!jsCacheAsmJSPath)
return false;