Bug 1437530: Cache template literal objects per call site again. r=arai

This commit is contained in:
André Bargull 2018-02-19 05:07:29 -08:00
parent 3971a035c7
commit 04c864d3c5
13 changed files with 32 additions and 158 deletions

View File

@ -774,7 +774,6 @@ struct CompartmentStats
macro(Other, MallocHeap, savedStacksSet) \
macro(Other, MallocHeap, varNamesSet) \
macro(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
macro(Other, MallocHeap, templateLiteralMap) \
macro(Other, MallocHeap, jitCompartment) \
macro(Other, MallocHeap, privateData) \
macro(Other, MallocHeap, scriptCountsMap)

View File

@ -2484,7 +2484,6 @@ GCRuntime::sweepZoneAfterCompacting(Zone* zone)
c->objectGroups.sweep(fop);
c->sweepRegExps();
c->sweepSavedStacks();
c->sweepTemplateLiteralMap();
c->sweepVarNames();
c->sweepGlobalObject();
c->sweepSelfHostingScriptSource();
@ -5362,7 +5361,6 @@ SweepMisc(JSRuntime* runtime)
c->sweepGlobalObject();
c->sweepTemplateObjects();
c->sweepSavedStacks();
c->sweepTemplateLiteralMap();
c->sweepSelfHostingScriptSource();
c->sweepNativeIterators();
}

View File

@ -1693,11 +1693,11 @@ bool
BaselineCompiler::emit_JSOP_CALLSITEOBJ()
{
RootedObject cso(cx, script->getObject(pc));
RootedArrayObject raw(cx, &script->getObject(GET_UINT32_INDEX(pc) + 1)->as<ArrayObject>());
RootedObject raw(cx, script->getObject(GET_UINT32_INDEX(pc) + 1));
if (!cso || !raw)
return false;
if (!cx->compartment()->getTemplateLiteralObject(cx, raw, &cso))
if (!ProcessCallSiteObjOperation(cx, cso, raw))
return false;
frame.push(ObjectValue(*cso));

View File

@ -2244,16 +2244,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_regexp(info().getRegExp(pc));
case JSOP_CALLSITEOBJ:
if (info().analysisMode() == Analysis_ArgumentsUsage) {
// When analyzing arguments usage, it is possible that the
// template object is not yet canonicalized. Push an incorrect
// object; it does not matter for arguments analysis.
pushConstant(ObjectValue(*info().getObject(pc)));
} else {
ArrayObject* raw = &script()->getObject(GET_UINT32_INDEX(pc) + 1)->as<ArrayObject>();
JSObject* obj = script()->compartment()->getExistingTemplateLiteralObject(raw);
pushConstant(ObjectValue(*obj));
}
pushConstant(ObjectValue(*info().getObject(pc)));
return Ok();
case JSOP_OBJECT:

View File

@ -459,3 +459,11 @@ skip script test262/harness/detachArrayBuffer.js
####################################################
# Tests disabled due to invalid test expectations #
####################################################
# https://github.com/tc39/test262/pull/972
skip script test262/language/expressions/tagged-template/cache-identical-source-new-function.js
skip script test262/language/expressions/tagged-template/cache-differing-expressions-new-function.js
skip script test262/language/expressions/tagged-template/cache-differing-expressions.js
skip script test262/language/expressions/tagged-template/cache-identical-source.js
skip script test262/language/expressions/tagged-template/cache-differing-expressions-eval.js
skip script test262/language/expressions/tagged-template/cache-identical-source-eval.js

View File

@ -203,7 +203,7 @@ for (var i = 1; i < 3; i++)
// Same call site object behavior
assertEq(callSiteObj[1], callSiteObj[2]);
// Template objects are canonicalized
assertEq(callSiteObj[0], callSiteObj[1]);
assertEq(callSiteObj[0] !== callSiteObj[1], true);
assertEq("raw" in callSiteObj[0], true);
// Array length
@ -227,7 +227,7 @@ function test() {
a[i] = eval("x``");
}
test();
assertEq(a[0], a[1]);
assertEq(a[0] !== a[1], true);
// Test that |obj.method`template`| works
var newObj = {

View File

@ -684,6 +684,24 @@ InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t
return true;
}
static MOZ_ALWAYS_INLINE bool
ProcessCallSiteObjOperation(JSContext* cx, HandleObject cso, HandleObject raw)
{
MOZ_ASSERT(cso->is<ArrayObject>());
MOZ_ASSERT(raw->is<ArrayObject>());
if (cso->nonProxyIsExtensible()) {
RootedValue rawValue(cx, ObjectValue(*raw));
if (!DefineDataProperty(cx, cso, cx->names().raw, rawValue, 0))
return false;
if (!FreezeObject(cx, raw))
return false;
if (!FreezeObject(cx, cso))
return false;
}
return true;
}
#define RELATIONAL_OP(OP) \
JS_BEGIN_MACRO \
/* Optimize for two int-tagged operands (typical loop control). */ \

View File

@ -3317,7 +3317,7 @@ CASE(JSOP_CALLSITEOBJ)
ReservedRooted<JSObject*> cso(&rootObject0, script->getObject(REGS.pc));
ReservedRooted<JSObject*> raw(&rootObject1, script->getObject(GET_UINT32_INDEX(REGS.pc) + 1));
if (!cx->compartment()->getTemplateLiteralObject(cx, raw.as<ArrayObject>(), &cso))
if (!ProcessCallSiteObjOperation(cx, cso, raw))
goto error;
PUSH_OBJECT(*cso);

View File

@ -156,7 +156,6 @@ JSCompartment::init(JSContext* maybecx)
if (!savedStacks_.init() ||
!varNames_.init() ||
!templateLiteralMap_.init() ||
!iteratorCache.init())
{
if (maybecx)
@ -620,70 +619,6 @@ JSCompartment::addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name)
return false;
}
/* static */ HashNumber
TemplateRegistryHashPolicy::hash(const Lookup& lookup)
{
size_t length = lookup->as<NativeObject>().getDenseInitializedLength();
HashNumber hash = 0;
for (uint32_t i = 0; i < length; i++) {
JSAtom& lookupAtom = lookup->as<NativeObject>().getDenseElement(i).toString()->asAtom();
hash = mozilla::AddToHash(hash, lookupAtom.hash());
}
return hash;
}
/* static */ bool
TemplateRegistryHashPolicy::match(const Key& key, const Lookup& lookup)
{
size_t length = lookup->as<NativeObject>().getDenseInitializedLength();
if (key->as<NativeObject>().getDenseInitializedLength() != length)
return false;
for (uint32_t i = 0; i < length; i++) {
JSAtom* a = &key->as<NativeObject>().getDenseElement(i).toString()->asAtom();
JSAtom* b = &lookup->as<NativeObject>().getDenseElement(i).toString()->asAtom();
if (a != b)
return false;
}
return true;
}
bool
JSCompartment::getTemplateLiteralObject(JSContext* cx, HandleArrayObject rawStrings,
MutableHandleObject templateObj)
{
if (TemplateRegistry::AddPtr p = templateLiteralMap_.lookupForAdd(rawStrings)) {
templateObj.set(p->value());
// The template object must have been frozen when it was added to the
// registry.
MOZ_ASSERT(!templateObj->nonProxyIsExtensible());
} else {
MOZ_ASSERT(templateObj->nonProxyIsExtensible());
RootedValue rawValue(cx, ObjectValue(*rawStrings));
if (!DefineDataProperty(cx, templateObj, cx->names().raw, rawValue, 0))
return false;
if (!FreezeObject(cx, rawStrings))
return false;
if (!FreezeObject(cx, templateObj))
return false;
if (!templateLiteralMap_.relookupOrAdd(p, rawStrings, templateObj))
return false;
}
return true;
}
JSObject*
JSCompartment::getExistingTemplateLiteralObject(ArrayObject* rawStrings)
{
TemplateRegistry::Ptr p = templateLiteralMap_.lookup(rawStrings);
MOZ_ASSERT(p);
return p->value();
}
void
JSCompartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc)
{
@ -725,10 +660,6 @@ JSCompartment::traceGlobal(JSTracer* trc)
savedStacks_.trace(trc);
// The template registry strongly holds everything in it by design and
// spec.
templateLiteralMap_.trace(trc);
// Atoms are always tenured.
if (!JS::CurrentThreadIsHeapMinorCollecting())
varNames_.trace(trc);
@ -836,12 +767,6 @@ JSCompartment::sweepSavedStacks()
savedStacks_.sweep();
}
void
JSCompartment::sweepTemplateLiteralMap()
{
templateLiteralMap_.sweep();
}
void
JSCompartment::sweepGlobalObject()
{
@ -1098,7 +1023,6 @@ JSCompartment::clearTables()
MOZ_ASSERT(!jitCompartment_);
MOZ_ASSERT(!debugEnvs);
MOZ_ASSERT(enumerators->next() == enumerators);
MOZ_ASSERT(templateLiteralMap_.empty());
objectGroups.clearTables();
if (savedStacks_.initialized())
@ -1381,7 +1305,6 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t* savedStacksSet,
size_t* varNamesSet,
size_t* nonSyntacticLexicalEnvironmentsArg,
size_t* templateLiteralMap,
size_t* jitCompartment,
size_t* privateData,
size_t* scriptCountsMapArg)
@ -1403,7 +1326,6 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
if (nonSyntacticLexicalEnvironments_)
*nonSyntacticLexicalEnvironmentsArg +=
nonSyntacticLexicalEnvironments_->sizeOfIncludingThis(mallocSizeOf);
*templateLiteralMap += templateLiteralMap_.sizeOfExcludingThis(mallocSizeOf);
if (jitCompartment_)
*jitCompartment += jitCompartment_->sizeOfIncludingThis(mallocSizeOf);

