diff options
Diffstat (limited to 'js/src/frontend/PropOpEmitter.h')
-rw-r--r-- | js/src/frontend/PropOpEmitter.h | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/js/src/frontend/PropOpEmitter.h b/js/src/frontend/PropOpEmitter.h new file mode 100644 index 0000000000..76402025ea --- /dev/null +++ b/js/src/frontend/PropOpEmitter.h @@ -0,0 +1,254 @@ +/* -*- 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 */ |