Files
dmcallis 65a0592776 Initial source code drop
Source code drop for the Actionscript virtual machine in the Adobe
Flash Player for December 2013
2013-12-02 16:04:04 -08:00

613 lines
29 KiB
C++

/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* 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 __avmplus_CodegenLIR__
#define __avmplus_CodegenLIR__
#include "LirHelper.h"
#include "InvokerCompiler.h"
#if defined(VMCFG_INTERRUPT_SAFEPOINT_POLL) && !defined(NJ_SAFEPOINT_POLLING_SUPPORTED)
#error "configuration error: safepoint polling not supported on this platform"
#endif
namespace avmplus
{
using namespace nanojit;
/**
* Each InEdge record tracks an unpatched branch. When the target code
* is generated in emitLabel(), we patch each tracked instruction or
* jtbl entry.
*/
struct InEdge {
LIns *branchIns; // the branch instruction that needs patching
uint32_t index; // if br is a jtbl, which index in table to patch
InEdge(LIns *br) : branchIns(br), index(0) {}
InEdge(LIns *jtbl, uint32_t index) : branchIns(jtbl), index(index) {}
};
/**
* CodegenLabel: information about a LIR label that hasn't been generated yet.
* Once code at the label is generated, we fill in bb. Later, we'll patch
* branch instructions to point to this bb. We have one of
* these for each verifier FrameState.
*/
class CodegenLabel {
public:
LIns *labelIns; // the LIR_label instruction for this code position
nanojit::BitSet *notnull; // merged nullability information for vars at this label
Seq<InEdge> *unpatchedEdges; // branches to this label that need patching
LIns** varTracker; // merged var tracker state at this label
LIns** tagTracker; // merged tag tracker state at this label
#ifdef NJ_VERBOSE
const char* name;
CodegenLabel() : labelIns(0), notnull(0), unpatchedEdges(0), varTracker(0), tagTracker(0), name(0)
{}
CodegenLabel(const char* name) : labelIns(0), notnull(0), unpatchedEdges(0), varTracker(0), tagTracker(0), name(name)
{}
#else
CodegenLabel() : labelIns(0), notnull(0), unpatchedEdges(0), varTracker(0), tagTracker(0)
{}
CodegenLabel(const char*) : labelIns(0), notnull(0), unpatchedEdges(0), varTracker(0), tagTracker(0)
{}
#endif
};
// Binding Cache Design
//
// When we don't know the type of the base object at a point we access a property,
// we must look up the property at runtime./ We cache the results of this lookup
// in a BindingCache instance, and install a handler specialized for the object
// type and binding kind. Each BindingCache consists of:
//
// call_handler initially, points to callprop_miss(), later points
// to the specialized handler
//
// vtable or tag VTable* or Atom tag for the base object. specialized
// handlers quickly check this and "miss" when they dont match
// the object seen at runtime.
//
// slot_offset or precomputed offset for a slot, for fast loads, or a preloaded
// method MethodEnv* for a method, for fast calls
//
// name Multiname* for this dynamic access. Used on a cache miss,
// and also for handlers that access dynamic properties.
//
// If jit'd code for a method needs cache entries, they are allocated and
// saved on MethodInfo::_abc.call_cache. The table is only allocated when jit
// compilation was successful, so jit'd code must load this pointer at runtime
// since we don't have the address at compile time.
//
// cache instances are in unmanaged memory, so VTable and MethodEnv pointers
// are effectively weak references: gc-visible pointers must exist elsewhere,
// and the cache doesn't cause them to be pinned.
//
// we allocate one entry for each unique Multiname in each method (only at
// late-bound reference sites, of course).
//
// Limitations:
//
// * we only use a binding cache if the name has no runtime parts.
// * only implemented for OP_callproperty OP_callproplex, OP_getproperty,
// and OP_setproperty
// * only common cases observed in testing are handled, others use a generic
// handler that's slightly slower than not using a cache at all.
// see callprop_miss() in jit-calls.h for detail on handled cases.
//
// Alternatives that led to current design:
//
// * specializing slot accessors on slot type, and storing slot_offset,
// avoids calling ScriptObject::getSlotAtom() (15% faster for gets & calls)
// * decl_type: when an object type doesn't match the cached type, sometimes the
// binding doesn't change. for example calling a method declared on
// a base class, on many different subclasses that don't override the
// method. the subsequent misses can be handled faster if we saved the method_id,
// and checked that the actual type & cached type are related by inheritance.
// This doesn't help for interface methods and the fast case didn't occur often
// enough for the extra cache size and code complexity.
// * vtable: When a single type (Traits*) is used in different environments we'll
// have distinct VTable*'s that point to the same Traits*. the cache might hit
// more often if we stored Traits*. however, specializing the cache on VTable*
// lest us pre-load the MethodEnv* for calls, saving one load. also, comparing
// vtable pointers instead of traits pointers saves one more load. (5% median speedup)
// * we pass the base object to CallCache::Handler instead of accessing it indirectly
// via args[], to save a load on the fast path. Worth 2-3%, and enables the same
// code to handle OP_callproperty and OP_callproplex.
// * we put Multiname* in the cache instead of passing it as a constant parameter,
// because the increase in cache size is smaller than the savings in code size,
// less parameters is faster, and the multiname is only used on relatively slow paths.
// * we allocate cache instances while generating code, which lets us embed
// the cache address in code instead of loading from methodinfo. some stats on ESC:
// call cache entries: 489
// bytes of call cache entries: 7,824
// instructions saved by early allocation (static): 1,445 (loads, movs, adds)
// MethodInfo instances: 2436
// bytes saved by eliminating 2 cache pointers on MethodInfo: 19,448
//
// (footnote: Times are from the tests in tamarin/test/performance as well as a
// selection of Flash/Flex benchmark apps)
//
// Alternatives not yet investigated:
//
// * we could put the whole Multiname in the cache, and maybe eliminate
// PoolObject::precomputedMultinames[]. Not all multinames are used in late bound
// call sites, so this could save some memory. precomputed multinames have been
// measured at over 10% of code size. Need to study cache size increase vs pool
// memory decrease. Later when we have a code cache, this could be more compelling.
// * we could specialize BKIND_METHOD handlers on method return type, enabling us
// to inline the native-value boxing logic from MethodEnv::endCoerce()
// * we could specialize getter & setter handlers on return/parameter type,
// allowing us to inline boxing & unboxing code from coerceEnter AND endCoerce
// * the MethodEnv* passed to each handler is only used on slow paths. Could we
// put it somewhere else? maybe core->currentMethodFrame->env?
// * on x86, FASTCALL might be faster, if it doesn't inhibit tail calls in handlers
// * other cache instance groupings:
// * one per call site instead of per-unique-multiname?
// * share them between methods?
// * handlers that access primitive dynamic properites have to call toplevel->toPrototype(val),
// maybe we could save the result and check its validity with (env->toplevel() == saved_proto->toplevel())
// * we could specialize on primitive type too, inlining just the toPrototype() path we need,
// instead of using a single set of handlers for all primitives types
// * OP_initproperty is rarely late bound in jit code; if this evidence changes
// then we should consider an inline cache for it.
// binding cache common code
class BindingCache {
public:
BindingCache(const Multiname*, BindingCache* next);
union {
VTable* vtable; // for kObjectType receivers
Atom tag; // for primitive receivers
};
union {
ptrdiff_t slot_offset; // for gets of a slot
MethodEnv* method; // calls to a method
};
const Multiname* const name; // multiname for this entry, saved when cache created.
BindingCache* const next; // singly-linked list
};
// cache for late bound calls
class CallCache: public BindingCache {
public:
typedef Atom (*Handler)(CallCache&, Atom base, int argc, Atom* args, MethodEnv*);
CallCache(const Multiname*, BindingCache* next);
Handler call_handler;
};
// cache for late bound gets
class GetCache: public BindingCache {
public:
typedef Atom (*Handler)(GetCache&, MethodEnv*, Atom);
GetCache(const Multiname*, BindingCache* next);
Handler get_handler;
};
// bind cache for sets. This is necessarily larger than for gets because
// an assignment implies a coercion, and the target type is an additional
// cached parameter to the coercion
class SetCache: public BindingCache {
public:
typedef void (*Handler)(SetCache&, Atom obj, Atom val, MethodEnv*);
SetCache(const Multiname*, BindingCache* next);
Handler set_handler;
union {
Traits* slot_type; // slot or setter type, for implicit coercion
GC* gc; // saved GC* for set-handlers that call WBATOM
};
};
/** helper class for allocating binding caches during jit compilation */
template <class C>
class CacheBuilder
{
SeqBuilder<C*> caches; // each entry points to an initialized cache
CodeMgr& codeMgr; // this allocator is used for new caches
C* findCacheSlot(const Multiname*);
public:
/** each new entry will be initialized with the given handler.
* temp_alloc is the allocator for this cache builder, with short lifetime.
* codeMgr.allocator is used to allocate memory for the method's caches, with method lifetime */
CacheBuilder(Allocator& builder_alloc, CodeMgr& codeMgr)
: caches(builder_alloc), codeMgr(codeMgr) {}
/** allocate a new cache slot or reuse an existing one with the same multiname */
C* allocateCacheSlot(const Multiname* name);
};
class VarTracker;
class MopsRangeCheckFilter;
class PrologWriter;
typedef HashMap<LIns*, nanojit::BitSet*> LabelBitSet;
// We may replace an existing function call with another based on the
// context in which it appears. For example, if the result is to be
// coerced to another type, there may be another function that directly
// generates the same value. For each such context, an array of
// Specialization structures provides a mapping from the old function
// to its replacement.
struct Specialization {
const CallInfo* oldFunc;
const CallInfo* newFunc;
};
// A compact representation of the possible types of a numeric vector
// index suitable for indexing a vector of accessor function ids. This
// is presently used only for an argument to CodegenLIR::emitGetIndexedProperty()
// and CodegenLIR::emitSetIndexedProperty().
typedef enum { VI_UINT, VI_INT, VI_DOUBLE, VI_SIZE } IndexKind;
/**
* CodegenLIR is a kitchen sink class containing all state for all passes
* of the JIT. It is intended to be instantiated on the stack once for each
* jit-compiled method, and is a terminator of a CodeWriter pipeline.
*/
class CodegenLIR : public LirHelper, public CodeWriter {
public:
#ifdef VTUNE
bool hasDebugInfo;
GCList<JITCodeInfo> jitInfoList;
GCList<LineNumberRecord> jitPendingRecords;
void jitPushInfo();
JITCodeInfo* jitCurrentInfo();
LineNumberRecord* jitAddRecord(uintptr_t pos, uint32_t filename, uint32_t line, bool pending=false);
void jitFilenameUpdate(uint32_t filename);
void jitLineNumUpdate(uint32_t line);
void jitCodePosUpdate(uint32_t pos);
#endif /* VTUNE */
protected:
friend struct JitInitVisitor;
MethodInfo *info;
const MethodSignaturep ms;
Toplevel* toplevel;
PoolObject *pool;
OSR* osr;
CodegenDriver* driver;
const FrameState *state;
const uint8_t* code_pos;
const uint8_t* try_from;
const uint8_t* try_to;
MopsRangeCheckFilter* mopsRangeCheckFilter;
LIns *vars, *tags;
LIns *env_param, *argc_param, *ap_param;
LIns *_save_eip, *_ef;
LIns *methodFrame;
LIns *csn;
LIns *undefConst;
LIns *restArgc; // NULL or the expression that computes the number of rest arguments
int restLocal; // -1 or the local var that holds the rest array
bool interruptable;
CodegenLabel npe_label;
CodegenLabel upe_label;
CodegenLabel interrupt_label;
CodegenLabel mop_rangeCheckFailed_label;
CodegenLabel catch_label;
CodegenLabel call_error_label;
const uint8_t* lastPcSave;
LIns *setjmpResult;
VarTracker *varTracker;
int framesize;
#ifdef DEBUGGER
int dbg_framesize; // count of locals & scopes visible to the debugger
#endif
int labelCount;
bool inlineFastpath; // Allow aggressive or speculative inlining, e.g., introducing new labels.
CacheBuilder<CallCache> call_cache_builder;
CacheBuilder<GetCache> get_cache_builder;
CacheBuilder<SetCache> set_cache_builder;
PrologWriter *prolog;
LIns* skip_ins; // Skips from start of body to end of prologue.
HashMap<LIns*, LIns*> *specializedCallHashMap;
HashMap<uint32_t, uint32_t> *builtinFunctionOptimizerHashMap;
HashMap<const uint8_t*, CodegenLabel*> *blockLabels;
LirWriter* redirectWriter;
CseFilter* cseFilter; // The CseFilter instance for this method, or NULL if none.
JITNoise* noise;
verbose_only(VerboseWriter *vbWriter;)
verbose_only(LInsPrinter* vbNames;)
JITDebugInfo *jit_debug_info;
#ifdef DEBUGGER
bool haveDebugger;
#else
static const bool haveDebugger = false;
#endif
#if defined VMCFG_VTUNE
static const bool haveVTune = true;
#else
static const bool haveVTune = false;
#endif
#ifdef DEBUG
/** jit_sst is an array of sst_mask bytes, used to double check that we
* are modeling storage types the same way the verifier did for us.
* Mismatches are caught in writeOpcodeVerified() after the Verifier has
* updated FrameValue.sst_mask. */
uint16_t *jit_sst; // array of SST masks to sanity check with FrameState
ValidateWriter* validate3; // ValidateWriter for method body.
#endif
LIns* insAlloc(int32_t);
LIns* insAllocForTraits(Traits *t);
LIns* atomToNativeRep(int loc, LIns *i);
LIns* atomToNativeRep(Traits *, LIns *i);
LIns* ptrToNativeRep(Traits*, LIns*);
LIns* loadAtomRep(int i);
LIns* localGet(int i);
LIns* localGetp(int i);
LIns* localGetd(int i);
LIns* localGetf(int i); // Aborts if float not enabled
LIns* localGetf4(int i); // Aborts if float not enabled
LIns* localGetf4Addr(int i); // Aborts if float not enabled
LIns* localCopy(int i); // sniff's type from FrameState
void branchToLabel(LOpcode op, LIns *cond, CodegenLabel& label);
void branchAndSavePC(LIns *flag, CodegenLabel& label);
LIns* branchJovToLabel(LOpcode op, LIns *a, LIns *b, CodegenLabel& label);
void branchToAbcPos(LOpcode op, LIns *cond, const uint8_t* target);
LIns* mopAddrToRangeCheckedRealAddrAndDisp(LIns* mopAddr, int32_t const size, int32_t* disp);
LIns* loadEnvScope();
LIns* loadEnvVTable();
LIns* loadEnvAbcEnv();
LIns* loadEnvDomainEnv();
LIns* loadEnvToplevel();
LIns* loadEnvFinddefTable();
LIns* copyMultiname(const Multiname* multiname);
LIns* initMultiname(const Multiname* multiname, int& csp, bool isDelete =false);
LIns* storeAtomArgs(int count, int index);
LIns* storeAtomArgs(LIns *obj, int count, int index);
LIns* promoteNumberIns(Traits *t, int i);
#ifdef VMCFG_FLOAT
LIns* promoteFloatIns(Traits *t, int i);
LIns* promoteFloat4Ins(Traits *t, int i);
#endif // VMCFG_FLOAT
LIns* loadVTable(LIns* obj, Traits* t);
LIns* cmpEq(const CallInfo *fid, int lhsi, int rhsi);
LIns* cmpLt(int lhsi, int rhsi);
LIns* cmpLe(int lhsi, int rhsi);
LIns* cmpOptimization(int lhsi, int rhsi, LOpcode icmp, LOpcode ucmp, LOpcode fcmp, bool strictOperation = false);
debug_only( bool isPointer(int i); )
void emitSetPc(const uint8_t* pc);
void emitSampleCheck();
bool verbose();
CodegenLabel& getCodegenLabel(const uint8_t* pc);
CodegenLabel& createLabel(const char *name);
CodegenLabel& createLabel(const char *prefix, int id);
void patchLater(LIns *br, CodegenLabel &);
void patchLater(LIns *jtbl, const uint8_t* pc, uint32_t index);
void emitLabel(CodegenLabel &l);
void deadvars();
void deadvars_analyze(Allocator& alloc,
nanojit::BitSet& varlivein, LabelBitSet& varlabels,
nanojit::BitSet& taglivein, LabelBitSet& taglabels);
void deadvars_kill(Allocator& alloc,
nanojit::BitSet& varlivein, LabelBitSet& varlabels,
nanojit::BitSet& taglivein, LabelBitSet& taglabels);
void copyParam(int i, int &offset);
bool haveSSE2() const;
/**
* Overwrite the given instruction with a LIR_skip and adjust
* skip_ins if it was pointing to the skipped instruction.
*/
void eraseIns(LIns* ins, LIns* prevIns);
LIns* loadIns(LOpcode op, int32_t disp, LIns *base, AccSet accSet, LoadQual loadQual=LOAD_NORMAL);
LIns* storeIns(LOpcode op, LIns* val, int32_t disp, LIns *base, AccSet accSet);
LIns* Ins(LOpcode op);
LIns* Ins(LOpcode op, LIns *a);
LIns* i2dIns(LIns* v);
LIns* ui2dIns(LIns* v);
LIns* callIns(const CallInfo *, uint32_t argc, ...);
#ifdef VMCFG_FLOAT
/* Handle 1- and 2-operand numeric operations. Assumption: "number"/"int" is the "fastpath",
the rest may be slow (should really be typed if the user wants speed) */
void emitNumericOp1(int32_t op1, const LIREmitter &emitIns);
void emitNumericOp2(int32_t op1, int32_t op2, const LIREmitter& emitIns);
#endif // VMCFG_FLOAT
/** emit a constructor call, and early bind if possible */
void emitConstruct(int argc, LIns* ctor, Traits* ctraits);
void emitCall(AbcOpcode opcode, intptr_t method_id, int argc, Traits* result, MethodSignaturep);
void emitCall(AbcOpcode opcode, intptr_t method_id, int argc, LIns* obj, Traits* objType, Traits* result, MethodSignaturep);
/** Verifier has already coerced args and emitted the null check; JIT just double checks and emits code */
void emitTypedCall(AbcOpcode opcode, intptr_t method_id, int argc, Traits* result, MethodInfo*);
/** emit a JIT-discovered early bound call. JIT must coerce args and receiver to the proper type */
void emitCoerceCall(AbcOpcode opcode, intptr_t method_id, int argc, MethodSignaturep mms);
/** emit a JIT-discovered early bound call to newInstance and invoke the initializer function */
void emitConstructCall(intptr_t method_id, int argc, LIns* ctor, Traits* ctraits);
/** helper to coerce args to an early bound call to the required types */
void coerceArgs(MethodSignaturep mms, int argc, int firstArg);
void emit(AbcOpcode opcode, uintptr_t op1=0, uintptr_t op2=0, Traits* result=NULL);
void emitIf(AbcOpcode opcode, const uint8_t* target, int lhs, int rhs);
void emitSwap(int i, int j);
void emitCopy(int src, int dest);
void emitGetscope(int scope, int dest);
void emitKill(int i);
#ifdef VMCFG_FASTPATH_ADD
#ifdef VMCFG_FASTPATH_ADD_INLINE
void emitIntPlusAtomFastpath(int i, Traits* type, LIns* lhs, LIns* rhs, CodegenLabel &fallback);
#endif
void emitAddIntToAtom(int i, int j, Traits* type);
void emitAddDoubleToAtom(int i, int j, Traits* type);
void emitAddAtomToInt(int i, int j, Traits* type);
void emitAddAtomToDouble(int i, int j, Traits* type);
#endif
void emitAddAtomToAtom(int i, int j, Traits* type);
void emitAdd(int i, int j, Traits* type);
void emitIntConst(int index, int32_t c, Traits* type);
void emitTaintedIntConst(int index, int32_t c, Traits* type);
void emitPtrConst(int index, void* c, Traits* type);
void emitDoubleConst(int index, const double* pd);
void emitTaintedDoubleConst(int index, const double* pd);
#ifdef VMCFG_FLOAT
void emitTaintedFloatConst(int index, const float f);
void emitTaintedFloat4Const(int index, const float4_t* pf4);
#endif // VMCFG_FLOAT
void emitGetslot(int slot, int ptr_index, Traits *slotType);
void emitSetslot(AbcOpcode opcode, int slot, int ptr_index);
void emitSetslot(AbcOpcode opcode, int slot, int ptr_index, LIns* value);
void emitGetGlobalScope(int dest);
void emitCoerce(uint32_t index, Traits* type);
void emitCheckNull(LIns* ptr, Traits* type);
LIns* emitGetIndexedProperty(int objIndex, LIns *index, Traits *result, IndexKind idxKind);
LIns* emitInlineVectorRead(int objIndexOnStack,
LIns* index,
size_t arrayDataOffset, size_t lenOffset, size_t entriesOffset, int scale, LOpcode load_item,
const CallInfo* helper);
LIns* emitInlineSpeculativeArrayRead(int objIndexOnStack,
LIns* index,
const CallInfo* helper);
void emitInlineVectorWrite(int objIndexOnStack,
LIns* index,
LIns* value,
size_t arrayDataOffset, size_t lenOffset, size_t entriesOffset, int scale, LOpcode store_item,
const CallInfo* helper);
void emitSetIndexedProperty(int objIndex, int valIndex, LIns *index, IndexKind idxKind);
void localSet(int i, LIns* o, Traits* type);
LIns* convertToString(int i, bool preserveNull);
LIns* coerceToString(int i);
LIns* coerceToNumber(int i);
#ifdef VMCFG_FLOAT
LIns* coerceToFloat(int i);
LIns* coerceToFloat4(int i);
LIns* coerceToNumeric(int i);
LIns* coerceFloatToInt(int i);
bool matchShuffler(MethodInfo* m, uint8_t* shuffle_mask);
#endif // VMCFG_FLOAT
LIns* loadFromSlot(int ptr_index, int slot, Traits* slotType);
LIns* coerceToType(int i, Traits*);
void emitInitializers();
void emitDebugEnter();
void emitOsrBranch();
bool isPromote(LOpcode op);
LIns* imm2Int(LIns* imm);
LIns* coerceNumberToInt(int i);
bool inlineBuiltinFunction(AbcOpcode opcode, intptr_t method_id, int argc, Traits* result, MethodInfo* mi);
LIns* optimizeIntCmpWithNumberCall(int callIndex, int otherIndex, LOpcode icmp, bool swap);
LIns* optimizeStringCmpWithStringCall(int callIndex, int otherIndex, LOpcode icmp, bool swap);
void suspendCSE();
void resumeCSE();
LIns* getSpecializedCall(LIns* call);
LIns* addSpecializedCall(LIns* origCall, LIns* specializedCall);
LIns* specializeIntCall(LIns *call, const Specialization* specs);
LIns* emitStringCall(int index, const CallInfo* stringCall, bool preserveNull);
typedef void (CodegenLIR::*EmitMethod)(Traits* t);
typedef struct {
int32_t methodId;
int32_t argCount;
BuiltinType argType[2];
const CallInfo *newFunction;
EmitMethod emitFunction;
} FunctionMatch;
static const FunctionMatch specializedFunctions[];
int32_t determineBuiltinMaskForArg (int argOffset);
LIns* getSpecializedArg (int argOffset, BuiltinType newBt);
void genBuiltinFunctionOptimizerHashMap();
void emitIsNaN(Traits* result);
void emitIntMathMin(Traits* result);
void emitIntMathMax(Traits* result);
void emitStringLength(Traits* result);
#ifdef VMCFG_FLOAT
// helpers
void emitFloatUnary(Traits* result, LOpcode op);
void emitFloat4unary(Traits*, LOpcode opcode);
void emitFloat4binary(Traits*, LOpcode opcode);
void emitFloat4dot(Traits*, LOpcode opcode);
LIns* magnitude(LOpcode dot_op, LIns* x);
void emitMagnitude(Traits* result, LOpcode dot_op);
void emitDistance(Traits* result, LOpcode dot_op);
// emitters for inline float/float4 functions
void emitFloatAbs(Traits* result);
void emitFloatReciprocal(Traits* result);
void emitFloatRsqrt(Traits* result);
void emitFloatSqrt(Traits* result);
void emitFloat4abs(Traits* result);
void emitFloat4max(Traits* result);
void emitFloat4min(Traits* result);
void emitFloat4reciprocal(Traits* result);
void emitFloat4rsqrt(Traits* result);
void emitFloat4sqrt(Traits* result);
void emitFloat4normalize(Traits* result);
void emitFloat4cross(Traits* result);
void emitFloat4dot(Traits* result);
void emitFloat4dot2(Traits* result);
void emitFloat4dot3(Traits* result);
void emitFloat4magnitude(Traits* result);
void emitFloat4magnitude2(Traits* result);
void emitFloat4magnitude3(Traits* result);
void emitFloat4distance(Traits* result);
void emitFloat4distance2(Traits* result);
void emitFloat4distance3(Traits* result);
LIns* emitDot(LOpcode, LIns*, LIns*);
void emitFloat4Greater(Traits* result);
void emitFloat4GreaterOrEqual(Traits* result);
void emitFloat4Less(Traits* result);
void emitFloat4LessOrEqual(Traits* result);
void emitFloat4Equal(Traits* result);
void emitFloat4NotEqual(Traits* result);
#endif
LIns *optimizeIndexArgumentType(int32_t sp, Traits** indexType);
JITDebugInfo* initJitDebugInfo();
public:
~CodegenLIR();
CodegenLIR(MethodInfo* info, MethodSignaturep ms, Toplevel* toplevel,
OSR *osr_state, JITNoise* noise);
GprMethodProc emitMD();
// May return true if JIT will always fail based on information known prior to invocation.
static bool jitWillFail(const MethodSignaturep ms);
// CodeWriter methods
void write(const FrameState* state, const uint8_t* pc, AbcOpcode opcode, Traits *type);
void writeOp1(const FrameState* state, const uint8_t *pc, AbcOpcode opcode, uint32_t opd1, Traits* type);
void writeOp2(const FrameState* state, const uint8_t *pc, AbcOpcode opcode, uint32_t opd1, uint32_t opd2, Traits* type);
void writeMethodCall(const FrameState* state, const uint8_t *pc, AbcOpcode opcode, MethodInfo*, uintptr_t disp_id, uint32_t argc, Traits* type);
void writeNip(const FrameState* state, const uint8_t *pc, uint32_t count);
void writeCheckNull(const FrameState* state, uint32_t index);
void writeCoerce(const FrameState* state, uint32_t index, Traits *type);
void writeCoerceToNumeric(const FrameState* state, uint32_t index);
void writeCoerceToFloat4(const FrameState* state, uint32_t index);
void writePrologue(const FrameState* state, const uint8_t *pc, CodegenDriver*);
void writeEpilogue(const FrameState* state);
void writeBlockStart(const FrameState* state);
void writeOpcodeVerified(const FrameState* state, const uint8_t* pc, AbcOpcode opcode);
void writeFixExceptionsAndLabels(const FrameState* state, const uint8_t* pc);
void cleanup();
};
}
#include "CodegenLIR-inlines.h"
#endif /* __avmplus_CodegenLIR__ */