• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_SCOPES_H_
29 #define V8_SCOPES_H_
30 
31 #include "ast.h"
32 #include "hashmap.h"
33 
34 namespace v8 {
35 namespace internal {
36 
37 class CompilationInfo;
38 
39 
40 // A hash map to support fast variable declaration and lookup.
41 class VariableMap: public HashMap {
42  public:
43   VariableMap();
44 
45   // Dummy constructor.  This constructor doesn't set up the map
46   // properly so don't use it unless you have a good reason.
47   explicit VariableMap(bool gotta_love_static_overloading);
48 
49   virtual ~VariableMap();
50 
51   Variable* Declare(Scope* scope,
52                     Handle<String> name,
53                     Variable::Mode mode,
54                     bool is_valid_lhs,
55                     Variable::Kind kind);
56 
57   Variable* Lookup(Handle<String> name);
58 };
59 
60 
61 // The dynamic scope part holds hash maps for the variables that will
62 // be looked up dynamically from within eval and with scopes. The objects
63 // are allocated on-demand from Scope::NonLocal to avoid wasting memory
64 // and setup time for scopes that don't need them.
65 class DynamicScopePart : public ZoneObject {
66  public:
GetMap(Variable::Mode mode)67   VariableMap* GetMap(Variable::Mode mode) {
68     int index = mode - Variable::DYNAMIC;
69     ASSERT(index >= 0 && index < 3);
70     return &maps_[index];
71   }
72 
73  private:
74   VariableMap maps_[3];
75 };
76 
77 
78 // Global invariants after AST construction: Each reference (i.e. identifier)
79 // to a JavaScript variable (including global properties) is represented by a
80 // VariableProxy node. Immediately after AST construction and before variable
81 // allocation, most VariableProxy nodes are "unresolved", i.e. not bound to a
82 // corresponding variable (though some are bound during parse time). Variable
83 // allocation binds each unresolved VariableProxy to one Variable and assigns
84 // a location. Note that many VariableProxy nodes may refer to the same Java-
85 // Script variable.
86 
87 class Scope: public ZoneObject {
88  public:
89   // ---------------------------------------------------------------------------
90   // Construction
91 
92   enum Type {
93     EVAL_SCOPE,     // the top-level scope for an 'eval' source
94     FUNCTION_SCOPE,  // the top-level scope for a function
95     GLOBAL_SCOPE    // the top-level scope for a program or a top-level eval
96   };
97 
98   enum LocalType {
99     PARAMETER,
100     VAR_OR_CONST
101   };
102 
103   Scope(Scope* outer_scope, Type type);
104 
~Scope()105   virtual ~Scope() { }
106 
107   // Compute top scope and allocate variables. For lazy compilation the top
108   // scope only contains the single lazily compiled function, so this
109   // doesn't re-allocate variables repeatedly.
110   static bool Analyze(CompilationInfo* info);
111 
112   static Scope* DeserializeScopeChain(CompilationInfo* info,
113                                       Scope* innermost_scope);
114 
115   // The scope name is only used for printing/debugging.
SetScopeName(Handle<String> scope_name)116   void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }
117 
118   virtual void Initialize(bool inside_with);
119 
120   // Called just before leaving a scope.
Leave()121   virtual void Leave() {
122     // No cleanup or fixup necessary.
123   }
124 
125   // ---------------------------------------------------------------------------
126   // Declarations
127 
128   // Lookup a variable in this scope. Returns the variable or NULL if not found.
129   virtual Variable* LocalLookup(Handle<String> name);
130 
131   // Lookup a variable in this scope or outer scopes.
132   // Returns the variable or NULL if not found.
133   virtual Variable* Lookup(Handle<String> name);
134 
135   // Declare the function variable for a function literal. This variable
136   // is in an intermediate scope between this function scope and the the
137   // outer scope. Only possible for function scopes; at most one variable.
138   Variable* DeclareFunctionVar(Handle<String> name);
139 
140   // Declare a local variable in this scope. If the variable has been
141   // declared before, the previously declared variable is returned.
142   virtual Variable* DeclareLocal(Handle<String> name,
143                                  Variable::Mode mode,
144                                  LocalType type);
145 
146   // Declare an implicit global variable in this scope which must be a
147   // global scope.  The variable was introduced (possibly from an inner
148   // scope) by a reference to an unresolved variable with no intervening
149   // with statements or eval calls.
150   Variable* DeclareGlobal(Handle<String> name);
151 
152   // Add a parameter to the parameter list. The parameter must have been
153   // declared via Declare. The same parameter may occur more than once in
154   // the parameter list; they must be added in source order, from left to
155   // right.
156   void AddParameter(Variable* var);
157 
158   // Create a new unresolved variable.
159   virtual VariableProxy* NewUnresolved(Handle<String> name,
160                                        bool inside_with,
161                                        int position = RelocInfo::kNoPosition);
162 
163   // Remove a unresolved variable. During parsing, an unresolved variable
164   // may have been added optimistically, but then only the variable name
165   // was used (typically for labels). If the variable was not declared, the
166   // addition introduced a new unresolved variable which may end up being
167   // allocated globally as a "ghost" variable. RemoveUnresolved removes
168   // such a variable again if it was added; otherwise this is a no-op.
169   void RemoveUnresolved(VariableProxy* var);
170 
171   // Creates a new temporary variable in this scope.  The name is only used
172   // for printing and cannot be used to find the variable.  In particular,
173   // the only way to get hold of the temporary is by keeping the Variable*
174   // around.
175   virtual Variable* NewTemporary(Handle<String> name);
176 
177   // Adds the specific declaration node to the list of declarations in
178   // this scope. The declarations are processed as part of entering
179   // the scope; see codegen.cc:ProcessDeclarations.
180   void AddDeclaration(Declaration* declaration);
181 
182   // ---------------------------------------------------------------------------
183   // Illegal redeclaration support.
184 
185   // Set an expression node that will be executed when the scope is
186   // entered. We only keep track of one illegal redeclaration node per
187   // scope - the first one - so if you try to set it multiple times
188   // the additional requests will be silently ignored.
189   void SetIllegalRedeclaration(Expression* expression);
190 
191   // Visit the illegal redeclaration expression. Do not call if the
192   // scope doesn't have an illegal redeclaration node.
193   void VisitIllegalRedeclaration(AstVisitor* visitor);
194 
195   // Check if the scope has (at least) one illegal redeclaration.
HasIllegalRedeclaration()196   bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }
197 
198 
199   // ---------------------------------------------------------------------------
200   // Scope-specific info.
201 
202   // Inform the scope that the corresponding code contains a with statement.
RecordWithStatement()203   void RecordWithStatement() { scope_contains_with_ = true; }
204 
205   // Inform the scope that the corresponding code contains an eval call.
RecordEvalCall()206   void RecordEvalCall() { scope_calls_eval_ = true; }
207 
208   // Enable strict mode for the scope (unless disabled by a global flag).
EnableStrictMode()209   void EnableStrictMode() {
210     strict_mode_ = FLAG_strict_mode;
211   }
212 
213   // ---------------------------------------------------------------------------
214   // Predicates.
215 
216   // Specific scope types.
is_eval_scope()217   bool is_eval_scope() const { return type_ == EVAL_SCOPE; }
is_function_scope()218   bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
is_global_scope()219   bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
is_strict_mode()220   bool is_strict_mode() const { return strict_mode_; }
221 
222   // Information about which scopes calls eval.
calls_eval()223   bool calls_eval() const { return scope_calls_eval_; }
outer_scope_calls_eval()224   bool outer_scope_calls_eval() const { return outer_scope_calls_eval_; }
225 
226   // Is this scope inside a with statement.
inside_with()227   bool inside_with() const { return scope_inside_with_; }
228   // Does this scope contain a with statement.
contains_with()229   bool contains_with() const { return scope_contains_with_; }
230 
231   // The scope immediately surrounding this scope, or NULL.
outer_scope()232   Scope* outer_scope() const { return outer_scope_; }
233 
234   // ---------------------------------------------------------------------------
235   // Accessors.
236 
237   // A new variable proxy corresponding to the (function) receiver.
receiver()238   VariableProxy* receiver() const {
239     VariableProxy* proxy =
240         new VariableProxy(FACTORY->this_symbol(), true, false);
241     proxy->BindTo(receiver_);
242     return proxy;
243   }
244 
245   // The variable holding the function literal for named function
246   // literals, or NULL.
247   // Only valid for function scopes.
function()248   Variable* function() const {
249     ASSERT(is_function_scope());
250     return function_;
251   }
252 
253   // Parameters. The left-most parameter has index 0.
254   // Only valid for function scopes.
parameter(int index)255   Variable* parameter(int index) const {
256     ASSERT(is_function_scope());
257     return params_[index];
258   }
259 
num_parameters()260   int num_parameters() const { return params_.length(); }
261 
262   // The local variable 'arguments' if we need to allocate it; NULL otherwise.
263   // If arguments() exist, arguments_shadow() exists, too.
arguments()264   Variable* arguments() const { return arguments_; }
265 
266   // The '.arguments' shadow variable if we need to allocate it; NULL otherwise.
267   // If arguments_shadow() exist, arguments() exists, too.
arguments_shadow()268   Variable* arguments_shadow() const { return arguments_shadow_; }
269 
270   // Declarations list.
declarations()271   ZoneList<Declaration*>* declarations() { return &decls_; }
272 
273 
274 
275   // ---------------------------------------------------------------------------
276   // Variable allocation.
277 
278   // Collect all used locals in this scope.
279   template<class Allocator>
280   void CollectUsedVariables(List<Variable*, Allocator>* locals);
281 
282   // Resolve and fill in the allocation information for all variables
283   // in this scopes. Must be called *after* all scopes have been
284   // processed (parsed) to ensure that unresolved variables can be
285   // resolved properly.
286   //
287   // In the case of code compiled and run using 'eval', the context
288   // parameter is the context in which eval was called.  In all other
289   // cases the context parameter is an empty handle.
290   void AllocateVariables(Handle<Context> context);
291 
292   // Current number of var or const locals.
num_var_or_const()293   int num_var_or_const() { return num_var_or_const_; }
294 
295   // Result of variable allocation.
num_stack_slots()296   int num_stack_slots() const { return num_stack_slots_; }
num_heap_slots()297   int num_heap_slots() const { return num_heap_slots_; }
298 
299   // Make sure this scope and all outer scopes are eagerly compiled.
ForceEagerCompilation()300   void ForceEagerCompilation()  { force_eager_compilation_ = true; }
301 
302   // Determine if we can use lazy compilation for this scope.
303   bool AllowsLazyCompilation() const;
304 
305   // True if the outer context of this scope is always the global context.
306   virtual bool HasTrivialOuterContext() const;
307 
308   // The number of contexts between this and scope; zero if this == scope.
309   int ContextChainLength(Scope* scope);
310 
311   // ---------------------------------------------------------------------------
312   // Strict mode support.
IsDeclared(Handle<String> name)313   bool IsDeclared(Handle<String> name) {
314     // During formal parameter list parsing the scope only contains
315     // two variables inserted at initialization: "this" and "arguments".
316     // "this" is an invalid parameter name and "arguments" is invalid parameter
317     // name in strict mode. Therefore looking up with the map which includes
318     // "this" and "arguments" in addition to all formal parameters is safe.
319     return variables_.Lookup(name) != NULL;
320   }
321 
322   // ---------------------------------------------------------------------------
323   // Debugging.
324 
325 #ifdef DEBUG
326   void Print(int n = 0);  // n = indentation; n < 0 => don't print recursively
327 #endif
328 
329   // ---------------------------------------------------------------------------
330   // Implementation.
331  protected:
332   friend class ParserFactory;
333 
334   explicit Scope(Type type);
335 
336   // Scope tree.
337   Scope* outer_scope_;  // the immediately enclosing outer scope, or NULL
338   ZoneList<Scope*> inner_scopes_;  // the immediately enclosed inner scopes
339 
340   // The scope type.
341   Type type_;
342 
343   // Debugging support.
344   Handle<String> scope_name_;
345 
346   // The variables declared in this scope:
347   //
348   // All user-declared variables (incl. parameters).  For global scopes
349   // variables may be implicitly 'declared' by being used (possibly in
350   // an inner scope) with no intervening with statements or eval calls.
351   VariableMap variables_;
352   // Compiler-allocated (user-invisible) temporaries.
353   ZoneList<Variable*> temps_;
354   // Parameter list in source order.
355   ZoneList<Variable*> params_;
356   // Variables that must be looked up dynamically.
357   DynamicScopePart* dynamics_;
358   // Unresolved variables referred to from this scope.
359   ZoneList<VariableProxy*> unresolved_;
360   // Declarations.
361   ZoneList<Declaration*> decls_;
362   // Convenience variable.
363   Variable* receiver_;
364   // Function variable, if any; function scopes only.
365   Variable* function_;
366   // Convenience variable; function scopes only.
367   Variable* arguments_;
368   // Convenience variable; function scopes only.
369   Variable* arguments_shadow_;
370 
371   // Illegal redeclaration.
372   Expression* illegal_redecl_;
373 
374   // Scope-specific information.
375   bool scope_inside_with_;  // this scope is inside a 'with' of some outer scope
376   bool scope_contains_with_;  // this scope contains a 'with' statement
377   bool scope_calls_eval_;  // this scope contains an 'eval' call
378   bool strict_mode_;  // this scope is a strict mode scope
379 
380   // Computed via PropagateScopeInfo.
381   bool outer_scope_calls_eval_;
382   bool inner_scope_calls_eval_;
383   bool outer_scope_is_eval_scope_;
384   bool force_eager_compilation_;
385 
386   // Computed as variables are declared.
387   int num_var_or_const_;
388 
389   // Computed via AllocateVariables; function scopes only.
390   int num_stack_slots_;
391   int num_heap_slots_;
392 
393   // Serialized scopes support.
394   Handle<SerializedScopeInfo> scope_info_;
resolved()395   bool resolved() { return !scope_info_.is_null(); }
396 
397   // Create a non-local variable with a given name.
398   // These variables are looked up dynamically at runtime.
399   Variable* NonLocal(Handle<String> name, Variable::Mode mode);
400 
401   // Variable resolution.
402   Variable* LookupRecursive(Handle<String> name,
403                             bool inner_lookup,
404                             Variable** invalidated_local);
405   void ResolveVariable(Scope* global_scope,
406                        Handle<Context> context,
407                        VariableProxy* proxy);
408   void ResolveVariablesRecursively(Scope* global_scope,
409                                    Handle<Context> context);
410 
411   // Scope analysis.
412   bool PropagateScopeInfo(bool outer_scope_calls_eval,
413                           bool outer_scope_is_eval_scope);
414   bool HasTrivialContext() const;
415 
416   // Predicates.
417   bool MustAllocate(Variable* var);
418   bool MustAllocateInContext(Variable* var);
419   bool HasArgumentsParameter();
420 
421   // Variable allocation.
422   void AllocateStackSlot(Variable* var);
423   void AllocateHeapSlot(Variable* var);
424   void AllocateParameterLocals();
425   void AllocateNonParameterLocal(Variable* var);
426   void AllocateNonParameterLocals();
427   void AllocateVariablesRecursively();
428 
429  private:
430   Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info);
431 
AddInnerScope(Scope * inner_scope)432   void AddInnerScope(Scope* inner_scope) {
433     if (inner_scope != NULL) {
434       inner_scopes_.Add(inner_scope);
435       inner_scope->outer_scope_ = this;
436     }
437   }
438 
439   void SetDefaults(Type type,
440                    Scope* outer_scope,
441                    Handle<SerializedScopeInfo> scope_info);
442 };
443 
444 
445 // Scope used during pre-parsing.
446 class DummyScope : public Scope {
447  public:
DummyScope()448   DummyScope()
449       : Scope(GLOBAL_SCOPE),
450         nesting_level_(1),  // Allows us to Leave the initial scope.
451         inside_with_level_(kNotInsideWith) {
452     outer_scope_ = this;
453     scope_inside_with_ = false;
454   }
455 
Initialize(bool inside_with)456   virtual void Initialize(bool inside_with) {
457     nesting_level_++;
458     if (inside_with && inside_with_level_ == kNotInsideWith) {
459       inside_with_level_ = nesting_level_;
460     }
461     ASSERT(inside_with_level_ <= nesting_level_);
462   }
463 
Leave()464   virtual void Leave() {
465     nesting_level_--;
466     ASSERT(nesting_level_ >= 0);
467     if (nesting_level_ < inside_with_level_) {
468       inside_with_level_ = kNotInsideWith;
469     }
470     ASSERT(inside_with_level_ <= nesting_level_);
471   }
472 
Lookup(Handle<String> name)473   virtual Variable* Lookup(Handle<String> name)  { return NULL; }
474 
475   virtual VariableProxy* NewUnresolved(Handle<String> name,
476                                        bool inside_with,
477                                        int position = RelocInfo::kNoPosition) {
478     return NULL;
479   }
480 
NewTemporary(Handle<String> name)481   virtual Variable* NewTemporary(Handle<String> name)  { return NULL; }
482 
HasTrivialOuterContext()483   virtual bool HasTrivialOuterContext() const {
484     return (nesting_level_ == 0 || inside_with_level_ <= 0);
485   }
486 
487  private:
488   static const int kNotInsideWith = -1;
489   // Number of surrounding scopes of the current scope.
490   int nesting_level_;
491   // Nesting level of outermost scope that is contained in a with statement,
492   // or kNotInsideWith if there are no with's around the current scope.
493   int inside_with_level_;
494 };
495 
496 
497 } }  // namespace v8::internal
498 
499 #endif  // V8_SCOPES_H_
500