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; typedef uint32_t AsmJSCookieType;
static const uint32_t sAsmJSCookie = 0x600d600d; 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 bool
OpenEntryForRead(JS::Handle<JSObject*> aGlobal, OpenEntryForRead(JS::Handle<JSObject*> aGlobal,
const jschar* aBegin,
const jschar* aLimit,
size_t* aSize, size_t* aSize,
const uint8_t** aMemory, const uint8_t** aMemory,
intptr_t* aFile) intptr_t* aFile)
{ {
if (size_t(aLimit - aBegin) < sMinCachedModuleLength) {
return false;
}
File::AutoClose file; File::AutoClose file;
if (!OpenFile(aGlobal, eOpenForRead, 0, &file)) { if (!OpenFile(aGlobal, eOpenForRead, 0, &file)) {
return false; return false;
@ -1073,10 +1083,16 @@ CloseEntryForRead(JS::Handle<JSObject*> global,
bool bool
OpenEntryForWrite(JS::Handle<JSObject*> aGlobal, OpenEntryForWrite(JS::Handle<JSObject*> aGlobal,
const jschar* aBegin,
const jschar* aEnd,
size_t aSize, size_t aSize,
uint8_t** aMemory, uint8_t** aMemory,
intptr_t* aFile) intptr_t* aFile)
{ {
if (size_t(aEnd - aBegin) < sMinCachedModuleLength) {
return false;
}
// Add extra space for the AsmJSCookieType (see OpenEntryForRead). // Add extra space for the AsmJSCookieType (see OpenEntryForRead).
aSize += sizeof(AsmJSCookieType); aSize += sizeof(AsmJSCookieType);

View File

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

View File

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

View File

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

View File

@ -776,7 +776,7 @@ class AsmJSModule
}; };
// Store the just-parsed module in the cache using AsmJSCacheOps. // Store the just-parsed module in the cache using AsmJSCacheOps.
extern void extern bool
StoreAsmJSModuleInCache(AsmJSParser &parser, StoreAsmJSModuleInCache(AsmJSParser &parser,
const AsmJSModule &module, const AsmJSModule &module,
const AsmJSStaticLinkData &linkData, 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 * 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 * existing cache entry for the given global and char range that may contain a
* callback shall return 'true' and return the size, base address and an opaque * module. If a cache entry exists, the callback shall return 'true' and return
* file handle as outparams. If the callback returns 'true', the JS engine * the size, base address and an opaque file handle as outparams. If the
* guarantees a call to CloseAsmJSCacheEntryForReadOp, passing the same base * callback returns 'true', the JS engine guarantees a call to
* address, size and handle. * CloseAsmJSCacheEntryForReadOp, passing the same base address, size and
* handle.
*/ */
typedef bool typedef bool
(* OpenAsmJSCacheEntryForReadOp)(HandleObject global, size_t *size, const uint8_t **memory, (* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const jschar *begin, const jschar *limit,
intptr_t *handle); size_t *size, const uint8_t **memory, intptr_t *handle);
typedef void typedef void
(* CloseAsmJSCacheEntryForReadOp)(HandleObject global, size_t size, const uint8_t *memory, (* CloseAsmJSCacheEntryForReadOp)(HandleObject global, size_t size, const uint8_t *memory,
intptr_t handle); intptr_t handle);
/* /*
* This callback represents a request by the JS engine to open for writing a * 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 * cache entry of the given size for the given global and char range containing
* available, the callback shall return 'true' and return the base address and * the just-compiled module. If cache entry space is available, the callback
* an opaque file handle as outparams. If the callback returns 'true', the JS * shall return 'true' and return the base address and an opaque file handle as
* engine guarantees a call to CloseAsmJSCacheEntryForWriteOp passing the same * outparams. If the callback returns 'true', the JS engine guarantees a call
* base address, size and handle. * to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and
* handle.
*/ */
typedef bool typedef bool
(* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t **memory, (* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, const jschar *begin, const jschar *end,
intptr_t *handle); size_t size, uint8_t **memory, intptr_t *handle);
typedef void typedef void
(* CloseAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t *memory, (* CloseAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t *memory,
intptr_t handle); intptr_t handle);

View File

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