1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright 2011 the V8 project authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Redistribution and use in source and binary forms, with or without 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// modification, are permitted provided that the following conditions are 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// met: 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// * Redistributions of source code must retain the above copyright 73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// notice, this list of conditions and the following disclaimer. 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// * Redistributions in binary form must reproduce the above 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// copyright notice, this list of conditions and the following 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// disclaimer in the documentation and/or other materials provided 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// with the distribution. 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// * Neither the name of Google Inc. nor the names of its 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// contributors may be used to endorse or promote products derived 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// from this software without specific prior written permission. 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "v8.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "bootstrapper.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "debug.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "scopeinfo.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace v8 { 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace internal { 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochContext* Context::declaration_context() { 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Context* current = this; 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (!current->IsFunctionContext() && !current->IsGlobalContext()) { 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current = current->previous(); 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT(current->closure() == closure()); 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return current; 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochJSBuiltinsObject* Context::builtins() { 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GlobalObject* object = global(); 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (object->IsJSGlobalObject()) { 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return JSGlobalObject::cast(object)->builtins(); 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT(object->IsJSBuiltinsObject()); 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return JSBuiltinsObject::cast(object); 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenContext* Context::global_context() { 5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Fast case: the global object for this context has been set. In 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that case, the global object has a direct pointer to the global 6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // context. 6272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (global()->IsGlobalObject()) { 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return global()->global_context(); 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // During bootstrapping, the global object might not be set and we 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have to search the context chain to find the global context. 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT(Isolate::Current()->bootstrapper()->IsActive()); 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Context* current = this; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (!current->IsGlobalContext()) { 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch JSFunction* closure = JSFunction::cast(current->closure()); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current = Context::cast(closure->context()); 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return current; 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochJSObject* Context::global_proxy() { 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return global_context()->global_proxy_object(); 8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid Context::set_global_proxy(JSObject* object) { 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch global_context()->set_global_proxy_object(object); 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochHandle<Object> Context::Lookup(Handle<String> name, 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ContextLookupFlags flags, 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int* index, 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PropertyAttributes* attributes, 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BindingFlags* binding_flags) { 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Isolate* isolate = GetIsolate(); 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Handle<Context> context(this, isolate); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *index = -1; 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *attributes = ABSENT; 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *binding_flags = MISSING_BINDING; 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (FLAG_trace_contexts) { 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrintF("Context::Lookup("); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch name->ShortPrint(); 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrintF(")\n"); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch do { 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (FLAG_trace_contexts) { 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (context->IsGlobalContext()) PrintF(" (global context)"); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrintF("\n"); 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 1. Check global objects, subjects of with, and extension objects. 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (context->IsGlobalContext() || 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch context->IsWithContext() || 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (context->IsFunctionContext() && context->has_extension())) { 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Handle<JSObject> object(JSObject::cast(context->extension()), isolate); 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Context extension objects needs to behave as if they have no 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // prototype. So even if we want to follow prototype chains, we need 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to only do a local lookup for context extension objects. 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch object->IsJSContextExtensionObject()) { 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *attributes = object->GetLocalPropertyAttribute(*name); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *attributes = object->GetPropertyAttribute(*name); 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (*attributes != ABSENT) { 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (FLAG_trace_contexts) { 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrintF("=> found property in context object %p\n", 130 reinterpret_cast<void*>(*object)); 131 } 132 return object; 133 } 134 } 135 136 // 2. Check the context proper if it has slots. 137 if (context->IsFunctionContext() || context->IsBlockContext()) { 138 // Use serialized scope information of functions and blocks to search 139 // for the context index. 140 Handle<ScopeInfo> scope_info; 141 if (context->IsFunctionContext()) { 142 scope_info = Handle<ScopeInfo>( 143 context->closure()->shared()->scope_info(), isolate); 144 } else { 145 scope_info = Handle<ScopeInfo>( 146 ScopeInfo::cast(context->extension()), isolate); 147 } 148 VariableMode mode; 149 InitializationFlag init_flag; 150 int slot_index = scope_info->ContextSlotIndex(*name, &mode, &init_flag); 151 ASSERT(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); 152 if (slot_index >= 0) { 153 if (FLAG_trace_contexts) { 154 PrintF("=> found local in context slot %d (mode = %d)\n", 155 slot_index, mode); 156 } 157 *index = slot_index; 158 // Note: Fixed context slots are statically allocated by the compiler. 159 // Statically allocated variables always have a statically known mode, 160 // which is the mode with which they were declared when added to the 161 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically 162 // declared variables that were introduced through declaration nodes) 163 // must not appear here. 164 switch (mode) { 165 case INTERNAL: // Fall through. 166 case VAR: 167 *attributes = NONE; 168 *binding_flags = MUTABLE_IS_INITIALIZED; 169 break; 170 case LET: 171 *attributes = NONE; 172 *binding_flags = (init_flag == kNeedsInitialization) 173 ? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED; 174 break; 175 case CONST: 176 *attributes = READ_ONLY; 177 *binding_flags = (init_flag == kNeedsInitialization) 178 ? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED; 179 break; 180 case CONST_HARMONY: 181 *attributes = READ_ONLY; 182 *binding_flags = (init_flag == kNeedsInitialization) 183 ? IMMUTABLE_CHECK_INITIALIZED_HARMONY : 184 IMMUTABLE_IS_INITIALIZED_HARMONY; 185 break; 186 case DYNAMIC: 187 case DYNAMIC_GLOBAL: 188 case DYNAMIC_LOCAL: 189 case TEMPORARY: 190 UNREACHABLE(); 191 break; 192 } 193 return context; 194 } 195 196 // Check the slot corresponding to the intermediate context holding 197 // only the function name variable. 198 if (follow_context_chain && context->IsFunctionContext()) { 199 VariableMode mode; 200 int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); 201 if (function_index >= 0) { 202 if (FLAG_trace_contexts) { 203 PrintF("=> found intermediate function in context slot %d\n", 204 function_index); 205 } 206 *index = function_index; 207 *attributes = READ_ONLY; 208 ASSERT(mode == CONST || mode == CONST_HARMONY); 209 *binding_flags = (mode == CONST) 210 ? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY; 211 return context; 212 } 213 } 214 215 } else if (context->IsCatchContext()) { 216 // Catch contexts have the variable name in the extension slot. 217 if (name->Equals(String::cast(context->extension()))) { 218 if (FLAG_trace_contexts) { 219 PrintF("=> found in catch context\n"); 220 } 221 *index = Context::THROWN_OBJECT_INDEX; 222 *attributes = NONE; 223 *binding_flags = MUTABLE_IS_INITIALIZED; 224 return context; 225 } 226 } 227 228 // 3. Prepare to continue with the previous (next outermost) context. 229 if (context->IsGlobalContext()) { 230 follow_context_chain = false; 231 } else { 232 context = Handle<Context>(context->previous(), isolate); 233 } 234 } while (follow_context_chain); 235 236 if (FLAG_trace_contexts) { 237 PrintF("=> no property/slot found\n"); 238 } 239 return Handle<Object>::null(); 240} 241 242 243void Context::AddOptimizedFunction(JSFunction* function) { 244 ASSERT(IsGlobalContext()); 245#ifdef DEBUG 246 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); 247 while (!element->IsUndefined()) { 248 CHECK(element != function); 249 element = JSFunction::cast(element)->next_function_link(); 250 } 251 252 CHECK(function->next_function_link()->IsUndefined()); 253 254 // Check that the context belongs to the weak global contexts list. 255 bool found = false; 256 Object* context = GetHeap()->global_contexts_list(); 257 while (!context->IsUndefined()) { 258 if (context == this) { 259 found = true; 260 break; 261 } 262 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); 263 } 264 CHECK(found); 265#endif 266 function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST)); 267 set(OPTIMIZED_FUNCTIONS_LIST, function); 268} 269 270 271void Context::RemoveOptimizedFunction(JSFunction* function) { 272 ASSERT(IsGlobalContext()); 273 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); 274 JSFunction* prev = NULL; 275 while (!element->IsUndefined()) { 276 JSFunction* element_function = JSFunction::cast(element); 277 ASSERT(element_function->next_function_link()->IsUndefined() || 278 element_function->next_function_link()->IsJSFunction()); 279 if (element_function == function) { 280 if (prev == NULL) { 281 set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link()); 282 } else { 283 prev->set_next_function_link(element_function->next_function_link()); 284 } 285 element_function->set_next_function_link(GetHeap()->undefined_value()); 286 return; 287 } 288 prev = element_function; 289 element = element_function->next_function_link(); 290 } 291 UNREACHABLE(); 292} 293 294 295Object* Context::OptimizedFunctionsListHead() { 296 ASSERT(IsGlobalContext()); 297 return get(OPTIMIZED_FUNCTIONS_LIST); 298} 299 300 301void Context::ClearOptimizedFunctions() { 302 set(OPTIMIZED_FUNCTIONS_LIST, GetHeap()->undefined_value()); 303} 304 305 306#ifdef DEBUG 307bool Context::IsBootstrappingOrContext(Object* object) { 308 // During bootstrapping we allow all objects to pass as 309 // contexts. This is necessary to fix circular dependencies. 310 return Isolate::Current()->bootstrapper()->IsActive() || object->IsContext(); 311} 312 313 314bool Context::IsBootstrappingOrGlobalObject(Object* object) { 315 // During bootstrapping we allow all objects to pass as global 316 // objects. This is necessary to fix circular dependencies. 317 Isolate* isolate = Isolate::Current(); 318 return isolate->heap()->gc_state() != Heap::NOT_IN_GC || 319 isolate->bootstrapper()->IsActive() || 320 object->IsGlobalObject(); 321} 322#endif 323 324} } // namespace v8::internal 325