Skip to content

Instantly share code, notes, and snippets.

@syg
Forked from nikomatsakis/gist:4063007
Created November 13, 2012 00:47
Show Gist options
  • Save syg/4063118 to your computer and use it in GitHub Desktop.
Save syg/4063118 to your computer and use it in GitHub Desktop.
# HG changeset patch
# Parent b857905d82b45456853866330c98b372b14f20db
# User Nicholas D. Matsakis <nmatsakis@mozilla.com>
Permit multiple ion compilation modes. This implies the possibility of
multiple ion scripts per JSScript.
* * *
Add abstractions for cases that handle all comp. modes at once.
* * *
split out separate fields for seq, par
* * *
Convert Invalidate() to assert that it is being run in sequential mode.
diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -8,16 +8,17 @@
#include "CodeGenerator.h"
#include "IonLinker.h"
#include "IonSpewer.h"
#include "MIRGenerator.h"
#include "shared/CodeGenerator-shared-inl.h"
#include "jsnum.h"
#include "jsmath.h"
#include "jsinterpinlines.h"
+#include "ExecutionModeInlines.h"
#include "vm/StringObject-inl.h"
using namespace js;
using namespace js::ion;
using mozilla::DebugOnly;
@@ -793,16 +794,27 @@ CodeGenerator::emitCallInvokeFunction(LI
if (!callVM(InvokeFunctionInfo, call))
return false;
// Un-nestle %esp from the argument vector. No prefix was pushed.
masm.reserveStack(unusedStack);
return true;
}
+static inline int32_t ionOffset(ExecutionMode executionMode)
+{
+ switch (executionMode) {
+ case SequentialExecution: return offsetof(JSScript, ion);
+ case ParallelExecution: return offsetof(JSScript, parallelIon);
+ }
+
+ JS_ASSERT(false);
+ return offsetof(JSScript, ion);
+}
+
bool
CodeGenerator::visitCallGeneric(LCallGeneric *call)
{
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
Register nargsreg = ToRegister(call->getNargsReg());
uint32 unusedStack = StackOffsetOfPassedArg(call->argslot());
Label invoke, thunk, makeCall, end;
@@ -826,17 +838,18 @@ CodeGenerator::visitCallGeneric(LCallGen
if (!bailoutIf(Assembler::NotEqual, call->snapshot()))
return false;
// Guard that calleereg is a non-native function:
masm.branchIfFunctionIsNative(calleereg, &invoke);
// Knowing that calleereg is a non-native function, load the JSScript.
masm.movePtr(Address(calleereg, offsetof(JSFunction, u.i.script_)), objreg);
- masm.movePtr(Address(objreg, offsetof(JSScript, ion)), objreg);
+ ExecutionMode executionMode = gen->info().executionMode();
+ masm.movePtr(Address(objreg, ionOffset(executionMode)), objreg);
// Guard that the IonScript has been compiled.
masm.branchPtr(Assembler::BelowOrEqual, objreg, ImmWord(ION_COMPILING_SCRIPT), &invoke);
// Nestle the StackPointer up to the argument vector.
masm.freeStack(unusedStack);
// Construct the IonFramePrefix.
@@ -884,48 +897,51 @@ CodeGenerator::visitCallGeneric(LCallGen
masm.bind(&end);
dropArguments(call->numStackArgs() + 1);
return true;
}
bool
CodeGenerator::visitCallKnown(LCallKnown *call)
{
+ JSContext *cx = GetIonContext()->cx;
Register calleereg = ToRegister(call->getFunction());
Register objreg = ToRegister(call->getTempObject());
uint32 unusedStack = StackOffsetOfPassedArg(call->argslot());
JSFunction *target = call->getSingleTarget();
Label end, invoke;
// Native single targets are handled by LCallNative.
JS_ASSERT(!target->isNative());
// Missing arguments must have been explicitly appended by the IonBuilder.
JS_ASSERT(target->nargs <= call->numStackArgs());
masm.checkStackAlignment();
// If the function is known to be uncompilable, only emit the call to InvokeFunction.
- if (target->script()->ion == ION_DISABLED_SCRIPT) {
+ ExecutionMode executionMode = gen->info().executionMode();
+ RootedScript targetScript(cx, target->script());
+ if (GetIonScript(targetScript, executionMode) == ION_DISABLED_SCRIPT) {
if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
return false;
if (call->mir()->isConstructing()) {
Label notPrimitive;
masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
masm.loadValue(Address(StackPointer, unusedStack), JSReturnOperand);
masm.bind(&notPrimitive);
}
dropArguments(call->numStackArgs() + 1);
return true;
}
// Knowing that calleereg is a non-native function, load the JSScript.
masm.movePtr(Address(calleereg, offsetof(JSFunction, u.i.script_)), objreg);
- masm.movePtr(Address(objreg, offsetof(JSScript, ion)), objreg);
+ masm.movePtr(Address(objreg, ionOffset(executionMode)), objreg);
// Guard that the IonScript has been compiled.
masm.branchPtr(Assembler::BelowOrEqual, objreg, ImmWord(ION_COMPILING_SCRIPT), &invoke);
// Load the start of the target IonCode.
masm.movePtr(Address(objreg, IonScript::offsetOfMethod()), objreg);
masm.movePtr(Address(objreg, IonCode::offsetOfCode()), objreg);
@@ -1083,16 +1099,18 @@ CodeGenerator::emitPopArguments(LApplyAr
{
// Pop |this| and Arguments.
masm.freeStack(extraStackSpace);
}
bool
CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply)
{
+ JSContext *cx = GetIonContext()->cx;
+
// Holds the function object.
Register calleereg = ToRegister(apply->getFunction());
// Temporary register for modifying the function object.
Register objreg = ToRegister(apply->getTempObject());
Register copyreg = ToRegister(apply->getTempCopy());
// Holds the function nargs. Initially undefined.
@@ -1107,39 +1125,40 @@ CodeGenerator::visitApplyArgsGeneric(LAp
}
// Copy the arguments of the current function.
emitPushArguments(apply, copyreg);
masm.checkStackAlignment();
// If the function is known to be uncompilable, only emit the call to InvokeFunction.
- if (apply->hasSingleTarget() &&
- (!apply->getSingleTarget()->isInterpreted() ||
- apply->getSingleTarget()->script()->ion == ION_DISABLED_SCRIPT))
- {
- if (!emitCallInvokeFunction(apply, copyreg))
- return false;
- emitPopArguments(apply, copyreg);
- return true;
+ ExecutionMode executionMode = gen->info().executionMode();
+ if (apply->hasSingleTarget()) {
+ RootedFunction target(cx, apply->getSingleTarget());
+ if (!CanIonCompile(cx, target, executionMode)) {
+ if (!emitCallInvokeFunction(apply, copyreg))
+ return false;
+ emitPopArguments(apply, copyreg);
+ return true;
+ }
}
Label end, invoke;
// Guard that calleereg is a non-native function:
if (!apply->hasSingleTarget()) {
masm.branchIfFunctionIsNative(calleereg, &invoke);
} else {
// Native single targets are handled by LCallNative.
JS_ASSERT(!apply->getSingleTarget()->isNative());
}
// Knowing that calleereg is a non-native function, load the JSScript.
masm.movePtr(Address(calleereg, offsetof(JSFunction, u.i.script_)), objreg);
- masm.movePtr(Address(objreg, offsetof(JSScript, ion)), objreg);
+ masm.movePtr(Address(objreg, ionOffset(executionMode)), objreg);
// Guard that the IonScript has been compiled.
masm.branchPtr(Assembler::BelowOrEqual, objreg, ImmWord(ION_COMPILING_SCRIPT), &invoke);
// Call with an Ion frame or a rectifier frame.
{
// Create the frame descriptor.
unsigned pushed = masm.framePushed();
@@ -2980,77 +2999,81 @@ CodeGenerator::generate()
IonCode *code = linker.newCode(cx);
if (!code)
return false;
// We encode safepoints after the OSI-point offsets have been determined.
encodeSafepoints();
RootedScript script(cx, gen->info().script());
- JS_ASSERT(!script->hasIonScript());
+ ExecutionMode executionMode = gen->info().executionMode();
+ JS_ASSERT(!HasIonScript(script, executionMode));
uint32 scriptFrameSize = frameClass_ == FrameSizeClass::None()
? frameDepth_
: FrameSizeClass::FromDepth(frameDepth_).frameSize();
// Check to make sure we didn't have a mid-build invalidation. If so, we
// will trickle to ion::Compile() and return Method_Skipped.
if (cx->compartment->types.compiledInfo.compilerOutput(cx)->isInvalidated())
return true;
- script->ion = IonScript::New(cx, slots, scriptFrameSize, snapshots_.size(),
- bailouts_.length(), graph.numConstants(),
- safepointIndices_.length(), osiIndices_.length(),
- cacheList_.length(), barrierOffsets_.length(),
- safepoints_.size(), graph.mir().numScripts());
- if (!script->ion)
+ IonScript *ionScript =
+ IonScript::New(cx, slots, scriptFrameSize, snapshots_.size(),
+ bailouts_.length(), graph.numConstants(),
+ safepointIndices_.length(), osiIndices_.length(),
+ cacheList_.length(), barrierOffsets_.length(),
+ safepoints_.size(), graph.mir().numScripts());
+ SetIonScript(script, executionMode, ionScript);
+
+ if (!ionScript)
return false;
invalidateEpilogueData_.fixup(&masm);
Assembler::patchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
- ImmWord(uintptr_t(script->ion)),
+ ImmWord(uintptr_t(ionScript)),
ImmWord(uintptr_t(-1)));
IonSpew(IonSpew_Codegen, "Created IonScript %p (raw %p)",
- (void *) script->ion, (void *) code->raw());
-
- script->ion->setInvalidationEpilogueDataOffset(invalidateEpilogueData_.offset());
- script->ion->setOsrPc(gen->info().osrPc());
- script->ion->setOsrEntryOffset(getOsrEntryOffset());
+ (void *) ionScript, (void *) code->raw());
+
+ ionScript->setInvalidationEpilogueDataOffset(invalidateEpilogueData_.offset());
+ ionScript->setOsrPc(gen->info().osrPc());
+ ionScript->setOsrEntryOffset(getOsrEntryOffset());
ptrdiff_t real_invalidate = masm.actualOffset(invalidate_.offset());
- script->ion->setInvalidationEpilogueOffset(real_invalidate);
-
- script->ion->setMethod(code);
- script->ion->setDeoptTable(deoptTable_);
+ ionScript->setInvalidationEpilogueOffset(real_invalidate);
+
+ ionScript->setMethod(code);
+ ionScript->setDeoptTable(deoptTable_);
if (snapshots_.size())
- script->ion->copySnapshots(&snapshots_);
+ ionScript->copySnapshots(&snapshots_);
if (bailouts_.length())
- script->ion->copyBailoutTable(&bailouts_[0]);
+ ionScript->copyBailoutTable(&bailouts_[0]);
if (graph.numConstants())
- script->ion->copyConstants(graph.constantPool());
+ ionScript->copyConstants(graph.constantPool());
if (safepointIndices_.length())
- script->ion->copySafepointIndices(&safepointIndices_[0], masm);
+ ionScript->copySafepointIndices(&safepointIndices_[0], masm);
if (osiIndices_.length())
- script->ion->copyOsiIndices(&osiIndices_[0], masm);
+ ionScript->copyOsiIndices(&osiIndices_[0], masm);
if (cacheList_.length())
- script->ion->copyCacheEntries(&cacheList_[0], masm);
+ ionScript->copyCacheEntries(&cacheList_[0], masm);
if (barrierOffsets_.length())
- script->ion->copyPrebarrierEntries(&barrierOffsets_[0], masm);
+ ionScript->copyPrebarrierEntries(&barrierOffsets_[0], masm);
if (safepoints_.size())
- script->ion->copySafepoints(&safepoints_);
+ ionScript->copySafepoints(&safepoints_);
JS_ASSERT(graph.mir().numScripts() > 0);
- script->ion->copyScriptEntries(graph.mir().scripts());
+ ionScript->copyScriptEntries(graph.mir().scripts());
linkAbsoluteLabels();
// The correct state for prebarriers is unknown until the end of compilation,
// since a GC can occur during code generation. All barriers are emitted
// off-by-default, and are toggled on here if necessary.
if (cx->compartment->needsBarrier())
- script->ion->toggleBarriers(true);
+ ionScript->toggleBarriers(true);
return true;
}
// An out-of-line path to convert a boxed int32 to a double.
class OutOfLineUnboxDouble : public OutOfLineCodeBase<CodeGenerator>
{
LUnboxDouble *unboxDouble_;
diff --git a/js/src/ion/CompileInfo.h b/js/src/ion/CompileInfo.h
--- a/js/src/ion/CompileInfo.h
+++ b/js/src/ion/CompileInfo.h
@@ -12,22 +12,33 @@ namespace js {
namespace ion {
inline unsigned
CountArgSlots(JSFunction *fun)
{
return fun ? fun->nargs + 2 : 1; // +2 for |scopeChain| and |this|, or +1 for |scopeChain|
}
+enum ExecutionMode {
+ // Normal JavaScript execution
+ SequentialExecution,
+
+ // JavaScript code to be executed in parallel worker threads,
+ // e.g. by ParallelArray
+ ParallelExecution
+};
+
// Contains information about the compilation source for IR being generated.
class CompileInfo
{
public:
- CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing)
- : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing)
+ CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing,
+ ExecutionMode executionMode)
+ : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing),
+ executionMode_(executionMode)
{
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
nslots_ = script->nslots + CountArgSlots(fun);
}
JSScript *script() const {
return script_;
}
@@ -128,20 +139,29 @@ class CompileInfo
uint32 stackSlot(uint32 i) const {
return firstStackSlot() + i;
}
bool hasArguments() {
return script()->argumentsHasVarBinding();
}
+ ExecutionMode executionMode() const {
+ return executionMode_;
+ }
+
+ bool isParallelExecution() const {
+ return executionMode_ == ParallelExecution;
+ }
+
private:
JSScript *script_;
JSFunction *fun_;
unsigned nslots_;
jsbytecode *osrPc_;
bool constructing_;
+ ExecutionMode executionMode_;
};
} // namespace ion
} // namespace js
#endif
diff --git a/js/src/ion/ExecutionModeInlines.h b/js/src/ion/ExecutionModeInlines.h
new file mode 100644
--- /dev/null
+++ b/js/src/ion/ExecutionModeInlines.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et 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 jsion_compilemode_h__
+#define jsion_compilemode_h__
+
+namespace js {
+namespace ion {
+
+static inline bool HasIonScript(JSScript *script, ExecutionMode cmode)
+{
+ switch (cmode) {
+ case SequentialExecution: return script->hasIonScript();
+ case ParallelExecution: return script->hasParallelIonScript();
+ }
+ JS_NOT_REACHED("No such execution mode");
+ return false;
+}
+
+static inline IonScript *GetIonScript(JSScript *script, ExecutionMode cmode)
+{
+ switch (cmode) {
+ case SequentialExecution: return script->ion;
+ case ParallelExecution: return script->parallelIon;
+ }
+ JS_NOT_REACHED("No such execution mode");
+ return NULL;
+}
+
+static inline void SetIonScript(JSScript *script, ExecutionMode cmode, IonScript *ionScript)
+{
+ switch (cmode) {
+ case SequentialExecution: script->ion = ionScript; return;
+ case ParallelExecution: script->parallelIon = ionScript; return;
+ }
+ JS_NOT_REACHED("No such execution mode");
+}
+
+static inline bool CanIonCompile(HandleScript script, ExecutionMode cmode)
+{
+ switch (cmode) {
+ case SequentialExecution: return script->canIonCompile();
+ case ParallelExecution: return script->canParallelIonCompile();
+ }
+ JS_NOT_REACHED("No such execution mode");
+ return false;
+}
+
+static inline bool CanIonCompile(JSContext *cx, HandleFunction fun, ExecutionMode cmode)
+{
+ if (!fun->isInterpreted())
+ return false;
+ RootedScript script(cx, fun->script());
+ return CanIonCompile(script, cmode);
+}
+
+static inline bool CompilingOffThread(JSScript *script, ExecutionMode cmode)
+{
+ switch (cmode) {
+ case SequentialExecution: return script->isIonCompilingOffThread();
+ case ParallelExecution: return script->isParallelIonCompilingOffThread();
+ }
+ JS_NOT_REACHED("No such execution mode");
+ return false;
+}
+
+static inline bool CompilingOffThread(HandleScript script, ExecutionMode cmode)
+{
+ switch (cmode) {
+ case SequentialExecution: return script->isIonCompilingOffThread();
+ case ParallelExecution: return script->isParallelIonCompilingOffThread();
+ }
+ JS_NOT_REACHED("No such execution mode");
+ return false;
+}
+
+static inline bool Disabled(JSScript *script, ExecutionMode cmode) {
+ switch (cmode) {
+ case SequentialExecution: return script->isIonCompilingOffThread();
+ case ParallelExecution: return script->isParallelIonCompilingOffThread();
+ }
+ JS_NOT_REACHED("No such execution mode");
+ return false;
+}
+
+static inline types::CompilerOutput::Kind CompilerOutputKind(ExecutionMode cmode)
+{
+ switch (cmode) {
+ case SequentialExecution: return types::CompilerOutput::Ion;
+ case ParallelExecution: return types::CompilerOutput::ParallelIon;
+ }
+ JS_NOT_REACHED("No such execution mode");
+ return types::CompilerOutput::Ion;
+}
+
+}
+}
+
+#endif
diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -32,16 +32,17 @@
#include "gc/Marking.h"
#include "jsgcinlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "vm/Stack-inl.h"
#include "ion/IonFrames-inl.h"
#include "ion/CompilerRoot.h"
#include "methodjit/Retcon.h"
+#include "ExecutionModeInlines.h"
#if JS_TRACE_LOGGING
#include "TraceLogging.h"
#endif
using namespace js;
using namespace js::ion;
@@ -958,16 +959,26 @@ class AutoDestroyAllocator
~AutoDestroyAllocator()
{
if (alloc)
js_delete(alloc);
}
};
+class SequentialCompileContext {
+public:
+ ExecutionMode executionMode() {
+ return SequentialExecution;
+ }
+
+ bool compile(IonBuilder *builder, MIRGraph *graph,
+ AutoDestroyAllocator &autoDestroy);
+};
+
void
AttachFinishedCompilations(JSContext *cx)
{
#ifdef JS_THREADSAFE
AssertCanGC();
IonCompartment *ion = cx->compartment->ionCompartment();
if (!ion || !cx->runtime->workerThreadState)
return;
@@ -983,17 +994,18 @@ AttachFinishedCompilations(JSContext *cx
IonBuilder *builder = compilations.popCopy();
if (builder->backgroundCompiledLir) {
RootedScript script(cx, builder->script());
IonContext ictx(cx, cx->compartment, &builder->temp());
CodeGenerator codegen(builder, *builder->backgroundCompiledLir);
- types::AutoEnterCompilation enterCompiler(cx, types::AutoEnterCompilation::Ion);
+ ExecutionMode executionMode = builder->info().executionMode();
+ types::AutoEnterCompilation enterCompiler(cx, CompilerOutputKind(executionMode));
enterCompiler.initExisting(builder->recompileInfo);
bool success;
{
// Release the worker thread lock and root the compiler for GC.
AutoTempAllocatorRooter root(cx, &builder->temp());
AutoUnlockWorkerThreadState unlock(cx->runtime);
success = codegen.generate();
@@ -1013,18 +1025,20 @@ AttachFinishedCompilations(JSContext *cx
}
compilations.clear();
#endif
}
static const size_t BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
+template <typename CompileContext>
static bool
-IonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing)
+IonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing,
+ CompileContext &compileContext)
{
AssertCanGC();
#if JS_TRACE_LOGGING
AutoTraceLog logger(TraceLogging::defaultLogger(),
TraceLogging::ION_COMPILE_START,
TraceLogging::ION_COMPILE_STOP,
script);
#endif
@@ -1040,35 +1054,50 @@ IonCompile(JSContext *cx, JSScript *scri
return false;
IonContext ictx(cx, cx->compartment, temp);
if (!cx->compartment->ensureIonCompartmentExists(cx))
return false;
MIRGraph *graph = alloc->new_<MIRGraph>(temp);
- CompileInfo *info = alloc->new_<CompileInfo>(script, fun, osrPc, constructing);
+ ExecutionMode executionMode = compileContext.executionMode();
+ CompileInfo *info = alloc->new_<CompileInfo>(script, fun, osrPc, constructing,
+ executionMode);
if (!info)
return false;
types::AutoEnterTypeInference enter(cx, true);
TypeInferenceOracle oracle;
if (!oracle.init(cx, script))
return false;
AutoFlushCache afc("IonCompile");
- types::AutoEnterCompilation enterCompiler(cx, types::AutoEnterCompilation::Ion);
+ types::AutoEnterCompilation enterCompiler(cx, CompilerOutputKind(executionMode));
enterCompiler.init(script, false, 0);
AutoTempAllocatorRooter root(cx, temp);
IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &oracle, info);
+ if (!compileContext.compile(builder, graph, autoDestroy)) {
+ IonSpew(IonSpew_Abort, "IM Compilation failed.");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+SequentialCompileContext::compile(IonBuilder *builder, MIRGraph *graph,
+ AutoDestroyAllocator &autoDestroy)
+{
JS_ASSERT(!builder->script()->ion);
+ JSContext *cx = GetIonContext()->cx;
IonSpewNewFunction(graph, builder->script().unsafeGet());
if (!builder->build()) {
IonSpew(IonSpew_Abort, "Builder failed to build.");
return false;
}
builder->clearForBackEnd();
@@ -1103,17 +1132,18 @@ IonCompile(JSContext *cx, JSScript *scri
IonSpewEndFunction();
return true;
}
bool
TestIonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing)
{
- if (!IonCompile(cx, script, fun, osrPc, constructing)) {
+ SequentialCompileContext compileContext;
+ if (!IonCompile(cx, script, fun, osrPc, constructing, compileContext)) {
if (!cx->isExceptionPending())
ForbidCompilation(cx, script);
return false;
}
return true;
}
static bool
@@ -1223,17 +1253,18 @@ Compile(JSContext *cx, JSScript *script,
// bumping the use count twice.
if (script->getUseCount() < js_IonOptions.usesBeforeCompile)
return Method_Skipped;
} else {
if (script->incUseCount() < js_IonOptions.usesBeforeCompileNoJaeger)
return Method_Skipped;
}
- if (!IonCompile(cx, script, fun, osrPc, constructing))
+ SequentialCompileContext compileContext;
+ if (!IonCompile(cx, script, fun, osrPc, constructing, compileContext))
return Method_CantCompile;
// Compilation succeeded, but we invalidated right away.
return script->hasIonScript() ? Method_Compiled : Method_Skipped;
}
} // namespace ion
} // namespace js
@@ -1719,17 +1750,21 @@ ion::Invalidate(types::TypeCompartment &
IonSpew(IonSpew_Invalidate, "Start invalidation.");
AutoFlushCache afc ("Invalidate");
// Add an invalidation reference to all invalidated IonScripts to indicate
// to the traversal which frames have been invalidated.
bool anyInvalidation = false;
for (size_t i = 0; i < invalid.length(); i++) {
const types::CompilerOutput &co = *invalid[i].compilerOutput(types);
- if (co.isIon()) {
+ switch (co.kind()) {
+ case types::CompilerOutput::MethodJIT:
+ break;
+ case types::CompilerOutput::Ion:
+ case types::CompilerOutput::ParallelIon:
JS_ASSERT(co.isValid());
IonSpew(IonSpew_Invalidate, " Invalidate %s:%u, IonScript %p",
co.script->filename, co.script->lineno, co.ion());
// Keep the ion script alive during the invalidation and flag this
// ionScript as being invalidated. This increment is removed by the
// loop after the calls to InvalidateActivation.
co.ion()->incref();
@@ -1745,39 +1780,48 @@ ion::Invalidate(types::TypeCompartment &
for (IonActivationIterator iter(fop->runtime()); iter.more(); ++iter)
InvalidateActivation(fop, iter.top(), false);
// Drop the references added above. If a script was never active, its
// IonScript will be immediately destroyed. Otherwise, it will be held live
// until its last invalidated frame is destroyed.
for (size_t i = 0; i < invalid.length(); i++) {
types::CompilerOutput &co = *invalid[i].compilerOutput(types);
- if (co.isIon()) {
- JS_ASSERT(co.isValid());
- JSScript *script = co.script;
- IonScript *ionScript = script->ionScript();
+ ExecutionMode executionMode;
+ switch (co.kind()) {
+ case types::CompilerOutput::MethodJIT:
+ continue;
+ case types::CompilerOutput::Ion:
+ executionMode = SequentialExecution;
+ break;
+ case types::CompilerOutput::ParallelIon:
+ executionMode = ParallelExecution;
+ break;
+ }
+ JS_ASSERT(co.isValid());
+ JSScript *script = co.script;
+ IonScript *ionScript = GetIonScript(script, executionMode);
- JSCompartment *compartment = script->compartment();
- if (compartment->needsBarrier()) {
- // We're about to remove edges from the JSScript to gcthings
- // embedded in the IonScript. Perform one final trace of the
- // IonScript for the incremental GC, as it must know about
- // those edges.
- IonScript::Trace(compartment->barrierTracer(), ionScript);
- }
+ JSCompartment *compartment = script->compartment();
+ if (compartment->needsBarrier()) {
+ // We're about to remove edges from the JSScript to gcthings
+ // embedded in the IonScript. Perform one final trace of the
+ // IonScript for the incremental GC, as it must know about
+ // those edges.
+ IonScript::Trace(compartment->barrierTracer(), ionScript);
+ }
- ionScript->decref(fop);
- script->ion = NULL;
- co.invalidate();
+ ionScript->decref(fop);
+ SetIonScript(script, executionMode, NULL);
+ co.invalidate();
- // Wait for the scripts to get warm again before doing another
- // compile, unless we are recompiling *because* a script got hot.
- if (resetUses)
- script->resetUseCount();
- }
+ // Wait for the scripts to get warm again before doing another
+ // compile, unless we are recompiling *because* a script got hot.
+ if (resetUses)
+ script->resetUseCount();
}
}
void
ion::Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses)
{
ion::Invalidate(cx->compartment->types, cx->runtime->defaultFreeOp(), invalid, resetUses);
}
@@ -1886,8 +1930,47 @@ AutoFlushCache::AutoFlushCache(const cha
comp->setFlusher(this);
} else {
IonSpew(IonSpew_CacheFlush, "<%s DEAD>\n", nonce);
}
myCompartment_ = comp;
}
int js::ion::LabelBase::id_count = 0;
+void
+ion::PurgeCaches(JSScript *script, JSCompartment *c) {
+ if (script->hasIonScript())
+ script->ion->purgeCaches(c);
+
+ if (script->hasParallelIonScript())
+ script->ion->purgeCaches(c);
+}
+
+size_t
+ion::MemoryUsed(JSScript *script, JSMallocSizeOfFun mallocSizeOf) {
+ size_t result = 0;
+
+ if (script->hasIonScript())
+ result += script->ion->sizeOfIncludingThis(mallocSizeOf);
+
+ if (script->hasParallelIonScript())
+ result += script->parallelIon->sizeOfIncludingThis(mallocSizeOf);
+
+ return result;
+}
+
+void
+ion::DestroyIonScripts(FreeOp *fop, JSScript *script) {
+ if (script->hasIonScript())
+ ion::IonScript::Destroy(fop, script->ion);
+
+ if (script->hasParallelIonScript())
+ ion::IonScript::Destroy(fop, script->parallelIon);
+}
+
+void
+ion::TraceIonScripts(JSTracer* trc, JSScript *script) {
+ if (script->hasIonScript())
+ ion::IonScript::Trace(trc, script->ion);
+
+ if (script->hasParallelIonScript())
+ ion::IonScript::Trace(trc, script->parallelIon);
+}
diff --git a/js/src/ion/Ion.h b/js/src/ion/Ion.h
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -263,13 +263,18 @@ bool TestIonCompile(JSContext *cx, JSScr
static inline bool IsEnabled(JSContext *cx)
{
return cx->hasRunOption(JSOPTION_ION) && cx->typeInferenceEnabled();
}
void ForbidCompilation(JSContext *cx, JSScript *script);
uint32_t UsesBeforeIonRecompile(JSScript *script, jsbytecode *pc);
+void PurgeCaches(JSScript *script, JSCompartment *c);
+size_t MemoryUsed(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
+void DestroyIonScripts(FreeOp *fop, JSScript *script);
+void TraceIonScripts(JSTracer* trc, JSScript *script);
+
} // namespace ion
} // namespace js
#endif // jsion_ion_h__
diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -10,16 +10,17 @@
#include "MIRGraph.h"
#include "Ion.h"
#include "IonAnalysis.h"
#include "IonSpewer.h"
#include "frontend/BytecodeEmitter.h"
#include "jsscriptinlines.h"
#include "jstypedarrayinlines.h"
+#include "ExecutionModeInlines.h"
#ifdef JS_THREADSAFE
# include "prthread.h"
#endif
using namespace js;
using namespace js::ion;
@@ -199,18 +200,18 @@ IonBuilder::canInlineTarget(JSFunction *
}
if (target->getParent() != &script_->global()) {
IonSpew(IonSpew_Inlining, "Cannot inline due to scope mismatch");
return false;
}
RootedScript inlineScript(cx, target->script());
-
- if (!inlineScript->canIonCompile()) {
+ ExecutionMode executionMode = info().executionMode();
+ if (!CanIonCompile(inlineScript, executionMode)) {
IonSpew(IonSpew_Inlining, "Cannot inline due to disable Ion compilation");
return false;
}
// Allow inlining of recursive calls, but only one level deep.
IonBuilder *builder = callerBuilder_;
while (builder) {
if (builder->script() == inlineScript) {
@@ -2824,17 +2825,18 @@ IonBuilder::jsop_call_inline(HandleFunct
return false;
for (int32 i = argc; i >= 0; i--)
argv[i] = current->pop();
// Compilation information is allocated for the duration of the current tempLifoAlloc
// lifetime.
RootedScript calleeScript(cx, callee->script());
CompileInfo *info = cx->tempLifoAlloc().new_<CompileInfo>(calleeScript.get(), callee,
- (jsbytecode *)NULL, constructing);
+ (jsbytecode *)NULL, constructing,
+ SequentialExecution);
if (!info)
return false;
MIRGraphExits saveExits;
AutoAccumulateExits aae(graph(), saveExits);
TypeInferenceOracle oracle;
if (!oracle.init(cx, calleeScript))
diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -547,18 +547,19 @@ JS_SetTopFrameAnnotation(JSContext *cx,
// because we will never EnterIon on a frame with an annotation.
fp->setAnnotation(annotation);
RawScript script = fp->script().get(nogc);
ReleaseAllJITCode(cx->runtime->defaultFreeOp());
// Ensure that we'll never try to compile this again.
- JS_ASSERT(!script->hasIonScript());
+ JS_ASSERT(!script->hasAnyIonScript());
script->ion = ION_DISABLED_SCRIPT;
+ script->parallelIon = ION_DISABLED_SCRIPT;
}
JS_PUBLIC_API(JSObject *)
JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fpArg)
{
StackFrame *fp = Valueify(fpArg);
JS_ASSERT(cx->stack.space().containsSlow(fp));
AutoCompartment ac(cx, fp->scopeChain());
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -127,17 +127,17 @@ fun_getProperty(JSContext *cx, HandleObj
#ifdef JS_ION
AutoAssertNoGC nogc;
// If this script hasn't been compiled yet, make sure it will never
// be compiled. IonMonkey does not guarantee |f.arguments| can be
// fully recovered, so we try to mitigate observing this behavior by
// detecting its use early.
RawScript script = iter.script().get(nogc);
- if (!script->hasIonScript())
+ if (!script->hasAnyIonScript())
ion::ForbidCompilation(cx, script);
#endif
vp.setObject(*argsobj);
return true;
}
#ifdef JS_METHODJIT
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -5870,18 +5870,17 @@ PurgeJITCaches(JSCompartment *c)
JSScript *script = i.get<JSScript>();
/* Discard JM caches. */
mjit::PurgeCaches(script);
#ifdef JS_ION
/* Discard Ion caches. */
- if (script->hasIonScript())
- script->ion->purgeCaches(c);
+ ion::PurgeCaches(script, c);
#endif
}
#endif
}
AutoTransplantGC::AutoTransplantGC(JSContext *cx)
: runtime(cx->runtime),
diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1992,17 +1992,17 @@ JITCodeHasCheck(HandleScript script, jsb
found = true;
}
if (!found)
return false;
}
}
#endif
- if (script->hasIonScript())
+ if (script->hasAnyIonScript())
return false;
return true;
}
/*
* Force recompilation of any jitcode for script at pc, or of any other script
* which this script was inlined into.
@@ -2021,18 +2021,24 @@ AddPendingRecompile(JSContext *cx, Handl
/*
* Remind Ion not to save the compile code if generating type
* inference information mid-compilation causes an invalidation of the
* script being compiled.
*/
RecompileInfo& info = cx->compartment->types.compiledInfo;
if (info.outputIndex != RecompileInfo::NoCompilerRunning) {
CompilerOutput *co = info.compilerOutput(cx);
- if (co->isIon() && co->script == script) {
- co->invalidate();
+ switch (co->kind()) {
+ case CompilerOutput::MethodJIT:
+ break;
+ case CompilerOutput::Ion:
+ case CompilerOutput::ParallelIon:
+ if (co->script == script)
+ co->invalidate();
+ break;
}
}
/*
* When one script is inlined into another the caller listens to state
* changes on the callee's script, so trigger these to force recompilation
* of any such callers.
*/
@@ -2412,21 +2418,26 @@ TypeCompartment::processPendingRecompile
JS_ASSERT(!pending->empty());
#ifdef JS_METHODJIT
mjit::ExpandInlineFrames(compartment());
for (unsigned i = 0; i < pending->length(); i++) {
CompilerOutput &co = *(*pending)[i].compilerOutput(*this);
- if (co.isJM()) {
+ switch (co.kind()) {
+ case CompilerOutput::MethodJIT:
JS_ASSERT(co.isValid());
mjit::Recompiler::clearStackReferences(fop, co.script);
co.mjit()->destroyChunk(fop, co.chunkIndex);
JS_ASSERT(co.script == NULL);
+ break;
+ case CompilerOutput::Ion:
+ case CompilerOutput::ParallelIon:
+ break;
}
}
# ifdef JS_ION
ion::Invalidate(*this, fop, *pending);
# endif
#endif /* JS_METHODJIT */
@@ -2513,17 +2524,17 @@ TypeCompartment::addPendingRecompile(JSC
return;
}
#ifdef JS_METHODJIT
mjit::JITScript *jit = co->script->getJIT(co->constructing, co->barriers);
bool hasJITCode = jit && jit->chunkDescriptor(co->chunkIndex).chunk;
# if defined(JS_ION)
- hasJITCode |= !!co->script->hasIonScript();
+ hasJITCode |= !!co->script->hasAnyIonScript();
# endif
if (!hasJITCode) {
/* Scripts which haven't been compiled yet don't need to be recompiled. */
return;
}
#endif
@@ -2580,16 +2591,19 @@ TypeCompartment::addPendingRecompile(JSC
}
}
# ifdef JS_ION
CancelOffThreadIonCompile(cx->compartment, script);
if (script->hasIonScript())
addPendingRecompile(cx, script->ionScript()->recompileInfo());
+
+ if (script->hasParallelIonScript())
+ addPendingRecompile(cx, script->parallelIonScript()->recompileInfo());
# endif
#endif
}
void
TypeCompartment::monitorBytecode(JSContext *cx, HandleScript script, uint32_t offset,
bool returnOnly)
{
diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1208,27 +1208,37 @@ typedef HashMap<AllocationSiteKey,ReadBa
/*
* Information about the result of the compilation of a script. This structure
* stored in the TypeCompartment is indexed by the RecompileInfo. This
* indirection enable the invalidation of all constraints related to the same
* compilation. The compiler output is build by the AutoEnterCompilation.
*/
struct CompilerOutput
{
+ enum Kind {
+ MethodJIT,
+ Ion,
+ ParallelIon
+ };
+
JSScript *script;
- bool isIonFlag : 1;
+
+ // This integer will always be a member of CompilerOutput::Kind,
+ // but, for portability, bitfields are limited to bool, int, and
+ // unsigned int. You should really use the accessor below.
+ unsigned kindInt : 2;
bool constructing : 1;
bool barriers : 1;
bool pendingRecompilation : 1;
- uint32_t chunkIndex:28;
+ uint32_t chunkIndex:27;
CompilerOutput();
- bool isJM() const { return !isIonFlag; }
- bool isIon() const { return isIonFlag; }
+ Kind kind() const { return static_cast<Kind>(kindInt); }
+ void setKind(Kind k) { kindInt = k; }
mjit::JITScript *mjit() const;
ion::IonScript *ion() const;
bool isValid() const;
void setPendingRecompilation() {
pendingRecompilation = true;
diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -83,79 +83,95 @@ namespace types {
/////////////////////////////////////////////////////////////////////
// CompilerOutput & RecompileInfo
/////////////////////////////////////////////////////////////////////
inline
CompilerOutput::CompilerOutput()
: script(NULL),
- isIonFlag(false),
+ kindInt(MethodJIT),
constructing(false),
barriers(false),
chunkIndex(false)
{
}
inline mjit::JITScript *
CompilerOutput::mjit() const
{
#ifdef JS_METHODJIT
- JS_ASSERT(isJM() && isValid());
+ JS_ASSERT(kind() == MethodJIT && isValid());
return script->getJIT(constructing, barriers);
#else
return NULL;
#endif
}
inline ion::IonScript *
CompilerOutput::ion() const
{
#ifdef JS_ION
- JS_ASSERT(isIon() && isValid());
- return script->ionScript();
-#else
+ JS_ASSERT(kind() != MethodJIT && isValid());
+ switch (kind()) {
+ case MethodJIT: break;
+ case Ion: return script->ionScript();
+ case ParallelIon: return script->parallelIonScript();
+ }
+#endif
+ JS_NOT_REACHED("Invalid kind of CompilerOutput");
return NULL;
-#endif
}
inline bool
CompilerOutput::isValid() const
{
if (!script)
return false;
#if defined(DEBUG) && (defined(JS_METHODJIT) || defined(JS_ION))
TypeCompartment &types = script->compartment()->types;
#endif
+ switch (kind()) {
+ case MethodJIT: {
#ifdef JS_METHODJIT
- if (isJM()) {
mjit::JITScript *jit = script->getJIT(constructing, barriers);
if (!jit)
return false;
mjit::JITChunk *chunk = jit->chunkDescriptor(chunkIndex).chunk;
if (!chunk)
return false;
JS_ASSERT(this == chunk->recompileInfo.compilerOutput(types));
return true;
- }
#endif
+ }
+ case Ion:
#ifdef JS_ION
- if (isIon()) {
if (script->hasIonScript()) {
JS_ASSERT(this == script->ion->recompileInfo().compilerOutput(types));
return true;
}
if (script->isIonCompilingOffThread())
return true;
+#endif
+ return false;
+
+ case ParallelIon:
+#ifdef JS_ION
+ if (script->hasParallelIonScript()) {
+ JS_ASSERT(this == script->parallelIonScript()->recompileInfo().compilerOutput(types));
+ return true;
+ }
+ if (script->isParallelIonCompilingOffThread())
+ return true;
+#endif
return false;
}
-#endif
return false;
}
inline CompilerOutput*
RecompileInfo::compilerOutput(TypeCompartment &types) const
{
return &(*types.constrainedOutputs)[outputIndex];
}
@@ -382,37 +398,32 @@ struct AutoEnterTypeInference
/*
* Structure marking the currently compiled script, for constraints which can
* trigger recompilation.
*/
struct AutoEnterCompilation
{
JSContext *cx;
RecompileInfo &info;
+ CompilerOutput::Kind kind;
- enum Compiler {
- JM,
- Ion
- };
- Compiler mode;
-
- AutoEnterCompilation(JSContext *cx, Compiler mode)
+ AutoEnterCompilation(JSContext *cx, CompilerOutput::Kind kind)
: cx(cx),
info(cx->compartment->types.compiledInfo),
- mode(mode)
+ kind(kind)
{
JS_ASSERT(cx->compartment->activeAnalysis);
JS_ASSERT(info.outputIndex == RecompileInfo::NoCompilerRunning);
}
bool init(JSScript *script, bool constructing, unsigned chunkIndex)
{
CompilerOutput co;
co.script = script;
- co.isIonFlag = (mode == Ion);
+ co.setKind(kind);
co.constructing = constructing;
co.barriers = cx->compartment->compileBarriers();
co.chunkIndex = chunkIndex;
// This flag is used to prevent adding the current compiled script in
// the list of compiler output which should be invalided. This is
// necessary because we can run some analysis might discard the script
// it-self, which can happen when the monitored value does not reflect
diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -1002,21 +1002,21 @@ class FastInvokeGuard
RootedScript script_;
#ifdef JS_ION
ion::IonContext ictx_;
bool useIon_;
#endif
public:
FastInvokeGuard(JSContext *cx, const Value &fval)
- : fun_(cx),
- script_(cx)
+ : fun_(cx)
+ , script_(cx)
#ifdef JS_ION
- , ictx_(cx, cx->compartment, NULL),
- useIon_(ion::IsEnabled(cx))
+ , ictx_(cx, cx->compartment, NULL)
+ , useIon_(ion::IsEnabled(cx))
#endif
{
initFunction(fval);
}
void initFunction(const Value &fval) {
if (fval.isObject() && fval.toObject().isFunction()) {
JSFunction *fun = fval.toObject().toFunction();
diff --git a/js/src/jsmemorymetrics.cpp b/js/src/jsmemorymetrics.cpp
--- a/js/src/jsmemorymetrics.cpp
+++ b/js/src/jsmemorymetrics.cpp
@@ -15,16 +15,17 @@
#include "jsgc.h"
#include "jsobj.h"
#include "jsscope.h"
#include "jsscript.h"
#include "jsobjinlines.h"
#include "ion/IonCode.h"
+#include "ion/Ion.h"
namespace js {
size_t MemoryReportingSundriesThreshold()
{
return 8 * 1024;
}
@@ -227,18 +228,17 @@ StatsCellCallback(JSRuntime *rt, void *d
case JSTRACE_SCRIPT:
{
JSScript *script = static_cast<JSScript *>(thing);
cStats->gcHeapScripts += thingSize;
cStats->scriptData += script->sizeOfData(rtStats->mallocSizeOf);
#ifdef JS_METHODJIT
cStats->jaegerData += script->sizeOfJitScripts(rtStats->mallocSizeOf);
# ifdef JS_ION
- if (script->hasIonScript())
- cStats->ionData += script->ion->sizeOfIncludingThis(rtStats->mallocSizeOf);
+ cStats->ionData += ion::MemoryUsed(script, rtStats->mallocSizeOf);
# endif
#endif
ScriptSource *ss = script->scriptSource();
SourceSet::AddPtr entry = closure->seenSources.lookupForAdd(ss);
if (!entry) {
closure->seenSources.add(entry, ss); // Not much to be done on failure.
rtStats->runtime.scriptSources += ss->sizeOfIncludingThis(rtStats->mallocSizeOf);
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1901,18 +1901,17 @@ JSScript::finalize(FreeOp *fop)
JS_DropPrincipals(fop->runtime(), originPrincipals);
if (types)
types->destroy();
#ifdef JS_METHODJIT
mjit::ReleaseScriptCode(fop, this);
# ifdef JS_ION
- if (hasIonScript())
- ion::IonScript::Destroy(fop, ion);
+ ion::DestroyIonScripts(fop, this);
# endif
#endif
destroyScriptCounts(fop);
destroyDebugScript(fop);
scriptSource_->decref(fop->runtime());
if (data) {
@@ -2594,18 +2593,17 @@ JSScript::markChildren(JSTracer *trc)
for (unsigned i = 0; i < length; i++) {
BreakpointSite *site = debugScript()->breakpoints[i];
if (site && site->trapHandler)
MarkValue(trc, &site->trapClosure, "trap closure");
}
}
#ifdef JS_ION
- if (hasIonScript())
- ion::IonScript::Trace(trc, ion);
+ ion::TraceIonScripts(trc, this);
#endif
}
void
JSScript::setArgumentsHasVarBinding()
{
argsHasVarBinding_ = true;
needsArgsAnalysis_ = true;
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -544,36 +544,60 @@ struct JSScript : public js::gc::Cell
* canonical location for the arguments. Note: if a formal is aliased
* through the scope chain, then script->formalIsAliased and JSOP_*ARG*
* opcodes won't be emitted at all.
*/
bool argsObjAliasesFormals() const {
return needsArgsObj() && !strictModeCode;
}
- js::ion::IonScript *ion; /* Information attached by Ion */
+ bool hasAnyIonScript() const {
+ return hasIonScript() || hasParallelIonScript();
+ }
-#if defined(JS_METHODJIT) && JS_BITS_PER_WORD == 32
- void *padding_;
-#endif
+ /* Information attached by Ion: script for sequential mode execution */
+ js::ion::IonScript *ion;
bool hasIonScript() const {
return ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
}
+
bool canIonCompile() const {
return ion != ION_DISABLED_SCRIPT;
}
+
bool isIonCompilingOffThread() const {
return ion == ION_COMPILING_SCRIPT;
}
+
js::ion::IonScript *ionScript() const {
JS_ASSERT(hasIonScript());
return ion;
}
+ /* Information attached by Ion: script for parallel mode execution */
+ js::ion::IonScript *parallelIon;
+
+ bool hasParallelIonScript() const {
+ return parallelIon && parallelIon != ION_DISABLED_SCRIPT && parallelIon != ION_COMPILING_SCRIPT;
+ }
+
+ bool canParallelIonCompile() const {
+ return parallelIon != ION_DISABLED_SCRIPT;
+ }
+
+ bool isParallelIonCompilingOffThread() const {
+ return parallelIon == ION_COMPILING_SCRIPT;
+ }
+
+ js::ion::IonScript *parallelIonScript() const {
+ JS_ASSERT(hasParallelIonScript());
+ return parallelIon;
+ }
+
/*
* Original compiled function for the script, if it has a function.
* NULL for global and eval scripts.
*/
JSFunction *function() const { return function_; }
void setFunction(JSFunction *fun);
JSFlatString *sourceData(JSContext *cx);
diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -3,16 +3,17 @@
/* 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/. */
#include "jsworkers.h"
#if JS_ION
# include "ion/IonBuilder.h"
+# include "ion/ExecutionModeInlines.h"
#endif
using namespace js;
using mozilla::DebugOnly;
#ifdef JS_PARALLEL_COMPILATION
@@ -289,17 +290,18 @@ WorkerThread::threadLoop()
state.unlock();
return;
}
state.wait(WorkerThreadState::WORKER);
}
ionBuilder = state.ionWorklist.popCopy();
- JS_ASSERT(ionBuilder->script()->ion == ION_COMPILING_SCRIPT);
+ ion::ExecutionMode executionMode = ionBuilder->info().executionMode();
+ JS_ASSERT(GetIonScript(ionBuilder->script().unsafeGet(), executionMode) == ION_COMPILING_SCRIPT);
state.unlock();
{
ion::IonContext ictx(NULL, ionBuilder->script()->compartment(), &ionBuilder->temp());
ionBuilder->backgroundCompiledLir = ion::CompileBackEnd(ionBuilder);
}
diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -534,17 +534,17 @@ mjit::Compiler::performCompilation()
#ifdef JS_METHODJIT
outerScript->debugMode = debugMode();
#endif
JS_ASSERT(cx->compartment->activeInference);
{
- types::AutoEnterCompilation enter(cx, types::AutoEnterCompilation::JM);
+ types::AutoEnterCompilation enter(cx, types::CompilerOutput::MethodJIT);
if (!enter.init(outerScript, isConstructing, chunkIndex)) {
js_ReportOutOfMemory(cx);
return Compile_Error;
}
CHECK_STATUS(checkAnalysis(outerScript));
if (inlining())
CHECK_STATUS(scanInlineCalls(CrossScriptSSA::OUTER_FRAME, 0));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment