📄 scopes.cc.svn-base
字号:
// which we don't know anything at this point. Thus we must be conservative // and assume they may invoke eval themselves. Eventually we could capture // this information in the ScopeInfo and then use it here (by traversing // the call chain stack, at compile time). PropagateScopeInfo(is_eval_scope()); // 2) Resolve variables. Scope* global_scope = NULL; if (is_global_scope()) global_scope = this; ResolveVariablesRecursively(global_scope); // 3) Allocate variables. AllocateVariablesRecursively();}bool Scope::SupportsEval() const { return scope_calls_eval_ || inner_scope_calls_eval_;}bool Scope::AllowsLazyCompilation() const { return !force_eager_compilation_ && HasTrivialOuterContext();}bool Scope::HasTrivialContext() const { // A function scope has a trivial context if it always is the global // context. We iteratively scan out the context chain to see if // there is anything that makes this scope non-trivial; otherwise we // return true. for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) { if (scope->is_eval_scope()) return false; if (scope->scope_inside_with_) return false; if (scope->num_heap_slots_ > 0) return false; } return true;}bool Scope::HasTrivialOuterContext() const { Scope* outer = outer_scope_; if (outer == NULL) return true; // Note that the outer context may be trivial in general, but the current // scope may be inside a 'with' statement in which case the outer context // for this scope is not trivial. return !scope_inside_with_ && outer->HasTrivialContext();}int Scope::ContextChainLength(Scope* scope) { int n = 0; for (Scope* s = this; s != scope; s = s->outer_scope_) { ASSERT(s != NULL); // scope must be in the scope chain if (s->num_heap_slots() > 0) n++; } return n;}#ifdef DEBUGstatic const char* Header(Scope::Type type) { switch (type) { case Scope::EVAL_SCOPE: return "eval"; case Scope::FUNCTION_SCOPE: return "function"; case Scope::GLOBAL_SCOPE: return "global"; } UNREACHABLE(); return NULL;}static void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str);}static void PrintName(Handle<String> name) { SmartPointer<char> s = name->ToCString(DISALLOW_NULLS); PrintF("%s", *s);}static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) { if (var->var_uses()->is_used() || var->rewrite() != NULL) { Indent(indent, Variable::Mode2String(var->mode())); PrintF(" "); PrintName(var->name()); PrintF("; // "); if (var->rewrite() != NULL) PrintF("%s, ", printer->Print(var->rewrite())); if (var->is_accessed_from_inner_scope()) PrintF("inner scope access, "); PrintF("var "); var->var_uses()->Print(); PrintF(", obj "); var->obj_uses()->Print(); PrintF("\n"); }}void Scope::Print(int n) { int n0 = (n > 0 ? n : 0); int n1 = n0 + 2; // indentation // Print header. Indent(n0, Header(type_)); if (scope_name_->length() > 0) { PrintF(" "); PrintName(scope_name_); } // Print parameters, if any. if (is_function_scope()) { PrintF(" ("); for (int i = 0; i < params_.length(); i++) { if (i > 0) PrintF(", "); PrintName(params_[i]->name()); } PrintF(")"); } PrintF(" {\n"); // Function name, if any (named function literals, only). if (function_ != NULL) { Indent(n1, "// (local) function name: "); PrintName(function_->name()); PrintF("\n"); } // Scope info. if (HasTrivialOuterContext()) { Indent(n1, "// scope has trivial outer context\n"); } if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n"); if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n"); if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n"); if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n"); if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n"); if (num_stack_slots_ > 0) { Indent(n1, "// "); PrintF("%d stack slots\n", num_stack_slots_); } if (num_heap_slots_ > 0) { Indent(n1, "// "); PrintF("%d heap slots\n", num_heap_slots_); } // Print locals. PrettyPrinter printer; Indent(n1, "// function var\n"); if (function_ != NULL) { PrintVar(&printer, n1, function_); } Indent(n1, "// temporary vars\n"); for (int i = 0; i < temps_.length(); i++) { PrintVar(&printer, n1, temps_[i]); } Indent(n1, "// local vars\n"); for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) { Variable* var = reinterpret_cast<Variable*>(p->value); PrintVar(&printer, n1, var); } Indent(n1, "// nonlocal vars\n"); for (int i = 0; i < nonlocals_.length(); i++) PrintVar(&printer, n1, nonlocals_[i]); // Print inner scopes (disable by providing negative n). if (n >= 0) { for (int i = 0; i < inner_scopes_.length(); i++) { PrintF("\n"); inner_scopes_[i]->Print(n1); } } Indent(n0, "}\n");}#endif // DEBUGVariable* Scope::NonLocal(Handle<String> name) { // Space optimization: reuse existing non-local with the same name. for (int i = 0; i < nonlocals_.length(); i++) { Variable* var = nonlocals_[i]; if (var->name().is_identical_to(name)) { ASSERT(var->mode() == Variable::DYNAMIC); return var; } } // Otherwise create a new new-local and add it to the list. Variable* var = new Variable( NULL /* we don't know the scope */, name, Variable::DYNAMIC, true, false); nonlocals_.Add(var); // Allocate it by giving it a dynamic lookup. var->rewrite_ = new Slot(var, Slot::LOOKUP, -1); return var;}// Lookup a variable starting with this scope. The result is either// the statically resolved (local!) variable belonging to an outer scope,// or NULL. It may be NULL because a) we couldn't find a variable, or b)// because the variable is just a guess (and may be shadowed by another// variable that is introduced dynamically via an 'eval' call or a 'with'// statement).Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) { // If we find a variable, but the current scope calls 'eval', the found // variable may not be the correct one (the 'eval' may introduce a // property with the same name). In that case, remember that the variable // found is just a guess. bool guess = scope_calls_eval_; // Try to find the variable in this scope. Variable* var = Lookup(name); if (var != NULL) { // We found a variable. If this is not an inner lookup, we are done. // (Even if there is an 'eval' in this scope which introduces the // same variable again, the resulting variable remains the same. // Note that enclosing 'with' statements are handled at the call site.) if (!inner_lookup) return var; } else { // We did not find a variable locally. Check against the function variable, // if any. We can do this for all scopes, since the function variable is // only present - if at all - for function scopes. // // This lookup corresponds to a lookup in the "intermediate" scope sitting // between this scope and the outer scope. (ECMA-262, 3rd., requires that // the name of named function literal is kept in an intermediate scope // inbetween this scope and the next outer scope.) if (function_ != NULL && function_->name().is_identical_to(name)) { var = function_; } else if (outer_scope_ != NULL) { var = outer_scope_->LookupRecursive(name, true /* inner lookup */); // We may have found a variable in an outer scope. However, if // the current scope is inside a 'with', the actual variable may // be a property introduced via the 'with' statement. Then, the // variable we may have found is just a guess. if (scope_inside_with_) guess = true; } // If we did not find a variable, we are done. if (var == NULL) return NULL; } ASSERT(var != NULL); // If this is a lookup from an inner scope, mark the variable. if (inner_lookup) var->is_accessed_from_inner_scope_ = true; // If the variable we have found is just a guess, invalidate the result. if (guess) var = NULL; return var;}void Scope::ResolveVariable(Scope* global_scope, VariableProxy* proxy) { ASSERT(global_scope == NULL || global_scope->is_global_scope()); // If the proxy is already resolved there's nothing to do // (functions and consts may be resolved by the parser). if (proxy->var() != NULL) return; // Otherwise, try to resolve the variable. Variable* var = LookupRecursive(proxy->name(), false); if (proxy->inside_with()) { // If we are inside a local 'with' statement, all bets are off // and we cannot resolve the proxy to a local variable even if // we found an outer matching variable. // Note that we must do a lookup anyway, because if we find one, // we must mark that variable as potentially accessed from this // inner scope (the property may not be in the 'with' object). var = NonLocal(proxy->name()); } else { // We are not inside a local 'with' statement. if (var == NULL) { // We did not find the variable. We have a global variable // if we are in the global scope (we know already that we // are outside a 'with' statement) or if there is no way // that the variable might be introduced dynamically (through // a local or outer eval() call, or an outer 'with' statement), // or we don't know about the outer scope (because we are // in an eval scope). if (!is_global_scope() && (is_eval_scope() || outer_scope_calls_eval_ ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -