| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef V8_AST_H_ |
| #define V8_AST_H_ |
| |
| #include "v8.h" |
| |
| #include "assembler.h" |
| #include "factory.h" |
| #include "feedback-slots.h" |
| #include "isolate.h" |
| #include "jsregexp.h" |
| #include "list-inl.h" |
| #include "runtime.h" |
| #include "small-pointer-list.h" |
| #include "smart-pointers.h" |
| #include "token.h" |
| #include "types.h" |
| #include "utils.h" |
| #include "variables.h" |
| #include "interface.h" |
| #include "zone-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // The abstract syntax tree is an intermediate, light-weight |
| // representation of the parsed JavaScript code suitable for |
| // compilation to native code. |
| |
| // Nodes are allocated in a separate zone, which allows faster |
| // allocation and constant-time deallocation of the entire syntax |
| // tree. |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Nodes of the abstract syntax tree. Only concrete classes are |
| // enumerated here. |
| |
| #define DECLARATION_NODE_LIST(V) \ |
| V(VariableDeclaration) \ |
| V(FunctionDeclaration) \ |
| V(ModuleDeclaration) \ |
| V(ImportDeclaration) \ |
| V(ExportDeclaration) \ |
| |
| #define MODULE_NODE_LIST(V) \ |
| V(ModuleLiteral) \ |
| V(ModuleVariable) \ |
| V(ModulePath) \ |
| V(ModuleUrl) |
| |
| #define STATEMENT_NODE_LIST(V) \ |
| V(Block) \ |
| V(ModuleStatement) \ |
| V(ExpressionStatement) \ |
| V(EmptyStatement) \ |
| V(IfStatement) \ |
| V(ContinueStatement) \ |
| V(BreakStatement) \ |
| V(ReturnStatement) \ |
| V(WithStatement) \ |
| V(SwitchStatement) \ |
| V(DoWhileStatement) \ |
| V(WhileStatement) \ |
| V(ForStatement) \ |
| V(ForInStatement) \ |
| V(ForOfStatement) \ |
| V(TryCatchStatement) \ |
| V(TryFinallyStatement) \ |
| V(DebuggerStatement) |
| |
| #define EXPRESSION_NODE_LIST(V) \ |
| V(FunctionLiteral) \ |
| V(NativeFunctionLiteral) \ |
| V(Conditional) \ |
| V(VariableProxy) \ |
| V(Literal) \ |
| V(RegExpLiteral) \ |
| V(ObjectLiteral) \ |
| V(ArrayLiteral) \ |
| V(Assignment) \ |
| V(Yield) \ |
| V(Throw) \ |
| V(Property) \ |
| V(Call) \ |
| V(CallNew) \ |
| V(CallRuntime) \ |
| V(UnaryOperation) \ |
| V(CountOperation) \ |
| V(BinaryOperation) \ |
| V(CompareOperation) \ |
| V(ThisFunction) \ |
| V(CaseClause) |
| |
| #define AST_NODE_LIST(V) \ |
| DECLARATION_NODE_LIST(V) \ |
| MODULE_NODE_LIST(V) \ |
| STATEMENT_NODE_LIST(V) \ |
| EXPRESSION_NODE_LIST(V) |
| |
| // Forward declarations |
| class AstConstructionVisitor; |
| template<class> class AstNodeFactory; |
| class AstVisitor; |
| class Declaration; |
| class Module; |
| class BreakableStatement; |
| class Expression; |
| class IterationStatement; |
| class MaterializedLiteral; |
| class Statement; |
| class TargetCollector; |
| class TypeFeedbackOracle; |
| |
| class RegExpAlternative; |
| class RegExpAssertion; |
| class RegExpAtom; |
| class RegExpBackReference; |
| class RegExpCapture; |
| class RegExpCharacterClass; |
| class RegExpCompiler; |
| class RegExpDisjunction; |
| class RegExpEmpty; |
| class RegExpLookahead; |
| class RegExpQuantifier; |
| class RegExpText; |
| |
| #define DEF_FORWARD_DECLARATION(type) class type; |
| AST_NODE_LIST(DEF_FORWARD_DECLARATION) |
| #undef DEF_FORWARD_DECLARATION |
| |
| |
| // Typedef only introduced to avoid unreadable code. |
| // Please do appreciate the required space in "> >". |
| typedef ZoneList<Handle<String> > ZoneStringList; |
| typedef ZoneList<Handle<Object> > ZoneObjectList; |
| |
| |
| #define DECLARE_NODE_TYPE(type) \ |
| virtual void Accept(AstVisitor* v) V8_OVERRIDE; \ |
| virtual AstNode::NodeType node_type() const V8_FINAL V8_OVERRIDE { \ |
| return AstNode::k##type; \ |
| } \ |
| template<class> friend class AstNodeFactory; |
| |
| |
| enum AstPropertiesFlag { |
| kDontInline, |
| kDontSelfOptimize, |
| kDontSoftInline, |
| kDontCache |
| }; |
| |
| |
| class AstProperties V8_FINAL BASE_EMBEDDED { |
| public: |
| class Flags : public EnumSet<AstPropertiesFlag, int> {}; |
| |
| AstProperties() : node_count_(0) {} |
| |
| Flags* flags() { return &flags_; } |
| int node_count() { return node_count_; } |
| void add_node_count(int count) { node_count_ += count; } |
| |
| private: |
| Flags flags_; |
| int node_count_; |
| }; |
| |
| |
| class AstNode: public ZoneObject { |
| public: |
| #define DECLARE_TYPE_ENUM(type) k##type, |
| enum NodeType { |
| AST_NODE_LIST(DECLARE_TYPE_ENUM) |
| kInvalid = -1 |
| }; |
| #undef DECLARE_TYPE_ENUM |
| |
| void* operator new(size_t size, Zone* zone) { |
| return zone->New(static_cast<int>(size)); |
| } |
| |
| explicit AstNode(int position): position_(position) {} |
| virtual ~AstNode() {} |
| |
| virtual void Accept(AstVisitor* v) = 0; |
| virtual NodeType node_type() const = 0; |
| int position() const { return position_; } |
| |
| // Type testing & conversion functions overridden by concrete subclasses. |
| #define DECLARE_NODE_FUNCTIONS(type) \ |
| bool Is##type() const { return node_type() == AstNode::k##type; } \ |
| type* As##type() { \ |
| return Is##type() ? reinterpret_cast<type*>(this) : NULL; \ |
| } \ |
| const type* As##type() const { \ |
| return Is##type() ? reinterpret_cast<const type*>(this) : NULL; \ |
| } |
| AST_NODE_LIST(DECLARE_NODE_FUNCTIONS) |
| #undef DECLARE_NODE_FUNCTIONS |
| |
| virtual TargetCollector* AsTargetCollector() { return NULL; } |
| virtual BreakableStatement* AsBreakableStatement() { return NULL; } |
| virtual IterationStatement* AsIterationStatement() { return NULL; } |
| virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; } |
| |
| protected: |
| static int GetNextId(Zone* zone) { |
| return ReserveIdRange(zone, 1); |
| } |
| |
| static int ReserveIdRange(Zone* zone, int n) { |
| int tmp = zone->isolate()->ast_node_id(); |
| zone->isolate()->set_ast_node_id(tmp + n); |
| return tmp; |
| } |
| |
| // Some nodes re-use bailout IDs for type feedback. |
| static TypeFeedbackId reuse(BailoutId id) { |
| return TypeFeedbackId(id.ToInt()); |
| } |
| |
| |
| private: |
| // Hidden to prevent accidental usage. It would have to load the |
| // current zone from the TLS. |
| void* operator new(size_t size); |
| |
| friend class CaseClause; // Generates AST IDs. |
| |
| int position_; |
| }; |
| |
| |
| class Statement : public AstNode { |
| public: |
| explicit Statement(Zone* zone, int position) : AstNode(position) {} |
| |
| bool IsEmpty() { return AsEmptyStatement() != NULL; } |
| virtual bool IsJump() const { return false; } |
| }; |
| |
| |
| class SmallMapList V8_FINAL { |
| public: |
| SmallMapList() {} |
| SmallMapList(int capacity, Zone* zone) : list_(capacity, zone) {} |
| |
| void Reserve(int capacity, Zone* zone) { list_.Reserve(capacity, zone); } |
| void Clear() { list_.Clear(); } |
| void Sort() { list_.Sort(); } |
| |
| bool is_empty() const { return list_.is_empty(); } |
| int length() const { return list_.length(); } |
| |
| void AddMapIfMissing(Handle<Map> map, Zone* zone) { |
| map = Map::CurrentMapForDeprecated(map); |
| if (map.is_null()) return; |
| for (int i = 0; i < length(); ++i) { |
| if (at(i).is_identical_to(map)) return; |
| } |
| Add(map, zone); |
| } |
| |
| void FilterForPossibleTransitions(Map* root_map) { |
| for (int i = list_.length() - 1; i >= 0; i--) { |
| if (at(i)->FindRootMap() != root_map) { |
| list_.RemoveElement(list_.at(i)); |
| } |
| } |
| } |
| |
| void Add(Handle<Map> handle, Zone* zone) { |
| list_.Add(handle.location(), zone); |
| } |
| |
| Handle<Map> at(int i) const { |
| return Handle<Map>(list_.at(i)); |
| } |
| |
| Handle<Map> first() const { return at(0); } |
| Handle<Map> last() const { return at(length() - 1); } |
| |
| private: |
| // The list stores pointers to Map*, that is Map**, so it's GC safe. |
| SmallPointerList<Map*> list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SmallMapList); |
| }; |
| |
| |
| class Expression : public AstNode { |
| public: |
| enum Context { |
| // Not assigned a context yet, or else will not be visited during |
| // code generation. |
| kUninitialized, |
| // Evaluated for its side effects. |
| kEffect, |
| // Evaluated for its value (and side effects). |
| kValue, |
| // Evaluated for control flow (and side effects). |
| kTest |
| }; |
| |
| virtual bool IsValidReferenceExpression() const { return false; } |
| |
| // Helpers for ToBoolean conversion. |
| virtual bool ToBooleanIsTrue() const { return false; } |
| virtual bool ToBooleanIsFalse() const { return false; } |
| |
| // Symbols that cannot be parsed as array indices are considered property |
| // names. We do not treat symbols that can be array indexes as property |
| // names because [] for string objects is handled only by keyed ICs. |
| virtual bool IsPropertyName() const { return false; } |
| |
| // True iff the result can be safely overwritten (to avoid allocation). |
| // False for operations that can return one of their operands. |
| virtual bool ResultOverwriteAllowed() const { return false; } |
| |
| // True iff the expression is a literal represented as a smi. |
| bool IsSmiLiteral() const; |
| |
| // True iff the expression is a string literal. |
| bool IsStringLiteral() const; |
| |
| // True iff the expression is the null literal. |
| bool IsNullLiteral() const; |
| |
| // True if we can prove that the expression is the undefined literal. |
| bool IsUndefinedLiteral(Isolate* isolate) const; |
| |
| // Expression type bounds |
| Bounds bounds() const { return bounds_; } |
| void set_bounds(Bounds bounds) { bounds_ = bounds; } |
| |
| // Type feedback information for assignments and properties. |
| virtual bool IsMonomorphic() { |
| UNREACHABLE(); |
| return false; |
| } |
| virtual SmallMapList* GetReceiverTypes() { |
| UNREACHABLE(); |
| return NULL; |
| } |
| virtual KeyedAccessStoreMode GetStoreMode() { |
| UNREACHABLE(); |
| return STANDARD_STORE; |
| } |
| |
| // TODO(rossberg): this should move to its own AST node eventually. |
| virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle); |
| byte to_boolean_types() const { return to_boolean_types_; } |
| |
| BailoutId id() const { return id_; } |
| TypeFeedbackId test_id() const { return test_id_; } |
| |
| protected: |
| Expression(Zone* zone, int pos) |
| : AstNode(pos), |
| bounds_(Bounds::Unbounded(zone)), |
| id_(GetNextId(zone)), |
| test_id_(GetNextId(zone)) {} |
| void set_to_boolean_types(byte types) { to_boolean_types_ = types; } |
| |
| private: |
| Bounds bounds_; |
| byte to_boolean_types_; |
| |
| const BailoutId id_; |
| const TypeFeedbackId test_id_; |
| }; |
| |
| |
| class BreakableStatement : public Statement { |
| public: |
| enum BreakableType { |
| TARGET_FOR_ANONYMOUS, |
| TARGET_FOR_NAMED_ONLY |
| }; |
| |
| // The labels associated with this statement. May be NULL; |
| // if it is != NULL, guaranteed to contain at least one entry. |
| ZoneStringList* labels() const { return labels_; } |
| |
| // Type testing & conversion. |
| virtual BreakableStatement* AsBreakableStatement() V8_FINAL V8_OVERRIDE { |
| return this; |
| } |
| |
| // Code generation |
| Label* break_target() { return &break_target_; } |
| |
| // Testers. |
| bool is_target_for_anonymous() const { |
| return breakable_type_ == TARGET_FOR_ANONYMOUS; |
| } |
| |
| BailoutId EntryId() const { return entry_id_; } |
| BailoutId ExitId() const { return exit_id_; } |
| |
| protected: |
| BreakableStatement( |
| Zone* zone, ZoneStringList* labels, |
| BreakableType breakable_type, int position) |
| : Statement(zone, position), |
| labels_(labels), |
| breakable_type_(breakable_type), |
| entry_id_(GetNextId(zone)), |
| exit_id_(GetNextId(zone)) { |
| ASSERT(labels == NULL || labels->length() > 0); |
| } |
| |
| |
| private: |
| ZoneStringList* labels_; |
| BreakableType breakable_type_; |
| Label break_target_; |
| const BailoutId entry_id_; |
| const BailoutId exit_id_; |
| }; |
| |
| |
| class Block V8_FINAL : public BreakableStatement { |
| public: |
| DECLARE_NODE_TYPE(Block) |
| |
| void AddStatement(Statement* statement, Zone* zone) { |
| statements_.Add(statement, zone); |
| } |
| |
| ZoneList<Statement*>* statements() { return &statements_; } |
| bool is_initializer_block() const { return is_initializer_block_; } |
| |
| virtual bool IsJump() const V8_OVERRIDE { |
| return !statements_.is_empty() && statements_.last()->IsJump() |
| && labels() == NULL; // Good enough as an approximation... |
| } |
| |
| Scope* scope() const { return scope_; } |
| void set_scope(Scope* scope) { scope_ = scope; } |
| |
| protected: |
| Block(Zone* zone, |
| ZoneStringList* labels, |
| int capacity, |
| bool is_initializer_block, |
| int pos) |
| : BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos), |
| statements_(capacity, zone), |
| is_initializer_block_(is_initializer_block), |
| scope_(NULL) { |
| } |
| |
| private: |
| ZoneList<Statement*> statements_; |
| bool is_initializer_block_; |
| Scope* scope_; |
| }; |
| |
| |
| class Declaration : public AstNode { |
| public: |
| VariableProxy* proxy() const { return proxy_; } |
| VariableMode mode() const { return mode_; } |
| Scope* scope() const { return scope_; } |
| virtual InitializationFlag initialization() const = 0; |
| virtual bool IsInlineable() const; |
| |
| protected: |
| Declaration(Zone* zone, |
| VariableProxy* proxy, |
| VariableMode mode, |
| Scope* scope, |
| int pos) |
| : AstNode(pos), |
| proxy_(proxy), |
| mode_(mode), |
| scope_(scope) { |
| ASSERT(IsDeclaredVariableMode(mode)); |
| } |
| |
| private: |
| VariableProxy* proxy_; |
| VariableMode mode_; |
| |
| // Nested scope from which the declaration originated. |
| Scope* scope_; |
| }; |
| |
| |
| class VariableDeclaration V8_FINAL : public Declaration { |
| public: |
| DECLARE_NODE_TYPE(VariableDeclaration) |
| |
| virtual InitializationFlag initialization() const V8_OVERRIDE { |
| return mode() == VAR ? kCreatedInitialized : kNeedsInitialization; |
| } |
| |
| protected: |
| VariableDeclaration(Zone* zone, |
| VariableProxy* proxy, |
| VariableMode mode, |
| Scope* scope, |
| int pos) |
| : Declaration(zone, proxy, mode, scope, pos) { |
| } |
| }; |
| |
| |
| class FunctionDeclaration V8_FINAL : public Declaration { |
| public: |
| DECLARE_NODE_TYPE(FunctionDeclaration) |
| |
| FunctionLiteral* fun() const { return fun_; } |
| virtual InitializationFlag initialization() const V8_OVERRIDE { |
| return kCreatedInitialized; |
| } |
| virtual bool IsInlineable() const V8_OVERRIDE; |
| |
| protected: |
| FunctionDeclaration(Zone* zone, |
| VariableProxy* proxy, |
| VariableMode mode, |
| FunctionLiteral* fun, |
| Scope* scope, |
| int pos) |
| : Declaration(zone, proxy, mode, scope, pos), |
| fun_(fun) { |
| // At the moment there are no "const functions" in JavaScript... |
| ASSERT(mode == VAR || mode == LET); |
| ASSERT(fun != NULL); |
| } |
| |
| private: |
| FunctionLiteral* fun_; |
| }; |
| |
| |
| class ModuleDeclaration V8_FINAL : public Declaration { |
| public: |
| DECLARE_NODE_TYPE(ModuleDeclaration) |
| |
| Module* module() const { return module_; } |
| virtual InitializationFlag initialization() const V8_OVERRIDE { |
| return kCreatedInitialized; |
| } |
| |
| protected: |
| ModuleDeclaration(Zone* zone, |
| VariableProxy* proxy, |
| Module* module, |
| Scope* scope, |
| int pos) |
| : Declaration(zone, proxy, MODULE, scope, pos), |
| module_(module) { |
| } |
| |
| private: |
| Module* module_; |
| }; |
| |
| |
| class ImportDeclaration V8_FINAL : public Declaration { |
| public: |
| DECLARE_NODE_TYPE(ImportDeclaration) |
| |
| Module* module() const { return module_; } |
| virtual InitializationFlag initialization() const V8_OVERRIDE { |
| return kCreatedInitialized; |
| } |
| |
| protected: |
| ImportDeclaration(Zone* zone, |
| VariableProxy* proxy, |
| Module* module, |
| Scope* scope, |
| int pos) |
| : Declaration(zone, proxy, LET, scope, pos), |
| module_(module) { |
| } |
| |
| private: |
| Module* module_; |
| }; |
| |
| |
| class ExportDeclaration V8_FINAL : public Declaration { |
| public: |
| DECLARE_NODE_TYPE(ExportDeclaration) |
| |
| virtual InitializationFlag initialization() const V8_OVERRIDE { |
| return kCreatedInitialized; |
| } |
| |
| protected: |
| ExportDeclaration(Zone* zone, VariableProxy* proxy, Scope* scope, int pos) |
| : Declaration(zone, proxy, LET, scope, pos) {} |
| }; |
| |
| |
| class Module : public AstNode { |
| public: |
| Interface* interface() const { return interface_; } |
| Block* body() const { return body_; } |
| |
| protected: |
| Module(Zone* zone, int pos) |
| : AstNode(pos), |
| interface_(Interface::NewModule(zone)), |
| body_(NULL) {} |
| Module(Zone* zone, Interface* interface, int pos, Block* body = NULL) |
| : AstNode(pos), |
| interface_(interface), |
| body_(body) {} |
| |
| private: |
| Interface* interface_; |
| Block* body_; |
| }; |
| |
| |
| class ModuleLiteral V8_FINAL : public Module { |
| public: |
| DECLARE_NODE_TYPE(ModuleLiteral) |
| |
| protected: |
| ModuleLiteral(Zone* zone, Block* body, Interface* interface, int pos) |
| : Module(zone, interface, pos, body) {} |
| }; |
| |
| |
| class ModuleVariable V8_FINAL : public Module { |
| public: |
| DECLARE_NODE_TYPE(ModuleVariable) |
| |
| VariableProxy* proxy() const { return proxy_; } |
| |
| protected: |
| inline ModuleVariable(Zone* zone, VariableProxy* proxy, int pos); |
| |
| private: |
| VariableProxy* proxy_; |
| }; |
| |
| |
| class ModulePath V8_FINAL : public Module { |
| public: |
| DECLARE_NODE_TYPE(ModulePath) |
| |
| Module* module() const { return module_; } |
| Handle<String> name() const { return name_; } |
| |
| protected: |
| ModulePath(Zone* zone, Module* module, Handle<String> name, int pos) |
| : Module(zone, pos), |
| module_(module), |
| name_(name) { |
| } |
| |
| private: |
| Module* module_; |
| Handle<String> name_; |
| }; |
| |
| |
| class ModuleUrl V8_FINAL : public Module { |
| public: |
| DECLARE_NODE_TYPE(ModuleUrl) |
| |
| Handle<String> url() const { return url_; } |
| |
| protected: |
| ModuleUrl(Zone* zone, Handle<String> url, int pos) |
| : Module(zone, pos), url_(url) { |
| } |
| |
| private: |
| Handle<String> url_; |
| }; |
| |
| |
| class ModuleStatement V8_FINAL : public Statement { |
| public: |
| DECLARE_NODE_TYPE(ModuleStatement) |
| |
| VariableProxy* proxy() const { return proxy_; } |
| Block* body() const { return body_; } |
| |
| protected: |
| ModuleStatement(Zone* zone, VariableProxy* proxy, Block* body, int pos) |
| : Statement(zone, pos), |
| proxy_(proxy), |
| body_(body) { |
| } |
| |
| private: |
| VariableProxy* proxy_; |
| Block* body_; |
| }; |
| |
| |
| class IterationStatement : public BreakableStatement { |
| public: |
| // Type testing & conversion. |
| virtual IterationStatement* AsIterationStatement() V8_FINAL V8_OVERRIDE { |
| return this; |
| } |
| |
| Statement* body() const { return body_; } |
| |
| BailoutId OsrEntryId() const { return osr_entry_id_; } |
| virtual BailoutId ContinueId() const = 0; |
| virtual BailoutId StackCheckId() const = 0; |
| |
| // Code generation |
| Label* continue_target() { return &continue_target_; } |
| |
| protected: |
| IterationStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos), |
| body_(NULL), |
| osr_entry_id_(GetNextId(zone)) { |
| } |
| |
| void Initialize(Statement* body) { |
| body_ = body; |
| } |
| |
| private: |
| Statement* body_; |
| Label continue_target_; |
| |
| const BailoutId osr_entry_id_; |
| }; |
| |
| |
| class DoWhileStatement V8_FINAL : public IterationStatement { |
| public: |
| DECLARE_NODE_TYPE(DoWhileStatement) |
| |
| void Initialize(Expression* cond, Statement* body) { |
| IterationStatement::Initialize(body); |
| cond_ = cond; |
| } |
| |
| Expression* cond() const { return cond_; } |
| |
| virtual BailoutId ContinueId() const V8_OVERRIDE { return continue_id_; } |
| virtual BailoutId StackCheckId() const V8_OVERRIDE { return back_edge_id_; } |
| BailoutId BackEdgeId() const { return back_edge_id_; } |
| |
| protected: |
| DoWhileStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : IterationStatement(zone, labels, pos), |
| cond_(NULL), |
| continue_id_(GetNextId(zone)), |
| back_edge_id_(GetNextId(zone)) { |
| } |
| |
| private: |
| Expression* cond_; |
| |
| const BailoutId continue_id_; |
| const BailoutId back_edge_id_; |
| }; |
| |
| |
| class WhileStatement V8_FINAL : public IterationStatement { |
| public: |
| DECLARE_NODE_TYPE(WhileStatement) |
| |
| void Initialize(Expression* cond, Statement* body) { |
| IterationStatement::Initialize(body); |
| cond_ = cond; |
| } |
| |
| Expression* cond() const { return cond_; } |
| bool may_have_function_literal() const { |
| return may_have_function_literal_; |
| } |
| void set_may_have_function_literal(bool value) { |
| may_have_function_literal_ = value; |
| } |
| |
| virtual BailoutId ContinueId() const V8_OVERRIDE { return EntryId(); } |
| virtual BailoutId StackCheckId() const V8_OVERRIDE { return body_id_; } |
| BailoutId BodyId() const { return body_id_; } |
| |
| protected: |
| WhileStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : IterationStatement(zone, labels, pos), |
| cond_(NULL), |
| may_have_function_literal_(true), |
| body_id_(GetNextId(zone)) { |
| } |
| |
| private: |
| Expression* cond_; |
| |
| // True if there is a function literal subexpression in the condition. |
| bool may_have_function_literal_; |
| |
| const BailoutId body_id_; |
| }; |
| |
| |
| class ForStatement V8_FINAL : public IterationStatement { |
| public: |
| DECLARE_NODE_TYPE(ForStatement) |
| |
| void Initialize(Statement* init, |
| Expression* cond, |
| Statement* next, |
| Statement* body) { |
| IterationStatement::Initialize(body); |
| init_ = init; |
| cond_ = cond; |
| next_ = next; |
| } |
| |
| Statement* init() const { return init_; } |
| Expression* cond() const { return cond_; } |
| Statement* next() const { return next_; } |
| |
| bool may_have_function_literal() const { |
| return may_have_function_literal_; |
| } |
| void set_may_have_function_literal(bool value) { |
| may_have_function_literal_ = value; |
| } |
| |
| virtual BailoutId ContinueId() const V8_OVERRIDE { return continue_id_; } |
| virtual BailoutId StackCheckId() const V8_OVERRIDE { return body_id_; } |
| BailoutId BodyId() const { return body_id_; } |
| |
| bool is_fast_smi_loop() { return loop_variable_ != NULL; } |
| Variable* loop_variable() { return loop_variable_; } |
| void set_loop_variable(Variable* var) { loop_variable_ = var; } |
| |
| protected: |
| ForStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : IterationStatement(zone, labels, pos), |
| init_(NULL), |
| cond_(NULL), |
| next_(NULL), |
| may_have_function_literal_(true), |
| loop_variable_(NULL), |
| continue_id_(GetNextId(zone)), |
| body_id_(GetNextId(zone)) { |
| } |
| |
| private: |
| Statement* init_; |
| Expression* cond_; |
| Statement* next_; |
| |
| // True if there is a function literal subexpression in the condition. |
| bool may_have_function_literal_; |
| Variable* loop_variable_; |
| |
| const BailoutId continue_id_; |
| const BailoutId body_id_; |
| }; |
| |
| |
| class ForEachStatement : public IterationStatement { |
| public: |
| enum VisitMode { |
| ENUMERATE, // for (each in subject) body; |
| ITERATE // for (each of subject) body; |
| }; |
| |
| void Initialize(Expression* each, Expression* subject, Statement* body) { |
| IterationStatement::Initialize(body); |
| each_ = each; |
| subject_ = subject; |
| } |
| |
| Expression* each() const { return each_; } |
| Expression* subject() const { return subject_; } |
| |
| protected: |
| ForEachStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : IterationStatement(zone, labels, pos), |
| each_(NULL), |
| subject_(NULL) { |
| } |
| |
| private: |
| Expression* each_; |
| Expression* subject_; |
| }; |
| |
| |
| class ForInStatement V8_FINAL : public ForEachStatement, |
| public FeedbackSlotInterface { |
| public: |
| DECLARE_NODE_TYPE(ForInStatement) |
| |
| Expression* enumerable() const { |
| return subject(); |
| } |
| |
| // Type feedback information. |
| virtual ComputablePhase GetComputablePhase() { return DURING_PARSE; } |
| virtual int ComputeFeedbackSlotCount(Isolate* isolate) { return 1; } |
| virtual void SetFirstFeedbackSlot(int slot) { for_in_feedback_slot_ = slot; } |
| |
| int ForInFeedbackSlot() { |
| ASSERT(for_in_feedback_slot_ != kInvalidFeedbackSlot); |
| return for_in_feedback_slot_; |
| } |
| |
| enum ForInType { FAST_FOR_IN, SLOW_FOR_IN }; |
| ForInType for_in_type() const { return for_in_type_; } |
| void set_for_in_type(ForInType type) { for_in_type_ = type; } |
| |
| BailoutId BodyId() const { return body_id_; } |
| BailoutId PrepareId() const { return prepare_id_; } |
| virtual BailoutId ContinueId() const V8_OVERRIDE { return EntryId(); } |
| virtual BailoutId StackCheckId() const V8_OVERRIDE { return body_id_; } |
| |
| protected: |
| ForInStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : ForEachStatement(zone, labels, pos), |
| for_in_type_(SLOW_FOR_IN), |
| for_in_feedback_slot_(kInvalidFeedbackSlot), |
| body_id_(GetNextId(zone)), |
| prepare_id_(GetNextId(zone)) { |
| } |
| |
| ForInType for_in_type_; |
| int for_in_feedback_slot_; |
| const BailoutId body_id_; |
| const BailoutId prepare_id_; |
| }; |
| |
| |
| class ForOfStatement V8_FINAL : public ForEachStatement { |
| public: |
| DECLARE_NODE_TYPE(ForOfStatement) |
| |
| void Initialize(Expression* each, |
| Expression* subject, |
| Statement* body, |
| Expression* assign_iterator, |
| Expression* next_result, |
| Expression* result_done, |
| Expression* assign_each) { |
| ForEachStatement::Initialize(each, subject, body); |
| assign_iterator_ = assign_iterator; |
| next_result_ = next_result; |
| result_done_ = result_done; |
| assign_each_ = assign_each; |
| } |
| |
| Expression* iterable() const { |
| return subject(); |
| } |
| |
| // var iterator = iterable; |
| Expression* assign_iterator() const { |
| return assign_iterator_; |
| } |
| |
| // var result = iterator.next(); |
| Expression* next_result() const { |
| return next_result_; |
| } |
| |
| // result.done |
| Expression* result_done() const { |
| return result_done_; |
| } |
| |
| // each = result.value |
| Expression* assign_each() const { |
| return assign_each_; |
| } |
| |
| virtual BailoutId ContinueId() const V8_OVERRIDE { return EntryId(); } |
| virtual BailoutId StackCheckId() const V8_OVERRIDE { return BackEdgeId(); } |
| |
| BailoutId BackEdgeId() const { return back_edge_id_; } |
| |
| protected: |
| ForOfStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : ForEachStatement(zone, labels, pos), |
| assign_iterator_(NULL), |
| next_result_(NULL), |
| result_done_(NULL), |
| assign_each_(NULL), |
| back_edge_id_(GetNextId(zone)) { |
| } |
| |
| Expression* assign_iterator_; |
| Expression* next_result_; |
| Expression* result_done_; |
| Expression* assign_each_; |
| const BailoutId back_edge_id_; |
| }; |
| |
| |
| class ExpressionStatement V8_FINAL : public Statement { |
| public: |
| DECLARE_NODE_TYPE(ExpressionStatement) |
| |
| void set_expression(Expression* e) { expression_ = e; } |
| Expression* expression() const { return expression_; } |
| virtual bool IsJump() const V8_OVERRIDE { return expression_->IsThrow(); } |
| |
| protected: |
| ExpressionStatement(Zone* zone, Expression* expression, int pos) |
| : Statement(zone, pos), expression_(expression) { } |
| |
| private: |
| Expression* expression_; |
| }; |
| |
| |
| class JumpStatement : public Statement { |
| public: |
| virtual bool IsJump() const V8_FINAL V8_OVERRIDE { return true; } |
| |
| protected: |
| explicit JumpStatement(Zone* zone, int pos) : Statement(zone, pos) {} |
| }; |
| |
| |
| class ContinueStatement V8_FINAL : public JumpStatement { |
| public: |
| DECLARE_NODE_TYPE(ContinueStatement) |
| |
| IterationStatement* target() const { return target_; } |
| |
| protected: |
| explicit ContinueStatement(Zone* zone, IterationStatement* target, int pos) |
| : JumpStatement(zone, pos), target_(target) { } |
| |
| private: |
| IterationStatement* target_; |
| }; |
| |
| |
| class BreakStatement V8_FINAL : public JumpStatement { |
| public: |
| DECLARE_NODE_TYPE(BreakStatement) |
| |
| BreakableStatement* target() const { return target_; } |
| |
| protected: |
| explicit BreakStatement(Zone* zone, BreakableStatement* target, int pos) |
| : JumpStatement(zone, pos), target_(target) { } |
| |
| private: |
| BreakableStatement* target_; |
| }; |
| |
| |
| class ReturnStatement V8_FINAL : public JumpStatement { |
| public: |
| DECLARE_NODE_TYPE(ReturnStatement) |
| |
| Expression* expression() const { return expression_; } |
| |
| protected: |
| explicit ReturnStatement(Zone* zone, Expression* expression, int pos) |
| : JumpStatement(zone, pos), expression_(expression) { } |
| |
| private: |
| Expression* expression_; |
| }; |
| |
| |
| class WithStatement V8_FINAL : public Statement { |
| public: |
| DECLARE_NODE_TYPE(WithStatement) |
| |
| Scope* scope() { return scope_; } |
| Expression* expression() const { return expression_; } |
| Statement* statement() const { return statement_; } |
| |
| protected: |
| WithStatement( |
| Zone* zone, Scope* scope, |
| Expression* expression, Statement* statement, int pos) |
| : Statement(zone, pos), |
| scope_(scope), |
| expression_(expression), |
| statement_(statement) { } |
| |
| private: |
| Scope* scope_; |
| Expression* expression_; |
| Statement* statement_; |
| }; |
| |
| |
| class CaseClause V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(CaseClause) |
| |
| bool is_default() const { return label_ == NULL; } |
| Expression* label() const { |
| CHECK(!is_default()); |
| return label_; |
| } |
| Label* body_target() { return &body_target_; } |
| ZoneList<Statement*>* statements() const { return statements_; } |
| |
| BailoutId EntryId() const { return entry_id_; } |
| |
| // Type feedback information. |
| TypeFeedbackId CompareId() { return compare_id_; } |
| Type* compare_type() { return compare_type_; } |
| void set_compare_type(Type* type) { compare_type_ = type; } |
| |
| private: |
| CaseClause(Zone* zone, |
| Expression* label, |
| ZoneList<Statement*>* statements, |
| int pos); |
| |
| Expression* label_; |
| Label body_target_; |
| ZoneList<Statement*>* statements_; |
| Type* compare_type_; |
| |
| const TypeFeedbackId compare_id_; |
| const BailoutId entry_id_; |
| }; |
| |
| |
| class SwitchStatement V8_FINAL : public BreakableStatement { |
| public: |
| DECLARE_NODE_TYPE(SwitchStatement) |
| |
| void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) { |
| tag_ = tag; |
| cases_ = cases; |
| } |
| |
| Expression* tag() const { return tag_; } |
| ZoneList<CaseClause*>* cases() const { return cases_; } |
| |
| protected: |
| SwitchStatement(Zone* zone, ZoneStringList* labels, int pos) |
| : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos), |
| tag_(NULL), |
| cases_(NULL) { } |
| |
| private: |
| Expression* tag_; |
| ZoneList<CaseClause*>* cases_; |
| }; |
| |
| |
| // If-statements always have non-null references to their then- and |
| // else-parts. When parsing if-statements with no explicit else-part, |
| // the parser implicitly creates an empty statement. Use the |
| // HasThenStatement() and HasElseStatement() functions to check if a |
| // given if-statement has a then- or an else-part containing code. |
| class IfStatement V8_FINAL : public Statement { |
| public: |
| DECLARE_NODE_TYPE(IfStatement) |
| |
| bool HasThenStatement() const { return !then_statement()->IsEmpty(); } |
| bool HasElseStatement() const { return !else_statement()->IsEmpty(); } |
| |
| Expression* condition() const { return condition_; } |
| Statement* then_statement() const { return then_statement_; } |
| Statement* else_statement() const { return else_statement_; } |
| |
| virtual bool IsJump() const V8_OVERRIDE { |
| return HasThenStatement() && then_statement()->IsJump() |
| && HasElseStatement() && else_statement()->IsJump(); |
| } |
| |
| BailoutId IfId() const { return if_id_; } |
| BailoutId ThenId() const { return then_id_; } |
| BailoutId ElseId() const { return else_id_; } |
| |
| protected: |
| IfStatement(Zone* zone, |
| Expression* condition, |
| Statement* then_statement, |
| Statement* else_statement, |
| int pos) |
| : Statement(zone, pos), |
| condition_(condition), |
| then_statement_(then_statement), |
| else_statement_(else_statement), |
| if_id_(GetNextId(zone)), |
| then_id_(GetNextId(zone)), |
| else_id_(GetNextId(zone)) { |
| } |
| |
| private: |
| Expression* condition_; |
| Statement* then_statement_; |
| Statement* else_statement_; |
| const BailoutId if_id_; |
| const BailoutId then_id_; |
| const BailoutId else_id_; |
| }; |
| |
| |
| // NOTE: TargetCollectors are represented as nodes to fit in the target |
| // stack in the compiler; this should probably be reworked. |
| class TargetCollector V8_FINAL : public AstNode { |
| public: |
| explicit TargetCollector(Zone* zone) |
| : AstNode(RelocInfo::kNoPosition), targets_(0, zone) { } |
| |
| // Adds a jump target to the collector. The collector stores a pointer not |
| // a copy of the target to make binding work, so make sure not to pass in |
| // references to something on the stack. |
| void AddTarget(Label* target, Zone* zone); |
| |
| // Virtual behaviour. TargetCollectors are never part of the AST. |
| virtual void Accept(AstVisitor* v) V8_OVERRIDE { UNREACHABLE(); } |
| virtual NodeType node_type() const V8_OVERRIDE { return kInvalid; } |
| virtual TargetCollector* AsTargetCollector() V8_OVERRIDE { return this; } |
| |
| ZoneList<Label*>* targets() { return &targets_; } |
| |
| private: |
| ZoneList<Label*> targets_; |
| }; |
| |
| |
| class TryStatement : public Statement { |
| public: |
| void set_escaping_targets(ZoneList<Label*>* targets) { |
| escaping_targets_ = targets; |
| } |
| |
| int index() const { return index_; } |
| Block* try_block() const { return try_block_; } |
| ZoneList<Label*>* escaping_targets() const { return escaping_targets_; } |
| |
| protected: |
| TryStatement(Zone* zone, int index, Block* try_block, int pos) |
| : Statement(zone, pos), |
| index_(index), |
| try_block_(try_block), |
| escaping_targets_(NULL) { } |
| |
| private: |
| // Unique (per-function) index of this handler. This is not an AST ID. |
| int index_; |
| |
| Block* try_block_; |
| ZoneList<Label*>* escaping_targets_; |
| }; |
| |
| |
| class TryCatchStatement V8_FINAL : public TryStatement { |
| public: |
| DECLARE_NODE_TYPE(TryCatchStatement) |
| |
| Scope* scope() { return scope_; } |
| Variable* variable() { return variable_; } |
| Block* catch_block() const { return catch_block_; } |
| |
| protected: |
| TryCatchStatement(Zone* zone, |
| int index, |
| Block* try_block, |
| Scope* scope, |
| Variable* variable, |
| Block* catch_block, |
| int pos) |
| : TryStatement(zone, index, try_block, pos), |
| scope_(scope), |
| variable_(variable), |
| catch_block_(catch_block) { |
| } |
| |
| private: |
| Scope* scope_; |
| Variable* variable_; |
| Block* catch_block_; |
| }; |
| |
| |
| class TryFinallyStatement V8_FINAL : public TryStatement { |
| public: |
| DECLARE_NODE_TYPE(TryFinallyStatement) |
| |
| Block* finally_block() const { return finally_block_; } |
| |
| protected: |
| TryFinallyStatement( |
| Zone* zone, int index, Block* try_block, Block* finally_block, int pos) |
| : TryStatement(zone, index, try_block, pos), |
| finally_block_(finally_block) { } |
| |
| private: |
| Block* finally_block_; |
| }; |
| |
| |
| class DebuggerStatement V8_FINAL : public Statement { |
| public: |
| DECLARE_NODE_TYPE(DebuggerStatement) |
| |
| protected: |
| explicit DebuggerStatement(Zone* zone, int pos): Statement(zone, pos) {} |
| }; |
| |
| |
| class EmptyStatement V8_FINAL : public Statement { |
| public: |
| DECLARE_NODE_TYPE(EmptyStatement) |
| |
| protected: |
| explicit EmptyStatement(Zone* zone, int pos): Statement(zone, pos) {} |
| }; |
| |
| |
| class Literal V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(Literal) |
| |
| virtual bool IsPropertyName() const V8_OVERRIDE { |
| if (value_->IsInternalizedString()) { |
| uint32_t ignored; |
| return !String::cast(*value_)->AsArrayIndex(&ignored); |
| } |
| return false; |
| } |
| |
| Handle<String> AsPropertyName() { |
| ASSERT(IsPropertyName()); |
| return Handle<String>::cast(value_); |
| } |
| |
| virtual bool ToBooleanIsTrue() const V8_OVERRIDE { |
| return value_->BooleanValue(); |
| } |
| virtual bool ToBooleanIsFalse() const V8_OVERRIDE { |
| return !value_->BooleanValue(); |
| } |
| |
| // Identity testers. |
| bool IsNull() const { |
| ASSERT(!value_.is_null()); |
| return value_->IsNull(); |
| } |
| bool IsTrue() const { |
| ASSERT(!value_.is_null()); |
| return value_->IsTrue(); |
| } |
| bool IsFalse() const { |
| ASSERT(!value_.is_null()); |
| return value_->IsFalse(); |
| } |
| |
| Handle<Object> value() const { return value_; } |
| |
| // Support for using Literal as a HashMap key. NOTE: Currently, this works |
| // only for string and number literals! |
| uint32_t Hash() { return ToString()->Hash(); } |
| |
| static bool Match(void* literal1, void* literal2) { |
| Handle<String> s1 = static_cast<Literal*>(literal1)->ToString(); |
| Handle<String> s2 = static_cast<Literal*>(literal2)->ToString(); |
| return s1->Equals(*s2); |
| } |
| |
| TypeFeedbackId LiteralFeedbackId() const { return reuse(id()); } |
| |
| protected: |
| Literal(Zone* zone, Handle<Object> value, int position) |
| : Expression(zone, position), |
| value_(value), |
| isolate_(zone->isolate()) { } |
| |
| private: |
| Handle<String> ToString(); |
| |
| Handle<Object> value_; |
| // TODO(dcarney): remove. this is only needed for Match and Hash. |
| Isolate* isolate_; |
| }; |
| |
| |
| // Base class for literals that needs space in the corresponding JSFunction. |
| class MaterializedLiteral : public Expression { |
| public: |
| virtual MaterializedLiteral* AsMaterializedLiteral() { return this; } |
| |
| int literal_index() { return literal_index_; } |
| |
| int depth() const { |
| // only callable after initialization. |
| ASSERT(depth_ >= 1); |
| return depth_; |
| } |
| |
| protected: |
| MaterializedLiteral(Zone* zone, |
| int literal_index, |
| int pos) |
| : Expression(zone, pos), |
| literal_index_(literal_index), |
| is_simple_(false), |
| depth_(0) {} |
| |
| // A materialized literal is simple if the values consist of only |
| // constants and simple object and array literals. |
| bool is_simple() const { return is_simple_; } |
| void set_is_simple(bool is_simple) { is_simple_ = is_simple; } |
| friend class CompileTimeValue; |
| |
| void set_depth(int depth) { |
| ASSERT(depth >= 1); |
| depth_ = depth; |
| } |
| |
| // Populate the constant properties/elements fixed array. |
| void BuildConstants(Isolate* isolate); |
| friend class ArrayLiteral; |
| friend class ObjectLiteral; |
| |
| // If the expression is a literal, return the literal value; |
| // if the expression is a materialized literal and is simple return a |
| // compile time value as encoded by CompileTimeValue::GetValue(). |
| // Otherwise, return undefined literal as the placeholder |
| // in the object literal boilerplate. |
| Handle<Object> GetBoilerplateValue(Expression* expression, Isolate* isolate); |
| |
| private: |
| int literal_index_; |
| bool is_simple_; |
| int depth_; |
| }; |
| |
| |
| // Property is used for passing information |
| // about an object literal's properties from the parser |
| // to the code generator. |
| class ObjectLiteralProperty V8_FINAL : public ZoneObject { |
| public: |
| enum Kind { |
| CONSTANT, // Property with constant value (compile time). |
| COMPUTED, // Property with computed value (execution time). |
| MATERIALIZED_LITERAL, // Property value is a materialized literal. |
| GETTER, SETTER, // Property is an accessor function. |
| PROTOTYPE // Property is __proto__. |
| }; |
| |
| ObjectLiteralProperty(Zone* zone, Literal* key, Expression* value); |
| |
| Literal* key() { return key_; } |
| Expression* value() { return value_; } |
| Kind kind() { return kind_; } |
| |
| // Type feedback information. |
| void RecordTypeFeedback(TypeFeedbackOracle* oracle); |
| bool IsMonomorphic() { return !receiver_type_.is_null(); } |
| Handle<Map> GetReceiverType() { return receiver_type_; } |
| |
| bool IsCompileTimeValue(); |
| |
| void set_emit_store(bool emit_store); |
| bool emit_store(); |
| |
| protected: |
| template<class> friend class AstNodeFactory; |
| |
| ObjectLiteralProperty(Zone* zone, bool is_getter, FunctionLiteral* value); |
| void set_key(Literal* key) { key_ = key; } |
| |
| private: |
| Literal* key_; |
| Expression* value_; |
| Kind kind_; |
| bool emit_store_; |
| Handle<Map> receiver_type_; |
| }; |
| |
| |
| // An object literal has a boilerplate object that is used |
| // for minimizing the work when constructing it at runtime. |
| class ObjectLiteral V8_FINAL : public MaterializedLiteral { |
| public: |
| typedef ObjectLiteralProperty Property; |
| |
| DECLARE_NODE_TYPE(ObjectLiteral) |
| |
| Handle<FixedArray> constant_properties() const { |
| return constant_properties_; |
| } |
| ZoneList<Property*>* properties() const { return properties_; } |
| bool fast_elements() const { return fast_elements_; } |
| bool may_store_doubles() const { return may_store_doubles_; } |
| bool has_function() const { return has_function_; } |
| |
| // Decide if a property should be in the object boilerplate. |
| static bool IsBoilerplateProperty(Property* property); |
| |
| // Populate the constant properties fixed array. |
| void BuildConstantProperties(Isolate* isolate); |
| |
| // Mark all computed expressions that are bound to a key that |
| // is shadowed by a later occurrence of the same key. For the |
| // marked expressions, no store code is emitted. |
| void CalculateEmitStore(Zone* zone); |
| |
| enum Flags { |
| kNoFlags = 0, |
| kFastElements = 1, |
| kHasFunction = 1 << 1 |
| }; |
| |
| struct Accessors: public ZoneObject { |
| Accessors() : getter(NULL), setter(NULL) { } |
| Expression* getter; |
| Expression* setter; |
| }; |
| |
| protected: |
| ObjectLiteral(Zone* zone, |
| ZoneList<Property*>* properties, |
| int literal_index, |
| int boilerplate_properties, |
| bool has_function, |
| int pos) |
| : MaterializedLiteral(zone, literal_index, pos), |
| properties_(properties), |
| boilerplate_properties_(boilerplate_properties), |
| fast_elements_(false), |
| may_store_doubles_(false), |
| has_function_(has_function) {} |
| |
| private: |
| Handle<FixedArray> constant_properties_; |
| ZoneList<Property*>* properties_; |
| int boilerplate_properties_; |
| bool fast_elements_; |
| bool may_store_doubles_; |
| bool has_function_; |
| }; |
| |
| |
| // Node for capturing a regexp literal. |
| class RegExpLiteral V8_FINAL : public MaterializedLiteral { |
| public: |
| DECLARE_NODE_TYPE(RegExpLiteral) |
| |
| Handle<String> pattern() const { return pattern_; } |
| Handle<String> flags() const { return flags_; } |
| |
| protected: |
| RegExpLiteral(Zone* zone, |
| Handle<String> pattern, |
| Handle<String> flags, |
| int literal_index, |
| int pos) |
| : MaterializedLiteral(zone, literal_index, pos), |
| pattern_(pattern), |
| flags_(flags) { |
| set_depth(1); |
| } |
| |
| private: |
| Handle<String> pattern_; |
| Handle<String> flags_; |
| }; |
| |
| |
| // An array literal has a literals object that is used |
| // for minimizing the work when constructing it at runtime. |
| class ArrayLiteral V8_FINAL : public MaterializedLiteral { |
| public: |
| DECLARE_NODE_TYPE(ArrayLiteral) |
| |
| Handle<FixedArray> constant_elements() const { return constant_elements_; } |
| ZoneList<Expression*>* values() const { return values_; } |
| |
| // Return an AST id for an element that is used in simulate instructions. |
| BailoutId GetIdForElement(int i) { |
| return BailoutId(first_element_id_.ToInt() + i); |
| } |
| |
| // Populate the constant elements fixed array. |
| void BuildConstantElements(Isolate* isolate); |
| |
| enum Flags { |
| kNoFlags = 0, |
| kShallowElements = 1, |
| kDisableMementos = 1 << 1 |
| }; |
| |
| protected: |
| ArrayLiteral(Zone* zone, |
| ZoneList<Expression*>* values, |
| int literal_index, |
| int pos) |
| : MaterializedLiteral(zone, literal_index, pos), |
| values_(values), |
| first_element_id_(ReserveIdRange(zone, values->length())) {} |
| |
| private: |
| Handle<FixedArray> constant_elements_; |
| ZoneList<Expression*>* values_; |
| const BailoutId first_element_id_; |
| }; |
| |
| |
| class VariableProxy V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(VariableProxy) |
| |
| virtual bool IsValidReferenceExpression() const V8_OVERRIDE { |
| return var_ == NULL ? true : var_->IsValidReference(); |
| } |
| |
| bool IsVariable(Handle<String> n) const { |
| return !is_this() && name().is_identical_to(n); |
| } |
| |
| bool IsArguments() const { return var_ != NULL && var_->is_arguments(); } |
| |
| bool IsLValue() const { return is_lvalue_; } |
| |
| Handle<String> name() const { return name_; } |
| Variable* var() const { return var_; } |
| bool is_this() const { return is_this_; } |
| Interface* interface() const { return interface_; } |
| |
| |
| void MarkAsTrivial() { is_trivial_ = true; } |
| void MarkAsLValue() { is_lvalue_ = true; } |
| |
| // Bind this proxy to the variable var. Interfaces must match. |
| void BindTo(Variable* var); |
| |
| protected: |
| VariableProxy(Zone* zone, Variable* var, int position); |
| |
| VariableProxy(Zone* zone, |
| Handle<String> name, |
| bool is_this, |
| Interface* interface, |
| int position); |
| |
| Handle<String> name_; |
| Variable* var_; // resolved variable, or NULL |
| bool is_this_; |
| bool is_trivial_; |
| // True if this variable proxy is being used in an assignment |
| // or with a increment/decrement operator. |
| bool is_lvalue_; |
| Interface* interface_; |
| }; |
| |
| |
| class Property V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(Property) |
| |
| virtual bool IsValidReferenceExpression() const V8_OVERRIDE { return true; } |
| |
| Expression* obj() const { return obj_; } |
| Expression* key() const { return key_; } |
| |
| BailoutId LoadId() const { return load_id_; } |
| |
| bool IsStringAccess() const { return is_string_access_; } |
| bool IsFunctionPrototype() const { return is_function_prototype_; } |
| |
| // Type feedback information. |
| virtual bool IsMonomorphic() V8_OVERRIDE { |
| return receiver_types_.length() == 1; |
| } |
| virtual SmallMapList* GetReceiverTypes() V8_OVERRIDE { |
| return &receiver_types_; |
| } |
| virtual KeyedAccessStoreMode GetStoreMode() V8_OVERRIDE { |
| return STANDARD_STORE; |
| } |
| bool IsUninitialized() { return !is_for_call_ && is_uninitialized_; } |
| bool HasNoTypeInformation() { |
| return is_uninitialized_; |
| } |
| void set_is_uninitialized(bool b) { is_uninitialized_ = b; } |
| void set_is_string_access(bool b) { is_string_access_ = b; } |
| void set_is_function_prototype(bool b) { is_function_prototype_ = b; } |
| void mark_for_call() { is_for_call_ = true; } |
| bool IsForCall() { return is_for_call_; } |
| |
| TypeFeedbackId PropertyFeedbackId() { return reuse(id()); } |
| |
| protected: |
| Property(Zone* zone, |
| Expression* obj, |
| Expression* key, |
| int pos) |
| : Expression(zone, pos), |
| obj_(obj), |
| key_(key), |
| load_id_(GetNextId(zone)), |
| is_for_call_(false), |
| is_uninitialized_(false), |
| is_string_access_(false), |
| is_function_prototype_(false) { } |
| |
| private: |
| Expression* obj_; |
| Expression* key_; |
| const BailoutId load_id_; |
| |
| SmallMapList receiver_types_; |
| bool is_for_call_ : 1; |
| bool is_uninitialized_ : 1; |
| bool is_string_access_ : 1; |
| bool is_function_prototype_ : 1; |
| }; |
| |
| |
| class Call V8_FINAL : public Expression, public FeedbackSlotInterface { |
| public: |
| DECLARE_NODE_TYPE(Call) |
| |
| Expression* expression() const { return expression_; } |
| ZoneList<Expression*>* arguments() const { return arguments_; } |
| |
| // Type feedback information. |
| virtual ComputablePhase GetComputablePhase() { return AFTER_SCOPING; } |
| virtual int ComputeFeedbackSlotCount(Isolate* isolate); |
| virtual void SetFirstFeedbackSlot(int slot) { |
| call_feedback_slot_ = slot; |
| } |
| |
| bool HasCallFeedbackSlot() const { |
| return call_feedback_slot_ != kInvalidFeedbackSlot; |
| } |
| int CallFeedbackSlot() const { return call_feedback_slot_; } |
| |
| virtual SmallMapList* GetReceiverTypes() V8_OVERRIDE { |
| if (expression()->IsProperty()) { |
| return expression()->AsProperty()->GetReceiverTypes(); |
| } |
| return NULL; |
| } |
| |
| virtual bool IsMonomorphic() V8_OVERRIDE { |
| if (expression()->IsProperty()) { |
| return expression()->AsProperty()->IsMonomorphic(); |
| } |
| return !target_.is_null(); |
| } |
| |
| Handle<JSFunction> target() { return target_; } |
| |
| Handle<Cell> cell() { return cell_; } |
| |
| void set_target(Handle<JSFunction> target) { target_ = target; } |
| bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupResult* lookup); |
| |
| BailoutId ReturnId() const { return return_id_; } |
| |
| enum CallType { |
| POSSIBLY_EVAL_CALL, |
| GLOBAL_CALL, |
| LOOKUP_SLOT_CALL, |
| PROPERTY_CALL, |
| OTHER_CALL |
| }; |
| |
| // Helpers to determine how to handle the call. |
| CallType GetCallType(Isolate* isolate) const; |
| |
| #ifdef DEBUG |
| // Used to assert that the FullCodeGenerator records the return site. |
| bool return_is_recorded_; |
| #endif |
| |
| protected: |
| Call(Zone* zone, |
| Expression* expression, |
| ZoneList<Expression*>* arguments, |
| int pos) |
| : Expression(zone, pos), |
| expression_(expression), |
| arguments_(arguments), |
| call_feedback_slot_(kInvalidFeedbackSlot), |
| return_id_(GetNextId(zone)) { |
| if (expression->IsProperty()) { |
| expression->AsProperty()->mark_for_call(); |
| } |
| } |
| |
| private: |
| Expression* expression_; |
| ZoneList<Expression*>* arguments_; |
| |
| Handle<JSFunction> target_; |
| Handle<Cell> cell_; |
| int call_feedback_slot_; |
| |
| const BailoutId return_id_; |
| }; |
| |
| |
| class CallNew V8_FINAL : public Expression, public FeedbackSlotInterface { |
| public: |
| DECLARE_NODE_TYPE(CallNew) |
| |
| Expression* expression() const { return expression_; } |
| ZoneList<Expression*>* arguments() const { return arguments_; } |
| |
| // Type feedback information. |
| virtual ComputablePhase GetComputablePhase() { return DURING_PARSE; } |
| virtual int ComputeFeedbackSlotCount(Isolate* isolate) { |
| return FLAG_pretenuring_call_new ? 2 : 1; |
| } |
| virtual void SetFirstFeedbackSlot(int slot) { |
| callnew_feedback_slot_ = slot; |
| } |
| |
| int CallNewFeedbackSlot() { |
| ASSERT(callnew_feedback_slot_ != kInvalidFeedbackSlot); |
| return callnew_feedback_slot_; |
| } |
| int AllocationSiteFeedbackSlot() { |
| ASSERT(callnew_feedback_slot_ != kInvalidFeedbackSlot); |
| ASSERT(FLAG_pretenuring_call_new); |
| return callnew_feedback_slot_ + 1; |
| } |
| |
| void RecordTypeFeedback(TypeFeedbackOracle* oracle); |
| virtual bool IsMonomorphic() V8_OVERRIDE { return is_monomorphic_; } |
| Handle<JSFunction> target() const { return target_; } |
| ElementsKind elements_kind() const { return elements_kind_; } |
| Handle<AllocationSite> allocation_site() const { |
| return allocation_site_; |
| } |
| |
| static int feedback_slots() { return 1; } |
| |
| BailoutId ReturnId() const { return return_id_; } |
| |
| protected: |
| CallNew(Zone* zone, |
| Expression* expression, |
| ZoneList<Expression*>* arguments, |
| int pos) |
| : Expression(zone, pos), |
| expression_(expression), |
| arguments_(arguments), |
| is_monomorphic_(false), |
| elements_kind_(GetInitialFastElementsKind()), |
| callnew_feedback_slot_(kInvalidFeedbackSlot), |
| return_id_(GetNextId(zone)) { } |
| |
| private: |
| Expression* expression_; |
| ZoneList<Expression*>* arguments_; |
| |
| bool is_monomorphic_; |
| Handle<JSFunction> target_; |
| ElementsKind elements_kind_; |
| Handle<AllocationSite> allocation_site_; |
| int callnew_feedback_slot_; |
| |
| const BailoutId return_id_; |
| }; |
| |
| |
| // The CallRuntime class does not represent any official JavaScript |
| // language construct. Instead it is used to call a C or JS function |
| // with a set of arguments. This is used from the builtins that are |
| // implemented in JavaScript (see "v8natives.js"). |
| class CallRuntime V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(CallRuntime) |
| |
| Handle<String> name() const { return name_; } |
| const Runtime::Function* function() const { return function_; } |
| ZoneList<Expression*>* arguments() const { return arguments_; } |
| bool is_jsruntime() const { return function_ == NULL; } |
| |
| TypeFeedbackId CallRuntimeFeedbackId() const { return reuse(id()); } |
| |
| protected: |
| CallRuntime(Zone* zone, |
| Handle<String> name, |
| const Runtime::Function* function, |
| ZoneList<Expression*>* arguments, |
| int pos) |
| : Expression(zone, pos), |
| name_(name), |
| function_(function), |
| arguments_(arguments) { } |
| |
| private: |
| Handle<String> name_; |
| const Runtime::Function* function_; |
| ZoneList<Expression*>* arguments_; |
| }; |
| |
| |
| class UnaryOperation V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(UnaryOperation) |
| |
| Token::Value op() const { return op_; } |
| Expression* expression() const { return expression_; } |
| |
| BailoutId MaterializeTrueId() { return materialize_true_id_; } |
| BailoutId MaterializeFalseId() { return materialize_false_id_; } |
| |
| virtual void RecordToBooleanTypeFeedback( |
| TypeFeedbackOracle* oracle) V8_OVERRIDE; |
| |
| protected: |
| UnaryOperation(Zone* zone, |
| Token::Value op, |
| Expression* expression, |
| int pos) |
| : Expression(zone, pos), |
| op_(op), |
| expression_(expression), |
| materialize_true_id_(GetNextId(zone)), |
| materialize_false_id_(GetNextId(zone)) { |
| ASSERT(Token::IsUnaryOp(op)); |
| } |
| |
| private: |
| Token::Value op_; |
| Expression* expression_; |
| |
| // For unary not (Token::NOT), the AST ids where true and false will |
| // actually be materialized, respectively. |
| const BailoutId materialize_true_id_; |
| const BailoutId materialize_false_id_; |
| }; |
| |
| |
| class BinaryOperation V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(BinaryOperation) |
| |
| virtual bool ResultOverwriteAllowed() const V8_OVERRIDE; |
| |
| Token::Value op() const { return op_; } |
| Expression* left() const { return left_; } |
| Expression* right() const { return right_; } |
| Handle<AllocationSite> allocation_site() const { return allocation_site_; } |
| void set_allocation_site(Handle<AllocationSite> allocation_site) { |
| allocation_site_ = allocation_site; |
| } |
| |
| BailoutId RightId() const { return right_id_; } |
| |
| TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); } |
| Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } |
| void set_fixed_right_arg(Maybe<int> arg) { fixed_right_arg_ = arg; } |
| |
| virtual void RecordToBooleanTypeFeedback( |
| TypeFeedbackOracle* oracle) V8_OVERRIDE; |
| |
| protected: |
| BinaryOperation(Zone* zone, |
| Token::Value op, |
| Expression* left, |
| Expression* right, |
| int pos) |
| : Expression(zone, pos), |
| op_(op), |
| left_(left), |
| right_(right), |
| right_id_(GetNextId(zone)) { |
| ASSERT(Token::IsBinaryOp(op)); |
| } |
| |
| private: |
| Token::Value op_; |
| Expression* left_; |
| Expression* right_; |
| Handle<AllocationSite> allocation_site_; |
| |
| // TODO(rossberg): the fixed arg should probably be represented as a Constant |
| // type for the RHS. |
| Maybe<int> fixed_right_arg_; |
| |
| // The short-circuit logical operations need an AST ID for their |
| // right-hand subexpression. |
| const BailoutId right_id_; |
| }; |
| |
| |
| class CountOperation V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(CountOperation) |
| |
| bool is_prefix() const { return is_prefix_; } |
| bool is_postfix() const { return !is_prefix_; } |
| |
| Token::Value op() const { return op_; } |
| Token::Value binary_op() { |
| return (op() == Token::INC) ? Token::ADD : Token::SUB; |
| } |
| |
| Expression* expression() const { return expression_; } |
| |
| virtual bool IsMonomorphic() V8_OVERRIDE { |
| return receiver_types_.length() == 1; |
| } |
| virtual SmallMapList* GetReceiverTypes() V8_OVERRIDE { |
| return &receiver_types_; |
| } |
| virtual KeyedAccessStoreMode GetStoreMode() V8_OVERRIDE { |
| return store_mode_; |
| } |
| Type* type() const { return type_; } |
| void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; } |
| void set_type(Type* type) { type_ = type; } |
| |
| BailoutId AssignmentId() const { return assignment_id_; } |
| |
| TypeFeedbackId CountBinOpFeedbackId() const { return count_id_; } |
| TypeFeedbackId CountStoreFeedbackId() const { return reuse(id()); } |
| |
| protected: |
| CountOperation(Zone* zone, |
| Token::Value op, |
| bool is_prefix, |
| Expression* expr, |
| int pos) |
| : Expression(zone, pos), |
| op_(op), |
| is_prefix_(is_prefix), |
| store_mode_(STANDARD_STORE), |
| expression_(expr), |
| assignment_id_(GetNextId(zone)), |
| count_id_(GetNextId(zone)) {} |
| |
| private: |
| Token::Value op_; |
| bool is_prefix_ : 1; |
| KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed, |
| // must have extra bit. |
| Type* type_; |
| |
| Expression* expression_; |
| const BailoutId assignment_id_; |
| const TypeFeedbackId count_id_; |
| SmallMapList receiver_types_; |
| }; |
| |
| |
| class CompareOperation V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(CompareOperation) |
| |
| Token::Value op() const { return op_; } |
| Expression* left() const { return left_; } |
| Expression* right() const { return right_; } |
| |
| // Type feedback information. |
| TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); } |
| Type* combined_type() const { return combined_type_; } |
| void set_combined_type(Type* type) { combined_type_ = type; } |
| |
| // Match special cases. |
| bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check); |
| bool IsLiteralCompareUndefined(Expression** expr, Isolate* isolate); |
| bool IsLiteralCompareNull(Expression** expr); |
| |
| protected: |
| CompareOperation(Zone* zone, |
| Token::Value op, |
| Expression* left, |
| Expression* right, |
| int pos) |
| : Expression(zone, pos), |
| op_(op), |
| left_(left), |
| right_(right), |
| combined_type_(Type::None(zone)) { |
| ASSERT(Token::IsCompareOp(op)); |
| } |
| |
| private: |
| Token::Value op_; |
| Expression* left_; |
| Expression* right_; |
| |
| Type* combined_type_; |
| }; |
| |
| |
| class Conditional V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(Conditional) |
| |
| Expression* condition() const { return condition_; } |
| Expression* then_expression() const { return then_expression_; } |
| Expression* else_expression() const { return else_expression_; } |
| |
| BailoutId ThenId() const { return then_id_; } |
| BailoutId ElseId() const { return else_id_; } |
| |
| protected: |
| Conditional(Zone* zone, |
| Expression* condition, |
| Expression* then_expression, |
| Expression* else_expression, |
| int position) |
| : Expression(zone, position), |
| condition_(condition), |
| then_expression_(then_expression), |
| else_expression_(else_expression), |
| then_id_(GetNextId(zone)), |
| else_id_(GetNextId(zone)) { } |
| |
| private: |
| Expression* condition_; |
| Expression* then_expression_; |
| Expression* else_expression_; |
| const BailoutId then_id_; |
| const BailoutId else_id_; |
| }; |
| |
| |
| class Assignment V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(Assignment) |
| |
| Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; } |
| |
| Token::Value binary_op() const; |
| |
| Token::Value op() const { return op_; } |
| Expression* target() const { return target_; } |
| Expression* value() const { return value_; } |
| BinaryOperation* binary_operation() const { return binary_operation_; } |
| |
| // This check relies on the definition order of token in token.h. |
| bool is_compound() const { return op() > Token::ASSIGN; } |
| |
| BailoutId AssignmentId() const { return assignment_id_; } |
| |
| // Type feedback information. |
| TypeFeedbackId AssignmentFeedbackId() { return reuse(id()); } |
| virtual bool IsMonomorphic() V8_OVERRIDE { |
| return receiver_types_.length() == 1; |
| } |
| bool IsUninitialized() { return is_uninitialized_; } |
| bool HasNoTypeInformation() { |
| return is_uninitialized_; |
| } |
| virtual SmallMapList* GetReceiverTypes() V8_OVERRIDE { |
| return &receiver_types_; |
| } |
| virtual KeyedAccessStoreMode GetStoreMode() V8_OVERRIDE { |
| return store_mode_; |
| } |
| void set_is_uninitialized(bool b) { is_uninitialized_ = b; } |
| void set_store_mode(KeyedAccessStoreMode mode) { store_mode_ = mode; } |
| |
| protected: |
| Assignment(Zone* zone, |
| Token::Value op, |
| Expression* target, |
| Expression* value, |
| int pos); |
| |
| template<class Visitor> |
| void Init(Zone* zone, AstNodeFactory<Visitor>* factory) { |
| ASSERT(Token::IsAssignmentOp(op_)); |
| if (is_compound()) { |
| binary_operation_ = factory->NewBinaryOperation( |
| binary_op(), target_, value_, position() + 1); |
| } |
| } |
| |
| private: |
| Token::Value op_; |
| Expression* target_; |
| Expression* value_; |
| BinaryOperation* binary_operation_; |
| const BailoutId assignment_id_; |
| |
| bool is_uninitialized_ : 1; |
| KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed, |
| // must have extra bit. |
| SmallMapList receiver_types_; |
| }; |
| |
| |
| class Yield V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(Yield) |
| |
| enum Kind { |
| INITIAL, // The initial yield that returns the unboxed generator object. |
| SUSPEND, // A normal yield: { value: EXPRESSION, done: false } |
| DELEGATING, // A yield*. |
| FINAL // A return: { value: EXPRESSION, done: true } |
| }; |
| |
| Expression* generator_object() const { return generator_object_; } |
| Expression* expression() const { return expression_; } |
| Kind yield_kind() const { return yield_kind_; } |
| |
| // Delegating yield surrounds the "yield" in a "try/catch". This index |
| // locates the catch handler in the handler table, and is equivalent to |
| // TryCatchStatement::index(). |
| int index() const { |
| ASSERT(yield_kind() == DELEGATING); |
| return index_; |
| } |
| void set_index(int index) { |
| ASSERT(yield_kind() == DELEGATING); |
| index_ = index; |
| } |
| |
| protected: |
| Yield(Zone* zone, |
| Expression* generator_object, |
| Expression* expression, |
| Kind yield_kind, |
| int pos) |
| : Expression(zone, pos), |
| generator_object_(generator_object), |
| expression_(expression), |
| yield_kind_(yield_kind), |
| index_(-1) { } |
| |
| private: |
| Expression* generator_object_; |
| Expression* expression_; |
| Kind yield_kind_; |
| int index_; |
| }; |
| |
| |
| class Throw V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(Throw) |
| |
| Expression* exception() const { return exception_; } |
| |
| protected: |
| Throw(Zone* zone, Expression* exception, int pos) |
| : Expression(zone, pos), exception_(exception) {} |
| |
| private: |
| Expression* exception_; |
| }; |
| |
| |
| class FunctionLiteral V8_FINAL : public Expression { |
| public: |
| enum FunctionType { |
| ANONYMOUS_EXPRESSION, |
| NAMED_EXPRESSION, |
| DECLARATION |
| }; |
| |
| enum ParameterFlag { |
| kNoDuplicateParameters = 0, |
| kHasDuplicateParameters = 1 |
| }; |
| |
| enum IsFunctionFlag { |
| kGlobalOrEval, |
| kIsFunction |
| }; |
| |
| enum IsParenthesizedFlag { |
| kIsParenthesized, |
| kNotParenthesized |
| }; |
| |
| enum IsGeneratorFlag { |
| kIsGenerator, |
| kNotGenerator |
| }; |
| |
| DECLARE_NODE_TYPE(FunctionLiteral) |
| |
| Handle<String> name() const { return name_; } |
| Scope* scope() const { return scope_; } |
| ZoneList<Statement*>* body() const { return body_; } |
| void set_function_token_position(int pos) { function_token_position_ = pos; } |
| int function_token_position() const { return function_token_position_; } |
| int start_position() const; |
| int end_position() const; |
| int SourceSize() const { return end_position() - start_position(); } |
| bool is_expression() const { return IsExpression::decode(bitfield_); } |
| bool is_anonymous() const { return IsAnonymous::decode(bitfield_); } |
| StrictMode strict_mode() const; |
| |
| int materialized_literal_count() { return materialized_literal_count_; } |
| int expected_property_count() { return expected_property_count_; } |
| int handler_count() { return handler_count_; } |
| int parameter_count() { return parameter_count_; } |
| |
| bool AllowsLazyCompilation(); |
| bool AllowsLazyCompilationWithoutContext(); |
| |
| void InitializeSharedInfo(Handle<Code> code); |
| |
| Handle<String> debug_name() const { |
| if (name_->length() > 0) return name_; |
| return inferred_name(); |
| } |
| |
| Handle<String> inferred_name() const { return inferred_name_; } |
| void set_inferred_name(Handle<String> inferred_name) { |
| inferred_name_ = inferred_name; |
| } |
| |
| // shared_info may be null if it's not cached in full code. |
| Handle<SharedFunctionInfo> shared_info() { return shared_info_; } |
| |
| bool pretenure() { return Pretenure::decode(bitfield_); } |
| void set_pretenure() { bitfield_ |= Pretenure::encode(true); } |
| |
| bool has_duplicate_parameters() { |
| return HasDuplicateParameters::decode(bitfield_); |
| } |
| |
| bool is_function() { return IsFunction::decode(bitfield_) == kIsFunction; } |
| |
| // This is used as a heuristic on when to eagerly compile a function |
| // literal. We consider the following constructs as hints that the |
| // function will be called immediately: |
| // - (function() { ... })(); |
| // - var x = function() { ... }(); |
| bool is_parenthesized() { |
| return IsParenthesized::decode(bitfield_) == kIsParenthesized; |
| } |
| void set_parenthesized() { |
| bitfield_ = IsParenthesized::update(bitfield_, kIsParenthesized); |
| } |
| |
| bool is_generator() { |
| return IsGenerator::decode(bitfield_) == kIsGenerator; |
| } |
| |
| int ast_node_count() { return ast_properties_.node_count(); } |
| AstProperties::Flags* flags() { return ast_properties_.flags(); } |
| void set_ast_properties(AstProperties* ast_properties) { |
| ast_properties_ = *ast_properties; |
| } |
| void set_slot_processor(DeferredFeedbackSlotProcessor* slot_processor) { |
| slot_processor_ = *slot_processor; |
| } |
| void ProcessFeedbackSlots(Isolate* isolate) { |
| slot_processor_.ProcessFeedbackSlots(isolate); |
| } |
| int slot_count() { |
| return slot_processor_.slot_count(); |
| } |
| bool dont_optimize() { return dont_optimize_reason_ != kNoReason; } |
| BailoutReason dont_optimize_reason() { return dont_optimize_reason_; } |
| void set_dont_optimize_reason(BailoutReason reason) { |
| dont_optimize_reason_ = reason; |
| } |
| |
| protected: |
| FunctionLiteral(Zone* zone, |
| Handle<String> name, |
| Scope* scope, |
| ZoneList<Statement*>* body, |
| int materialized_literal_count, |
| int expected_property_count, |
| int handler_count, |
| int parameter_count, |
| FunctionType function_type, |
| ParameterFlag has_duplicate_parameters, |
| IsFunctionFlag is_function, |
| IsParenthesizedFlag is_parenthesized, |
| IsGeneratorFlag is_generator, |
| int position) |
| : Expression(zone, position), |
| name_(name), |
| scope_(scope), |
| body_(body), |
| inferred_name_(zone->isolate()->factory()->empty_string()), |
| dont_optimize_reason_(kNoReason), |
| materialized_literal_count_(materialized_literal_count), |
| expected_property_count_(expected_property_count), |
| handler_count_(handler_count), |
| parameter_count_(parameter_count), |
| function_token_position_(RelocInfo::kNoPosition) { |
| bitfield_ = |
| IsExpression::encode(function_type != DECLARATION) | |
| IsAnonymous::encode(function_type == ANONYMOUS_EXPRESSION) | |
| Pretenure::encode(false) | |
| HasDuplicateParameters::encode(has_duplicate_parameters) | |
| IsFunction::encode(is_function) | |
| IsParenthesized::encode(is_parenthesized) | |
| IsGenerator::encode(is_generator); |
| } |
| |
| private: |
| Handle<String> name_; |
| Handle<SharedFunctionInfo> shared_info_; |
| Scope* scope_; |
| ZoneList<Statement*>* body_; |
| Handle<String> inferred_name_; |
| AstProperties ast_properties_; |
| DeferredFeedbackSlotProcessor slot_processor_; |
| BailoutReason dont_optimize_reason_; |
| |
| int materialized_literal_count_; |
| int expected_property_count_; |
| int handler_count_; |
| int parameter_count_; |
| int function_token_position_; |
| |
| unsigned bitfield_; |
| class IsExpression: public BitField<bool, 0, 1> {}; |
| class IsAnonymous: public BitField<bool, 1, 1> {}; |
| class Pretenure: public BitField<bool, 2, 1> {}; |
| class HasDuplicateParameters: public BitField<ParameterFlag, 3, 1> {}; |
| class IsFunction: public BitField<IsFunctionFlag, 4, 1> {}; |
| class IsParenthesized: public BitField<IsParenthesizedFlag, 5, 1> {}; |
| class IsGenerator: public BitField<IsGeneratorFlag, 6, 1> {}; |
| }; |
| |
| |
| class NativeFunctionLiteral V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(NativeFunctionLiteral) |
| |
| Handle<String> name() const { return name_; } |
| v8::Extension* extension() const { return extension_; } |
| |
| protected: |
| NativeFunctionLiteral( |
| Zone* zone, Handle<String> name, v8::Extension* extension, int pos) |
| : Expression(zone, pos), name_(name), extension_(extension) {} |
| |
| private: |
| Handle<String> name_; |
| v8::Extension* extension_; |
| }; |
| |
| |
| class ThisFunction V8_FINAL : public Expression { |
| public: |
| DECLARE_NODE_TYPE(ThisFunction) |
| |
| protected: |
| explicit ThisFunction(Zone* zone, int pos): Expression(zone, pos) {} |
| }; |
| |
| #undef DECLARE_NODE_TYPE |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Regular expressions |
| |
| |
| class RegExpVisitor BASE_EMBEDDED { |
| public: |
| virtual ~RegExpVisitor() { } |
| #define MAKE_CASE(Name) \ |
| virtual void* Visit##Name(RegExp##Name*, void* data) = 0; |
| FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE) |
| #undef MAKE_CASE |
| }; |
| |
| |
| class RegExpTree : public ZoneObject { |
| public: |
| static const int kInfinity = kMaxInt; |
| virtual ~RegExpTree() {} |
| virtual void* Accept(RegExpVisitor* visitor, void* data) = 0; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) = 0; |
| virtual bool IsTextElement() { return false; } |
| virtual bool IsAnchoredAtStart() { return false; } |
| virtual bool IsAnchoredAtEnd() { return false; } |
| virtual int min_match() = 0; |
| virtual int max_match() = 0; |
| // Returns the interval of registers used for captures within this |
| // expression. |
| virtual Interval CaptureRegisters() { return Interval::Empty(); } |
| virtual void AppendToText(RegExpText* text, Zone* zone); |
| SmartArrayPointer<const char> ToString(Zone* zone); |
| #define MAKE_ASTYPE(Name) \ |
| virtual RegExp##Name* As##Name(); \ |
| virtual bool Is##Name(); |
| FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ASTYPE) |
| #undef MAKE_ASTYPE |
| }; |
| |
| |
| class RegExpDisjunction V8_FINAL : public RegExpTree { |
| public: |
| explicit RegExpDisjunction(ZoneList<RegExpTree*>* alternatives); |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpDisjunction* AsDisjunction() V8_OVERRIDE; |
| virtual Interval CaptureRegisters() V8_OVERRIDE; |
| virtual bool IsDisjunction() V8_OVERRIDE; |
| virtual bool IsAnchoredAtStart() V8_OVERRIDE; |
| virtual bool IsAnchoredAtEnd() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return min_match_; } |
| virtual int max_match() V8_OVERRIDE { return max_match_; } |
| ZoneList<RegExpTree*>* alternatives() { return alternatives_; } |
| private: |
| ZoneList<RegExpTree*>* alternatives_; |
| int min_match_; |
| int max_match_; |
| }; |
| |
| |
| class RegExpAlternative V8_FINAL : public RegExpTree { |
| public: |
| explicit RegExpAlternative(ZoneList<RegExpTree*>* nodes); |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpAlternative* AsAlternative() V8_OVERRIDE; |
| virtual Interval CaptureRegisters() V8_OVERRIDE; |
| virtual bool IsAlternative() V8_OVERRIDE; |
| virtual bool IsAnchoredAtStart() V8_OVERRIDE; |
| virtual bool IsAnchoredAtEnd() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return min_match_; } |
| virtual int max_match() V8_OVERRIDE { return max_match_; } |
| ZoneList<RegExpTree*>* nodes() { return nodes_; } |
| private: |
| ZoneList<RegExpTree*>* nodes_; |
| int min_match_; |
| int max_match_; |
| }; |
| |
| |
| class RegExpAssertion V8_FINAL : public RegExpTree { |
| public: |
| enum AssertionType { |
| START_OF_LINE, |
| START_OF_INPUT, |
| END_OF_LINE, |
| END_OF_INPUT, |
| BOUNDARY, |
| NON_BOUNDARY |
| }; |
| explicit RegExpAssertion(AssertionType type) : assertion_type_(type) { } |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpAssertion* AsAssertion() V8_OVERRIDE; |
| virtual bool IsAssertion() V8_OVERRIDE; |
| virtual bool IsAnchoredAtStart() V8_OVERRIDE; |
| virtual bool IsAnchoredAtEnd() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return 0; } |
| virtual int max_match() V8_OVERRIDE { return 0; } |
| AssertionType assertion_type() { return assertion_type_; } |
| private: |
| AssertionType assertion_type_; |
| }; |
| |
| |
| class CharacterSet V8_FINAL BASE_EMBEDDED { |
| public: |
| explicit CharacterSet(uc16 standard_set_type) |
| : ranges_(NULL), |
| standard_set_type_(standard_set_type) {} |
| explicit CharacterSet(ZoneList<CharacterRange>* ranges) |
| : ranges_(ranges), |
| standard_set_type_(0) {} |
| ZoneList<CharacterRange>* ranges(Zone* zone); |
| uc16 standard_set_type() { return standard_set_type_; } |
| void set_standard_set_type(uc16 special_set_type) { |
| standard_set_type_ = special_set_type; |
| } |
| bool is_standard() { return standard_set_type_ != 0; } |
| void Canonicalize(); |
| private: |
| ZoneList<CharacterRange>* ranges_; |
| // If non-zero, the value represents a standard set (e.g., all whitespace |
| // characters) without having to expand the ranges. |
| uc16 standard_set_type_; |
| }; |
| |
| |
| class RegExpCharacterClass V8_FINAL : public RegExpTree { |
| public: |
| RegExpCharacterClass(ZoneList<CharacterRange>* ranges, bool is_negated) |
| : set_(ranges), |
| is_negated_(is_negated) { } |
| explicit RegExpCharacterClass(uc16 type) |
| : set_(type), |
| is_negated_(false) { } |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpCharacterClass* AsCharacterClass() V8_OVERRIDE; |
| virtual bool IsCharacterClass() V8_OVERRIDE; |
| virtual bool IsTextElement() V8_OVERRIDE { return true; } |
| virtual int min_match() V8_OVERRIDE { return 1; } |
| virtual int max_match() V8_OVERRIDE { return 1; } |
| virtual void AppendToText(RegExpText* text, Zone* zone) V8_OVERRIDE; |
| CharacterSet character_set() { return set_; } |
| // TODO(lrn): Remove need for complex version if is_standard that |
| // recognizes a mangled standard set and just do { return set_.is_special(); } |
| bool is_standard(Zone* zone); |
| // Returns a value representing the standard character set if is_standard() |
| // returns true. |
| // Currently used values are: |
| // s : unicode whitespace |
| // S : unicode non-whitespace |
| // w : ASCII word character (digit, letter, underscore) |
| // W : non-ASCII word character |
| // d : ASCII digit |
| // D : non-ASCII digit |
| // . : non-unicode non-newline |
| // * : All characters |
| uc16 standard_type() { return set_.standard_set_type(); } |
| ZoneList<CharacterRange>* ranges(Zone* zone) { return set_.ranges(zone); } |
| bool is_negated() { return is_negated_; } |
| |
| private: |
| CharacterSet set_; |
| bool is_negated_; |
| }; |
| |
| |
| class RegExpAtom V8_FINAL : public RegExpTree { |
| public: |
| explicit RegExpAtom(Vector<const uc16> data) : data_(data) { } |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpAtom* AsAtom() V8_OVERRIDE; |
| virtual bool IsAtom() V8_OVERRIDE; |
| virtual bool IsTextElement() V8_OVERRIDE { return true; } |
| virtual int min_match() V8_OVERRIDE { return data_.length(); } |
| virtual int max_match() V8_OVERRIDE { return data_.length(); } |
| virtual void AppendToText(RegExpText* text, Zone* zone) V8_OVERRIDE; |
| Vector<const uc16> data() { return data_; } |
| int length() { return data_.length(); } |
| private: |
| Vector<const uc16> data_; |
| }; |
| |
| |
| class RegExpText V8_FINAL : public RegExpTree { |
| public: |
| explicit RegExpText(Zone* zone) : elements_(2, zone), length_(0) {} |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpText* AsText() V8_OVERRIDE; |
| virtual bool IsText() V8_OVERRIDE; |
| virtual bool IsTextElement() V8_OVERRIDE { return true; } |
| virtual int min_match() V8_OVERRIDE { return length_; } |
| virtual int max_match() V8_OVERRIDE { return length_; } |
| virtual void AppendToText(RegExpText* text, Zone* zone) V8_OVERRIDE; |
| void AddElement(TextElement elm, Zone* zone) { |
| elements_.Add(elm, zone); |
| length_ += elm.length(); |
| } |
| ZoneList<TextElement>* elements() { return &elements_; } |
| private: |
| ZoneList<TextElement> elements_; |
| int length_; |
| }; |
| |
| |
| class RegExpQuantifier V8_FINAL : public RegExpTree { |
| public: |
| enum QuantifierType { GREEDY, NON_GREEDY, POSSESSIVE }; |
| RegExpQuantifier(int min, int max, QuantifierType type, RegExpTree* body) |
| : body_(body), |
| min_(min), |
| max_(max), |
| min_match_(min * body->min_match()), |
| quantifier_type_(type) { |
| if (max > 0 && body->max_match() > kInfinity / max) { |
| max_match_ = kInfinity; |
| } else { |
| max_match_ = max * body->max_match(); |
| } |
| } |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| static RegExpNode* ToNode(int min, |
| int max, |
| bool is_greedy, |
| RegExpTree* body, |
| RegExpCompiler* compiler, |
| RegExpNode* on_success, |
| bool not_at_start = false); |
| virtual RegExpQuantifier* AsQuantifier() V8_OVERRIDE; |
| virtual Interval CaptureRegisters() V8_OVERRIDE; |
| virtual bool IsQuantifier() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return min_match_; } |
| virtual int max_match() V8_OVERRIDE { return max_match_; } |
| int min() { return min_; } |
| int max() { return max_; } |
| bool is_possessive() { return quantifier_type_ == POSSESSIVE; } |
| bool is_non_greedy() { return quantifier_type_ == NON_GREEDY; } |
| bool is_greedy() { return quantifier_type_ == GREEDY; } |
| RegExpTree* body() { return body_; } |
| |
| private: |
| RegExpTree* body_; |
| int min_; |
| int max_; |
| int min_match_; |
| int max_match_; |
| QuantifierType quantifier_type_; |
| }; |
| |
| |
| class RegExpCapture V8_FINAL : public RegExpTree { |
| public: |
| explicit RegExpCapture(RegExpTree* body, int index) |
| : body_(body), index_(index) { } |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| static RegExpNode* ToNode(RegExpTree* body, |
| int index, |
| RegExpCompiler* compiler, |
| RegExpNode* on_success); |
| virtual RegExpCapture* AsCapture() V8_OVERRIDE; |
| virtual bool IsAnchoredAtStart() V8_OVERRIDE; |
| virtual bool IsAnchoredAtEnd() V8_OVERRIDE; |
| virtual Interval CaptureRegisters() V8_OVERRIDE; |
| virtual bool IsCapture() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return body_->min_match(); } |
| virtual int max_match() V8_OVERRIDE { return body_->max_match(); } |
| RegExpTree* body() { return body_; } |
| int index() { return index_; } |
| static int StartRegister(int index) { return index * 2; } |
| static int EndRegister(int index) { return index * 2 + 1; } |
| |
| private: |
| RegExpTree* body_; |
| int index_; |
| }; |
| |
| |
| class RegExpLookahead V8_FINAL : public RegExpTree { |
| public: |
| RegExpLookahead(RegExpTree* body, |
| bool is_positive, |
| int capture_count, |
| int capture_from) |
| : body_(body), |
| is_positive_(is_positive), |
| capture_count_(capture_count), |
| capture_from_(capture_from) { } |
| |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpLookahead* AsLookahead() V8_OVERRIDE; |
| virtual Interval CaptureRegisters() V8_OVERRIDE; |
| virtual bool IsLookahead() V8_OVERRIDE; |
| virtual bool IsAnchoredAtStart() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return 0; } |
| virtual int max_match() V8_OVERRIDE { return 0; } |
| RegExpTree* body() { return body_; } |
| bool is_positive() { return is_positive_; } |
| int capture_count() { return capture_count_; } |
| int capture_from() { return capture_from_; } |
| |
| private: |
| RegExpTree* body_; |
| bool is_positive_; |
| int capture_count_; |
| int capture_from_; |
| }; |
| |
| |
| class RegExpBackReference V8_FINAL : public RegExpTree { |
| public: |
| explicit RegExpBackReference(RegExpCapture* capture) |
| : capture_(capture) { } |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpBackReference* AsBackReference() V8_OVERRIDE; |
| virtual bool IsBackReference() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return 0; } |
| virtual int max_match() V8_OVERRIDE { return capture_->max_match(); } |
| int index() { return capture_->index(); } |
| RegExpCapture* capture() { return capture_; } |
| private: |
| RegExpCapture* capture_; |
| }; |
| |
| |
| class RegExpEmpty V8_FINAL : public RegExpTree { |
| public: |
| RegExpEmpty() { } |
| virtual void* Accept(RegExpVisitor* visitor, void* data) V8_OVERRIDE; |
| virtual RegExpNode* ToNode(RegExpCompiler* compiler, |
| RegExpNode* on_success) V8_OVERRIDE; |
| virtual RegExpEmpty* AsEmpty() V8_OVERRIDE; |
| virtual bool IsEmpty() V8_OVERRIDE; |
| virtual int min_match() V8_OVERRIDE { return 0; } |
| virtual int max_match() V8_OVERRIDE { return 0; } |
| static RegExpEmpty* GetInstance() { |
| static RegExpEmpty* instance = ::new RegExpEmpty(); |
| return instance; |
| } |
| }; |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Out-of-line inline constructors (to side-step cyclic dependencies). |
| |
| inline ModuleVariable::ModuleVariable(Zone* zone, VariableProxy* proxy, int pos) |
| : Module(zone, proxy->interface(), pos), |
| proxy_(proxy) { |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Basic visitor |
| // - leaf node visitors are abstract. |
| |
| class AstVisitor BASE_EMBEDDED { |
| public: |
| AstVisitor() {} |
| virtual ~AstVisitor() {} |
| |
| // Stack overflow check and dynamic dispatch. |
| virtual void Visit(AstNode* node) = 0; |
| |
| // Iteration left-to-right. |
| virtual void VisitDeclarations(ZoneList<Declaration*>* declarations); |
| virtual void VisitStatements(ZoneList<Statement*>* statements); |
| virtual void VisitExpressions(ZoneList<Expression*>* expressions); |
| |
| // Individual AST nodes. |
| #define DEF_VISIT(type) \ |
| virtual void Visit##type(type* node) = 0; |
| AST_NODE_LIST(DEF_VISIT) |
| #undef DEF_VISIT |
| }; |
| |
| |
| #define DEFINE_AST_VISITOR_SUBCLASS_MEMBERS() \ |
| public: \ |
| virtual void Visit(AstNode* node) V8_FINAL V8_OVERRIDE { \ |
| if (!CheckStackOverflow()) node->Accept(this); \ |
| } \ |
| \ |
| void SetStackOverflow() { stack_overflow_ = true; } \ |
| void ClearStackOverflow() { stack_overflow_ = false; } \ |
| bool HasStackOverflow() const { return stack_overflow_; } \ |
| \ |
| bool CheckStackOverflow() { \ |
| if (stack_overflow_) return true; \ |
| StackLimitCheck check(zone_->isolate()); \ |
| if (!check.HasOverflowed()) return false; \ |
| return (stack_overflow_ = true); \ |
| } \ |
| \ |
| private: \ |
| void InitializeAstVisitor(Zone* zone) { \ |
| zone_ = zone; \ |
| stack_overflow_ = false; \ |
| } \ |
| Zone* zone() { return zone_; } \ |
| Isolate* isolate() { return zone_->isolate(); } \ |
| \ |
| Zone* zone_; \ |
| bool stack_overflow_ |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Construction time visitor. |
| |
| class AstConstructionVisitor BASE_EMBEDDED { |
| public: |
| explicit AstConstructionVisitor(Zone* zone) |
| : dont_optimize_reason_(kNoReason), |
| zone_(zone) { } |
| |
| AstProperties* ast_properties() { return &properties_; } |
| BailoutReason dont_optimize_reason() { return dont_optimize_reason_; } |
| DeferredFeedbackSlotProcessor* slot_processor() { return &slot_processor_; } |
| |
| private: |
| template<class> friend class AstNodeFactory; |
| |
| // Node visitors. |
| #define DEF_VISIT(type) \ |
| void Visit##type(type* node); |
| AST_NODE_LIST(DEF_VISIT) |
| #undef DEF_VISIT |
| |
| void increase_node_count() { properties_.add_node_count(1); } |
| void add_flag(AstPropertiesFlag flag) { properties_.flags()->Add(flag); } |
| void set_dont_optimize_reason(BailoutReason reason) { |
| dont_optimize_reason_ = reason; |
| } |
| |
| void add_slot_node(FeedbackSlotInterface* slot_node) { |
| slot_processor_.add_slot_node(zone_, slot_node); |
| } |
| |
| AstProperties properties_; |
| DeferredFeedbackSlotProcessor slot_processor_; |
| BailoutReason dont_optimize_reason_; |
| Zone* zone_; |
| }; |
| |
| |
| class AstNullVisitor BASE_EMBEDDED { |
| public: |
| explicit AstNullVisitor(Zone* zone) {} |
| |
| // Node visitors. |
| #define DEF_VISIT(type) \ |
| void Visit##type(type* node) {} |
| AST_NODE_LIST(DEF_VISIT) |
| #undef DEF_VISIT |
| }; |
| |
| |
| |
| // ---------------------------------------------------------------------------- |
| // AstNode factory |
| |
| template<class Visitor> |
| class AstNodeFactory V8_FINAL BASE_EMBEDDED { |
| public: |
| explicit AstNodeFactory(Zone* zone) |
| : zone_(zone), |
| visitor_(zone) { } |
| |
| Visitor* visitor() { return &visitor_; } |
| |
| #define VISIT_AND_RETURN(NodeType, node) \ |
| visitor_.Visit##NodeType((node)); \ |
| return node; |
| |
| VariableDeclaration* NewVariableDeclaration(VariableProxy* proxy, |
| VariableMode mode, |
| Scope* scope, |
| int pos) { |
| VariableDeclaration* decl = |
| new(zone_) VariableDeclaration(zone_, proxy, mode, scope, pos); |
| VISIT_AND_RETURN(VariableDeclaration, decl) |
| } |
| |
| FunctionDeclaration* NewFunctionDeclaration(VariableProxy* proxy, |
| VariableMode mode, |
| FunctionLiteral* fun, |
| Scope* scope, |
| int pos) { |
| FunctionDeclaration* decl = |
| new(zone_) FunctionDeclaration(zone_, proxy, mode, fun, scope, pos); |
| VISIT_AND_RETURN(FunctionDeclaration, decl) |
| } |
| |
| ModuleDeclaration* NewModuleDeclaration(VariableProxy* proxy, |
| Module* module, |
| Scope* scope, |
| int pos) { |
| ModuleDeclaration* decl = |
| new(zone_) ModuleDeclaration(zone_, proxy, module, scope, pos); |
| VISIT_AND_RETURN(ModuleDeclaration, decl) |
| } |
| |
| ImportDeclaration* NewImportDeclaration(VariableProxy* proxy, |
| Module* module, |
| Scope* scope, |
| int pos) { |
| ImportDeclaration* decl = |
| new(zone_) ImportDeclaration(zone_, proxy, module, scope, pos); |
| VISIT_AND_RETURN(ImportDeclaration, decl) |
| } |
| |
| ExportDeclaration* NewExportDeclaration(VariableProxy* proxy, |
| Scope* scope, |
| int pos) { |
| ExportDeclaration* decl = |
| new(zone_) ExportDeclaration(zone_, proxy, scope, pos); |
| VISIT_AND_RETURN(ExportDeclaration, decl) |
| } |
| |
| ModuleLiteral* NewModuleLiteral(Block* body, Interface* interface, int pos) { |
| ModuleLiteral* module = |
| new(zone_) ModuleLiteral(zone_, body, interface, pos); |
| VISIT_AND_RETURN(ModuleLiteral, module) |
| } |
| |
| ModuleVariable* NewModuleVariable(VariableProxy* proxy, int pos) { |
| ModuleVariable* module = new(zone_) ModuleVariable(zone_, proxy, pos); |
| VISIT_AND_RETURN(ModuleVariable, module) |
| } |
| |
| ModulePath* NewModulePath(Module* origin, Handle<String> name, int pos) { |
| ModulePath* module = new(zone_) ModulePath(zone_, origin, name, pos); |
| VISIT_AND_RETURN(ModulePath, module) |
| } |
| |
| ModuleUrl* NewModuleUrl(Handle<String> url, int pos) { |
| ModuleUrl* module = new(zone_) ModuleUrl(zone_, url, pos); |
| VISIT_AND_RETURN(ModuleUrl, module) |
| } |
| |
| Block* NewBlock(ZoneStringList* labels, |
| int capacity, |
| bool is_initializer_block, |
| int pos) { |
| Block* block = new(zone_) Block( |
| zone_, labels, capacity, is_initializer_block, pos); |
| VISIT_AND_RETURN(Block, block) |
| } |
| |
| #define STATEMENT_WITH_LABELS(NodeType) \ |
| NodeType* New##NodeType(ZoneStringList* labels, int pos) { \ |
| NodeType* stmt = new(zone_) NodeType(zone_, labels, pos); \ |
| VISIT_AND_RETURN(NodeType, stmt); \ |
| } |
| STATEMENT_WITH_LABELS(DoWhileStatement) |
| STATEMENT_WITH_LABELS(WhileStatement) |
| STATEMENT_WITH_LABELS(ForStatement) |
| STATEMENT_WITH_LABELS(SwitchStatement) |
| #undef STATEMENT_WITH_LABELS |
| |
| ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode, |
| ZoneStringList* labels, |
| int pos) { |
| switch (visit_mode) { |
| case ForEachStatement::ENUMERATE: { |
| ForInStatement* stmt = new(zone_) ForInStatement(zone_, labels, pos); |
| VISIT_AND_RETURN(ForInStatement, stmt); |
| } |
| case ForEachStatement::ITERATE: { |
| ForOfStatement* stmt = new(zone_) ForOfStatement(zone_, labels, pos); |
| VISIT_AND_RETURN(ForOfStatement, stmt); |
| } |
| } |
| UNREACHABLE(); |
| return NULL; |
| } |
| |
| ModuleStatement* NewModuleStatement( |
| VariableProxy* proxy, Block* body, int pos) { |
| ModuleStatement* stmt = new(zone_) ModuleStatement(zone_, proxy, body, pos); |
| VISIT_AND_RETURN(ModuleStatement, stmt) |
| } |
| |
| ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) { |
| ExpressionStatement* stmt = |
| new(zone_) ExpressionStatement(zone_, expression, pos); |
| VISIT_AND_RETURN(ExpressionStatement, stmt) |
| } |
| |
| ContinueStatement* NewContinueStatement(IterationStatement* target, int pos) { |
| ContinueStatement* stmt = new(zone_) ContinueStatement(zone_, target, pos); |
| VISIT_AND_RETURN(ContinueStatement, stmt) |
| } |
| |
| BreakStatement* NewBreakStatement(BreakableStatement* target, int pos) { |
| BreakStatement* stmt = new(zone_) BreakStatement(zone_, target, pos); |
| VISIT_AND_RETURN(BreakStatement, stmt) |
| } |
| |
| ReturnStatement* NewReturnStatement(Expression* expression, int pos) { |
| ReturnStatement* stmt = new(zone_) ReturnStatement(zone_, expression, pos); |
| VISIT_AND_RETURN(ReturnStatement, stmt) |
| } |
| |
| WithStatement* NewWithStatement(Scope* scope, |
| Expression* expression, |
| Statement* statement, |
| int pos) { |
| WithStatement* stmt = new(zone_) WithStatement( |
| zone_, scope, expression, statement, pos); |
| VISIT_AND_RETURN(WithStatement, stmt) |
| } |
| |
| IfStatement* NewIfStatement(Expression* condition, |
| Statement* then_statement, |
| Statement* else_statement, |
| int pos) { |
| IfStatement* stmt = new(zone_) IfStatement( |
| zone_, condition, then_statement, else_statement, pos); |
| VISIT_AND_RETURN(IfStatement, stmt) |
| } |
| |
| TryCatchStatement* NewTryCatchStatement(int index, |
| Block* try_block, |
| Scope* scope, |
| Variable* variable, |
| Block* catch_block, |
| int pos) { |
| TryCatchStatement* stmt = new(zone_) TryCatchStatement( |
| zone_, index, try_block, scope, variable, catch_block, pos); |
| VISIT_AND_RETURN(TryCatchStatement, stmt) |
| } |
| |
| TryFinallyStatement* NewTryFinallyStatement(int index, |
| Block* try_block, |
| Block* finally_block, |
| int pos) { |
| TryFinallyStatement* stmt = new(zone_) TryFinallyStatement( |
| zone_, index, try_block, finally_block, pos); |
| VISIT_AND_RETURN(TryFinallyStatement, stmt) |
| } |
| |
| DebuggerStatement* NewDebuggerStatement(int pos) { |
| DebuggerStatement* stmt = new(zone_) DebuggerStatement(zone_, pos); |
| VISIT_AND_RETURN(DebuggerStatement, stmt) |
| } |
| |
| EmptyStatement* NewEmptyStatement(int pos) { |
| return new(zone_) EmptyStatement(zone_, pos); |
| } |
| |
| CaseClause* NewCaseClause( |
| Expression* label, ZoneList<Statement*>* statements, int pos) { |
| CaseClause* clause = |
| new(zone_) CaseClause(zone_, label, statements, pos); |
| VISIT_AND_RETURN(CaseClause, clause) |
| } |
| |
| Literal* NewLiteral(Handle<Object> handle, int pos) { |
| Literal* lit = new(zone_) Literal(zone_, handle, pos); |
| VISIT_AND_RETURN(Literal, lit) |
| } |
| |
| Literal* NewNumberLiteral(double number, int pos) { |
| return NewLiteral( |
| zone_->isolate()->factory()->NewNumber(number, TENURED), pos); |
| } |
| |
| ObjectLiteral* NewObjectLiteral( |
| ZoneList<ObjectLiteral::Property*>* properties, |
| int literal_index, |
| int boilerplate_properties, |
| bool has_function, |
| int pos) { |
| ObjectLiteral* lit = new(zone_) ObjectLiteral( |
| zone_, properties, literal_index, boilerplate_properties, |
| has_function, pos); |
| VISIT_AND_RETURN(ObjectLiteral, lit) |
| } |
| |
| ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key, |
| Expression* value) { |
| return new(zone_) ObjectLiteral::Property(zone_, key, value); |
| } |
| |
| ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter, |
| FunctionLiteral* value, |
| int pos) { |
| ObjectLiteral::Property* prop = |
| new(zone_) ObjectLiteral::Property(zone_, is_getter, value); |
| prop->set_key(NewLiteral(value->name(), pos)); |
| return prop; // Not an AST node, will not be visited. |
| } |
| |
| RegExpLiteral* NewRegExpLiteral(Handle<String> pattern, |
| Handle<String> flags, |
| int literal_index, |
| int pos) { |
| RegExpLiteral* lit = |
| new(zone_) RegExpLiteral(zone_, pattern, flags, literal_index, pos); |
| VISIT_AND_RETURN(RegExpLiteral, lit); |
| } |
| |
| ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values, |
| int literal_index, |
| int pos) { |
| ArrayLiteral* lit = new(zone_) ArrayLiteral( |
| zone_, values, literal_index, pos); |
| VISIT_AND_RETURN(ArrayLiteral, lit) |
| } |
| |
| VariableProxy* NewVariableProxy(Variable* var, |
| int pos = RelocInfo::kNoPosition) { |
| VariableProxy* proxy = new(zone_) VariableProxy(zone_, var, pos); |
| VISIT_AND_RETURN(VariableProxy, proxy) |
| } |
| |
| VariableProxy* NewVariableProxy(Handle<String> name, |
| bool is_this, |
| Interface* interface = Interface::NewValue(), |
| int position = RelocInfo::kNoPosition) { |
| VariableProxy* proxy = |
| new(zone_) VariableProxy(zone_, name, is_this, interface, position); |
| VISIT_AND_RETURN(VariableProxy, proxy) |
| } |
| |
| Property* NewProperty(Expression* obj, Expression* key, int pos) { |
| Property* prop = new(zone_) Property(zone_, obj, key, pos); |
| VISIT_AND_RETURN(Property, prop) |
| } |
| |
| Call* NewCall(Expression* expression, |
| ZoneList<Expression*>* arguments, |
| int pos) { |
| Call* call = new(zone_) Call(zone_, expression, arguments, pos); |
| VISIT_AND_RETURN(Call, call) |
| } |
| |
| CallNew* NewCallNew(Expression* expression, |
| ZoneList<Expression*>* arguments, |
| int pos) { |
| CallNew* call = new(zone_) CallNew(zone_, expression, arguments, pos); |
| VISIT_AND_RETURN(CallNew, call) |
| } |
| |
| CallRuntime* NewCallRuntime(Handle<String> name, |
| const Runtime::Function* function, |
| ZoneList<Expression*>* arguments, |
| int pos) { |
| CallRuntime* call = |
| new(zone_) CallRuntime(zone_, name, function, arguments, pos); |
| VISIT_AND_RETURN(CallRuntime, call) |
| } |
| |
| UnaryOperation* NewUnaryOperation(Token::Value op, |
| Expression* expression, |
| int pos) { |
| UnaryOperation* node = |
| new(zone_) UnaryOperation(zone_, op, expression, pos); |
| VISIT_AND_RETURN(UnaryOperation, node) |
| } |
| |
| BinaryOperation* NewBinaryOperation(Token::Value op, |
| Expression* left, |
| Expression* right, |
| int pos) { |
| BinaryOperation* node = |
| new(zone_) BinaryOperation(zone_, op, left, right, pos); |
| VISIT_AND_RETURN(BinaryOperation, node) |
| } |
| |
| CountOperation* NewCountOperation(Token::Value op, |
| bool is_prefix, |
| Expression* expr, |
| int pos) { |
| CountOperation* node = |
| new(zone_) CountOperation(zone_, op, is_prefix, expr, pos); |
| VISIT_AND_RETURN(CountOperation, node) |
| } |
| |
| CompareOperation* NewCompareOperation(Token::Value op, |
| Expression* left, |
| Expression* right, |
| int pos) { |
| CompareOperation* node = |
| new(zone_) CompareOperation(zone_, op, left, right, pos); |
| VISIT_AND_RETURN(CompareOperation, node) |
| } |
| |
| Conditional* NewConditional(Expression* condition, |
| Expression* then_expression, |
| Expression* else_expression, |
| int position) { |
| Conditional* cond = new(zone_) Conditional( |
| zone_, condition, then_expression, else_expression, position); |
| VISIT_AND_RETURN(Conditional, cond) |
| } |
| |
| Assignment* NewAssignment(Token::Value op, |
| Expression* target, |
| Expression* value, |
| int pos) { |
| Assignment* assign = |
| new(zone_) Assignment(zone_, op, target, value, pos); |
| assign->Init(zone_, this); |
| VISIT_AND_RETURN(Assignment, assign) |
| } |
| |
| Yield* NewYield(Expression *generator_object, |
| Expression* expression, |
| Yield::Kind yield_kind, |
| int pos) { |
| Yield* yield = new(zone_) Yield( |
| zone_, generator_object, expression, yield_kind, pos); |
| VISIT_AND_RETURN(Yield, yield) |
| } |
| |
| Throw* NewThrow(Expression* exception, int pos) { |
| Throw* t = new(zone_) Throw(zone_, exception, pos); |
| VISIT_AND_RETURN(Throw, t) |
| } |
| |
| FunctionLiteral* NewFunctionLiteral( |
| Handle<String> name, |
| Scope* scope, |
| ZoneList<Statement*>* body, |
| int materialized_literal_count, |
| int expected_property_count, |
| int handler_count, |
| int parameter_count, |
| FunctionLiteral::ParameterFlag has_duplicate_parameters, |
| FunctionLiteral::FunctionType function_type, |
| FunctionLiteral::IsFunctionFlag is_function, |
| FunctionLiteral::IsParenthesizedFlag is_parenthesized, |
| FunctionLiteral::IsGeneratorFlag is_generator, |
| int position) { |
| FunctionLiteral* lit = new(zone_) FunctionLiteral( |
| zone_, name, scope, body, |
| materialized_literal_count, expected_property_count, handler_count, |
| parameter_count, function_type, has_duplicate_parameters, is_function, |
| is_parenthesized, is_generator, position); |
| // Top-level literal doesn't count for the AST's properties. |
| if (is_function == FunctionLiteral::kIsFunction) { |
| visitor_.VisitFunctionLiteral(lit); |
| } |
| return lit; |
| } |
| |
| NativeFunctionLiteral* NewNativeFunctionLiteral( |
| Handle<String> name, v8::Extension* extension, int pos) { |
| NativeFunctionLiteral* lit = |
| new(zone_) NativeFunctionLiteral(zone_, name, extension, pos); |
| VISIT_AND_RETURN(NativeFunctionLiteral, lit) |
| } |
| |
| ThisFunction* NewThisFunction(int pos) { |
| ThisFunction* fun = new(zone_) ThisFunction(zone_, pos); |
| VISIT_AND_RETURN(ThisFunction, fun) |
| } |
| |
| #undef VISIT_AND_RETURN |
| |
| private: |
| Zone* zone_; |
| Visitor visitor_; |
| }; |
| |
| |
| } } // namespace v8::internal |
| |
| #endif // V8_AST_H_ |