1 // Copyright 2006-2008 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 #include "v8.h" 29 30 #include "bootstrapper.h" 31 #include "debug.h" 32 #include "scopeinfo.h" 33 34 namespace v8 { 35 namespace internal { 36 37 JSBuiltinsObject* Context::builtins() { 38 GlobalObject* object = global(); 39 if (object->IsJSGlobalObject()) { 40 return JSGlobalObject::cast(object)->builtins(); 41 } else { 42 ASSERT(object->IsJSBuiltinsObject()); 43 return JSBuiltinsObject::cast(object); 44 } 45 } 46 47 48 Context* Context::global_context() { 49 // Fast case: the global object for this context has been set. In 50 // that case, the global object has a direct pointer to the global 51 // context. 52 if (global()->IsGlobalObject()) { 53 return global()->global_context(); 54 } 55 56 // During bootstrapping, the global object might not be set and we 57 // have to search the context chain to find the global context. 58 ASSERT(Bootstrapper::IsActive()); 59 Context* current = this; 60 while (!current->IsGlobalContext()) { 61 JSFunction* closure = JSFunction::cast(current->closure()); 62 current = Context::cast(closure->context()); 63 } 64 return current; 65 } 66 67 68 JSObject* Context::global_proxy() { 69 return global_context()->global_proxy_object(); 70 } 71 72 void Context::set_global_proxy(JSObject* object) { 73 global_context()->set_global_proxy_object(object); 74 } 75 76 77 Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, 78 int* index_, PropertyAttributes* attributes) { 79 Handle<Context> context(this); 80 81 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; 82 *index_ = -1; 83 *attributes = ABSENT; 84 85 if (FLAG_trace_contexts) { 86 PrintF("Context::Lookup("); 87 name->ShortPrint(); 88 PrintF(")\n"); 89 } 90 91 do { 92 if (FLAG_trace_contexts) { 93 PrintF(" - looking in context %p", *context); 94 if (context->IsGlobalContext()) PrintF(" (global context)"); 95 PrintF("\n"); 96 } 97 98 // check extension/with object 99 if (context->has_extension()) { 100 Handle<JSObject> extension = Handle<JSObject>(context->extension()); 101 // Context extension objects needs to behave as if they have no 102 // prototype. So even if we want to follow prototype chains, we 103 // need to only do a local lookup for context extension objects. 104 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || 105 extension->IsJSContextExtensionObject()) { 106 *attributes = extension->GetLocalPropertyAttribute(*name); 107 } else { 108 *attributes = extension->GetPropertyAttribute(*name); 109 } 110 if (*attributes != ABSENT) { 111 // property found 112 if (FLAG_trace_contexts) { 113 PrintF("=> found property in context object %p\n", *extension); 114 } 115 return extension; 116 } 117 } 118 119 if (context->is_function_context()) { 120 // we have context-local slots 121 122 // check non-parameter locals in context 123 Handle<Code> code(context->closure()->code()); 124 Variable::Mode mode; 125 int index = ScopeInfo<>::ContextSlotIndex(*code, *name, &mode); 126 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); 127 if (index >= 0) { 128 // slot found 129 if (FLAG_trace_contexts) { 130 PrintF("=> found local in context slot %d (mode = %d)\n", 131 index, mode); 132 } 133 *index_ = index; 134 // Note: Fixed context slots are statically allocated by the compiler. 135 // Statically allocated variables always have a statically known mode, 136 // which is the mode with which they were declared when added to the 137 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically 138 // declared variables that were introduced through declaration nodes) 139 // must not appear here. 140 switch (mode) { 141 case Variable::INTERNAL: // fall through 142 case Variable::VAR: *attributes = NONE; break; 143 case Variable::CONST: *attributes = READ_ONLY; break; 144 case Variable::DYNAMIC: UNREACHABLE(); break; 145 case Variable::DYNAMIC_GLOBAL: UNREACHABLE(); break; 146 case Variable::DYNAMIC_LOCAL: UNREACHABLE(); break; 147 case Variable::TEMPORARY: UNREACHABLE(); break; 148 } 149 return context; 150 } 151 152 // check parameter locals in context 153 int param_index = ScopeInfo<>::ParameterIndex(*code, *name); 154 if (param_index >= 0) { 155 // slot found. 156 int index = 157 ScopeInfo<>::ContextSlotIndex(*code, 158 Heap::arguments_shadow_symbol(), 159 NULL); 160 ASSERT(index >= 0); // arguments must exist and be in the heap context 161 Handle<JSObject> arguments(JSObject::cast(context->get(index))); 162 ASSERT(arguments->HasLocalProperty(Heap::length_symbol())); 163 if (FLAG_trace_contexts) { 164 PrintF("=> found parameter %d in arguments object\n", param_index); 165 } 166 *index_ = param_index; 167 *attributes = NONE; 168 return arguments; 169 } 170 171 // check intermediate context (holding only the function name variable) 172 if (follow_context_chain) { 173 int index = ScopeInfo<>::FunctionContextSlotIndex(*code, *name); 174 if (index >= 0) { 175 // slot found 176 if (FLAG_trace_contexts) { 177 PrintF("=> found intermediate function in context slot %d\n", 178 index); 179 } 180 *index_ = index; 181 *attributes = READ_ONLY; 182 return context; 183 } 184 } 185 } 186 187 // proceed with enclosing context 188 if (context->IsGlobalContext()) { 189 follow_context_chain = false; 190 } else if (context->is_function_context()) { 191 context = Handle<Context>(Context::cast(context->closure()->context())); 192 } else { 193 context = Handle<Context>(context->previous()); 194 } 195 } while (follow_context_chain); 196 197 // slot not found 198 if (FLAG_trace_contexts) { 199 PrintF("=> no property/slot found\n"); 200 } 201 return Handle<Object>::null(); 202 } 203 204 205 bool Context::GlobalIfNotShadowedByEval(Handle<String> name) { 206 Context* context = this; 207 208 // Check that there is no local with the given name in contexts 209 // before the global context and check that there are no context 210 // extension objects (conservative check for with statements). 211 while (!context->IsGlobalContext()) { 212 // Check if the context is a potentially a with context. 213 if (context->has_extension()) return false; 214 215 // Not a with context so it must be a function context. 216 ASSERT(context->is_function_context()); 217 218 // Check non-parameter locals. 219 Handle<Code> code(context->closure()->code()); 220 Variable::Mode mode; 221 int index = ScopeInfo<>::ContextSlotIndex(*code, *name, &mode); 222 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); 223 if (index >= 0) return false; 224 225 // Check parameter locals. 226 int param_index = ScopeInfo<>::ParameterIndex(*code, *name); 227 if (param_index >= 0) return false; 228 229 // Check context only holding the function name variable. 230 index = ScopeInfo<>::FunctionContextSlotIndex(*code, *name); 231 if (index >= 0) return false; 232 context = Context::cast(context->closure()->context()); 233 } 234 235 // No local or potential with statement found so the variable is 236 // global unless it is shadowed by an eval-introduced variable. 237 return true; 238 } 239 240 241 #ifdef DEBUG 242 bool Context::IsBootstrappingOrContext(Object* object) { 243 // During bootstrapping we allow all objects to pass as 244 // contexts. This is necessary to fix circular dependencies. 245 return Bootstrapper::IsActive() || object->IsContext(); 246 } 247 248 249 bool Context::IsBootstrappingOrGlobalObject(Object* object) { 250 // During bootstrapping we allow all objects to pass as global 251 // objects. This is necessary to fix circular dependencies. 252 return Bootstrapper::IsActive() || object->IsGlobalObject(); 253 } 254 #endif 255 256 } } // namespace v8::internal 257