Bug 928562 - Remove uses of JSContext for BytecodeAnalysis, BaselineInspector, and constructing bytecode type maps, r=jandem.

This commit is contained in:
Brian Hackett 2013-10-22 08:08:10 -06:00
parent 381b632044
commit ab56ef38b6
14 changed files with 103 additions and 96 deletions

View File

@ -33,7 +33,7 @@ BaselineCompiler::BaselineCompiler(JSContext *cx, HandleScript script)
bool
BaselineCompiler::init()
{
if (!analysis_.init(cx))
if (!analysis_.init(cx->runtime()->gsnCache))
return false;
if (!labels_.init(script->length))
@ -74,7 +74,7 @@ BaselineCompiler::compile()
IonSpew(IonSpew_Codegen, "# Emitting baseline code for script %s:%d",
script->filename(), script->lineno);
if (cx->typeInferenceEnabled() && !script->ensureHasBytecodeTypeMap(cx))
if (cx->typeInferenceEnabled() && !script->ensureHasTypes(cx))
return Method_Error;
// Only need to analyze scripts which are marked |argumensHasVarBinding|, to
@ -155,11 +155,15 @@ BaselineCompiler::compile()
prologueOffset_.fixup(&masm);
spsPushToggleOffset_.fixup(&masm);
// Note: There is an extra entry in the bytecode type map for the search hint, see below.
size_t bytecodeTypeMapEntries = cx->typeInferenceEnabled() ? script->nTypeSets + 1 : 0;
BaselineScript *baselineScript = BaselineScript::New(cx, prologueOffset_.offset(),
spsPushToggleOffset_.offset(),
icEntries_.length(),
pcMappingIndexEntries.length(),
pcEntries.length());
pcEntries.length(),
bytecodeTypeMapEntries);
if (!baselineScript)
return Method_Error;
@ -210,6 +214,26 @@ BaselineCompiler::compile()
if (cx->runtime()->spsProfiler.enabled())
baselineScript->toggleSPS(true);
if (cx->typeInferenceEnabled()) {
uint32_t *bytecodeMap = baselineScript->bytecodeTypeMap();
uint32_t added = 0;
for (jsbytecode *pc = script->code; pc < script->code + script->length; pc += GetBytecodeLength(pc)) {
JSOp op = JSOp(*pc);
if (js_CodeSpec[op].format & JOF_TYPESET) {
bytecodeMap[added++] = pc - script->code;
if (added == script->nTypeSets)
break;
}
}
JS_ASSERT(added == script->nTypeSets);
// The last entry in the last index found, and is used to avoid binary
// searches for the sought entry when queries are in linear order.
bytecodeMap[script->nTypeSets] = 0;
}
return Method_Compiled;
}

View File

