00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "v8.h"
00029
00030 #include "prettyprinter.h"
00031 #include "scopeinfo.h"
00032 #include "scopes.h"
00033
00034 namespace v8 { namespace internal {
00035
00036
00037
00038
00039 class ZoneAllocator: public Allocator {
00040 public:
00041
00042 virtual ~ZoneAllocator() {}
00043
00044 virtual void* New(size_t size) { return Zone::New(size); }
00045
00046
00047 virtual void Delete(void* p) {}
00048 };
00049
00050
00051 static ZoneAllocator LocalsMapAllocator;
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 static bool Match(void* key1, void* key2) {
00064 String* name1 = *reinterpret_cast<String**>(key1);
00065 String* name2 = *reinterpret_cast<String**>(key2);
00066 ASSERT(name1->IsSymbol());
00067 ASSERT(name2->IsSymbol());
00068 return name1 == name2;
00069 }
00070
00071
00072
00073 LocalsMap::LocalsMap(bool gotta_love_static_overloading) : HashMap() {}
00074
00075 LocalsMap::LocalsMap() : HashMap(Match, &LocalsMapAllocator, 8) {}
00076 LocalsMap::~LocalsMap() {}
00077
00078
00079 Variable* LocalsMap::Declare(Scope* scope,
00080 Handle<String> name,
00081 Variable::Mode mode,
00082 bool is_valid_LHS,
00083 bool is_this) {
00084 HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), true);
00085 if (p->value == NULL) {
00086
00087 ASSERT(p->key == name.location());
00088 p->value = new Variable(scope, name, mode, is_valid_LHS, is_this);
00089 }
00090 return reinterpret_cast<Variable*>(p->value);
00091 }
00092
00093
00094 Variable* LocalsMap::Lookup(Handle<String> name) {
00095 HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), false);
00096 if (p != NULL) {
00097 ASSERT(*reinterpret_cast<String**>(p->key) == *name);
00098 ASSERT(p->value != NULL);
00099 return reinterpret_cast<Variable*>(p->value);
00100 }
00101 return NULL;
00102 }
00103
00104
00105
00106
00107
00108
00109
00110 Scope::Scope()
00111 : inner_scopes_(0),
00112 locals_(false),
00113 temps_(0),
00114 params_(0),
00115 nonlocals_(0),
00116 unresolved_(0),
00117 decls_(0) {
00118 }
00119
00120
00121 Scope::Scope(Scope* outer_scope, Type type)
00122 : outer_scope_(outer_scope),
00123 inner_scopes_(4),
00124 type_(type),
00125 scope_name_(Factory::empty_symbol()),
00126 locals_(),
00127 temps_(4),
00128 params_(4),
00129 nonlocals_(4),
00130 unresolved_(16),
00131 decls_(4),
00132 receiver_(NULL),
00133 function_(NULL),
00134 arguments_(NULL),
00135 arguments_shadow_(NULL),
00136 illegal_redecl_(NULL),
00137 scope_inside_with_(false),
00138 scope_contains_with_(false),
00139 scope_calls_eval_(false),
00140 outer_scope_calls_eval_(false),
00141 inner_scope_calls_eval_(false),
00142 force_eager_compilation_(false),
00143 num_stack_slots_(0),
00144 num_heap_slots_(0) {
00145
00146
00147
00148 ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
00149 ASSERT(!HasIllegalRedeclaration());
00150 }
00151
00152
00153 void Scope::Initialize(bool inside_with) {
00154
00155 if (outer_scope_ != NULL) {
00156 outer_scope_->inner_scopes_.Add(this);
00157 scope_inside_with_ = outer_scope_->scope_inside_with_ || inside_with;
00158 } else {
00159 scope_inside_with_ = inside_with;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 { Variable* var =
00171 locals_.Declare(this, Factory::this_symbol(), Variable::VAR, false, true);
00172 var->rewrite_ = new Slot(var, Slot::PARAMETER, -1);
00173 receiver_ = new VariableProxy(Factory::this_symbol(), true, false);
00174 receiver_->BindTo(var);
00175 }
00176
00177 if (is_function_scope()) {
00178
00179
00180
00181 Declare(Factory::arguments_symbol(), Variable::VAR);
00182 }
00183 }
00184
00185
00186
00187 Variable* Scope::Lookup(Handle<String> name) {
00188 return locals_.Lookup(name);
00189 }
00190
00191
00192 Variable* Scope::DeclareFunctionVar(Handle<String> name) {
00193 ASSERT(is_function_scope() && function_ == NULL);
00194 function_ = new Variable(this, name, Variable::CONST, true, false);
00195 return function_;
00196 }
00197
00198
00199 Variable* Scope::Declare(Handle<String> name, Variable::Mode mode) {
00200
00201
00202
00203 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
00204 return locals_.Declare(this, name, mode, true, false);
00205 }
00206
00207
00208 void Scope::AddParameter(Variable* var) {
00209 ASSERT(is_function_scope());
00210 ASSERT(Lookup(var->name()) == var);
00211 params_.Add(var);
00212 }
00213
00214
00215 VariableProxy* Scope::NewUnresolved(Handle<String> name, bool inside_with) {
00216
00217
00218
00219 VariableProxy* proxy = new VariableProxy(name, false, inside_with);
00220 unresolved_.Add(proxy);
00221 return proxy;
00222 }
00223
00224
00225 void Scope::RemoveUnresolved(VariableProxy* var) {
00226
00227
00228 for (int i = unresolved_.length(); i-- > 0;) {
00229 if (unresolved_[i] == var) {
00230 unresolved_.Remove(i);
00231 return;
00232 }
00233 }
00234 }
00235
00236
00237 VariableProxy* Scope::NewTemporary(Handle<String> name) {
00238 Variable* var = new Variable(this, name, Variable::TEMPORARY, true, false);
00239 VariableProxy* tmp = new VariableProxy(name, false, false);
00240 tmp->BindTo(var);
00241 temps_.Add(var);
00242 return tmp;
00243 }
00244
00245
00246 void Scope::AddDeclaration(Declaration* declaration) {
00247 decls_.Add(declaration);
00248 }
00249
00250
00251 void Scope::SetIllegalRedeclaration(Expression* expression) {
00252
00253
00254 if (!HasIllegalRedeclaration()) {
00255 illegal_redecl_ = expression;
00256 }
00257 ASSERT(HasIllegalRedeclaration());
00258 }
00259
00260
00261 void Scope::VisitIllegalRedeclaration(Visitor* visitor) {
00262 ASSERT(HasIllegalRedeclaration());
00263 illegal_redecl_->Accept(visitor);
00264 }
00265
00266
00267 template<class Allocator>
00268 void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
00269
00270
00271
00272
00273 for (int i = 0; i < temps_.length(); i++) {
00274 Variable* var = temps_[i];
00275 if (var->var_uses()->is_used()) {
00276 locals->Add(var);
00277 }
00278 }
00279 for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
00280 Variable* var = reinterpret_cast<Variable*>(p->value);
00281 if (var->var_uses()->is_used()) {
00282 locals->Add(var);
00283 }
00284 }
00285 }
00286
00287
00288
00289 template void Scope::CollectUsedVariables(
00290 List<Variable*, FreeStoreAllocationPolicy>* locals);
00291 template void Scope::CollectUsedVariables(
00292 List<Variable*, PreallocatedStorage>* locals);
00293
00294
00295 void Scope::AllocateVariables() {
00296 ASSERT(outer_scope_ == NULL);
00297
00298
00299
00300
00301
00302
00303
00304 PropagateScopeInfo(is_eval_scope());
00305
00306
00307 Scope* global_scope = NULL;
00308 if (is_global_scope()) global_scope = this;
00309 ResolveVariablesRecursively(global_scope);
00310
00311
00312 AllocateVariablesRecursively();
00313 }
00314
00315
00316 bool Scope::SupportsEval() const {
00317 return scope_calls_eval_ || inner_scope_calls_eval_;
00318 }
00319
00320
00321 bool Scope::AllowsLazyCompilation() const {
00322 return !force_eager_compilation_ && HasTrivialOuterContext();
00323 }
00324
00325
00326 bool Scope::HasTrivialContext() const {
00327
00328
00329
00330
00331 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
00332 if (scope->is_eval_scope()) return false;
00333 if (scope->scope_inside_with_) return false;
00334 if (scope->num_heap_slots_ > 0) return false;
00335 }
00336 return true;
00337 }
00338
00339
00340 bool Scope::HasTrivialOuterContext() const {
00341 Scope* outer = outer_scope_;
00342 if (outer == NULL) return true;
00343
00344
00345
00346 return !scope_inside_with_ && outer->HasTrivialContext();
00347 }
00348
00349
00350 int Scope::ContextChainLength(Scope* scope) {
00351 int n = 0;
00352 for (Scope* s = this; s != scope; s = s->outer_scope_) {
00353 ASSERT(s != NULL);
00354 if (s->num_heap_slots() > 0) n++;
00355 }
00356 return n;
00357 }
00358
00359
00360 #ifdef DEBUG
00361 static const char* Header(Scope::Type type) {
00362 switch (type) {
00363 case Scope::EVAL_SCOPE: return "eval";
00364 case Scope::FUNCTION_SCOPE: return "function";
00365 case Scope::GLOBAL_SCOPE: return "global";
00366 }
00367 UNREACHABLE();
00368 return NULL;
00369 }
00370
00371
00372 static void Indent(int n, const char* str) {
00373 PrintF("%*s%s", n, "", str);
00374 }
00375
00376
00377 static void PrintName(Handle<String> name) {
00378 SmartPointer<char> s = name->ToCString(DISALLOW_NULLS);
00379 PrintF("%s", *s);
00380 }
00381
00382
00383 static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
00384 if (var->var_uses()->is_used() || var->rewrite() != NULL) {
00385 Indent(indent, Variable::Mode2String(var->mode()));
00386 PrintF(" ");
00387 PrintName(var->name());
00388 PrintF("; // ");
00389 if (var->rewrite() != NULL) PrintF("%s, ", printer->Print(var->rewrite()));
00390 if (var->is_accessed_from_inner_scope()) PrintF("inner scope access, ");
00391 PrintF("var ");
00392 var->var_uses()->Print();
00393 PrintF(", obj ");
00394 var->obj_uses()->Print();
00395 PrintF("\n");
00396 }
00397 }
00398
00399
00400 void Scope::Print(int n) {
00401 int n0 = (n > 0 ? n : 0);
00402 int n1 = n0 + 2;
00403
00404
00405 Indent(n0, Header(type_));
00406 if (scope_name_->length() > 0) {
00407 PrintF(" ");
00408 PrintName(scope_name_);
00409 }
00410
00411
00412 if (is_function_scope()) {
00413 PrintF(" (");
00414 for (int i = 0; i < params_.length(); i++) {
00415 if (i > 0) PrintF(", ");
00416 PrintName(params_[i]->name());
00417 }
00418 PrintF(")");
00419 }
00420
00421 PrintF(" {\n");
00422
00423
00424 if (function_ != NULL) {
00425 Indent(n1, "// (local) function name: ");
00426 PrintName(function_->name());
00427 PrintF("\n");
00428 }
00429
00430
00431 if (HasTrivialOuterContext()) {
00432 Indent(n1, "// scope has trivial outer context\n");
00433 }
00434 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
00435 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
00436 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
00437 if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
00438 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
00439 if (num_stack_slots_ > 0) { Indent(n1, "// ");
00440 PrintF("%d stack slots\n", num_stack_slots_); }
00441 if (num_heap_slots_ > 0) { Indent(n1, "// ");
00442 PrintF("%d heap slots\n", num_heap_slots_); }
00443
00444
00445 PrettyPrinter printer;
00446 Indent(n1, "// function var\n");
00447 if (function_ != NULL) {
00448 PrintVar(&printer, n1, function_);
00449 }
00450
00451 Indent(n1, "// temporary vars\n");
00452 for (int i = 0; i < temps_.length(); i++) {
00453 PrintVar(&printer, n1, temps_[i]);
00454 }
00455
00456 Indent(n1, "// local vars\n");
00457 for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
00458 Variable* var = reinterpret_cast<Variable*>(p->value);
00459 PrintVar(&printer, n1, var);
00460 }
00461
00462 Indent(n1, "// nonlocal vars\n");
00463 for (int i = 0; i < nonlocals_.length(); i++)
00464 PrintVar(&printer, n1, nonlocals_[i]);
00465
00466
00467 if (n >= 0) {
00468 for (int i = 0; i < inner_scopes_.length(); i++) {
00469 PrintF("\n");
00470 inner_scopes_[i]->Print(n1);
00471 }
00472 }
00473
00474 Indent(n0, "}\n");
00475 }
00476 #endif // DEBUG
00477
00478
00479 Variable* Scope::NonLocal(Handle<String> name) {
00480
00481 for (int i = 0; i < nonlocals_.length(); i++) {
00482 Variable* var = nonlocals_[i];
00483 if (var->name().is_identical_to(name)) {
00484 ASSERT(var->mode() == Variable::DYNAMIC);
00485 return var;
00486 }
00487 }
00488
00489
00490 Variable* var = new Variable(
00491 NULL ,
00492 name, Variable::DYNAMIC, true, false);
00493 nonlocals_.Add(var);
00494
00495
00496 var->rewrite_ = new Slot(var, Slot::LOOKUP, -1);
00497
00498 return var;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508 Variable* Scope::LookupRecursive(Handle<String> name, bool inner_lookup) {
00509
00510
00511
00512
00513 bool guess = scope_calls_eval_;
00514
00515
00516 Variable* var = Lookup(name);
00517
00518 if (var != NULL) {
00519
00520
00521
00522
00523 if (!inner_lookup)
00524 return var;
00525
00526 } else {
00527
00528
00529
00530
00531
00532
00533
00534
00535 if (function_ != NULL && function_->name().is_identical_to(name)) {
00536 var = function_;
00537
00538 } else if (outer_scope_ != NULL) {
00539 var = outer_scope_->LookupRecursive(name, true );
00540
00541
00542
00543
00544 if (scope_inside_with_)
00545 guess = true;
00546 }
00547
00548
00549 if (var == NULL)
00550 return NULL;
00551 }
00552
00553 ASSERT(var != NULL);
00554
00555
00556 if (inner_lookup)
00557 var->is_accessed_from_inner_scope_ = true;
00558
00559
00560 if (guess)
00561 var = NULL;
00562
00563 return var;
00564 }
00565
00566
00567 void Scope::ResolveVariable(Scope* global_scope, VariableProxy* proxy) {
00568 ASSERT(global_scope == NULL || global_scope->is_global_scope());
00569
00570
00571
00572 if (proxy->var() != NULL) return;
00573
00574
00575 Variable* var = LookupRecursive(proxy->name(), false);
00576
00577 if (proxy->inside_with()) {
00578
00579
00580
00581
00582
00583
00584 var = NonLocal(proxy->name());
00585
00586 } else {
00587
00588
00589 if (var == NULL) {
00590
00591
00592
00593
00594
00595
00596
00597 if (!is_global_scope() &&
00598 (is_eval_scope() || outer_scope_calls_eval_ ||
00599 scope_calls_eval_ || scope_inside_with_)) {
00600
00601
00602 var = NonLocal(proxy->name());
00603
00604 } else {
00605
00606 ASSERT(global_scope != NULL);
00607 var = new Variable(global_scope, proxy->name(),
00608 Variable::DYNAMIC, true, false);
00609
00610
00611
00612
00613
00614
00615
00616
00617 }
00618 }
00619 }
00620
00621 proxy->BindTo(var);
00622 }
00623
00624
00625 void Scope::ResolveVariablesRecursively(Scope* global_scope) {
00626 ASSERT(global_scope == NULL || global_scope->is_global_scope());
00627
00628
00629 for (int i = 0; i < unresolved_.length(); i++) {
00630 ResolveVariable(global_scope, unresolved_[i]);
00631 }
00632
00633
00634 for (int i = 0; i < inner_scopes_.length(); i++) {
00635 inner_scopes_[i]->ResolveVariablesRecursively(global_scope);
00636 }
00637 }
00638
00639
00640 bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval) {
00641 if (outer_scope_calls_eval) {
00642 outer_scope_calls_eval_ = true;
00643 }
00644
00645 bool b = scope_calls_eval_ || outer_scope_calls_eval_;
00646 for (int i = 0; i < inner_scopes_.length(); i++) {
00647 Scope* inner_scope = inner_scopes_[i];
00648 if (inner_scope->PropagateScopeInfo(b)) {
00649 inner_scope_calls_eval_ = true;
00650 }
00651 if (inner_scope->force_eager_compilation_) {
00652 force_eager_compilation_ = true;
00653 }
00654 }
00655
00656 return scope_calls_eval_ || inner_scope_calls_eval_;
00657 }
00658
00659
00660 bool Scope::MustAllocate(Variable* var) {
00661
00662
00663
00664 if ((var->is_this() || var->name()->length() > 0) &&
00665 (var->is_accessed_from_inner_scope_ ||
00666 scope_calls_eval_ || inner_scope_calls_eval_ ||
00667 scope_contains_with_ || var->is_global())) {
00668 var->var_uses()->RecordAccess(1);
00669 }
00670 return var->var_uses()->is_used();
00671 }
00672
00673
00674 bool Scope::MustAllocateInContext(Variable* var) {
00675
00676
00677
00678
00679
00680
00681 return
00682 var->mode() != Variable::TEMPORARY &&
00683 (var->is_accessed_from_inner_scope_ ||
00684 scope_calls_eval_ || inner_scope_calls_eval_ ||
00685 scope_contains_with_ || var->is_global());
00686 }
00687
00688
00689 bool Scope::HasArgumentsParameter() {
00690 for (int i = 0; i < params_.length(); i++) {
00691 if (params_[i]->name().is_identical_to(Factory::arguments_symbol()))
00692 return true;
00693 }
00694 return false;
00695 }
00696
00697
00698 void Scope::AllocateStackSlot(Variable* var) {
00699 var->rewrite_ = new Slot(var, Slot::LOCAL, num_stack_slots_++);
00700 }
00701
00702
00703 void Scope::AllocateHeapSlot(Variable* var) {
00704 var->rewrite_ = new Slot(var, Slot::CONTEXT, num_heap_slots_++);
00705 }
00706
00707
00708 void Scope::AllocateParameterLocals() {
00709 ASSERT(is_function_scope());
00710 Variable* arguments = Lookup(Factory::arguments_symbol());
00711 ASSERT(arguments != NULL);
00712 if (MustAllocate(arguments) && !HasArgumentsParameter()) {
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 arguments_ = new VariableProxy(Factory::arguments_symbol(), false, false);
00742 arguments_->BindTo(arguments);
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753 Variable* arguments_shadow =
00754 new Variable(this, Factory::arguments_shadow_symbol(),
00755 Variable::INTERNAL, true, false);
00756 arguments_shadow_ =
00757 new VariableProxy(Factory::arguments_shadow_symbol(), false, false);
00758 arguments_shadow_->BindTo(arguments_shadow);
00759 temps_.Add(arguments_shadow);
00760
00761
00762 for (int i = 0; i < params_.length(); i++) {
00763 Variable* var = params_[i];
00764 ASSERT(var->scope() == this);
00765 if (MustAllocate(var)) {
00766 if (MustAllocateInContext(var)) {
00767
00768
00769
00770 arguments_shadow->is_accessed_from_inner_scope_ = true;
00771 }
00772 var->rewrite_ =
00773 new Property(arguments_shadow_,
00774 new Literal(Handle<Object>(Smi::FromInt(i))),
00775 RelocInfo::kNoPosition);
00776 arguments_shadow->var_uses()->RecordUses(var->var_uses());
00777 }
00778 }
00779
00780 } else {
00781
00782
00783
00784
00785
00786 for (int i = 0; i < params_.length(); i++) {
00787 Variable* var = params_[i];
00788 ASSERT(var->scope() == this);
00789 if (MustAllocate(var)) {
00790 if (MustAllocateInContext(var)) {
00791 ASSERT(var->rewrite_ == NULL ||
00792 (var->slot() != NULL && var->slot()->type() == Slot::CONTEXT));
00793 if (var->rewrite_ == NULL) {
00794
00795
00796 AllocateHeapSlot(var);
00797 }
00798 } else {
00799 ASSERT(var->rewrite_ == NULL ||
00800 (var->slot() != NULL &&
00801 var->slot()->type() == Slot::PARAMETER));
00802
00803
00804
00805
00806 var->rewrite_ = new Slot(var, Slot::PARAMETER, i);
00807 }
00808 }
00809 }
00810 }
00811 }
00812
00813
00814 void Scope::AllocateNonParameterLocal(Variable* var) {
00815 ASSERT(var->scope() == this);
00816 ASSERT(var->rewrite_ == NULL ||
00817 (!var->IsVariable(Factory::result_symbol())) ||
00818 (var->slot() == NULL || var->slot()->type() != Slot::LOCAL));
00819 if (MustAllocate(var) && var->rewrite_ == NULL) {
00820 if (MustAllocateInContext(var)) {
00821 AllocateHeapSlot(var);
00822 } else {
00823 AllocateStackSlot(var);
00824 }
00825 }
00826 }
00827
00828
00829 void Scope::AllocateNonParameterLocals() {
00830
00831
00832
00833
00834
00835 if (FLAG_usage_computation) {
00836
00837 }
00838
00839 for (int i = 0; i < temps_.length(); i++) {
00840 AllocateNonParameterLocal(temps_[i]);
00841 }
00842
00843 for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
00844 Variable* var = reinterpret_cast<Variable*>(p->value);
00845 AllocateNonParameterLocal(var);
00846 }
00847
00848
00849
00850
00851
00852 if (function_ != NULL) {
00853 AllocateNonParameterLocal(function_);
00854 }
00855 }
00856
00857
00858 void Scope::AllocateVariablesRecursively() {
00859
00860 num_stack_slots_ = 0;
00861 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
00862
00863
00864 for (int i = 0; i < inner_scopes_.length(); i++) {
00865 inner_scopes_[i]->AllocateVariablesRecursively();
00866 }
00867
00868
00869
00870 if (is_function_scope()) AllocateParameterLocals();
00871 AllocateNonParameterLocals();
00872
00873
00874 bool must_have_local_context = false;
00875 if (scope_calls_eval_ || scope_contains_with_) {
00876
00877
00878
00879
00880
00881 must_have_local_context = is_function_scope();
00882 }
00883
00884
00885
00886 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
00887 !must_have_local_context) {
00888 num_heap_slots_ = 0;
00889 }
00890
00891
00892 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
00893 }
00894
00895 } }