Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1 | // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef V8_COMPILER_AST_GRAPH_BUILDER_H_ |
| 6 | #define V8_COMPILER_AST_GRAPH_BUILDER_H_ |
| 7 | |
| 8 | #include "src/v8.h" |
| 9 | |
| 10 | #include "src/ast.h" |
| 11 | #include "src/compiler/graph-builder.h" |
| 12 | #include "src/compiler/js-graph.h" |
| 13 | |
| 14 | namespace v8 { |
| 15 | namespace internal { |
| 16 | namespace compiler { |
| 17 | |
| 18 | class ControlBuilder; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 19 | class Graph; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 20 | class LoopAssignmentAnalysis; |
| 21 | class LoopBuilder; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 22 | |
| 23 | // The AstGraphBuilder produces a high-level IR graph, based on an |
| 24 | // underlying AST. The produced graph can either be compiled into a |
| 25 | // stand-alone function or be wired into another graph for the purposes |
| 26 | // of function inlining. |
| 27 | class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { |
| 28 | public: |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 29 | AstGraphBuilder(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph, |
| 30 | LoopAssignmentAnalysis* loop_assignment = NULL); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 31 | |
| 32 | // Creates a graph by visiting the entire AST. |
| 33 | bool CreateGraph(); |
| 34 | |
| 35 | protected: |
| 36 | class AstContext; |
| 37 | class AstEffectContext; |
| 38 | class AstValueContext; |
| 39 | class AstTestContext; |
| 40 | class BreakableScope; |
| 41 | class ContextScope; |
| 42 | class Environment; |
| 43 | |
| 44 | Environment* environment() { |
| 45 | return reinterpret_cast<Environment*>( |
| 46 | StructuredGraphBuilder::environment()); |
| 47 | } |
| 48 | |
| 49 | AstContext* ast_context() const { return ast_context_; } |
| 50 | BreakableScope* breakable() const { return breakable_; } |
| 51 | ContextScope* execution_context() const { return execution_context_; } |
| 52 | |
| 53 | void set_ast_context(AstContext* ctx) { ast_context_ = ctx; } |
| 54 | void set_breakable(BreakableScope* brk) { breakable_ = brk; } |
| 55 | void set_execution_context(ContextScope* ctx) { execution_context_ = ctx; } |
| 56 | |
| 57 | // Support for control flow builders. The concrete type of the environment |
| 58 | // depends on the graph builder, but environments themselves are not virtual. |
| 59 | typedef StructuredGraphBuilder::Environment BaseEnvironment; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 60 | BaseEnvironment* CopyEnvironment(BaseEnvironment* env) OVERRIDE; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 61 | |
| 62 | // Getters for values in the activation record. |
| 63 | Node* GetFunctionClosure(); |
| 64 | Node* GetFunctionContext(); |
| 65 | |
| 66 | // |
| 67 | // The following build methods all generate graph fragments and return one |
| 68 | // resulting node. The operand stack height remains the same, variables and |
| 69 | // other dependencies tracked by the environment might be mutated though. |
| 70 | // |
| 71 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 72 | // Builder to create a receiver check for sloppy mode. |
| 73 | Node* BuildPatchReceiverToGlobalProxy(Node* receiver); |
| 74 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 75 | // Builder to create a local function context. |
| 76 | Node* BuildLocalFunctionContext(Node* context, Node* closure); |
| 77 | |
| 78 | // Builder to create an arguments object if it is used. |
| 79 | Node* BuildArgumentsObject(Variable* arguments); |
| 80 | |
| 81 | // Builders for variable load and assignment. |
| 82 | Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op, |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 83 | BailoutId bailout_id, |
| 84 | OutputFrameStateCombine state_combine = |
| 85 | OutputFrameStateCombine::Ignore()); |
| 86 | Node* BuildVariableDelete(Variable* var, BailoutId bailout_id, |
| 87 | OutputFrameStateCombine state_combine); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 88 | Node* BuildVariableLoad(Variable* var, BailoutId bailout_id, |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 89 | const VectorSlotPair& feedback, |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 90 | ContextualMode mode = CONTEXTUAL); |
| 91 | |
| 92 | // Builders for accessing the function context. |
| 93 | Node* BuildLoadBuiltinsObject(); |
| 94 | Node* BuildLoadGlobalObject(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 95 | Node* BuildLoadGlobalProxy(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 96 | Node* BuildLoadClosure(); |
| 97 | Node* BuildLoadObjectField(Node* object, int offset); |
| 98 | |
| 99 | // Builders for automatic type conversion. |
| 100 | Node* BuildToBoolean(Node* value); |
| 101 | |
| 102 | // Builders for error reporting at runtime. |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 103 | Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id); |
| 104 | Node* BuildThrowConstAssignError(BailoutId bailout_id); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 105 | |
| 106 | // Builders for dynamic hole-checks at runtime. |
| 107 | Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 108 | Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole, |
| 109 | BailoutId bailout_id); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 110 | |
| 111 | // Builders for binary operations. |
| 112 | Node* BuildBinaryOp(Node* left, Node* right, Token::Value op); |
| 113 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 114 | // Builder for stack-check guards. |
| 115 | Node* BuildStackCheck(); |
| 116 | |
| 117 | #define DECLARE_VISIT(type) void Visit##type(type* node) OVERRIDE; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 118 | // Visiting functions for AST nodes make this an AstVisitor. |
| 119 | AST_NODE_LIST(DECLARE_VISIT) |
| 120 | #undef DECLARE_VISIT |
| 121 | |
| 122 | // Visiting function for declarations list is overridden. |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 123 | void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 124 | |
| 125 | private: |
| 126 | CompilationInfo* info_; |
| 127 | AstContext* ast_context_; |
| 128 | JSGraph* jsgraph_; |
| 129 | |
| 130 | // List of global declarations for functions and variables. |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 131 | ZoneVector<Handle<Object>> globals_; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 132 | |
| 133 | // Stack of breakable statements entered by the visitor. |
| 134 | BreakableScope* breakable_; |
| 135 | |
| 136 | // Stack of context objects pushed onto the chain by the visitor. |
| 137 | ContextScope* execution_context_; |
| 138 | |
| 139 | // Nodes representing values in the activation record. |
| 140 | SetOncePointer<Node> function_closure_; |
| 141 | SetOncePointer<Node> function_context_; |
| 142 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 143 | // Result of loop assignment analysis performed before graph creation. |
| 144 | LoopAssignmentAnalysis* loop_assignment_analysis_; |
| 145 | |
| 146 | CompilationInfo* info() const { return info_; } |
| 147 | inline StrictMode strict_mode() const; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 148 | JSGraph* jsgraph() { return jsgraph_; } |
| 149 | JSOperatorBuilder* javascript() { return jsgraph_->javascript(); } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 150 | ZoneVector<Handle<Object>>* globals() { return &globals_; } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 151 | |
| 152 | // Current scope during visitation. |
| 153 | inline Scope* current_scope() const; |
| 154 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 155 | // Named and keyed loads require a VectorSlotPair for successful lowering. |
| 156 | VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const; |
| 157 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 158 | // Process arguments to a call by popping {arity} elements off the operand |
| 159 | // stack and build a call node using the given call operator. |
| 160 | Node* ProcessArguments(const Operator* op, int arity); |
| 161 | |
| 162 | // Visit statements. |
| 163 | void VisitIfNotNull(Statement* stmt); |
| 164 | |
| 165 | // Visit expressions. |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 166 | void Visit(Expression* expr); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 167 | void VisitForTest(Expression* expr); |
| 168 | void VisitForEffect(Expression* expr); |
| 169 | void VisitForValue(Expression* expr); |
| 170 | void VisitForValueOrNull(Expression* expr); |
| 171 | void VisitForValues(ZoneList<Expression*>* exprs); |
| 172 | |
| 173 | // Common for all IterationStatement bodies. |
| 174 | void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop, int); |
| 175 | |
| 176 | // Dispatched from VisitCallRuntime. |
| 177 | void VisitCallJSRuntime(CallRuntime* expr); |
| 178 | |
| 179 | // Dispatched from VisitUnaryOperation. |
| 180 | void VisitDelete(UnaryOperation* expr); |
| 181 | void VisitVoid(UnaryOperation* expr); |
| 182 | void VisitTypeof(UnaryOperation* expr); |
| 183 | void VisitNot(UnaryOperation* expr); |
| 184 | |
| 185 | // Dispatched from VisitBinaryOperation. |
| 186 | void VisitComma(BinaryOperation* expr); |
| 187 | void VisitLogicalExpression(BinaryOperation* expr); |
| 188 | void VisitArithmeticExpression(BinaryOperation* expr); |
| 189 | |
| 190 | // Dispatched from VisitForInStatement. |
| 191 | void VisitForInAssignment(Expression* expr, Node* value); |
| 192 | |
| 193 | // Builds deoptimization for a given node. |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 194 | void PrepareFrameState( |
| 195 | Node* node, BailoutId ast_id, |
| 196 | OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 197 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 198 | BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 199 | |
| 200 | DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
| 201 | DISALLOW_COPY_AND_ASSIGN(AstGraphBuilder); |
| 202 | }; |
| 203 | |
| 204 | |
| 205 | // The abstract execution environment for generated code consists of |
| 206 | // parameter variables, local variables and the operand stack. The |
| 207 | // environment will perform proper SSA-renaming of all tracked nodes |
| 208 | // at split and merge points in the control flow. Internally all the |
| 209 | // values are stored in one list using the following layout: |
| 210 | // |
| 211 | // [parameters (+receiver)] [locals] [operand stack] |
| 212 | // |
| 213 | class AstGraphBuilder::Environment |
| 214 | : public StructuredGraphBuilder::Environment { |
| 215 | public: |
| 216 | Environment(AstGraphBuilder* builder, Scope* scope, Node* control_dependency); |
| 217 | Environment(const Environment& copy); |
| 218 | |
| 219 | int parameters_count() const { return parameters_count_; } |
| 220 | int locals_count() const { return locals_count_; } |
| 221 | int stack_height() { |
| 222 | return static_cast<int>(values()->size()) - parameters_count_ - |
| 223 | locals_count_; |
| 224 | } |
| 225 | |
| 226 | // Operations on parameter or local variables. The parameter indices are |
| 227 | // shifted by 1 (receiver is parameter index -1 but environment index 0). |
| 228 | void Bind(Variable* variable, Node* node) { |
| 229 | DCHECK(variable->IsStackAllocated()); |
| 230 | if (variable->IsParameter()) { |
| 231 | values()->at(variable->index() + 1) = node; |
| 232 | } else { |
| 233 | DCHECK(variable->IsStackLocal()); |
| 234 | values()->at(variable->index() + parameters_count_) = node; |
| 235 | } |
| 236 | } |
| 237 | Node* Lookup(Variable* variable) { |
| 238 | DCHECK(variable->IsStackAllocated()); |
| 239 | if (variable->IsParameter()) { |
| 240 | return values()->at(variable->index() + 1); |
| 241 | } else { |
| 242 | DCHECK(variable->IsStackLocal()); |
| 243 | return values()->at(variable->index() + parameters_count_); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | // Operations on the operand stack. |
| 248 | void Push(Node* node) { |
| 249 | values()->push_back(node); |
| 250 | } |
| 251 | Node* Top() { |
| 252 | DCHECK(stack_height() > 0); |
| 253 | return values()->back(); |
| 254 | } |
| 255 | Node* Pop() { |
| 256 | DCHECK(stack_height() > 0); |
| 257 | Node* back = values()->back(); |
| 258 | values()->pop_back(); |
| 259 | return back; |
| 260 | } |
| 261 | |
| 262 | // Direct mutations of the operand stack. |
| 263 | void Poke(int depth, Node* node) { |
| 264 | DCHECK(depth >= 0 && depth < stack_height()); |
| 265 | int index = static_cast<int>(values()->size()) - depth - 1; |
| 266 | values()->at(index) = node; |
| 267 | } |
| 268 | Node* Peek(int depth) { |
| 269 | DCHECK(depth >= 0 && depth < stack_height()); |
| 270 | int index = static_cast<int>(values()->size()) - depth - 1; |
| 271 | return values()->at(index); |
| 272 | } |
| 273 | void Drop(int depth) { |
| 274 | DCHECK(depth >= 0 && depth <= stack_height()); |
| 275 | values()->erase(values()->end() - depth, values()->end()); |
| 276 | } |
| 277 | |
| 278 | // Preserve a checkpoint of the environment for the IR graph. Any |
| 279 | // further mutation of the environment will not affect checkpoints. |
| 280 | Node* Checkpoint(BailoutId ast_id, OutputFrameStateCombine combine); |
| 281 | |
| 282 | protected: |
| 283 | AstGraphBuilder* builder() const { |
| 284 | return reinterpret_cast<AstGraphBuilder*>( |
| 285 | StructuredGraphBuilder::Environment::builder()); |
| 286 | } |
| 287 | |
| 288 | private: |
| 289 | void UpdateStateValues(Node** state_values, int offset, int count); |
| 290 | |
| 291 | int parameters_count_; |
| 292 | int locals_count_; |
| 293 | Node* parameters_node_; |
| 294 | Node* locals_node_; |
| 295 | Node* stack_node_; |
| 296 | }; |
| 297 | |
| 298 | |
| 299 | // Each expression in the AST is evaluated in a specific context. This context |
| 300 | // decides how the evaluation result is passed up the visitor. |
| 301 | class AstGraphBuilder::AstContext BASE_EMBEDDED { |
| 302 | public: |
| 303 | bool IsEffect() const { return kind_ == Expression::kEffect; } |
| 304 | bool IsValue() const { return kind_ == Expression::kValue; } |
| 305 | bool IsTest() const { return kind_ == Expression::kTest; } |
| 306 | |
| 307 | // Determines how to combine the frame state with the value |
| 308 | // that is about to be plugged into this AstContext. |
| 309 | OutputFrameStateCombine GetStateCombine() { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 310 | return IsEffect() ? OutputFrameStateCombine::Ignore() |
| 311 | : OutputFrameStateCombine::Push(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 312 | } |
| 313 | |
| 314 | // Plug a node into this expression context. Call this function in tail |
| 315 | // position in the Visit functions for expressions. |
| 316 | virtual void ProduceValue(Node* value) = 0; |
| 317 | |
| 318 | // Unplugs a node from this expression context. Call this to retrieve the |
| 319 | // result of another Visit function that already plugged the context. |
| 320 | virtual Node* ConsumeValue() = 0; |
| 321 | |
| 322 | // Shortcut for "context->ProduceValue(context->ConsumeValue())". |
| 323 | void ReplaceValue() { ProduceValue(ConsumeValue()); } |
| 324 | |
| 325 | protected: |
| 326 | AstContext(AstGraphBuilder* owner, Expression::Context kind); |
| 327 | virtual ~AstContext(); |
| 328 | |
| 329 | AstGraphBuilder* owner() const { return owner_; } |
| 330 | Environment* environment() const { return owner_->environment(); } |
| 331 | |
| 332 | // We want to be able to assert, in a context-specific way, that the stack |
| 333 | // height makes sense when the context is filled. |
| 334 | #ifdef DEBUG |
| 335 | int original_height_; |
| 336 | #endif |
| 337 | |
| 338 | private: |
| 339 | Expression::Context kind_; |
| 340 | AstGraphBuilder* owner_; |
| 341 | AstContext* outer_; |
| 342 | }; |
| 343 | |
| 344 | |
| 345 | // Context to evaluate expression for its side effects only. |
| 346 | class AstGraphBuilder::AstEffectContext FINAL : public AstContext { |
| 347 | public: |
| 348 | explicit AstEffectContext(AstGraphBuilder* owner) |
| 349 | : AstContext(owner, Expression::kEffect) {} |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 350 | ~AstEffectContext() FINAL; |
| 351 | void ProduceValue(Node* value) FINAL; |
| 352 | Node* ConsumeValue() FINAL; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 353 | }; |
| 354 | |
| 355 | |
| 356 | // Context to evaluate expression for its value (and side effects). |
| 357 | class AstGraphBuilder::AstValueContext FINAL : public AstContext { |
| 358 | public: |
| 359 | explicit AstValueContext(AstGraphBuilder* owner) |
| 360 | : AstContext(owner, Expression::kValue) {} |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 361 | ~AstValueContext() FINAL; |
| 362 | void ProduceValue(Node* value) FINAL; |
| 363 | Node* ConsumeValue() FINAL; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 364 | }; |
| 365 | |
| 366 | |
| 367 | // Context to evaluate expression for a condition value (and side effects). |
| 368 | class AstGraphBuilder::AstTestContext FINAL : public AstContext { |
| 369 | public: |
| 370 | explicit AstTestContext(AstGraphBuilder* owner) |
| 371 | : AstContext(owner, Expression::kTest) {} |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 372 | ~AstTestContext() FINAL; |
| 373 | void ProduceValue(Node* value) FINAL; |
| 374 | Node* ConsumeValue() FINAL; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 375 | }; |
| 376 | |
| 377 | |
| 378 | // Scoped class tracking breakable statements entered by the visitor. Allows to |
| 379 | // properly 'break' and 'continue' iteration statements as well as to 'break' |
| 380 | // from blocks within switch statements. |
| 381 | class AstGraphBuilder::BreakableScope BASE_EMBEDDED { |
| 382 | public: |
| 383 | BreakableScope(AstGraphBuilder* owner, BreakableStatement* target, |
| 384 | ControlBuilder* control, int drop_extra) |
| 385 | : owner_(owner), |
| 386 | target_(target), |
| 387 | next_(owner->breakable()), |
| 388 | control_(control), |
| 389 | drop_extra_(drop_extra) { |
| 390 | owner_->set_breakable(this); // Push. |
| 391 | } |
| 392 | |
| 393 | ~BreakableScope() { |
| 394 | owner_->set_breakable(next_); // Pop. |
| 395 | } |
| 396 | |
| 397 | // Either 'break' or 'continue' the target statement. |
| 398 | void BreakTarget(BreakableStatement* target); |
| 399 | void ContinueTarget(BreakableStatement* target); |
| 400 | |
| 401 | private: |
| 402 | AstGraphBuilder* owner_; |
| 403 | BreakableStatement* target_; |
| 404 | BreakableScope* next_; |
| 405 | ControlBuilder* control_; |
| 406 | int drop_extra_; |
| 407 | |
| 408 | // Find the correct scope for the target statement. Note that this also drops |
| 409 | // extra operands from the environment for each scope skipped along the way. |
| 410 | BreakableScope* FindBreakable(BreakableStatement* target); |
| 411 | }; |
| 412 | |
| 413 | |
| 414 | // Scoped class tracking context objects created by the visitor. Represents |
| 415 | // mutations of the context chain within the function body and allows to |
| 416 | // change the current {scope} and {context} during visitation. |
| 417 | class AstGraphBuilder::ContextScope BASE_EMBEDDED { |
| 418 | public: |
| 419 | ContextScope(AstGraphBuilder* owner, Scope* scope, Node* context) |
| 420 | : owner_(owner), |
| 421 | next_(owner->execution_context()), |
| 422 | outer_(owner->current_context()), |
| 423 | scope_(scope) { |
| 424 | owner_->set_execution_context(this); // Push. |
| 425 | owner_->set_current_context(context); |
| 426 | } |
| 427 | |
| 428 | ~ContextScope() { |
| 429 | owner_->set_execution_context(next_); // Pop. |
| 430 | owner_->set_current_context(outer_); |
| 431 | } |
| 432 | |
| 433 | // Current scope during visitation. |
| 434 | Scope* scope() const { return scope_; } |
| 435 | |
| 436 | private: |
| 437 | AstGraphBuilder* owner_; |
| 438 | ContextScope* next_; |
| 439 | Node* outer_; |
| 440 | Scope* scope_; |
| 441 | }; |
| 442 | |
| 443 | Scope* AstGraphBuilder::current_scope() const { |
| 444 | return execution_context_->scope(); |
| 445 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 446 | |
| 447 | } // namespace compiler |
| 448 | } // namespace internal |
| 449 | } // namespace v8 |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 450 | |
| 451 | #endif // V8_COMPILER_AST_GRAPH_BUILDER_H_ |