@ -46,12 +46,12 @@ class SetElemICInspector : public ICInspector
class BaselineInspector
{
private:
RootedScript script;
JSScript *script;
ICEntry *prevLookedUpEntry;
public:
BaselineInspector(JSContext *cx, JSScript *rawScript)
: script(cx, rawScript), prevLookedUpEntry(nullptr)
BaselineInspector(JSScript *script)
: script(script), prevLookedUpEntry(nullptr)
{
JS_ASSERT(script);
}

View File

@ -211,8 +211,8 @@ jit::EnterBaselineAtBranch(JSContext *cx, StackFrame *fp, jsbytecode *pc)
return IonExec_Ok;
}
static MethodStatus
BaselineCompile(JSContext *cx, HandleScript script)
MethodStatus
jit::BaselineCompile(JSContext *cx, HandleScript script)
{
JS_ASSERT(!script->hasBaselineScript());
JS_ASSERT(script->canBaselineCompile());
@ -361,21 +361,25 @@ static const unsigned DataAlignment = sizeof(uintptr_t);
BaselineScript *
BaselineScript::New(JSContext *cx, uint32_t prologueOffset,
uint32_t spsPushToggleOffset, size_t icEntries,
size_t pcMappingIndexEntries, size_t pcMappingSize)
size_t pcMappingIndexEntries, size_t pcMappingSize,
size_t bytecodeTypeMapEntries)
{
size_t paddedBaselineScriptSize = AlignBytes(sizeof(BaselineScript), DataAlignment);
size_t icEntriesSize = icEntries * sizeof(ICEntry);
size_t pcMappingIndexEntriesSize = pcMappingIndexEntries * sizeof(PCMappingIndexEntry);
size_t bytecodeTypeMapSize = bytecodeTypeMapEntries * sizeof(uint32_t);
size_t paddedICEntriesSize = AlignBytes(icEntriesSize, DataAlignment);
size_t paddedPCMappingIndexEntriesSize = AlignBytes(pcMappingIndexEntriesSize, DataAlignment);
size_t paddedPCMappingSize = AlignBytes(pcMappingSize, DataAlignment);
size_t paddedBytecodeTypesMapSize = AlignBytes(bytecodeTypeMapSize, DataAlignment);
size_t allocBytes = paddedBaselineScriptSize +
paddedICEntriesSize +
paddedPCMappingIndexEntriesSize +
paddedPCMappingSize;
paddedPCMappingSize +
paddedBytecodeTypesMapSize;
uint8_t *buffer = (uint8_t *)cx->malloc_(allocBytes);
if (!buffer)
@ -398,6 +402,8 @@ BaselineScript::New(JSContext *cx, uint32_t prologueOffset,
script->pcMappingSize_ = pcMappingSize;
offsetCursor += paddedPCMappingSize;
script->bytecodeTypeMapOffset_ = bytecodeTypeMapEntries ? offsetCursor : 0;
return script;
}

View File

@ -146,13 +146,18 @@ struct BaselineScript
uint32_t pcMappingOffset_;
uint32_t pcMappingSize_;
// List mapping indexes of bytecode type sets to the offset of the opcode
// they correspond to, for use by TypeScript::BytecodeTypes.
uint32_t bytecodeTypeMapOffset_;
public:
// Do not call directly, use BaselineScript::New. This is public for cx->new_.
BaselineScript(uint32_t prologueOffset, uint32_t spsPushToggleOffset);
static BaselineScript *New(JSContext *cx, uint32_t prologueOffset,
uint32_t spsPushToggleOffset, size_t icEntries,
size_t pcMappingIndexEntries, size_t pcMappingSize);
size_t pcMappingIndexEntries, size_t pcMappingSize,
size_t bytecodeTypeMapEntries);
static void Trace(JSTracer *trc, BaselineScript *script);
static void Destroy(FreeOp *fop, BaselineScript *script);
@ -269,6 +274,11 @@ struct BaselineScript
}
static void writeBarrierPre(Zone *zone, BaselineScript *script);
uint32_t *bytecodeTypeMap() {
JS_ASSERT(bytecodeTypeMapOffset_);
return reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(this) + bytecodeTypeMapOffset_);
}
};
inline bool
@ -348,6 +358,9 @@ BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterato
void
MarkActiveBaselineScripts(Zone *zone);
MethodStatus
BaselineCompile(JSContext *cx, HandleScript script);
} // namespace jit
} // namespace js

View File

