/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * 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 frontend_PropOpEmitter_h #define frontend_PropOpEmitter_h #include "mozilla/Attributes.h" #include "vm/SharedStencil.h" // GCThingIndex namespace js { namespace frontend { struct BytecodeEmitter; class TaggedParserAtomIndex; enum class ValueUsage; // Class for emitting bytecode for property operation. // // Usage: (check for the return value is omitted for simplicity) // // `obj.prop;` // PropOpEmitter poe(this, // PropOpEmitter::Kind::Get, // PropOpEmitter::ObjKind::Other); // poe.prepareForObj(); // emit(obj); // poe.emitGet(atom_of_prop); // // `super.prop;` // PropOpEmitter poe(this, // PropOpEmitter::Kind::Get, // PropOpEmitter::ObjKind::Super); // poe.prepareForObj(); // emit(obj); // poe.emitGet(atom_of_prop); // // `obj.prop();` // PropOpEmitter poe(this, // PropOpEmitter::Kind::Call, // PropOpEmitter::ObjKind::Other); // poe.prepareForObj(); // emit(obj); // poe.emitGet(atom_of_prop); // emit_call_here(); // // `new obj.prop();` // PropOpEmitter poe(this, // PropOpEmitter::Kind::Call, // PropOpEmitter::ObjKind::Other); // poe.prepareForObj(); // emit(obj); // poe.emitGet(atom_of_prop); // emit_call_here(); // // `delete obj.prop;` // PropOpEmitter poe(this, // PropOpEmitter::Kind::Delete, // PropOpEmitter::ObjKind::Other); // poe.prepareForObj(); // emit(obj); // poe.emitDelete(atom_of_prop); // // `delete super.prop;` // PropOpEmitter poe(this, // PropOpEmitter::Kind::Delete, // PropOpEmitter::ObjKind::Other); // poe.emitDelete(atom_of_prop); // // `obj.prop++;` // PropOpEmitter poe(this, // PropOpEmitter::Kind::PostIncrement, // PropOpEmitter::ObjKind::Other); // poe.prepareForObj(); // emit(obj); // poe.emitIncDec(atom_of_prop); // // `obj.prop = value;` // PropOpEmitter poe(this, // PropOpEmitter::Kind::SimpleAssignment, // PropOpEmitter::ObjKind::Other); // poe.prepareForObj(); // emit(obj); // poe.prepareForRhs(); // emit(value); // poe.emitAssignment(atom_of_prop); // // `obj.prop += value;` // PropOpEmitter poe(this, // PropOpEmitter::Kind::CompoundAssignment, // PropOpEmitter::ObjKind::Other); // poe.prepareForObj(); // emit(obj); // poe.emitGet(atom_of_prop); // poe.prepareForRhs(); // emit(value); // emit_add_op_here(); // poe.emitAssignment(nullptr); // nullptr for CompoundAssignment // class MOZ_STACK_CLASS PropOpEmitter { public: enum class Kind { Get, Call, Delete, PostIncrement, PreIncrement, PostDecrement, PreDecrement, SimpleAssignment, PropInit, CompoundAssignment }; enum class ObjKind { Super, Other }; private: BytecodeEmitter* bce_; Kind kind_; ObjKind objKind_; // The index for the property name's atom. GCThingIndex propAtomIndex_; #ifdef DEBUG // The state of this emitter. // // skipObjAndRhs // +----------------------------+ // | | // +-------+ | prepareForObj +-----+ | // | Start |-+-------------->| Obj |-+ | // +-------+ +-----+ | | // | | // +---------------------------------+ | // | | // | | // | [Get] | // | [Call] | // | emitGet +-----+ | // +---------->| Get | | // | +-----+ | // | | // | [Delete] | // | emitDelete +--------+ | // +------------->| Delete | | // | +--------+ | // | | // | [PostIncrement] | // | [PreIncrement] | // | [PostDecrement] | // | [PreDecrement] | // | emitIncDec +--------+ | // +------------->| IncDec | | // | +--------+ | // | | // | [SimpleAssignment] | // | [PropInit] | // | prepareForRhs | +-----+ // +--------------------->+-------------->+->| Rhs |-+ // | ^ +-----+ | // | | | // | | +---------+ // | [CompoundAssignment] | | // | emitGet +-----+ | | emitAssignment +------------+ // +---------->| Get |----+ + -------------->| Assignment | // +-----+ +------------+ enum class State { // The initial state. Start, // After calling prepareForObj. Obj, // After calling emitGet. Get, // After calling emitDelete. Delete, // After calling emitIncDec. IncDec, // After calling prepareForRhs or skipObjAndRhs. Rhs, // After calling emitAssignment. Assignment, }; State state_ = State::Start; #endif public: PropOpEmitter(BytecodeEmitter* bce, Kind kind, ObjKind objKind); private: [[nodiscard]] bool isCall() const { return kind_ == Kind::Call; } [[nodiscard]] bool isSuper() const { return objKind_ == ObjKind::Super; } [[nodiscard]] bool isSimpleAssignment() const { return kind_ == Kind::SimpleAssignment; } [[nodiscard]] bool isPropInit() const { return kind_ == Kind::PropInit; } [[nodiscard]] bool isDelete() const { return kind_ == Kind::Delete; } [[nodiscard]] bool isCompoundAssignment() const { return kind_ == Kind::CompoundAssignment; } [[nodiscard]] bool isIncDec() const { return isPostIncDec() || isPreIncDec(); } [[nodiscard]] bool isPostIncDec() const { return kind_ == Kind::PostIncrement || kind_ == Kind::PostDecrement; } [[nodiscard]] bool isPreIncDec() const { return kind_ == Kind::PreIncrement || kind_ == Kind::PreDecrement; } [[nodiscard]] bool isInc() const { return kind_ == Kind::PostIncrement || kind_ == Kind::PreIncrement; } [[nodiscard]] bool prepareAtomIndex(TaggedParserAtomIndex prop); public: [[nodiscard]] bool prepareForObj(); [[nodiscard]] bool emitGet(TaggedParserAtomIndex prop); [[nodiscard]] bool prepareForRhs(); [[nodiscard]] bool skipObjAndRhs(); [[nodiscard]] bool emitDelete(TaggedParserAtomIndex prop); // `prop` can be nullptr for CompoundAssignment. [[nodiscard]] bool emitAssignment(TaggedParserAtomIndex prop); [[nodiscard]] bool emitIncDec(TaggedParserAtomIndex prop, ValueUsage valueUsage); }; } /* namespace frontend */ } /* namespace js */ #endif /* frontend_PropOpEmitter_h */