Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 148 unresolved_(16), | 148 unresolved_(16), |
| 149 decls_(4) { | 149 decls_(4) { |
| 150 ASSERT(scope_info != NULL); | 150 ASSERT(scope_info != NULL); |
| 151 SetDefaults(FUNCTION_SCOPE, NULL, scope_info); | 151 SetDefaults(FUNCTION_SCOPE, NULL, scope_info); |
| 152 ASSERT(resolved()); | 152 ASSERT(resolved()); |
| 153 if (scope_info->HasHeapAllocatedLocals()) { | 153 if (scope_info->HasHeapAllocatedLocals()) { |
| 154 num_heap_slots_ = scope_info_->NumberOfContextSlots(); | 154 num_heap_slots_ = scope_info_->NumberOfContextSlots(); |
| 155 } | 155 } |
| 156 | 156 |
| 157 AddInnerScope(inner_scope); | 157 AddInnerScope(inner_scope); |
| 158 | |
| 159 // This scope's arguments shadow (if present) is context-allocated if an inner | |
| 160 // scope accesses this one's parameters. Allocate the arguments_shadow_ | |
| 161 // variable if necessary. | |
| 162 Variable::Mode mode; | |
| 163 int arguments_shadow_index = | |
| 164 scope_info_->ContextSlotIndex(Heap::arguments_shadow_symbol(), &mode); | |
| 165 if (arguments_shadow_index >= 0) { | |
| 166 ASSERT(mode == Variable::INTERNAL); | |
| 167 arguments_shadow_ = new Variable(this, | |
| 168 Factory::arguments_shadow_symbol(), | |
| 169 Variable::INTERNAL, | |
| 170 true, | |
| 171 Variable::ARGUMENTS); | |
| 172 arguments_shadow_->set_rewrite( | |
| 173 new Slot(arguments_shadow_, Slot::CONTEXT, arguments_shadow_index)); | |
| 174 arguments_shadow_->set_is_used(true); | |
| 175 } | |
| 176 } | 158 } |
| 177 | 159 |
| 178 | 160 |
| 179 Scope* Scope::DeserializeScopeChain(CompilationInfo* info, | 161 Scope* Scope::DeserializeScopeChain(CompilationInfo* info, |
| 180 Scope* global_scope) { | 162 Scope* global_scope) { |
| 181 ASSERT(!info->closure().is_null()); | 163 ASSERT(!info->closure().is_null()); |
| 182 // If we have a serialized scope info, reuse it. | 164 // If we have a serialized scope info, reuse it. |
| 183 Scope* innermost_scope = NULL; | 165 Scope* innermost_scope = NULL; |
| 184 Scope* scope = NULL; | 166 Scope* scope = NULL; |
| 185 | 167 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 258 true, Variable::ARGUMENTS); | 240 true, Variable::ARGUMENTS); |
| 259 } | 241 } |
| 260 } | 242 } |
| 261 | 243 |
| 262 | 244 |
| 263 Variable* Scope::LocalLookup(Handle<String> name) { | 245 Variable* Scope::LocalLookup(Handle<String> name) { |
| 264 Variable* result = variables_.Lookup(name); | 246 Variable* result = variables_.Lookup(name); |
| 265 if (result != NULL || !resolved()) { | 247 if (result != NULL || !resolved()) { |
| 266 return result; | 248 return result; |
| 267 } | 249 } |
| 268 // If the scope is resolved, we can find a variable in serialized scope info. | 250 // If the scope is resolved, we can find a variable in serialized scope |
| 269 | 251 // info. |
| 270 // We should never lookup 'arguments' in this scope | 252 // |
| 271 // as it is implicitly present in any scope. | 253 // We should never lookup 'arguments' in this scope as it is implicitly |
| 254 // present in every scope. | |
| 272 ASSERT(*name != *Factory::arguments_symbol()); | 255 ASSERT(*name != *Factory::arguments_symbol()); |
| 273 | 256 // There should be no local slot with the given name. |
| 274 // Assert that there is no local slot with the given name. | |
| 275 ASSERT(scope_info_->StackSlotIndex(*name) < 0); | 257 ASSERT(scope_info_->StackSlotIndex(*name) < 0); |
| 276 | 258 |
| 277 // Check context slot lookup. | 259 // Check context slot lookup. |
| 278 Variable::Mode mode; | 260 Variable::Mode mode; |
| 279 int index = scope_info_->ContextSlotIndex(*name, &mode); | 261 int index = scope_info_->ContextSlotIndex(*name, &mode); |
| 280 if (index >= 0) { | 262 if (index < 0) { |
| 281 Variable* var = | 263 // Check parameters. |
| 282 variables_.Declare(this, name, mode, true, Variable::NORMAL); | 264 mode = Variable::VAR; |
| 283 var->set_rewrite(new Slot(var, Slot::CONTEXT, index)); | 265 index = scope_info_->ParameterIndex(*name); |
| 284 return var; | 266 if (index < 0) { |
| 267 // Check the function name. | |
| 268 index = scope_info_->FunctionContextSlotIndex(*name); | |
| 269 if (index < 0) return NULL; | |
| 270 } | |
| 285 } | 271 } |
| 286 | 272 |
| 287 index = scope_info_->ParameterIndex(*name); | 273 Variable* var = |
| 288 if (index >= 0) { | 274 variables_.Declare(this, name, mode, true, Variable::NORMAL); |
| 289 // ".arguments" must be present in context slots. | 275 var->set_rewrite(new Slot(var, Slot::CONTEXT, index)); |
| 290 ASSERT(arguments_shadow_ != NULL); | 276 return var; |
| 291 Variable* var = | |
| 292 variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); | |
| 293 Property* rewrite = | |
| 294 new Property(new VariableProxy(arguments_shadow_), | |
| 295 new Literal(Handle<Object>(Smi::FromInt(index))), | |
| 296 RelocInfo::kNoPosition, | |
| 297 Property::SYNTHETIC); | |
| 298 rewrite->set_is_arguments_access(true); | |
| 299 var->set_rewrite(rewrite); | |
| 300 return var; | |
| 301 } | |
| 302 | |
| 303 index = scope_info_->FunctionContextSlotIndex(*name); | |
| 304 if (index >= 0) { | |
| 305 // Check that there is no local slot with the given name. | |
| 306 ASSERT(scope_info_->StackSlotIndex(*name) < 0); | |
| 307 Variable* var = | |
| 308 variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); | |
|
Kevin Millikin (Chromium)
2011/03/17 13:47:46
I made these variables all have mode VAR, but I th
| |
| 309 var->set_rewrite(new Slot(var, Slot::CONTEXT, index)); | |
| 310 return var; | |
| 311 } | |
| 312 | |
| 313 return NULL; | |
| 314 } | 277 } |
| 315 | 278 |
| 316 | 279 |
| 317 Variable* Scope::Lookup(Handle<String> name) { | 280 Variable* Scope::Lookup(Handle<String> name) { |
| 318 for (Scope* scope = this; | 281 for (Scope* scope = this; |
| 319 scope != NULL; | 282 scope != NULL; |
| 320 scope = scope->outer_scope()) { | 283 scope = scope->outer_scope()) { |
| 321 Variable* var = scope->LocalLookup(name); | 284 Variable* var = scope->LocalLookup(name); |
| 322 if (var != NULL) return var; | 285 if (var != NULL) return var; |
| 323 } | 286 } |
| (...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 883 void Scope::AllocateHeapSlot(Variable* var) { | 846 void Scope::AllocateHeapSlot(Variable* var) { |
| 884 var->set_rewrite(new Slot(var, Slot::CONTEXT, num_heap_slots_++)); | 847 var->set_rewrite(new Slot(var, Slot::CONTEXT, num_heap_slots_++)); |
| 885 } | 848 } |
| 886 | 849 |
| 887 | 850 |
| 888 void Scope::AllocateParameterLocals() { | 851 void Scope::AllocateParameterLocals() { |
| 889 ASSERT(is_function_scope()); | 852 ASSERT(is_function_scope()); |
| 890 Variable* arguments = LocalLookup(Factory::arguments_symbol()); | 853 Variable* arguments = LocalLookup(Factory::arguments_symbol()); |
| 891 ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly | 854 ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly |
| 892 | 855 |
| 893 // Parameters are rewritten to arguments[i] if 'arguments' is used in | 856 bool uses_nonstrict_arguments = false; |
| 894 // a non-strict mode function. Strict mode code doesn't alias arguments. | |
| 895 bool rewrite_parameters = false; | |
| 896 | 857 |
| 897 if (MustAllocate(arguments) && !HasArgumentsParameter()) { | 858 if (MustAllocate(arguments) && !HasArgumentsParameter()) { |
| 898 // 'arguments' is used. Unless there is also a parameter called | 859 // 'arguments' is used. Unless there is also a parameter called |
| 899 // 'arguments', we must be conservative and access all parameters via | 860 // 'arguments', we must be conservative and allocate all parameters to |
| 900 // the arguments object: The i'th parameter is rewritten into | 861 // the context assuming they will be captured by the arguments object. |
| 901 // '.arguments[i]' (*). If we have a parameter named 'arguments', a | 862 // (*). If we have a parameter named 'arguments', a (new) value is |
|
Mads Ager (chromium)
2011/03/17 14:28:10
The (*) is not gone. :-)
Kevin Millikin (Chromium)
2011/03/17 14:35:04
It is now.
| |
| 902 // (new) value is always assigned to it via the function | 863 // always assigned to it via the function invocation. Then 'arguments' |
| 903 // invocation. Then 'arguments' denotes that specific parameter value | 864 // denotes that specific parameter value and cannot be used to access |
| 904 // and cannot be used to access the parameters, which is why we don't | 865 // the parameters, which is why we don't need to allocate an arguments |
| 905 // need to rewrite in that case. | 866 // object in that case. |
| 906 // | |
| 907 // (*) Instead of having a parameter called 'arguments', we may have an | |
| 908 // assignment to 'arguments' in the function body, at some arbitrary | |
| 909 // point in time (possibly through an 'eval()' call!). After that | |
| 910 // assignment any re-write of parameters would be invalid (was bug | |
| 911 // 881452). Thus, we introduce a shadow '.arguments' | |
| 912 // variable which also points to the arguments object. For rewrites we | |
| 913 // use '.arguments' which remains valid even if we assign to | |
| 914 // 'arguments'. To summarize: If we need to rewrite, we allocate an | |
| 915 // 'arguments' object dynamically upon function invocation. The compiler | |
| 916 // introduces 2 local variables 'arguments' and '.arguments', both of | |
| 917 // which originally point to the arguments object that was | |
| 918 // allocated. All parameters are rewritten into property accesses via | |
| 919 // the '.arguments' variable. Thus, any changes to properties of | |
| 920 // 'arguments' are reflected in the variables and vice versa. If the | |
| 921 // 'arguments' variable is changed, '.arguments' still points to the | |
| 922 // correct arguments object and the rewrites still work. | |
| 923 | 867 |
| 924 // We are using 'arguments'. Tell the code generator that is needs to | 868 // We are using 'arguments'. Tell the code generator that is needs to |
| 925 // allocate the arguments object by setting 'arguments_'. | 869 // allocate the arguments object by setting 'arguments_'. |
| 926 arguments_ = arguments; | 870 arguments_ = arguments; |
| 927 | 871 |
| 928 // In strict mode 'arguments' does not alias formal parameters. | 872 // In strict mode 'arguments' does not alias formal parameters. |
| 929 // Therefore in strict mode we allocate parameters as if 'arguments' | 873 // Therefore in strict mode we allocate parameters as if 'arguments' |
| 930 // were not used. | 874 // were not used. |
| 931 rewrite_parameters = !is_strict_mode(); | 875 uses_nonstrict_arguments = !is_strict_mode(); |
| 932 } | 876 } |
| 933 | 877 |
| 934 if (rewrite_parameters) { | 878 // The same parameter may occur multiple times in the parameters_ list. |
| 935 // We also need the '.arguments' shadow variable. Declare it and create | 879 // If it does, and if it is not copied into the context object, it must |
| 936 // and bind the corresponding proxy. It's ok to declare it only now | 880 // receive the highest parameter index for that parameter; thus iteration |
| 937 // because it's a local variable that is allocated after the parameters | 881 // order is relevant! |
| 938 // have been allocated. | 882 for (int i = params_.length() - 1; i >= 0; --i) { |
| 939 // | 883 Variable* var = params_[i]; |
| 940 // Note: This is "almost" at temporary variable but we cannot use | 884 ASSERT(var->scope() == this); |
| 941 // NewTemporary() because the mode needs to be INTERNAL since this | 885 if (uses_nonstrict_arguments) { |
| 942 // variable may be allocated in the heap-allocated context (temporaries | 886 // Give the parameter a use from an inner scope, to force allocation |
| 943 // are never allocated in the context). | 887 // to the context. |
| 944 arguments_shadow_ = new Variable(this, | 888 var->MarkAsAccessedFromInnerScope(); |
| 945 Factory::arguments_shadow_symbol(), | |
| 946 Variable::INTERNAL, | |
| 947 true, | |
| 948 Variable::ARGUMENTS); | |
| 949 arguments_shadow_->set_is_used(true); | |
| 950 temps_.Add(arguments_shadow_); | |
| 951 | |
| 952 // Allocate the parameters by rewriting them into '.arguments[i]' accesses. | |
| 953 for (int i = 0; i < params_.length(); i++) { | |
| 954 Variable* var = params_[i]; | |
| 955 ASSERT(var->scope() == this); | |
| 956 if (MustAllocate(var)) { | |
| 957 if (MustAllocateInContext(var)) { | |
| 958 // It is ok to set this only now, because arguments is a local | |
| 959 // variable that is allocated after the parameters have been | |
| 960 // allocated. | |
| 961 arguments_shadow_->MarkAsAccessedFromInnerScope(); | |
| 962 } | |
| 963 Property* rewrite = | |
| 964 new Property(new VariableProxy(arguments_shadow_), | |
| 965 new Literal(Handle<Object>(Smi::FromInt(i))), | |
| 966 RelocInfo::kNoPosition, | |
| 967 Property::SYNTHETIC); | |
| 968 rewrite->set_is_arguments_access(true); | |
| 969 var->set_rewrite(rewrite); | |
| 970 } | |
| 971 } | 889 } |
| 972 | 890 |
| 973 } else { | 891 if (MustAllocate(var)) { |
| 974 // The arguments object is not used, so we can access parameters directly. | 892 if (MustAllocateInContext(var)) { |
| 975 // The same parameter may occur multiple times in the parameters_ list. | 893 ASSERT(var->rewrite() == NULL || var->IsContextSlot()); |
| 976 // If it does, and if it is not copied into the context object, it must | 894 if (var->rewrite() == NULL) { |
| 977 // receive the highest parameter index for that parameter; thus iteration | 895 AllocateHeapSlot(var); |
| 978 // order is relevant! | 896 } |
| 979 for (int i = 0; i < params_.length(); i++) { | 897 } else { |
| 980 Variable* var = params_[i]; | 898 ASSERT(var->rewrite() == NULL || var->IsParameter()); |
| 981 ASSERT(var->scope() == this); | 899 if (var->rewrite() == NULL) { |
| 982 if (MustAllocate(var)) { | |
| 983 if (MustAllocateInContext(var)) { | |
| 984 ASSERT(var->rewrite() == NULL || | |
| 985 (var->AsSlot() != NULL && | |
| 986 var->AsSlot()->type() == Slot::CONTEXT)); | |
| 987 if (var->rewrite() == NULL) { | |
| 988 // Only set the heap allocation if the parameter has not | |
| 989 // been allocated yet. | |
| 990 AllocateHeapSlot(var); | |
| 991 } | |
| 992 } else { | |
| 993 ASSERT(var->rewrite() == NULL || | |
| 994 (var->AsSlot() != NULL && | |
| 995 var->AsSlot()->type() == Slot::PARAMETER)); | |
| 996 // Set the parameter index always, even if the parameter | |
| 997 // was seen before! (We need to access the actual parameter | |
| 998 // supplied for the last occurrence of a multiply declared | |
| 999 // parameter.) | |
| 1000 var->set_rewrite(new Slot(var, Slot::PARAMETER, i)); | 900 var->set_rewrite(new Slot(var, Slot::PARAMETER, i)); |
| 1001 } | 901 } |
| 1002 } | 902 } |
| 1003 } | 903 } |
| 1004 } | 904 } |
| 1005 } | 905 } |
| 1006 | 906 |
| 1007 | 907 |
| 1008 void Scope::AllocateNonParameterLocal(Variable* var) { | 908 void Scope::AllocateNonParameterLocal(Variable* var) { |
| 1009 ASSERT(var->scope() == this); | 909 ASSERT(var->scope() == this); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1077 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && | 977 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && |
| 1078 !must_have_local_context) { | 978 !must_have_local_context) { |
| 1079 num_heap_slots_ = 0; | 979 num_heap_slots_ = 0; |
| 1080 } | 980 } |
| 1081 | 981 |
| 1082 // Allocation done. | 982 // Allocation done. |
| 1083 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); | 983 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); |
| 1084 } | 984 } |
| 1085 | 985 |
| 1086 } } // namespace v8::internal | 986 } } // namespace v8::internal |
| OLD | NEW |