@ -39,7 +39,7 @@ struct CatchFinallyRange
};
bool
BytecodeAnalysis::init(JSContext *cx)
BytecodeAnalysis::init(GSNCache &gsn)
{
if (!infos_.growByUninitialized(script_->length))
return false;
@ -120,7 +120,7 @@ BytecodeAnalysis::init(JSContext *cx)
// Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
// jump over the catch/finally blocks.
jssrcnote *sn = js_GetSrcNote(cx, script_, pc);
jssrcnote *sn = GetSrcNote(gsn, script_, pc);
JS_ASSERT(SN_TYPE(sn) == SRC_TRY);
jsbytecode *endOfTry = pc + js_GetSrcNoteOffset(sn, 0);

View File

@ -47,7 +47,7 @@ class BytecodeAnalysis
public:
explicit BytecodeAnalysis(JSScript *script);
bool init(JSContext *cx);
bool init(GSNCache &gsn);
BytecodeInfo &info(jsbytecode *pc) {
JS_ASSERT(infos_[pc - script_->code].initialized);

View File

@ -671,7 +671,7 @@ IonCode::finalize(FreeOp *fop)
// Buffer can be freed at any time hereafter. Catch use-after-free bugs.
// Don't do this if the Ion code is protected, as the signal handler will
// deadlock trying to reaqcuire the operation callback lock.
if (!fop->runtime()->ionRuntime()->ionCodeProtected())
if (fop->runtime()->ionRuntime() && !fop->runtime()->ionRuntime()->ionCodeProtected())
JS_POISON(code_, JS_FREE_PATTERN, bufferSize_);
#endif
@ -1594,7 +1594,7 @@ IonCompile(JSContext *cx, JSScript *script,
if (!info)
return AbortReason_Alloc;
BaselineInspector inspector(cx, script);
BaselineInspector inspector(script);
AutoFlushCache afc("IonCompile", cx->runtime()->ionRuntime());
@ -1762,7 +1762,7 @@ Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode
JS_ASSERT(jit::IsBaselineEnabled(cx));
JS_ASSERT_IF(osrPc != nullptr, (JSOp)*osrPc == JSOP_LOOPENTRY);
if (executionMode == SequentialExecution && !script->hasBaselineScript())
if (!script->hasBaselineScript())
return Method_Skipped;
if (cx->compartment()->debugMode()) {

View File

@ -9,6 +9,7 @@
#include "jsanalyze.h"
#include "jit/BaselineInspector.h"
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "jit/IonBuilder.h"
#include "jit/LIR.h"
@ -2065,18 +2066,14 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
// which will definitely be added to the created object before it has a
// chance to escape and be accessed elsewhere.
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) {
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
return false;
}
if (!fun->nonLazyScript()->compileAndGo)
RootedScript script(cx, fun->nonLazyScript());
if (!script->compileAndGo || !script->canBaselineCompile())
return true;
if (!fun->nonLazyScript()->ensureHasTypes(cx))
return false;
types::TypeScript::SetThis(cx, fun->nonLazyScript(), types::Type::ObjectType(type));
Vector<PropertyName *> accessedProperties(cx);
LifoAlloc alloc(types::TypeZone::TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
@ -2086,18 +2083,28 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
types::AutoEnterAnalysis enter(cx);
if (!fun->nonLazyScript()->ensureRanAnalysis(cx))
return false;
if (!cx->compartment()->ensureIonCompartmentExists(cx))
return Method_Error;
if (!script->hasBaselineScript()) {
MethodStatus status = BaselineCompile(cx, script);
if (status == Method_Error)
return false;
if (status != Method_Compiled)
return true;
}
types::TypeScript::SetThis(cx, script, types::Type::ObjectType(type));
MIRGraph graph(&temp);
CompileInfo info(fun->nonLazyScript(), fun,
CompileInfo info(script, fun,
/* osrPc = */ nullptr, /* constructing = */ false,
DefinitePropertiesAnalysis);
AutoTempAllocatorRooter root(cx, &temp);
types::CompilerConstraintList *constraints = types::NewCompilerConstraintList();
BaselineInspector inspector(cx, fun->nonLazyScript());
BaselineInspector inspector(script);
IonBuilder builder(cx, &temp, &graph, constraints,
&inspector, &info, /* baselineFrame = */ nullptr);

View File

@ -66,6 +66,8 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
{
script_.init(info->script());
pc = info->startPC();
JS_ASSERT(script()->hasBaselineScript());
}
void
@ -279,7 +281,7 @@ IonBuilder::canInlineTarget(JSFunction *target, bool constructing)
// Allow constructing lazy scripts when performing the definite properties
// analysis, as baseline has not been used to warm the caller up yet.
if (target->isInterpretedLazy() && info().executionMode() == DefinitePropertiesAnalysis) {
if (!target->getOrCreateScript(cx))
if (!target->getOrCreateScript(context()))
return false;
}
@ -301,8 +303,8 @@ IonBuilder::canInlineTarget(JSFunction *target, bool constructing)
return false;
}
// Don't inline functions which don't have baseline scripts compiled for them.
if (executionMode == SequentialExecution && !inlineScript->hasBaselineScript()) {
// Don't inline functions which don't have baseline scripts.
if (!inlineScript->hasBaselineScript()) {
IonSpew(IonSpew_Inlining, "%s:%d Cannot inline target with no baseline jitcode",
inlineScript->filename(), inlineScript->lineno);
return false;
@ -513,16 +515,13 @@ IonBuilder::pushLoop(CFGState::State initial, jsbytecode *stopAt, MBasicBlock *e
bool
IonBuilder::init()
{
if (!script()->ensureHasBytecodeTypeMap(cx))
return false;
if (!types::TypeScript::FreezeTypeSets(constraints(), script(),
&thisTypes, &argTypes, &typeArray))
{
return false;
}
if (!analysis().init(cx))
if (!analysis().init(gsn))
return false;
return true;
@ -3753,7 +3752,7 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
current->push(callInfo.fun());
JSScript *calleeScript = target->nonLazyScript();
BaselineInspector inspector(cx, calleeScript);
BaselineInspector inspector(calleeScript);
// Improve type information of |this| when not set.
if (callInfo.constructing() &&

View File

@ -138,6 +138,8 @@ JSRuntime::createIonRuntime(JSContext *cx)
js_delete(ionRuntime_);
ionRuntime_ = nullptr;
AutoLockForExclusiveAccess atomsLock(cx);
JSCompartment *comp = cx->runtime()->atomsCompartment();
if (comp->ionCompartment_) {
js_delete(comp->ionCompartment_);

View File

@ -3352,16 +3352,11 @@ types::TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const
if (!(js_CodeSpec[*pc].format & JOF_TYPESET))
return;
if (!script->types)
if (!script->hasBaselineScript())
return;
AutoEnterAnalysis enter(cx);
if (!script->ensureHasBytecodeTypeMap(cx)) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
Type type = GetValueType(rval);
TypeSet *types = TypeScript::BytecodeTypes(script, pc);
if (types->hasType(type))
@ -3483,36 +3478,6 @@ JSScript::makeTypes(JSContext *cx)
return analyzedArgsUsage() || ensureRanAnalysis(cx);
}
bool
JSScript::makeBytecodeTypeMap(JSContext *cx)
{
JS_ASSERT(cx->typeInferenceEnabled());
JS_ASSERT(types && !types->bytecodeMap);
types->bytecodeMap = cx->typeLifoAlloc().newArrayUninitialized<uint32_t>(nTypeSets + 1);
if (!types->bytecodeMap)
return false;
uint32_t added = 0;
for (jsbytecode *pc = code; pc < code + length; pc += GetBytecodeLength(pc)) {
JSOp op = JSOp(*pc);
if (js_CodeSpec[op].format & JOF_TYPESET) {
types->bytecodeMap[added++] = pc - code;
if (added == nTypeSets)
break;
}
}
JS_ASSERT(added == nTypeSets);
// The last entry in the last index found, and is used to avoid binary
// searches for the sought entry when queries are in linear order.
types->bytecodeMap[nTypeSets] = 0;
return true;
}
bool
JSScript::makeAnalysis(JSContext *cx)
{
@ -4370,7 +4335,7 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const
{
JS_ASSERT(script->types == this);
if (!bytecodeMap)
if (!script->hasBaselineScript())
return;
AutoEnterAnalysis enter(nullptr, script->compartment());

View File

@ -1150,12 +1150,6 @@ class TypeScript
/* Analysis information for the script, cleared on each GC. */
analyze::ScriptAnalysis *analysis;
/*
* List mapping indexes of bytecode type sets to the offset of the opcode
* they correspond to. Cleared on each GC.
*/
uint32_t *bytecodeMap;
public:
/* Array of type type sets for variables and JOF_TYPESET ops. */
StackTypeSet *typeArray() const { return (StackTypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }

View File

@ -609,8 +609,12 @@ template <typename TYPESET>
TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPESET *typeArray)
{
JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
JS_ASSERT(script->types && script->types->bytecodeMap);
uint32_t *bytecodeMap = script->types->bytecodeMap;
#ifdef JS_ION
uint32_t *bytecodeMap = script->baselineScript()->bytecodeTypeMap();
#else
uint32_t *bytecodeMap = NULL;
MOZ_CRASH();
#endif
uint32_t offset = pc - script->code;
JS_ASSERT(offset < script->length);
@ -651,7 +655,12 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPE
TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanAccessRuntime(script->runtimeFromMainThread()));
uint32_t *hint = script->types->bytecodeMap + script->nTypeSets;
#ifdef JS_ION
uint32_t *hint = script->baselineScript()->bytecodeTypeMap() + script->nTypeSets;
#else
uint32_t *hint = NULL;
MOZ_CRASH();
#endif
return BytecodeTypes(script, pc, hint, script->types->typeArray());
}
@ -1452,12 +1461,6 @@ JSScript::ensureHasTypes(JSContext *cx)
return types || makeTypes(cx);
}
inline bool
JSScript::ensureHasBytecodeTypeMap(JSContext *cx)
{
return ensureHasTypes(cx) && (types->bytecodeMap || makeBytecodeTypeMap(cx));
}
inline bool
JSScript::ensureRanAnalysis(JSContext *cx)
{
@ -1487,10 +1490,8 @@ JSScript::analysis()
inline void
JSScript::clearAnalysis()
{
if (types) {
if (types)
types->analysis = nullptr;
types->bytecodeMap = nullptr;
}
}
namespace js {

View File

@ -833,9 +833,6 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
/* Ensure the script has a TypeScript. */
inline bool ensureHasTypes(JSContext *cx);
/* Ensure the script has a TypeScript and map for computing BytecodeTypes. */
inline bool ensureHasBytecodeTypeMap(JSContext *cx);
/*
* Ensure the script has bytecode analysis information. Performed when the
* script first runs, or first runs after a TypeScript GC purge.
@ -873,7 +870,6 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
private:
bool makeTypes(JSContext *cx);
bool makeBytecodeTypeMap(JSContext *cx);
bool makeAnalysis(JSContext *cx);
public: