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 3 // found in the LICENSE file. 4 5 #include "src/contexts.h" 6 7 #include "src/bootstrapper.h" 8 #include "src/debug/debug.h" 9 #include "src/isolate-inl.h" 10 11 namespace v8 { 12 namespace internal { 13 14 15 Handle<ScriptContextTable> ScriptContextTable::Extend( 16 Handle<ScriptContextTable> table, Handle<Context> script_context) { 17 Handle<ScriptContextTable> result; 18 int used = table->used(); 19 int length = table->length(); 20 CHECK(used >= 0 && length > 0 && used < length); 21 if (used + kFirstContextSlot == length) { 22 CHECK(length < Smi::kMaxValue / 2); 23 Isolate* isolate = table->GetIsolate(); 24 Handle<FixedArray> copy = 25 isolate->factory()->CopyFixedArrayAndGrow(table, length); 26 copy->set_map(isolate->heap()->script_context_table_map()); 27 result = Handle<ScriptContextTable>::cast(copy); 28 } else { 29 result = table; 30 } 31 result->set_used(used + 1); 32 33 DCHECK(script_context->IsScriptContext()); 34 result->set(used + kFirstContextSlot, *script_context); 35 return result; 36 } 37 38 39 bool ScriptContextTable::Lookup(Handle<ScriptContextTable> table, 40 Handle<String> name, LookupResult* result) { 41 for (int i = 0; i < table->used(); i++) { 42 Handle<Context> context = GetContext(table, i); 43 DCHECK(context->IsScriptContext()); 44 Handle<ScopeInfo> scope_info(context->scope_info()); 45 int slot_index = ScopeInfo::ContextSlotIndex( 46 scope_info, name, &result->mode, &result->init_flag, 47 &result->maybe_assigned_flag); 48 49 if (slot_index >= 0) { 50 result->context_index = i; 51 result->slot_index = slot_index; 52 return true; 53 } 54 } 55 return false; 56 } 57 58 59 bool Context::is_declaration_context() { 60 if (IsFunctionContext() || IsNativeContext() || IsScriptContext() || 61 IsModuleContext()) { 62 return true; 63 } 64 if (IsEvalContext()) return closure()->shared()->language_mode() == STRICT; 65 if (!IsBlockContext()) return false; 66 Object* ext = extension(); 67 // If we have the special extension, we immediately know it must be a 68 // declaration scope. That's just a small performance shortcut. 69 return ext->IsContextExtension() || 70 ScopeInfo::cast(ext)->is_declaration_scope(); 71 } 72 73 74 Context* Context::declaration_context() { 75 Context* current = this; 76 while (!current->is_declaration_context()) { 77 current = current->previous(); 78 } 79 return current; 80 } 81 82 Context* Context::closure_context() { 83 Context* current = this; 84 while (!current->IsFunctionContext() && !current->IsScriptContext() && 85 !current->IsModuleContext() && !current->IsNativeContext() && 86 !current->IsEvalContext()) { 87 current = current->previous(); 88 DCHECK(current->closure() == closure()); 89 } 90 return current; 91 } 92 93 JSObject* Context::extension_object() { 94 DCHECK(IsNativeContext() || IsFunctionContext() || IsBlockContext() || 95 IsEvalContext()); 96 HeapObject* object = extension(); 97 if (object->IsTheHole(GetIsolate())) return nullptr; 98 if (IsBlockContext()) { 99 if (!object->IsContextExtension()) return nullptr; 100 object = JSObject::cast(ContextExtension::cast(object)->extension()); 101 } 102 DCHECK(object->IsJSContextExtensionObject() || 103 (IsNativeContext() && object->IsJSGlobalObject())); 104 return JSObject::cast(object); 105 } 106 107 JSReceiver* Context::extension_receiver() { 108 DCHECK(IsNativeContext() || IsWithContext() || IsEvalContext() || 109 IsFunctionContext() || IsBlockContext()); 110 return IsWithContext() ? JSReceiver::cast( 111 ContextExtension::cast(extension())->extension()) 112 : extension_object(); 113 } 114 115 ScopeInfo* Context::scope_info() { 116 DCHECK(!IsNativeContext()); 117 if (IsFunctionContext() || IsModuleContext() || IsEvalContext()) { 118 return closure()->shared()->scope_info(); 119 } 120 HeapObject* object = extension(); 121 if (object->IsContextExtension()) { 122 DCHECK(IsBlockContext() || IsCatchContext() || IsWithContext() || 123 IsDebugEvaluateContext()); 124 object = ContextExtension::cast(object)->scope_info(); 125 } 126 return ScopeInfo::cast(object); 127 } 128 129 Module* Context::module() { 130 Context* current = this; 131 while (!current->IsModuleContext()) { 132 current = current->previous(); 133 } 134 return Module::cast(current->extension()); 135 } 136 137 String* Context::catch_name() { 138 DCHECK(IsCatchContext()); 139 return String::cast(ContextExtension::cast(extension())->extension()); 140 } 141 142 143 JSGlobalObject* Context::global_object() { 144 return JSGlobalObject::cast(native_context()->extension()); 145 } 146 147 148 Context* Context::script_context() { 149 Context* current = this; 150 while (!current->IsScriptContext()) { 151 current = current->previous(); 152 } 153 return current; 154 } 155 156 157 JSObject* Context::global_proxy() { 158 return native_context()->global_proxy_object(); 159 } 160 161 162 void Context::set_global_proxy(JSObject* object) { 163 native_context()->set_global_proxy_object(object); 164 } 165 166 167 /** 168 * Lookups a property in an object environment, taking the unscopables into 169 * account. This is used For HasBinding spec algorithms for ObjectEnvironment. 170 */ 171 static Maybe<bool> UnscopableLookup(LookupIterator* it) { 172 Isolate* isolate = it->isolate(); 173 174 Maybe<bool> found = JSReceiver::HasProperty(it); 175 if (!found.IsJust() || !found.FromJust()) return found; 176 177 Handle<Object> unscopables; 178 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 179 isolate, unscopables, 180 JSReceiver::GetProperty(Handle<JSReceiver>::cast(it->GetReceiver()), 181 isolate->factory()->unscopables_symbol()), 182 Nothing<bool>()); 183 if (!unscopables->IsJSReceiver()) return Just(true); 184 Handle<Object> blacklist; 185 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 186 isolate, blacklist, 187 JSReceiver::GetProperty(Handle<JSReceiver>::cast(unscopables), 188 it->name()), 189 Nothing<bool>()); 190 return Just(!blacklist->BooleanValue()); 191 } 192 193 static PropertyAttributes GetAttributesForMode(VariableMode mode) { 194 DCHECK(IsDeclaredVariableMode(mode)); 195 return mode == CONST ? READ_ONLY : NONE; 196 } 197 198 Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, 199 int* index, PropertyAttributes* attributes, 200 InitializationFlag* init_flag, 201 VariableMode* variable_mode) { 202 DCHECK(!IsModuleContext()); 203 Isolate* isolate = GetIsolate(); 204 Handle<Context> context(this, isolate); 205 206 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; 207 bool failed_whitelist = false; 208 *index = kNotFound; 209 *attributes = ABSENT; 210 *init_flag = kCreatedInitialized; 211 *variable_mode = VAR; 212 213 if (FLAG_trace_contexts) { 214 PrintF("Context::Lookup("); 215 name->ShortPrint(); 216 PrintF(")\n"); 217 } 218 219 do { 220 if (FLAG_trace_contexts) { 221 PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); 222 if (context->IsScriptContext()) PrintF(" (script context)"); 223 if (context->IsNativeContext()) PrintF(" (native context)"); 224 PrintF("\n"); 225 } 226 227 // 1. Check global objects, subjects of with, and extension objects. 228 DCHECK_IMPLIES(context->IsEvalContext(), 229 context->extension()->IsTheHole(isolate)); 230 if ((context->IsNativeContext() || 231 (context->IsWithContext() && ((flags & SKIP_WITH_CONTEXT) == 0)) || 232 context->IsFunctionContext() || context->IsBlockContext()) && 233 context->extension_receiver() != nullptr) { 234 Handle<JSReceiver> object(context->extension_receiver()); 235 236 if (context->IsNativeContext()) { 237 if (FLAG_trace_contexts) { 238 PrintF(" - trying other script contexts\n"); 239 } 240 // Try other script contexts. 241 Handle<ScriptContextTable> script_contexts( 242 context->global_object()->native_context()->script_context_table()); 243 ScriptContextTable::LookupResult r; 244 if (ScriptContextTable::Lookup(script_contexts, name, &r)) { 245 if (FLAG_trace_contexts) { 246 Handle<Context> c = ScriptContextTable::GetContext(script_contexts, 247 r.context_index); 248 PrintF("=> found property in script context %d: %p\n", 249 r.context_index, reinterpret_cast<void*>(*c)); 250 } 251 *index = r.slot_index; 252 *variable_mode = r.mode; 253 *init_flag = r.init_flag; 254 *attributes = GetAttributesForMode(r.mode); 255 return ScriptContextTable::GetContext(script_contexts, 256 r.context_index); 257 } 258 } 259 260 // Context extension objects needs to behave as if they have no 261 // prototype. So even if we want to follow prototype chains, we need 262 // to only do a local lookup for context extension objects. 263 Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>(); 264 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || 265 object->IsJSContextExtensionObject()) { 266 maybe = JSReceiver::GetOwnPropertyAttributes(object, name); 267 } else if (context->IsWithContext()) { 268 // A with context will never bind "this", but debug-eval may look into 269 // a with context when resolving "this". Other synthetic variables such 270 // as new.target may be resolved as DYNAMIC_LOCAL due to bug v8:5405 , 271 // skipping them here serves as a workaround until a more thorough 272 // fix can be applied. 273 // TODO(v8:5405): Replace this check with a DCHECK when resolution of 274 // of synthetic variables does not go through this code path. 275 if (ScopeInfo::VariableIsSynthetic(*name)) { 276 maybe = Just(ABSENT); 277 } else { 278 LookupIterator it(object, name, object); 279 Maybe<bool> found = UnscopableLookup(&it); 280 if (found.IsNothing()) { 281 maybe = Nothing<PropertyAttributes>(); 282 } else { 283 // Luckily, consumers of |maybe| only care whether the property 284 // was absent or not, so we can return a dummy |NONE| value 285 // for its attributes when it was present. 286 maybe = Just(found.FromJust() ? NONE : ABSENT); 287 } 288 } 289 } else { 290 maybe = JSReceiver::GetPropertyAttributes(object, name); 291 } 292 293 if (!maybe.IsJust()) return Handle<Object>(); 294 DCHECK(!isolate->has_pending_exception()); 295 *attributes = maybe.FromJust(); 296 297 if (maybe.FromJust() != ABSENT) { 298 if (FLAG_trace_contexts) { 299 PrintF("=> found property in context object %p\n", 300 reinterpret_cast<void*>(*object)); 301 } 302 return object; 303 } 304 } 305 306 // 2. Check the context proper if it has slots. 307 if (context->IsFunctionContext() || context->IsBlockContext() || 308 context->IsScriptContext() || context->IsEvalContext()) { 309 // Use serialized scope information of functions and blocks to search 310 // for the context index. 311 Handle<ScopeInfo> scope_info(context->scope_info()); 312 VariableMode mode; 313 InitializationFlag flag; 314 MaybeAssignedFlag maybe_assigned_flag; 315 int slot_index = ScopeInfo::ContextSlotIndex(scope_info, name, &mode, 316 &flag, &maybe_assigned_flag); 317 DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); 318 if (slot_index >= 0) { 319 if (FLAG_trace_contexts) { 320 PrintF("=> found local in context slot %d (mode = %d)\n", 321 slot_index, mode); 322 } 323 *index = slot_index; 324 *variable_mode = mode; 325 *init_flag = flag; 326 *attributes = GetAttributesForMode(mode); 327 return context; 328 } 329 330 // Check the slot corresponding to the intermediate context holding 331 // only the function name variable. It's conceptually (and spec-wise) 332 // in an outer scope of the function's declaration scope. 333 if (follow_context_chain && (flags & STOP_AT_DECLARATION_SCOPE) == 0 && 334 context->IsFunctionContext()) { 335 int function_index = scope_info->FunctionContextSlotIndex(*name); 336 if (function_index >= 0) { 337 if (FLAG_trace_contexts) { 338 PrintF("=> found intermediate function in context slot %d\n", 339 function_index); 340 } 341 *index = function_index; 342 *attributes = READ_ONLY; 343 *init_flag = kCreatedInitialized; 344 *variable_mode = CONST; 345 return context; 346 } 347 } 348 349 } else if (context->IsCatchContext()) { 350 // Catch contexts have the variable name in the extension slot. 351 if (String::Equals(name, handle(context->catch_name()))) { 352 if (FLAG_trace_contexts) { 353 PrintF("=> found in catch context\n"); 354 } 355 *index = Context::THROWN_OBJECT_INDEX; 356 *attributes = NONE; 357 *init_flag = kCreatedInitialized; 358 *variable_mode = VAR; 359 return context; 360 } 361 } else if (context->IsDebugEvaluateContext()) { 362 // Check materialized locals. 363 Object* ext = context->get(EXTENSION_INDEX); 364 if (ext->IsContextExtension()) { 365 Object* obj = ContextExtension::cast(ext)->extension(); 366 if (obj->IsJSReceiver()) { 367 Handle<JSReceiver> extension(JSReceiver::cast(obj)); 368 LookupIterator it(extension, name, extension); 369 Maybe<bool> found = JSReceiver::HasProperty(&it); 370 if (found.FromMaybe(false)) { 371 *attributes = NONE; 372 return extension; 373 } 374 } 375 } 376 // Check the original context, but do not follow its context chain. 377 Object* obj = context->get(WRAPPED_CONTEXT_INDEX); 378 if (obj->IsContext()) { 379 Handle<Object> result = 380 Context::cast(obj)->Lookup(name, DONT_FOLLOW_CHAINS, index, 381 attributes, init_flag, variable_mode); 382 if (!result.is_null()) return result; 383 } 384 // Check whitelist. Names that do not pass whitelist shall only resolve 385 // to with, script or native contexts up the context chain. 386 obj = context->get(WHITE_LIST_INDEX); 387 if (obj->IsStringSet()) { 388 failed_whitelist = failed_whitelist || !StringSet::cast(obj)->Has(name); 389 } 390 } 391 392 // 3. Prepare to continue with the previous (next outermost) context. 393 if (context->IsNativeContext() || 394 ((flags & STOP_AT_DECLARATION_SCOPE) != 0 && 395 context->is_declaration_context())) { 396 follow_context_chain = false; 397 } else { 398 do { 399 context = Handle<Context>(context->previous(), isolate); 400 // If we come across a whitelist context, and the name is not 401 // whitelisted, then only consider with, script or native contexts. 402 } while (failed_whitelist && !context->IsScriptContext() && 403 !context->IsNativeContext() && !context->IsWithContext()); 404 } 405 } while (follow_context_chain); 406 407 if (FLAG_trace_contexts) { 408 PrintF("=> no property/slot found\n"); 409 } 410 return Handle<Object>::null(); 411 } 412 413 static const int kSharedOffset = 0; 414 static const int kCachedCodeOffset = 1; 415 static const int kOsrAstIdOffset = 2; 416 static const int kEntryLength = 3; 417 static const int kInitialLength = kEntryLength; 418 419 int Context::SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared, 420 BailoutId osr_ast_id) { 421 DisallowHeapAllocation no_gc; 422 DCHECK(this->IsNativeContext()); 423 if (!OptimizedCodeMapIsCleared()) { 424 FixedArray* optimized_code_map = this->osr_code_table(); 425 int length = optimized_code_map->length(); 426 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt()); 427 for (int i = 0; i < length; i += kEntryLength) { 428 if (WeakCell::cast(optimized_code_map->get(i + kSharedOffset))->value() == 429 shared && 430 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) { 431 return i; 432 } 433 } 434 } 435 return -1; 436 } 437 438 Code* Context::SearchOptimizedCodeMap(SharedFunctionInfo* shared, 439 BailoutId osr_ast_id) { 440 DCHECK(this->IsNativeContext()); 441 int entry = SearchOptimizedCodeMapEntry(shared, osr_ast_id); 442 if (entry != -1) { 443 FixedArray* code_map = osr_code_table(); 444 DCHECK_LE(entry + kEntryLength, code_map->length()); 445 WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset)); 446 return cell->cleared() ? nullptr : Code::cast(cell->value()); 447 } 448 return nullptr; 449 } 450 451 void Context::AddToOptimizedCodeMap(Handle<Context> native_context, 452 Handle<SharedFunctionInfo> shared, 453 Handle<Code> code, 454 BailoutId osr_ast_id) { 455 DCHECK(native_context->IsNativeContext()); 456 Isolate* isolate = native_context->GetIsolate(); 457 if (isolate->serializer_enabled()) return; 458 459 STATIC_ASSERT(kEntryLength == 3); 460 Handle<FixedArray> new_code_map; 461 int entry; 462 463 if (native_context->OptimizedCodeMapIsCleared()) { 464 new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED); 465 entry = 0; 466 } else { 467 Handle<FixedArray> old_code_map(native_context->osr_code_table(), isolate); 468 entry = native_context->SearchOptimizedCodeMapEntry(*shared, osr_ast_id); 469 if (entry >= 0) { 470 // Just set the code of the entry. 471 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); 472 old_code_map->set(entry + kCachedCodeOffset, *code_cell); 473 return; 474 } 475 476 // Can we reuse an entry? 477 DCHECK(entry < 0); 478 int length = old_code_map->length(); 479 for (int i = 0; i < length; i += kEntryLength) { 480 if (WeakCell::cast(old_code_map->get(i + kSharedOffset))->cleared()) { 481 new_code_map = old_code_map; 482 entry = i; 483 break; 484 } 485 } 486 487 if (entry < 0) { 488 // Copy old optimized code map and append one new entry. 489 new_code_map = isolate->factory()->CopyFixedArrayAndGrow( 490 old_code_map, kEntryLength, TENURED); 491 entry = old_code_map->length(); 492 } 493 } 494 495 Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code); 496 Handle<WeakCell> shared_cell = isolate->factory()->NewWeakCell(shared); 497 498 new_code_map->set(entry + kSharedOffset, *shared_cell); 499 new_code_map->set(entry + kCachedCodeOffset, *code_cell); 500 new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt())); 501 502 #ifdef DEBUG 503 for (int i = 0; i < new_code_map->length(); i += kEntryLength) { 504 WeakCell* cell = WeakCell::cast(new_code_map->get(i + kSharedOffset)); 505 DCHECK(cell->cleared() || cell->value()->IsSharedFunctionInfo()); 506 cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset)); 507 DCHECK(cell->cleared() || 508 (cell->value()->IsCode() && 509 Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION)); 510 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi()); 511 } 512 #endif 513 514 FixedArray* old_code_map = native_context->osr_code_table(); 515 if (old_code_map != *new_code_map) { 516 native_context->set_osr_code_table(*new_code_map); 517 } 518 } 519 520 void Context::EvictFromOptimizedCodeMap(Code* optimized_code, 521 const char* reason) { 522 DCHECK(IsNativeContext()); 523 DisallowHeapAllocation no_gc; 524 if (OptimizedCodeMapIsCleared()) return; 525 526 Heap* heap = GetHeap(); 527 FixedArray* code_map = osr_code_table(); 528 int dst = 0; 529 int length = code_map->length(); 530 for (int src = 0; src < length; src += kEntryLength) { 531 if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() == 532 optimized_code) { 533 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value()); 534 if (FLAG_trace_opt) { 535 PrintF( 536 "[evicting entry from native context optimizing code map (%s) for ", 537 reason); 538 ShortPrint(); 539 DCHECK(!osr.IsNone()); 540 PrintF(" (osr ast id %d)]\n", osr.ToInt()); 541 } 542 // Evict the src entry by not copying it to the dst entry. 543 continue; 544 } 545 // Keep the src entry by copying it to the dst entry. 546 if (dst != src) { 547 code_map->set(dst + kSharedOffset, code_map->get(src + kSharedOffset)); 548 code_map->set(dst + kCachedCodeOffset, 549 code_map->get(src + kCachedCodeOffset)); 550 code_map->set(dst + kOsrAstIdOffset, 551 code_map->get(src + kOsrAstIdOffset)); 552 } 553 dst += kEntryLength; 554 } 555 if (dst != length) { 556 // Always trim even when array is cleared because of heap verifier. 557 heap->RightTrimFixedArray(code_map, length - dst); 558 if (code_map->length() == 0) { 559 ClearOptimizedCodeMap(); 560 } 561 } 562 } 563 564 void Context::ClearOptimizedCodeMap() { 565 DCHECK(IsNativeContext()); 566 FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array(); 567 set_osr_code_table(empty_fixed_array); 568 } 569 570 void Context::AddOptimizedFunction(JSFunction* function) { 571 DCHECK(IsNativeContext()); 572 Isolate* isolate = GetIsolate(); 573 #ifdef ENABLE_SLOW_DCHECKS 574 if (FLAG_enable_slow_asserts) { 575 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); 576 while (!element->IsUndefined(isolate)) { 577 CHECK(element != function); 578 element = JSFunction::cast(element)->next_function_link(); 579 } 580 } 581 582 // Check that the context belongs to the weak native contexts list. 583 bool found = false; 584 Object* context = isolate->heap()->native_contexts_list(); 585 while (!context->IsUndefined(isolate)) { 586 if (context == this) { 587 found = true; 588 break; 589 } 590 context = Context::cast(context)->next_context_link(); 591 } 592 CHECK(found); 593 #endif 594 595 // If the function link field is already used then the function was 596 // enqueued as a code flushing candidate and we remove it now. 597 if (!function->next_function_link()->IsUndefined(isolate)) { 598 CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher(); 599 flusher->EvictCandidate(function); 600 } 601 602 DCHECK(function->next_function_link()->IsUndefined(isolate)); 603 604 function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST), 605 UPDATE_WEAK_WRITE_BARRIER); 606 set(OPTIMIZED_FUNCTIONS_LIST, function, UPDATE_WEAK_WRITE_BARRIER); 607 } 608 609 610 void Context::RemoveOptimizedFunction(JSFunction* function) { 611 DCHECK(IsNativeContext()); 612 Object* element = get(OPTIMIZED_FUNCTIONS_LIST); 613 JSFunction* prev = NULL; 614 Isolate* isolate = function->GetIsolate(); 615 while (!element->IsUndefined(isolate)) { 616 JSFunction* element_function = JSFunction::cast(element); 617 DCHECK(element_function->next_function_link()->IsUndefined(isolate) || 618 element_function->next_function_link()->IsJSFunction()); 619 if (element_function == function) { 620 if (prev == NULL) { 621 set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link(), 622 UPDATE_WEAK_WRITE_BARRIER); 623 } else { 624 prev->set_next_function_link(element_function->next_function_link(), 625 UPDATE_WEAK_WRITE_BARRIER); 626 } 627 element_function->set_next_function_link(GetHeap()->undefined_value(), 628 UPDATE_WEAK_WRITE_BARRIER); 629 return; 630 } 631 prev = element_function; 632 element = element_function->next_function_link(); 633 } 634 UNREACHABLE(); 635 } 636 637 638 void Context::SetOptimizedFunctionsListHead(Object* head) { 639 DCHECK(IsNativeContext()); 640 set(OPTIMIZED_FUNCTIONS_LIST, head, UPDATE_WEAK_WRITE_BARRIER); 641 } 642 643 644 Object* Context::OptimizedFunctionsListHead() { 645 DCHECK(IsNativeContext()); 646 return get(OPTIMIZED_FUNCTIONS_LIST); 647 } 648 649 650 void Context::AddOptimizedCode(Code* code) { 651 DCHECK(IsNativeContext()); 652 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); 653 DCHECK(code->next_code_link()->IsUndefined(GetIsolate())); 654 code->set_next_code_link(get(OPTIMIZED_CODE_LIST)); 655 set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER); 656 } 657 658 659 void Context::SetOptimizedCodeListHead(Object* head) { 660 DCHECK(IsNativeContext()); 661 set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER); 662 } 663 664 665 Object* Context::OptimizedCodeListHead() { 666 DCHECK(IsNativeContext()); 667 return get(OPTIMIZED_CODE_LIST); 668 } 669 670 671 void Context::SetDeoptimizedCodeListHead(Object* head) { 672 DCHECK(IsNativeContext()); 673 set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER); 674 } 675 676 677 Object* Context::DeoptimizedCodeListHead() { 678 DCHECK(IsNativeContext()); 679 return get(DEOPTIMIZED_CODE_LIST); 680 } 681 682 683 Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() { 684 Isolate* isolate = GetIsolate(); 685 Handle<Object> result(error_message_for_code_gen_from_strings(), isolate); 686 if (!result->IsUndefined(isolate)) return result; 687 return isolate->factory()->NewStringFromStaticChars( 688 "Code generation from strings disallowed for this context"); 689 } 690 691 692 #define COMPARE_NAME(index, type, name) \ 693 if (string->IsOneByteEqualTo(STATIC_CHAR_VECTOR(#name))) return index; 694 695 int Context::ImportedFieldIndexForName(Handle<String> string) { 696 NATIVE_CONTEXT_IMPORTED_FIELDS(COMPARE_NAME) 697 return kNotFound; 698 } 699 700 701 int Context::IntrinsicIndexForName(Handle<String> string) { 702 NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME); 703 return kNotFound; 704 } 705 706 #undef COMPARE_NAME 707 708 #define COMPARE_NAME(index, type, name) \ 709 if (strncmp(string, #name, length) == 0) return index; 710 711 int Context::IntrinsicIndexForName(const unsigned char* unsigned_string, 712 int length) { 713 const char* string = reinterpret_cast<const char*>(unsigned_string); 714 NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME); 715 return kNotFound; 716 } 717 718 #undef COMPARE_NAME 719 720 #ifdef DEBUG 721 722 bool Context::IsBootstrappingOrNativeContext(Isolate* isolate, Object* object) { 723 // During bootstrapping we allow all objects to pass as global 724 // objects. This is necessary to fix circular dependencies. 725 return isolate->heap()->gc_state() != Heap::NOT_IN_GC || 726 isolate->bootstrapper()->IsActive() || object->IsNativeContext(); 727 } 728 729 730 bool Context::IsBootstrappingOrValidParentContext( 731 Object* object, Context* child) { 732 // During bootstrapping we allow all objects to pass as 733 // contexts. This is necessary to fix circular dependencies. 734 if (child->GetIsolate()->bootstrapper()->IsActive()) return true; 735 if (!object->IsContext()) return false; 736 Context* context = Context::cast(object); 737 return context->IsNativeContext() || context->IsScriptContext() || 738 context->IsModuleContext() || !child->IsModuleContext(); 739 } 740 741 #endif 742 743 void Context::ResetErrorsThrown() { 744 DCHECK(IsNativeContext()); 745 set_errors_thrown(Smi::FromInt(0)); 746 } 747 748 void Context::IncrementErrorsThrown() { 749 DCHECK(IsNativeContext()); 750 751 int previous_value = errors_thrown()->value(); 752 set_errors_thrown(Smi::FromInt(previous_value + 1)); 753 } 754 755 756 int Context::GetErrorsThrown() { return errors_thrown()->value(); } 757 758 } // namespace internal 759 } // namespace v8 760