Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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_NameOpEmitter_h
#define frontend_NameOpEmitter_h
#include "mozilla/Attributes.h"
#include "frontend/NameAnalysisTypes.h"
#include "frontend/ParserAtom.h" // TaggedParserAtomIndex
#include "vm/SharedStencil.h" // GCThingIndex
namespace js {
namespace frontend {
struct BytecodeEmitter;
enum class ValueUsage;
// Class for emitting bytecode for name operation.
//
// Usage: (check for the return value is omitted for simplicity)
//
// `name;`
// NameOpEmitter noe(this, atom_of_name
// NameOpEmitter::Kind::Get);
// noe.emitGet();
//
// `name();`
// this is handled in CallOrNewEmitter
//
// `name++;`
// NameOpEmitter noe(this, atom_of_name
// NameOpEmitter::Kind::PostIncrement);
// noe.emitIncDec();
//
// `name = 10;`
// NameOpEmitter noe(this, atom_of_name
// NameOpEmitter::Kind::SimpleAssignment);
// noe.prepareForRhs();
// emit(10);
// noe.emitAssignment();
//
// `name += 10;`
// NameOpEmitter noe(this, atom_of_name
// NameOpEmitter::Kind::CompoundAssignment);
// noe.prepareForRhs();
// emit(10);
// emit_add_op_here();
// noe.emitAssignment();
//
// `name = 10;` part of `let name = 10;`
// NameOpEmitter noe(this, atom_of_name
// NameOpEmitter::Kind::Initialize);
// noe.prepareForRhs();
// emit(10);
// noe.emitAssignment();
//
class MOZ_STACK_CLASS NameOpEmitter {
public:
enum class Kind {
Get,
Call,
PostIncrement,
PreIncrement,
PostDecrement,
PreDecrement,
SimpleAssignment,
CompoundAssignment,
Initialize
};
private:
BytecodeEmitter* bce_;
Kind kind_;
bool emittedBindOp_ = false;
TaggedParserAtomIndex name_;
GCThingIndex atomIndex_;
NameLocation loc_;
#ifdef DEBUG
// The state of this emitter.
//
// [Get]
// [Call]
// +-------+ emitGet +-----+
// | Start |-+-+--------->| Get |
// +-------+ | +-----+
// |
// | [PostIncrement]
// | [PreIncrement]
// | [PostDecrement]
// | [PreDecrement]
// | emitIncDec +--------+
// +------------->| IncDec |
// | +--------+
// |
// | [SimpleAssignment]
// | prepareForRhs +-----+
// +--------------------->+-------------->| Rhs |-+
// | ^ +-----+ |
// | | |
// | | +------------------+
// | [CompoundAssignment] | |
// | emitGet +-----+ | | emitAssignment +------------+
// +---------->| Get |----+ + -------------->| Assignment |
// +-----+ +------------+
enum class State {
// The initial state.
Start,
// After calling emitGet.
Get,
// After calling emitIncDec.
IncDec,
// After calling prepareForRhs.
Rhs,
// After calling emitAssignment.
Assignment,
};
State state_ = State::Start;
#endif
public:
NameOpEmitter(BytecodeEmitter* bce, TaggedParserAtomIndex name, Kind kind);
NameOpEmitter(BytecodeEmitter* bce, TaggedParserAtomIndex name,
const NameLocation& loc, Kind kind);
private:
[[nodiscard]] bool isCall() const { return kind_ == Kind::Call; }
[[nodiscard]] bool isSimpleAssignment() const {
return kind_ == Kind::SimpleAssignment;
}
[[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 isInitialize() const { return kind_ == Kind::Initialize; }
public:
[[nodiscard]] bool emittedBindOp() const { return emittedBindOp_; }
[[nodiscard]] const NameLocation& loc() const { return loc_; }
[[nodiscard]] bool emitGet();
[[nodiscard]] bool prepareForRhs();
[[nodiscard]] bool emitAssignment();
[[nodiscard]] bool emitIncDec(ValueUsage valueUsage);
};
} /* namespace frontend */
} /* namespace js */
#endif /* frontend_NameOpEmitter_h */