| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
| 8 #include "src/debug.h" | 8 #include "src/debug.h" |
| 9 #include "src/scopeinfo.h" | 9 #include "src/scopeinfo.h" |
| 10 | 10 |
| 11 namespace v8 { | 11 namespace v8 { |
| 12 namespace internal { | 12 namespace internal { |
| 13 | 13 |
| 14 Context* Context::declaration_context() { | 14 Context* Context::declaration_context() { |
| 15 Context* current = this; | 15 Context* current = this; |
| 16 while (!current->IsFunctionContext() && !current->IsNativeContext()) { | 16 while (!current->IsFunctionContext() && !current->IsNativeContext()) { |
| 17 current = current->previous(); | 17 current = current->previous(); |
| 18 ASSERT(current->closure() == closure()); | 18 DCHECK(current->closure() == closure()); |
| 19 } | 19 } |
| 20 return current; | 20 return current; |
| 21 } | 21 } |
| 22 | 22 |
| 23 | 23 |
| 24 JSBuiltinsObject* Context::builtins() { | 24 JSBuiltinsObject* Context::builtins() { |
| 25 GlobalObject* object = global_object(); | 25 GlobalObject* object = global_object(); |
| 26 if (object->IsJSGlobalObject()) { | 26 if (object->IsJSGlobalObject()) { |
| 27 return JSGlobalObject::cast(object)->builtins(); | 27 return JSGlobalObject::cast(object)->builtins(); |
| 28 } else { | 28 } else { |
| 29 ASSERT(object->IsJSBuiltinsObject()); | 29 DCHECK(object->IsJSBuiltinsObject()); |
| 30 return JSBuiltinsObject::cast(object); | 30 return JSBuiltinsObject::cast(object); |
| 31 } | 31 } |
| 32 } | 32 } |
| 33 | 33 |
| 34 | 34 |
| 35 Context* Context::global_context() { | 35 Context* Context::global_context() { |
| 36 Context* current = this; | 36 Context* current = this; |
| 37 while (!current->IsGlobalContext()) { | 37 while (!current->IsGlobalContext()) { |
| 38 current = current->previous(); | 38 current = current->previous(); |
| 39 } | 39 } |
| 40 return current; | 40 return current; |
| 41 } | 41 } |
| 42 | 42 |
| 43 | 43 |
| 44 Context* Context::native_context() { | 44 Context* Context::native_context() { |
| 45 // Fast case: the global object for this context has been set. In | 45 // Fast case: the global object for this context has been set. In |
| 46 // that case, the global object has a direct pointer to the global | 46 // that case, the global object has a direct pointer to the global |
| 47 // context. | 47 // context. |
| 48 if (global_object()->IsGlobalObject()) { | 48 if (global_object()->IsGlobalObject()) { |
| 49 return global_object()->native_context(); | 49 return global_object()->native_context(); |
| 50 } | 50 } |
| 51 | 51 |
| 52 // During bootstrapping, the global object might not be set and we | 52 // During bootstrapping, the global object might not be set and we |
| 53 // have to search the context chain to find the native context. | 53 // have to search the context chain to find the native context. |
| 54 ASSERT(this->GetIsolate()->bootstrapper()->IsActive()); | 54 DCHECK(this->GetIsolate()->bootstrapper()->IsActive()); |
| 55 Context* current = this; | 55 Context* current = this; |
| 56 while (!current->IsNativeContext()) { | 56 while (!current->IsNativeContext()) { |
| 57 JSFunction* closure = JSFunction::cast(current->closure()); | 57 JSFunction* closure = JSFunction::cast(current->closure()); |
| 58 current = Context::cast(closure->context()); | 58 current = Context::cast(closure->context()); |
| 59 } | 59 } |
| 60 return current; | 60 return current; |
| 61 } | 61 } |
| 62 | 62 |
| 63 | 63 |
| 64 JSObject* Context::global_proxy() { | 64 JSObject* Context::global_proxy() { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 // prototype. So even if we want to follow prototype chains, we need | 107 // prototype. So even if we want to follow prototype chains, we need |
| 108 // to only do a local lookup for context extension objects. | 108 // to only do a local lookup for context extension objects. |
| 109 Maybe<PropertyAttributes> maybe; | 109 Maybe<PropertyAttributes> maybe; |
| 110 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || | 110 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || |
| 111 object->IsJSContextExtensionObject()) { | 111 object->IsJSContextExtensionObject()) { |
| 112 maybe = JSReceiver::GetOwnPropertyAttributes(object, name); | 112 maybe = JSReceiver::GetOwnPropertyAttributes(object, name); |
| 113 } else { | 113 } else { |
| 114 maybe = JSReceiver::GetPropertyAttributes(object, name); | 114 maybe = JSReceiver::GetPropertyAttributes(object, name); |
| 115 } | 115 } |
| 116 if (!maybe.has_value) return Handle<Object>(); | 116 if (!maybe.has_value) return Handle<Object>(); |
| 117 ASSERT(!isolate->has_pending_exception()); | 117 DCHECK(!isolate->has_pending_exception()); |
| 118 *attributes = maybe.value; | 118 *attributes = maybe.value; |
| 119 | 119 |
| 120 if (maybe.value != ABSENT) { | 120 if (maybe.value != ABSENT) { |
| 121 if (FLAG_trace_contexts) { | 121 if (FLAG_trace_contexts) { |
| 122 PrintF("=> found property in context object %p\n", | 122 PrintF("=> found property in context object %p\n", |
| 123 reinterpret_cast<void*>(*object)); | 123 reinterpret_cast<void*>(*object)); |
| 124 } | 124 } |
| 125 return object; | 125 return object; |
| 126 } | 126 } |
| 127 } | 127 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 138 scope_info = Handle<ScopeInfo>( | 138 scope_info = Handle<ScopeInfo>( |
| 139 ScopeInfo::cast(context->extension()), isolate); | 139 ScopeInfo::cast(context->extension()), isolate); |
| 140 } | 140 } |
| 141 VariableMode mode; | 141 VariableMode mode; |
| 142 InitializationFlag init_flag; | 142 InitializationFlag init_flag; |
| 143 // TODO(sigurds) Figure out whether maybe_assigned_flag should | 143 // TODO(sigurds) Figure out whether maybe_assigned_flag should |
| 144 // be used to compute binding_flags. | 144 // be used to compute binding_flags. |
| 145 MaybeAssignedFlag maybe_assigned_flag; | 145 MaybeAssignedFlag maybe_assigned_flag; |
| 146 int slot_index = ScopeInfo::ContextSlotIndex( | 146 int slot_index = ScopeInfo::ContextSlotIndex( |
| 147 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); | 147 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); |
| 148 ASSERT(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); | 148 DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); |
| 149 if (slot_index >= 0) { | 149 if (slot_index >= 0) { |
| 150 if (FLAG_trace_contexts) { | 150 if (FLAG_trace_contexts) { |
| 151 PrintF("=> found local in context slot %d (mode = %d)\n", | 151 PrintF("=> found local in context slot %d (mode = %d)\n", |
| 152 slot_index, mode); | 152 slot_index, mode); |
| 153 } | 153 } |
| 154 *index = slot_index; | 154 *index = slot_index; |
| 155 // Note: Fixed context slots are statically allocated by the compiler. | 155 // Note: Fixed context slots are statically allocated by the compiler. |
| 156 // Statically allocated variables always have a statically known mode, | 156 // Statically allocated variables always have a statically known mode, |
| 157 // which is the mode with which they were declared when added to the | 157 // which is the mode with which they were declared when added to the |
| 158 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically | 158 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 if (follow_context_chain && context->IsFunctionContext()) { | 199 if (follow_context_chain && context->IsFunctionContext()) { |
| 200 VariableMode mode; | 200 VariableMode mode; |
| 201 int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); | 201 int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); |
| 202 if (function_index >= 0) { | 202 if (function_index >= 0) { |
| 203 if (FLAG_trace_contexts) { | 203 if (FLAG_trace_contexts) { |
| 204 PrintF("=> found intermediate function in context slot %d\n", | 204 PrintF("=> found intermediate function in context slot %d\n", |
| 205 function_index); | 205 function_index); |
| 206 } | 206 } |
| 207 *index = function_index; | 207 *index = function_index; |
| 208 *attributes = READ_ONLY; | 208 *attributes = READ_ONLY; |
| 209 ASSERT(mode == CONST_LEGACY || mode == CONST); | 209 DCHECK(mode == CONST_LEGACY || mode == CONST); |
| 210 *binding_flags = (mode == CONST_LEGACY) | 210 *binding_flags = (mode == CONST_LEGACY) |
| 211 ? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY; | 211 ? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY; |
| 212 return context; | 212 return context; |
| 213 } | 213 } |
| 214 } | 214 } |
| 215 | 215 |
| 216 } else if (context->IsCatchContext()) { | 216 } else if (context->IsCatchContext()) { |
| 217 // Catch contexts have the variable name in the extension slot. | 217 // Catch contexts have the variable name in the extension slot. |
| 218 if (String::Equals(name, handle(String::cast(context->extension())))) { | 218 if (String::Equals(name, handle(String::cast(context->extension())))) { |
| 219 if (FLAG_trace_contexts) { | 219 if (FLAG_trace_contexts) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 235 } while (follow_context_chain); | 235 } while (follow_context_chain); |
| 236 | 236 |
| 237 if (FLAG_trace_contexts) { | 237 if (FLAG_trace_contexts) { |
| 238 PrintF("=> no property/slot found\n"); | 238 PrintF("=> no property/slot found\n"); |
| 239 } | 239 } |
| 240 return Handle<Object>::null(); | 240 return Handle<Object>::null(); |
| 241 } | 241 } |
| 242 | 242 |
| 243 | 243 |
| 244 void Context::AddOptimizedFunction(JSFunction* function) { | 244 void Context::AddOptimizedFunction(JSFunction* function) { |
| 245 ASSERT(IsNativeContext()); | 245 DCHECK(IsNativeContext()); |
| 246 #ifdef ENABLE_SLOW_ASSERTS | 246 #ifdef ENABLE_SLOW_DCHECKS |
| 247 if (FLAG_enable_slow_asserts) { | 247 if (FLAG_enable_slow_asserts) { |
| 248 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); | 248 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); |
| 249 while (!element->IsUndefined()) { | 249 while (!element->IsUndefined()) { |
| 250 CHECK(element != function); | 250 CHECK(element != function); |
| 251 element = JSFunction::cast(element)->next_function_link(); | 251 element = JSFunction::cast(element)->next_function_link(); |
| 252 } | 252 } |
| 253 } | 253 } |
| 254 | 254 |
| 255 // Check that the context belongs to the weak native contexts list. | 255 // Check that the context belongs to the weak native contexts list. |
| 256 bool found = false; | 256 bool found = false; |
| 257 Object* context = GetHeap()->native_contexts_list(); | 257 Object* context = GetHeap()->native_contexts_list(); |
| 258 while (!context->IsUndefined()) { | 258 while (!context->IsUndefined()) { |
| 259 if (context == this) { | 259 if (context == this) { |
| 260 found = true; | 260 found = true; |
| 261 break; | 261 break; |
| 262 } | 262 } |
| 263 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 263 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| 264 } | 264 } |
| 265 CHECK(found); | 265 CHECK(found); |
| 266 #endif | 266 #endif |
| 267 | 267 |
| 268 // If the function link field is already used then the function was | 268 // If the function link field is already used then the function was |
| 269 // enqueued as a code flushing candidate and we remove it now. | 269 // enqueued as a code flushing candidate and we remove it now. |
| 270 if (!function->next_function_link()->IsUndefined()) { | 270 if (!function->next_function_link()->IsUndefined()) { |
| 271 CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher(); | 271 CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher(); |
| 272 flusher->EvictCandidate(function); | 272 flusher->EvictCandidate(function); |
| 273 } | 273 } |
| 274 | 274 |
| 275 ASSERT(function->next_function_link()->IsUndefined()); | 275 DCHECK(function->next_function_link()->IsUndefined()); |
| 276 | 276 |
| 277 function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST)); | 277 function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST)); |
| 278 set(OPTIMIZED_FUNCTIONS_LIST, function); | 278 set(OPTIMIZED_FUNCTIONS_LIST, function); |
| 279 } | 279 } |
| 280 | 280 |
| 281 | 281 |
| 282 void Context::RemoveOptimizedFunction(JSFunction* function) { | 282 void Context::RemoveOptimizedFunction(JSFunction* function) { |
| 283 ASSERT(IsNativeContext()); | 283 DCHECK(IsNativeContext()); |
| 284 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); | 284 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); |
| 285 JSFunction* prev = NULL; | 285 JSFunction* prev = NULL; |
| 286 while (!element->IsUndefined()) { | 286 while (!element->IsUndefined()) { |
| 287 JSFunction* element_function = JSFunction::cast(element); | 287 JSFunction* element_function = JSFunction::cast(element); |
| 288 ASSERT(element_function->next_function_link()->IsUndefined() || | 288 DCHECK(element_function->next_function_link()->IsUndefined() || |
| 289 element_function->next_function_link()->IsJSFunction()); | 289 element_function->next_function_link()->IsJSFunction()); |
| 290 if (element_function == function) { | 290 if (element_function == function) { |
| 291 if (prev == NULL) { | 291 if (prev == NULL) { |
| 292 set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link()); | 292 set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link()); |
| 293 } else { | 293 } else { |
| 294 prev->set_next_function_link(element_function->next_function_link()); | 294 prev->set_next_function_link(element_function->next_function_link()); |
| 295 } | 295 } |
| 296 element_function->set_next_function_link(GetHeap()->undefined_value()); | 296 element_function->set_next_function_link(GetHeap()->undefined_value()); |
| 297 return; | 297 return; |
| 298 } | 298 } |
| 299 prev = element_function; | 299 prev = element_function; |
| 300 element = element_function->next_function_link(); | 300 element = element_function->next_function_link(); |
| 301 } | 301 } |
| 302 UNREACHABLE(); | 302 UNREACHABLE(); |
| 303 } | 303 } |
| 304 | 304 |
| 305 | 305 |
| 306 void Context::SetOptimizedFunctionsListHead(Object* head) { | 306 void Context::SetOptimizedFunctionsListHead(Object* head) { |
| 307 ASSERT(IsNativeContext()); | 307 DCHECK(IsNativeContext()); |
| 308 set(OPTIMIZED_FUNCTIONS_LIST, head); | 308 set(OPTIMIZED_FUNCTIONS_LIST, head); |
| 309 } | 309 } |
| 310 | 310 |
| 311 | 311 |
| 312 Object* Context::OptimizedFunctionsListHead() { | 312 Object* Context::OptimizedFunctionsListHead() { |
| 313 ASSERT(IsNativeContext()); | 313 DCHECK(IsNativeContext()); |
| 314 return get(OPTIMIZED_FUNCTIONS_LIST); | 314 return get(OPTIMIZED_FUNCTIONS_LIST); |
| 315 } | 315 } |
| 316 | 316 |
| 317 | 317 |
| 318 void Context::AddOptimizedCode(Code* code) { | 318 void Context::AddOptimizedCode(Code* code) { |
| 319 ASSERT(IsNativeContext()); | 319 DCHECK(IsNativeContext()); |
| 320 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION); | 320 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); |
| 321 ASSERT(code->next_code_link()->IsUndefined()); | 321 DCHECK(code->next_code_link()->IsUndefined()); |
| 322 code->set_next_code_link(get(OPTIMIZED_CODE_LIST)); | 322 code->set_next_code_link(get(OPTIMIZED_CODE_LIST)); |
| 323 set(OPTIMIZED_CODE_LIST, code); | 323 set(OPTIMIZED_CODE_LIST, code); |
| 324 } | 324 } |
| 325 | 325 |
| 326 | 326 |
| 327 void Context::SetOptimizedCodeListHead(Object* head) { | 327 void Context::SetOptimizedCodeListHead(Object* head) { |
| 328 ASSERT(IsNativeContext()); | 328 DCHECK(IsNativeContext()); |
| 329 set(OPTIMIZED_CODE_LIST, head); | 329 set(OPTIMIZED_CODE_LIST, head); |
| 330 } | 330 } |
| 331 | 331 |
| 332 | 332 |
| 333 Object* Context::OptimizedCodeListHead() { | 333 Object* Context::OptimizedCodeListHead() { |
| 334 ASSERT(IsNativeContext()); | 334 DCHECK(IsNativeContext()); |
| 335 return get(OPTIMIZED_CODE_LIST); | 335 return get(OPTIMIZED_CODE_LIST); |
| 336 } | 336 } |
| 337 | 337 |
| 338 | 338 |
| 339 void Context::SetDeoptimizedCodeListHead(Object* head) { | 339 void Context::SetDeoptimizedCodeListHead(Object* head) { |
| 340 ASSERT(IsNativeContext()); | 340 DCHECK(IsNativeContext()); |
| 341 set(DEOPTIMIZED_CODE_LIST, head); | 341 set(DEOPTIMIZED_CODE_LIST, head); |
| 342 } | 342 } |
| 343 | 343 |
| 344 | 344 |
| 345 Object* Context::DeoptimizedCodeListHead() { | 345 Object* Context::DeoptimizedCodeListHead() { |
| 346 ASSERT(IsNativeContext()); | 346 DCHECK(IsNativeContext()); |
| 347 return get(DEOPTIMIZED_CODE_LIST); | 347 return get(DEOPTIMIZED_CODE_LIST); |
| 348 } | 348 } |
| 349 | 349 |
| 350 | 350 |
| 351 Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() { | 351 Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() { |
| 352 Isolate* isolate = GetIsolate(); | 352 Isolate* isolate = GetIsolate(); |
| 353 Handle<Object> result(error_message_for_code_gen_from_strings(), isolate); | 353 Handle<Object> result(error_message_for_code_gen_from_strings(), isolate); |
| 354 if (!result->IsUndefined()) return result; | 354 if (!result->IsUndefined()) return result; |
| 355 return isolate->factory()->NewStringFromStaticAscii( | 355 return isolate->factory()->NewStringFromStaticAscii( |
| 356 "Code generation from strings disallowed for this context"); | 356 "Code generation from strings disallowed for this context"); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 373 bool Context::IsBootstrappingOrGlobalObject(Isolate* isolate, Object* object) { | 373 bool Context::IsBootstrappingOrGlobalObject(Isolate* isolate, Object* object) { |
| 374 // During bootstrapping we allow all objects to pass as global | 374 // During bootstrapping we allow all objects to pass as global |
| 375 // objects. This is necessary to fix circular dependencies. | 375 // objects. This is necessary to fix circular dependencies. |
| 376 return isolate->heap()->gc_state() != Heap::NOT_IN_GC || | 376 return isolate->heap()->gc_state() != Heap::NOT_IN_GC || |
| 377 isolate->bootstrapper()->IsActive() || | 377 isolate->bootstrapper()->IsActive() || |
| 378 object->IsGlobalObject(); | 378 object->IsGlobalObject(); |
| 379 } | 379 } |
| 380 #endif | 380 #endif |
| 381 | 381 |
| 382 } } // namespace v8::internal | 382 } } // namespace v8::internal |
| OLD | NEW |