/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the JavaScript 2 Prototype. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License (the "GPL"), in which case the * provisions of the GPL are applicable instead of those above. * If you wish to allow use of your version of this file only * under the terms of the GPL and not to allow others to use your * version of this file under the NPL, indicate your decision by * deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete * the provisions above, a recipient may use your version of this * file under either the NPL or the GPL. */ #ifndef bytecodegen_h___ #define bytecodegen_h___ #ifdef _WIN32 // Turn off warnings about identifiers too long in browser information #pragma warning(disable: 4786) #endif #include #include #include "systemtypes.h" #include "strings.h" #include "tracer.h" namespace JavaScript { namespace JS2Runtime { typedef enum { // 1st 2 bits specify what kind of 'this' exists NoThis = 0x00, Inherent = 0x01, Explicit = 0x02, ThisFlags = 0x03, // bit #3 indicates presence of named arguments NamedArguments = 0x04, // but #4 is set for the invocation of the super constructor // from inside a constructor SuperInvoke = 0x08 } CallFlag; typedef enum { LoadConstantUndefinedOp,// --> LoadConstantTrueOp, // --> LoadConstantFalseOp, // --> LoadConstantNullOp, // --> LoadConstantZeroOp, // --> <+0.0 value object> LoadConstantNumberOp, // --> LoadConstantStringOp, // --> LoadConstantRegExpOp, // --> LoadThisOp, // --> LoadFunctionOp, // XXX !!! XXX LoadTypeOp, // XXX !!! XXX InvokeOp, // --> [] GetTypeOp, // --> CastOp, // --> DoUnaryOp, // --> DoOperatorOp, // --> PushNullOp, // --> PushIntOp, // --> PushNumOp, // --> PushStringOp, // --> PushTypeOp, // ReturnOp, // --> ReturnVoidOp, // --> GetConstructorOp, // --> NewObjectOp, // --> NewThisOp, // --> NewInstanceOp, // --> DeleteOp, // --> DeleteNameOp, // --> TypeOfOp, // --> InstanceOfOp, // --> AsOp, // --> IsOp, // --> ToBooleanOp, // --> JumpFalseOp, // --> JumpTrueOp, // --> JumpOp, // TryOp, // JsrOp, // RtsOp, WithinOp, // --> WithoutOp, // ThrowOp, // --> HandlerOp, LogicalXorOp, // --> LogicalNotOp, // --> SwapOp, // --> DupOp, // --> DupInsertOp, // --> DupNOp, // --> DupInsertNOp, // --> PopOp, // --> PopNOp, // --> VoidPopOp, // --> (doesn't cache result value) // for instance members GetFieldOp, // --> SetFieldOp, // --> // for instance methods GetMethodOp, // --> GetMethodRefOp, // --> // for argumentz GetArgOp, // --> SetArgOp, // --> // for local variables in the immediate scope GetLocalVarOp, // --> SetLocalVarOp, // --> // for local variables in the nth closure scope GetClosureVarOp, // , --> SetClosureVarOp, // , --> // for array elements GetElementOp, // ... --> SetElementOp, // ... --> DeleteElementOp, // ... --> // for properties GetPropertyOp, // --> GetInvokePropertyOp, // --> SetPropertyOp, // --> // for all generic names GetNameOp, // --> GetTypeOfNameOp, // --> SetNameOp, // --> LoadGlobalObjectOp, // --> PushScopeOp, // XXX !!! XXX PopScopeOp, // XXX !!! XXX NewClosureOp, // --> JuxtaposeOp, // --> NamedArgOp, // --> UseOp, // --> UseOnceOp, // OpCodeCount } ByteCodeOp; struct ByteCodeData { int8 stackImpact; char *opName; }; extern ByteCodeData gByteCodeData[OpCodeCount]; typedef std::pair PC_Position; class ByteCodeModule { public: ByteCodeModule(ByteCodeGen *bcg, JSFunction *f); ByteCodeModule(size_t pos); ~ByteCodeModule(); #ifdef DEBUG void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("ByteCodeModule", s, t); return t; } void operator delete(void* t) { trace_release("ByteCodeModule", t); STD::free(t); } #endif uint32 getLong(uint32 index) const { return *((uint32 *)&mCodeBase[index]); } uint16 getShort(uint32 index) const { return *((uint16 *)&mCodeBase[index]); } int32 getOffset(uint32 index) const { return *((int32 *)&mCodeBase[index]); } const StringAtom *getString(uint32 index) const { return (const StringAtom *)(index); } float64 getNumber(uint8 *p) const { return *((float64 *)p); } void setSource(const String &source, const String &sourceLocation) { mSource = source; mSourceLocation = sourceLocation; } JSFunction *mFunction; String mSource; String mSourceLocation; uint32 mLocalsCount; // number of local vars to allocate space for uint32 mStackDepth; // max. depth of execution stack uint8 *mCodeBase; uint32 mLength; PC_Position *mCodeMap; uint32 mCodeMapLength; size_t mErrorPos; size_t getPositionForPC(uint32 pc); }; Formatter& operator<<(Formatter& f, const ByteCodeModule& bcm); #define BufferIncrement (32) #define NotALabel ((uint32)(-1)) class Label { public: typedef enum { InternalLabel, NamedLabel, BreakLabel, ContinueLabel } LabelKind; Label() : mKind(InternalLabel), mHasLocation(false) { } Label(LabelStmtNode *lbl) : mKind(NamedLabel), mHasLocation(false), mLabelStmt(lbl) { } Label(LabelKind kind) : mKind(kind), mHasLocation(false) { } bool matches(const StringAtom *name) { return ((mKind == NamedLabel) && (mLabelStmt->name.compare(*name) == 0)); } bool matches(LabelKind kind) { return (mKind == kind); } void addFixup(ByteCodeGen *bcg, uint32 branchLocation); void setLocation(ByteCodeGen *bcg, uint32 location); std::vector mFixupList; LabelKind mKind; bool mHasLocation; LabelStmtNode *mLabelStmt; uint32 mLocation; }; class ByteCodeGen { public: ByteCodeGen(Context *cx, ScopeChain *scopeChain) : mBuffer(new CodeBuffer), mScopeChain(scopeChain), mPC_Map(new CodeMap), m_cx(cx), mStackTop(0), mStackMax(0) { } ~ByteCodeGen() { delete mBuffer; delete mPC_Map; } #ifdef DEBUG void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("ByteCodeGen", s, t); return t; } void operator delete(void* t) { trace_release("ByteCodeGen", t); STD::free(t); } #endif ByteCodeModule *genCodeForScript(StmtNode *p); bool genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint32 finallyLabel); void genCodeForFunction(FunctionDefinition &f, size_t pos, JSFunction *fnc, bool isConstructor, JSType *topClass); ByteCodeModule *genCodeForExpression(ExprNode *p); JSType *genExpr(ExprNode *p); Reference *genReference(ExprNode *p, Access acc); void genReferencePair(ExprNode *p, Reference *&readRef, Reference *&writeRef); typedef std::vector CodeBuffer; typedef std::vector CodeMap; // this is the current code buffer CodeBuffer *mBuffer; ScopeChain *mScopeChain; CodeMap *mPC_Map; Context *m_cx; std::vector