View File

@ -25,7 +25,6 @@
#include "vm/ReceiverGuard.h"
#include "vm/RegExpShared.h"
#include "vm/SavedStacks.h"
#include "vm/TemplateRegistry.h"
#include "vm/Time.h"
#include "wasm/WasmCompartment.h"
@ -779,7 +778,6 @@ struct JSCompartment
size_t* savedStacksSet,
size_t* varNamesSet,
size_t* nonSyntacticLexicalScopes,
size_t* templateLiteralMap,
size_t* jitCompartment,
size_t* privateData,
size_t* scriptCountsMapArg);
@ -822,12 +820,6 @@ struct JSCompartment
// to use the same lexical environment to persist lexical bindings.
js::ObjectWeakMap* nonSyntacticLexicalEnvironments_;
// The realm's [[TemplateMap]], used for mapping template literals to
// unique template objects used in evaluation of tagged template literals.
//
// See ES 12.2.9.3.
js::TemplateRegistry templateLiteralMap_;
public:
/*
* During GC, stores the head of a list of incoming pointers from gray cells.
@ -955,7 +947,6 @@ struct JSCompartment
void sweepCrossCompartmentWrappers();
void sweepSavedStacks();
void sweepTemplateLiteralMap();
void sweepGlobalObject();
void sweepSelfHostingScriptSource();
void sweepJitCompartment(js::FreeOp* fop);
@ -1001,16 +992,6 @@ struct JSCompartment
return varNames_.has(name);
}
// Get a unique template object given a JS array of raw template strings
// and a template object. If a template object is found in template
// registry, that object is returned. Otherwise, the passed-in templateObj
// is added to the registry.
bool getTemplateLiteralObject(JSContext* cx, js::HandleArrayObject rawStrings,
js::MutableHandleObject templateObj);
// Per above, but an entry must already exist in the template registry.
JSObject* getExistingTemplateLiteralObject(js::ArrayObject* rawStrings);
void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
js::DtoaCache dtoaCache;

View File

@ -361,7 +361,6 @@ StatsCompartmentCallback(JSContext* cx, void* data, JSCompartment* compartment)
&cStats.savedStacksSet,
&cStats.varNamesSet,
&cStats.nonSyntacticLexicalScopesTable,
&cStats.templateLiteralMap,
&cStats.jitCompartment,
&cStats.privateData,
&cStats.scriptCountsMap);

View File

@ -1,38 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_TemplateRegistry_h
#define vm_TemplateRegistry_h
#include "gc/Marking.h"
#include "js/GCHashTable.h"
#include "vm/JSObject.h"
namespace js {
// Data structures to maintain unique template objects mapped to by lists of
// raw strings.
//
// See ES 12.2.9.3.
struct TemplateRegistryHashPolicy
{
// For use as HashPolicy. Expects keys as arrays of atoms.
using Key = JSObject*;
using Lookup = JSObject*;
static HashNumber hash(const Lookup& lookup);
static bool match(const Key& key, const Lookup& lookup);
};
using TemplateRegistry = JS::GCHashMap<JSObject*,
JSObject*,
TemplateRegistryHashPolicy,
SystemAllocPolicy>;
} // namespace js
#endif // vm_TemplateRegistery_h

View File

@ -1830,10 +1830,6 @@ ReportCompartmentStats(const JS::CompartmentStats& cStats,
cStats.nonSyntacticLexicalScopesTable,
"The non-syntactic lexical scopes table.");
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("template-literal-map"),
cStats.templateLiteralMap,
"The template literal registry.");
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("jit-compartment"),
cStats.jitCompartment,
"The JIT compartment.");