From 3d01d25dc6efe4b050bf25ad652485bf559f8a18 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 18 Nov 2013 16:02:05 -0600 Subject: [PATCH] Bug 929236 - Don't waste time caching small asm.js modules (r=sstangl) --HG-- extra : rebase_source : 03c1f15c9ad89e0cae2e53a633ab743656380bf5 --- dom/asmjscache/AsmJSCache.cpp | 16 +++++++++++ dom/asmjscache/AsmJSCache.h | 28 ++++++++++++++------ js/src/jit/AsmJS.cpp | 12 +++++---- js/src/jit/AsmJSModule.cpp | 50 ++++++++++++++++++++++------------- js/src/jit/AsmJSModule.h | 2 +- js/src/jsapi.h | 30 +++++++++++---------- js/src/shell/js.cpp | 9 ++++--- 7 files changed, 96 insertions(+), 51 deletions(-) diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index f182b03dd994..996794ec6353 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -1023,12 +1023,22 @@ OpenFile(JS::Handle 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 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 global, bool OpenEntryForWrite(JS::Handle 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); diff --git a/dom/asmjscache/AsmJSCache.h b/dom/asmjscache/AsmJSCache.h index 6a7ffa66c747..cd40fce74e45 100644 --- a/dom/asmjscache/AsmJSCache.h +++ b/dom/asmjscache/AsmJSCache.h @@ -35,17 +35,29 @@ enum OpenMode // Implementation of AsmJSCacheOps, installed by nsJSEnvironment: bool -OpenEntryForRead(JS::Handle aGlobal, size_t* aSize, - const uint8_t** aMemory, intptr_t *aHandle); +OpenEntryForRead(JS::Handle aGlobal, + const jschar* aBegin, + const jschar* aLimit, + size_t* aSize, + const uint8_t** aMemory, + intptr_t *aHandle); void -CloseEntryForRead(JS::Handle aGlobal, size_t aSize, - const uint8_t* aMemory, intptr_t aHandle); +CloseEntryForRead(JS::Handle aGlobal, + size_t aSize, + const uint8_t* aMemory, + intptr_t aHandle); bool -OpenEntryForWrite(JS::Handle aGlobal, size_t aSize, - uint8_t** aMemory, intptr_t* aHandle); +OpenEntryForWrite(JS::Handle aGlobal, + const jschar* aBegin, + const jschar* aEnd, + size_t aSize, + uint8_t** aMemory, + intptr_t* aHandle); void -CloseEntryForWrite(JS::Handle aGlobal, size_t aSize, - uint8_t* aMemory, intptr_t aHandle); +CloseEntryForWrite(JS::Handle aGlobal, + size_t aSize, + uint8_t* aMemory, + intptr_t aHandle); bool GetBuildId(js::Vector* aBuildId); diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index ad7e6bc7528d..552049299e1c 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -1632,7 +1632,7 @@ class MOZ_STACK_CLASS ModuleCompiler module_->exportedFunction(exportIndex).initCodeOffset(masm_.size()); } - void buildCompilationTimeReport(ScopedJSFreePtr *out) { + void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr *out) { ScopedJSFreePtr 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; } diff --git a/js/src/jit/AsmJSModule.cpp b/js/src/jit/AsmJSModule.cpp index 03aedb635b12..9e80215c2ff1 100644 --- a/js/src/jit/AsmJSModule.cpp +++ b/js/src/jit/AsmJSModule.cpp @@ -802,6 +802,14 @@ class ModuleChars Vector 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; diff --git a/js/src/jit/AsmJSModule.h b/js/src/jit/AsmJSModule.h index b04e5e5f0b47..91d2b815d6bb 100644 --- a/js/src/jit/AsmJSModule.h +++ b/js/src/jit/AsmJSModule.h @@ -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, diff --git a/js/src/jsapi.h b/js/src/jsapi.h index cd29c4bfb234..eca78dbc00dd 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -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); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f95c2e3b3c98..bb2f066fab9b 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -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;