diff options
Diffstat (limited to 'js/src/frontend/ElemOpEmitter.h')
-rw-r--r-- | js/src/frontend/ElemOpEmitter.h | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/js/src/frontend/ElemOpEmitter.h b/js/src/frontend/ElemOpEmitter.h new file mode 100644 index 0000000000..d6f21315ee --- /dev/null +++ b/js/src/frontend/ElemOpEmitter.h @@ -0,0 +1,279 @@ +/* -*- 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_ElemOpEmitter_h +#define frontend_ElemOpEmitter_h + +#include "mozilla/Attributes.h" +#include "frontend/Token.h" + +namespace js { +namespace frontend { + +struct BytecodeEmitter; + +// Class for emitting bytecode for element operation. +// +// Usage: (check for the return value is omitted for simplicity) +// +// `obj[key];` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::Get, +// ElemOpEmitter::ObjKind::Other); +// eoe.prepareForObj(); +// emit(obj); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitGet(); +// +// `super[key];` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::Get, +// ElemOpEmitter::ObjKind::Super); +// eoe.prepareForObj(); +// emit(this_for_super); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitGet(); +// +// `obj[key]();` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::Call, +// ElemOpEmitter::ObjKind::Other); +// eoe.prepareForObj(); +// emit(obj); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitGet(); +// emit_call_here(); +// +// `new obj[key]();` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::Call, +// ElemOpEmitter::ObjKind::Other); +// eoe.prepareForObj(); +// emit(obj); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitGet(); +// emit_call_here(); +// +// `delete obj[key];` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::Delete, +// ElemOpEmitter::ObjKind::Other); +// eoe.prepareForObj(); +// emit(obj); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitDelete(); +// +// `delete super[key];` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::Delete, +// ElemOpEmitter::ObjKind::Super); +// eoe.prepareForObj(); +// emit(this_for_super); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitDelete(); +// +// `obj[key]++;` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::PostIncrement, +// ElemOpEmitter::ObjKind::Other); +// eoe.prepareForObj(); +// emit(obj); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitIncDec(); +// +// `obj[key] = value;` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::SimpleAssignment, +// ElemOpEmitter::ObjKind::Other); +// eoe.prepareForObj(); +// emit(obj); +// eoe.prepareForKey(); +// emit(key); +// eoe.prepareForRhs(); +// emit(value); +// eoe.emitAssignment(); +// +// `obj[key] += value;` +// ElemOpEmitter eoe(this, +// ElemOpEmitter::Kind::CompoundAssignment, +// ElemOpEmitter::ObjKind::Other); +// eoe.prepareForObj(); +// emit(obj); +// eoe.prepareForKey(); +// emit(key); +// eoe.emitGet(); +// eoe.prepareForRhs(); +// emit(value); +// emit_add_op_here(); +// eoe.emitAssignment(); +// +class MOZ_STACK_CLASS ElemOpEmitter { + public: + enum class Kind { + Get, + Call, + Set, + Delete, + PostIncrement, + PreIncrement, + PostDecrement, + PreDecrement, + SimpleAssignment, + PropInit, + CompoundAssignment + }; + enum class ObjKind { Super, Other }; + + private: + BytecodeEmitter* bce_; + + Kind kind_; + ObjKind objKind_; + NameVisibility visibility_ = NameVisibility::Public; + +#ifdef DEBUG + // The state of this emitter. + // + // skipObjAndKeyAndRhs + // +------------------------------------------------+ + // | | + // +-------+ | prepareForObj +-----+ prepareForKey +-----+ | + // | Start |-+-------------->| Obj |-------------->| Key |-+ | + // +-------+ +-----+ +-----+ | | + // | | + // +-------------------------------------------------------+ | + // | | + // | [Get] | + // | [Call] | + // | emitGet +-----+ | + // +---------->| Get | | + // | +-----+ | + // | | + // | [Delete] | + // | emitDelete +--------+ | + // +------------->| Delete | | + // | +--------+ | + // | | + // | [PostIncrement] | + // | [PreIncrement] | + // | [PostDecrement] | + // | [PreDecrement] | + // | emitIncDec +--------+ | + // +------------->| IncDec | | + // | +--------+ | + // | +-------------------+ + // | [SimpleAssignment] | + // | [PropInit] | + // | prepareForRhs v +-----+ + // +--------------------->+-------------->+->| Rhs |-+ + // | ^ +-----+ | + // | | | + // | | +-------------+ + // | [CompoundAssignment] | | + // | emitGet +-----+ | | emitAssignment +------------+ + // +---------->| Get |----+ +--------------->| Assignment | + // +-----+ +------------+ + enum class State { + // The initial state. + Start, + + // After calling prepareForObj. + Obj, + + // After calling emitKey. + Key, + + // After calling emitGet. + Get, + + // After calling emitDelete. + Delete, + + // After calling emitIncDec. + IncDec, + + // After calling prepareForRhs or skipObjAndKeyAndRhs. + Rhs, + + // After calling emitAssignment. + Assignment, + }; + State state_ = State::Start; +#endif + + public: + ElemOpEmitter(BytecodeEmitter* bce, Kind kind, ObjKind objKind, + NameVisibility visibility); + + private: + MOZ_MUST_USE bool isCall() const { return kind_ == Kind::Call; } + + MOZ_MUST_USE bool isSimpleAssignment() const { + return kind_ == Kind::SimpleAssignment; + } + + bool isPrivate() { return visibility_ == NameVisibility::Private; } + + MOZ_MUST_USE bool isPropInit() const { return kind_ == Kind::PropInit; } + + MOZ_MUST_USE bool isPrivateGet() const { + return visibility_ == NameVisibility::Private && kind_ == Kind::Get; + } + + MOZ_MUST_USE bool isDelete() const { return kind_ == Kind::Delete; } + + MOZ_MUST_USE bool isCompoundAssignment() const { + return kind_ == Kind::CompoundAssignment; + } + + MOZ_MUST_USE bool isIncDec() const { return isPostIncDec() || isPreIncDec(); } + + MOZ_MUST_USE bool isPostIncDec() const { + return kind_ == Kind::PostIncrement || kind_ == Kind::PostDecrement; + } + + MOZ_MUST_USE bool isPreIncDec() const { + return kind_ == Kind::PreIncrement || kind_ == Kind::PreDecrement; + } + + MOZ_MUST_USE bool isInc() const { + return kind_ == Kind::PostIncrement || kind_ == Kind::PreIncrement; + } + + MOZ_MUST_USE bool isSuper() const { return objKind_ == ObjKind::Super; } + + public: + MOZ_MUST_USE bool prepareForObj(); + MOZ_MUST_USE bool prepareForKey(); + + MOZ_MUST_USE bool emitGet(); + + MOZ_MUST_USE bool prepareForRhs(); + MOZ_MUST_USE bool skipObjAndKeyAndRhs(); + + MOZ_MUST_USE bool emitDelete(); + + MOZ_MUST_USE bool emitAssignment(); + + MOZ_MUST_USE bool emitIncDec(); + + private: + // When we have private names, we may need to emit a CheckPrivateField + // op to potentially throw errors where required. + MOZ_MUST_USE bool emitPrivateGuard(); +}; + +} /* namespace frontend */ +} // namespace js + +#endif /* frontend_ElemOpEmitter_h */ |