зеркало из https://github.com/mozilla/gecko-dev.git
Bug 929236 - Don't waste time caching small asm.js modules (r=sstangl)
--HG-- extra : rebase_source : 03c1f15c9ad89e0cae2e53a633ab743656380bf5
This commit is contained in:
Родитель
5ed834b091
Коммит
3d01d25dc6
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче