author Hannes Verschore <hv1989@gmail.com>
Thu, 12 Dec 2013 15:14:13 +0100
changeset 176241 31d0d40d4a7ce9aac74aa2f4fcad36b47e70595f
parent 176240 2b87186ddb6df93d330d948e7a9bf5eef558ba2d
child 176256 a29d7f5ddde63e437958b32305bd9896c210f750
permissions -rw-r--r--
Bug 939614: IonMonkey: Use logic in UsesBeforeCompile to get actual needed usecount, r=jandem

/* -*- 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 jit_Ion_h
#define jit_Ion_h

#ifdef JS_ION

#include "mozilla/MemoryReporting.h"

#include "jscntxt.h"
#include "jscompartment.h"

#include "jit/CompileInfo.h"
#include "jit/CompileWrappers.h"
#include "jit/JitOptions.h"

namespace js {
namespace jit {

class TempAllocator;

enum MethodStatus

enum AbortReason {

// An Ion context is needed to enter into either an Ion method or an instance
// of the Ion compiler. It points to a temporary allocator and the active
// JSContext, either of which may be nullptr, and the active compartment, which
// will not be nullptr.

class IonContext
    IonContext(JSContext *cx, TempAllocator *temp);
    IonContext(ExclusiveContext *cx, TempAllocator *temp);
    IonContext(CompileRuntime *rt, CompileCompartment *comp, TempAllocator *temp);
    IonContext(CompileRuntime *rt);

    // Running context when executing on the main thread. Not available during
    // compilation.
    JSContext *cx;

    // Allocator for temporary memory during compilation.
    TempAllocator *temp;

    // Wrappers with information about the current runtime/compartment for use
    // during compilation.
    CompileRuntime *runtime;
    CompileCompartment *compartment;

    int getNextAssemblerId() {
        return assemblerCount_++;
    IonContext *prev_;
    int assemblerCount_;

// Initialize Ion statically for all JSRuntimes.
bool InitializeIon();

// Get and set the current Ion context.
IonContext *GetIonContext();
IonContext *MaybeGetIonContext();

bool SetIonContext(IonContext *ctx);

bool CanIonCompileScript(JSContext *cx, HandleScript script, bool osr);

MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
                              BaselineFrame *frame, jsbytecode *pc, bool isConstructing);
MethodStatus CanEnter(JSContext *cx, RunState &state);
MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame,
                                        bool isConstructing);
MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);

MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script);

Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
          bool constructing);

enum IonExecStatus
    // The method call had to be aborted due to a stack limit check. This
    // error indicates that Ion never attempted to clean up frames.

    // The method call resulted in an error, and IonMonkey has cleaned up
    // frames.

    // The method call succeeed and returned a value.

static inline bool
IsErrorStatus(IonExecStatus status)
    return status == IonExec_Error || status == IonExec_Aborted;

struct EnterJitData;

bool SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoValueVector &vals);

IonExecStatus IonCannon(JSContext *cx, RunState &state);

// Used to enter Ion from C++ natives like Array.map. Called from FastInvokeGuard.
IonExecStatus FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args);

// Walk the stack and invalidate active Ion frames for the invalid scripts.
void Invalidate(types::TypeCompartment &types, FreeOp *fop,
                const Vector<types::RecompileInfo> &invalid, bool resetUses = true,
                bool cancelOffThread = true);
void Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses = true,
                bool cancelOffThread = true);
bool Invalidate(JSContext *cx, JSScript *script, ExecutionMode mode, bool resetUses = true,
                bool cancelOffThread = true);
bool Invalidate(JSContext *cx, JSScript *script, bool resetUses = true,
                bool cancelOffThread = true);

void MarkValueFromIon(JSRuntime *rt, Value *vp);
void MarkShapeFromIon(JSRuntime *rt, Shape **shapep);

void ToggleBarriers(JS::Zone *zone, bool needs);

class IonBuilder;
class MIRGenerator;
class LIRGraph;
class CodeGenerator;

bool OptimizeMIR(MIRGenerator *mir);
LIRGraph *GenerateLIR(MIRGenerator *mir);
CodeGenerator *GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm = nullptr);
CodeGenerator *CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm = nullptr);

void AttachFinishedCompilations(JSContext *cx);
void FinishOffThreadBuilder(IonBuilder *builder);

static inline bool
IsIonEnabled(JSContext *cx)
    return cx->compartment()->options().ion(cx) &&
        cx->compartment()->options().baseline(cx) &&

inline bool
IsIonInlinablePC(jsbytecode *pc) {
    // CALL, FUNCALL, FUNAPPLY, EVAL, NEW (Normal Callsites)
    // GETPROP, CALLPROP, and LENGTH. (Inlined Getters)
    // SETPROP, SETNAME, SETGNAME (Inlined Setters)
    return IsCallPC(pc) || IsGetPropPC(pc) || IsSetPropPC(pc);

inline bool
TooManyArguments(unsigned nargs)
    return (nargs >= SNAPSHOT_MAX_NARGS || nargs > js_JitOptions.maxStackArgs);

void ForbidCompilation(JSContext *cx, JSScript *script);
void ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode);

void PurgeCaches(JSScript *script, JS::Zone *zone);
size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
void DestroyIonScripts(FreeOp *fop, JSScript *script);
void TraceIonScripts(JSTracer* trc, JSScript *script);

void TriggerOperationCallbackForIonCode(JSRuntime *rt, JSRuntime::OperationCallbackTrigger trigger);

} // namespace jit
} // namespace js

#endif // JS_ION

#endif /* jit_Ion_h */