Line data Source code
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 11615 : 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 11615 : CHECK(used >= 0 && length > 0 && used < length);
21 11615 : if (used + kFirstContextSlot == length) {
22 9163 : CHECK(length < Smi::kMaxValue / 2);
23 : Isolate* isolate = table->GetIsolate();
24 : Handle<FixedArray> copy =
25 9163 : isolate->factory()->CopyFixedArrayAndGrow(table, length);
26 18326 : 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 11615 : result->set(used + kFirstContextSlot, *script_context);
35 11615 : return result;
36 : }
37 :
38 :
39 9506182 : bool ScriptContextTable::Lookup(Handle<ScriptContextTable> table,
40 : Handle<String> name, LookupResult* result) {
41 39567772 : for (int i = 0; i < table->used(); i++) {
42 10347324 : Handle<Context> context = GetContext(table, i);
43 : DCHECK(context->IsScriptContext());
44 10347325 : Handle<ScopeInfo> scope_info(context->scope_info());
45 : int slot_index = ScopeInfo::ContextSlotIndex(
46 : scope_info, name, &result->mode, &result->init_flag,
47 10347325 : &result->maybe_assigned_flag);
48 :
49 10347325 : if (slot_index >= 0) {
50 69621 : result->context_index = i;
51 69621 : result->slot_index = slot_index;
52 69621 : return true;
53 : }
54 : }
55 : return false;
56 : }
57 :
58 :
59 819435 : bool Context::is_declaration_context() {
60 823715 : if (IsFunctionContext() || IsNativeContext() || IsScriptContext() ||
61 4280 : IsModuleContext()) {
62 : return true;
63 : }
64 4634 : if (IsEvalContext()) return closure()->shared()->language_mode() == STRICT;
65 3926 : 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 5768 : return ext->IsContextExtension() ||
70 5768 : ScopeInfo::cast(ext)->is_declaration_scope();
71 : }
72 :
73 :
74 515538 : Context* Context::declaration_context() {
75 : Context* current = this;
76 1031907 : while (!current->is_declaration_context()) {
77 : current = current->previous();
78 : }
79 515538 : return current;
80 : }
81 :
82 37590 : Context* Context::closure_context() {
83 : Context* current = this;
84 131807 : while (!current->IsFunctionContext() && !current->IsScriptContext() &&
85 54232 : !current->IsModuleContext() && !current->IsNativeContext() &&
86 4048 : !current->IsEvalContext()) {
87 : current = current->previous();
88 : DCHECK(current->closure() == closure());
89 : }
90 37590 : return current;
91 : }
92 :
93 11252549 : JSObject* Context::extension_object() {
94 : DCHECK(IsNativeContext() || IsFunctionContext() || IsBlockContext() ||
95 : IsEvalContext());
96 : HeapObject* object = extension();
97 11252549 : if (object->IsTheHole(GetIsolate())) return nullptr;
98 6413292 : if (IsBlockContext()) {
99 33148 : if (!object->IsContextExtension()) return nullptr;
100 : object = JSObject::cast(ContextExtension::cast(object)->extension());
101 : }
102 : DCHECK(object->IsJSContextExtensionObject() ||
103 : (IsNativeContext() && object->IsJSGlobalObject()));
104 6383924 : return JSObject::cast(object);
105 : }
106 :
107 18293227 : JSReceiver* Context::extension_receiver() {
108 : DCHECK(IsNativeContext() || IsWithContext() || IsEvalContext() ||
109 : IsFunctionContext() || IsBlockContext());
110 18293227 : return IsWithContext() ? JSReceiver::cast(
111 : ContextExtension::cast(extension())->extension())
112 29241974 : : extension_object();
113 : }
114 :
115 17164715 : ScopeInfo* Context::scope_info() {
116 : DCHECK(!IsNativeContext());
117 17164715 : if (IsFunctionContext() || IsModuleContext() || IsEvalContext()) {
118 6190240 : return closure()->shared()->scope_info();
119 : }
120 : HeapObject* object = extension();
121 10974476 : if (object->IsContextExtension()) {
122 : DCHECK(IsBlockContext() || IsCatchContext() || IsWithContext() ||
123 : IsDebugEvaluateContext());
124 : object = ContextExtension::cast(object)->scope_info();
125 : }
126 10974476 : return ScopeInfo::cast(object);
127 : }
128 :
129 353 : Module* Context::module() {
130 : Context* current = this;
131 706 : while (!current->IsModuleContext()) {
132 : current = current->previous();
133 : }
134 353 : return Module::cast(current->extension());
135 : }
136 :
137 1794 : String* Context::catch_name() {
138 : DCHECK(IsCatchContext());
139 1794 : return String::cast(ContextExtension::cast(extension())->extension());
140 : }
141 :
142 :
143 17824470 : JSGlobalObject* Context::global_object() {
144 17824470 : return JSGlobalObject::cast(native_context()->extension());
145 : }
146 :
147 :
148 0 : Context* Context::script_context() {
149 : Context* current = this;
150 0 : while (!current->IsScriptContext()) {
151 : current = current->previous();
152 : }
153 0 : return current;
154 : }
155 :
156 :
157 3934582 : JSObject* Context::global_proxy() {
158 3934582 : return native_context()->global_proxy_object();
159 : }
160 :
161 :
162 106897 : void Context::set_global_proxy(JSObject* object) {
163 : native_context()->set_global_proxy_object(object);
164 106897 : }
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 3667863 : static Maybe<bool> UnscopableLookup(LookupIterator* it) {
172 : Isolate* isolate = it->isolate();
173 :
174 3667863 : Maybe<bool> found = JSReceiver::HasProperty(it);
175 7335670 : if (!found.IsJust() || !found.FromJust()) return found;
176 :
177 : Handle<Object> unscopables;
178 1427832 : 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 713874 : if (!unscopables->IsJSReceiver()) return Just(true);
184 : Handle<Object> blacklist;
185 385896 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
186 : isolate, blacklist,
187 : JSReceiver::GetProperty(Handle<JSReceiver>::cast(unscopables),
188 : it->name()),
189 : Nothing<bool>());
190 192934 : return Just(!blacklist->BooleanValue());
191 : }
192 :
193 : static PropertyAttributes GetAttributesForMode(VariableMode mode) {
194 : DCHECK(IsDeclaredVariableMode(mode));
195 2814675 : return mode == CONST ? READ_ONLY : NONE;
196 : }
197 :
198 6462830 : 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 6462830 : bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
207 : bool failed_whitelist = false;
208 6462830 : *index = kNotFound;
209 6462830 : *attributes = ABSENT;
210 6462830 : *init_flag = kCreatedInitialized;
211 6462830 : *variable_mode = VAR;
212 :
213 : if (FLAG_trace_contexts) {
214 : PrintF("Context::Lookup(");
215 : name->ShortPrint();
216 : PrintF(")\n");
217 : }
218 :
219 6271196 : 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 34142978 : if ((context->IsNativeContext() ||
231 19790179 : (context->IsWithContext() && ((flags & SKIP_WITH_CONTEXT) == 0)) ||
232 30505464 : context->IsFunctionContext() || context->IsBlockContext()) &&
233 11559841 : context->extension_receiver() != nullptr) {
234 6725702 : Handle<JSReceiver> object(context->extension_receiver());
235 :
236 6725702 : 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 2229064 : context->global_object()->native_context()->script_context_table());
243 : ScriptContextTable::LookupResult r;
244 2229064 : 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 53 : *index = r.slot_index;
252 53 : *variable_mode = r.mode;
253 53 : *init_flag = r.init_flag;
254 53 : *attributes = GetAttributesForMode(r.mode);
255 : return ScriptContextTable::GetContext(script_contexts,
256 53 : 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 12512478 : if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
265 : object->IsJSContextExtensionObject()) {
266 1218254 : maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
267 5507395 : } 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 3668088 : if (ScopeInfo::VariableIsSynthetic(*name)) {
276 : maybe = Just(ABSENT);
277 : } else {
278 3667863 : LookupIterator it(object, name, object);
279 3667863 : Maybe<bool> found = UnscopableLookup(&it);
280 3667863 : 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 3667751 : maybe = Just(found.FromJust() ? NONE : ABSENT);
287 : }
288 : }
289 : } else {
290 1839307 : maybe = JSReceiver::GetPropertyAttributes(object, name);
291 : }
292 :
293 6725649 : if (!maybe.IsJust()) return Handle<Object>();
294 : DCHECK(!isolate->has_pending_exception());
295 6725537 : *attributes = maybe.FromJust();
296 :
297 6725537 : 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 3028101 : return object;
303 : }
304 : }
305 :
306 : // 2. Check the context proper if it has slots.
307 25459712 : if (context->IsFunctionContext() || context->IsBlockContext() ||
308 16152000 : context->IsScriptContext() || context->IsEvalContext()) {
309 : // Use serialized scope information of functions and blocks to search
310 : // for the context index.
311 5659217 : 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 5659217 : &flag, &maybe_assigned_flag);
317 : DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
318 5659217 : 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 2814622 : *index = slot_index;
324 2814622 : *variable_mode = mode;
325 2814622 : *init_flag = flag;
326 2814622 : *attributes = GetAttributesForMode(mode);
327 2814622 : 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 5084009 : if (follow_context_chain && (flags & STOP_AT_DECLARATION_SCOPE) == 0 &&
334 2239414 : context->IsFunctionContext()) {
335 2064757 : int function_index = scope_info->FunctionContextSlotIndex(*name);
336 2064757 : if (function_index >= 0) {
337 : if (FLAG_trace_contexts) {
338 : PrintF("=> found intermediate function in context slot %d\n",
339 : function_index);
340 : }
341 236 : *index = function_index;
342 236 : *attributes = READ_ONLY;
343 236 : *init_flag = kCreatedInitialized;
344 236 : *variable_mode = CONST;
345 236 : return context;
346 : }
347 : }
348 :
349 3436531 : } else if (context->IsCatchContext()) {
350 : // Catch contexts have the variable name in the extension slot.
351 366169 : if (String::Equals(name, handle(context->catch_name()))) {
352 : if (FLAG_trace_contexts) {
353 : PrintF("=> found in catch context\n");
354 : }
355 119 : *index = Context::THROWN_OBJECT_INDEX;
356 119 : *attributes = NONE;
357 119 : *init_flag = kCreatedInitialized;
358 119 : *variable_mode = VAR;
359 119 : return context;
360 : }
361 3070362 : } else if (context->IsDebugEvaluateContext()) {
362 : // Check materialized locals.
363 : Object* ext = context->get(EXTENSION_INDEX);
364 14855 : if (ext->IsContextExtension()) {
365 : Object* obj = ContextExtension::cast(ext)->extension();
366 14855 : if (obj->IsJSReceiver()) {
367 : Handle<JSReceiver> extension(JSReceiver::cast(obj));
368 14337 : LookupIterator it(extension, name, extension);
369 14337 : Maybe<bool> found = JSReceiver::HasProperty(&it);
370 14337 : if (found.FromMaybe(false)) {
371 8699 : *attributes = NONE;
372 8699 : 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 6156 : if (obj->IsContext()) {
379 : Handle<Object> result =
380 : Context::cast(obj)->Lookup(name, DONT_FOLLOW_CHAINS, index,
381 1464 : attributes, init_flag, variable_mode);
382 1464 : 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 5280 : if (obj->IsStringSet()) {
388 4632 : failed_whitelist = failed_whitelist || !StringSet::cast(obj)->Has(name);
389 : }
390 : }
391 :
392 : // 3. Prepare to continue with the previous (next outermost) context.
393 18808844 : if (context->IsNativeContext() ||
394 6569518 : ((flags & STOP_AT_DECLARATION_SCOPE) != 0 &&
395 303066 : context->is_declaration_context())) {
396 : follow_context_chain = false;
397 : } else {
398 5964267 : 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 8598 : } while (failed_whitelist && !context->IsScriptContext() &&
403 5968483 : !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 9552 : int Context::SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared,
420 : BailoutId osr_ast_id) {
421 : DisallowHeapAllocation no_gc;
422 : DCHECK(this->IsNativeContext());
423 9552 : 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 43997 : for (int i = 0; i < length; i += kEntryLength) {
428 41845 : if (WeakCell::cast(optimized_code_map->get(i + kSharedOffset))->value() ==
429 42112 : shared &&
430 267 : optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
431 : return i;
432 : }
433 : }
434 : }
435 : return -1;
436 : }
437 :
438 8477 : Code* Context::SearchOptimizedCodeMap(SharedFunctionInfo* shared,
439 : BailoutId osr_ast_id) {
440 : DCHECK(this->IsNativeContext());
441 8477 : int entry = SearchOptimizedCodeMapEntry(shared, osr_ast_id);
442 8477 : if (entry != -1) {
443 : FixedArray* code_map = osr_code_table();
444 : DCHECK_LE(entry + kEntryLength, code_map->length());
445 211 : WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
446 211 : return cell->cleared() ? nullptr : Code::cast(cell->value());
447 : }
448 : return nullptr;
449 : }
450 :
451 2546 : 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 2546 : Isolate* isolate = native_context->GetIsolate();
457 2546 : if (isolate->serializer_enabled()) return;
458 :
459 : STATIC_ASSERT(kEntryLength == 3);
460 : Handle<FixedArray> new_code_map;
461 : int entry;
462 :
463 2546 : if (native_context->OptimizedCodeMapIsCleared()) {
464 1471 : 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 1075 : entry = native_context->SearchOptimizedCodeMapEntry(*shared, osr_ast_id);
469 1075 : if (entry >= 0) {
470 : // Just set the code of the entry.
471 0 : Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
472 0 : 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 21689 : for (int i = 0; i < length; i += kEntryLength) {
480 20614 : 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 1075 : if (entry < 0) {
488 : // Copy old optimized code map and append one new entry.
489 : new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
490 1075 : old_code_map, kEntryLength, TENURED);
491 : entry = old_code_map->length();
492 : }
493 : }
494 :
495 2546 : Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
496 2546 : Handle<WeakCell> shared_cell = isolate->factory()->NewWeakCell(shared);
497 :
498 2546 : new_code_map->set(entry + kSharedOffset, *shared_cell);
499 5092 : 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 2546 : if (old_code_map != *new_code_map) {
516 : native_context->set_osr_code_table(*new_code_map);
517 : }
518 : }
519 :
520 1084953 : void Context::EvictFromOptimizedCodeMap(Code* optimized_code,
521 : const char* reason) {
522 : DCHECK(IsNativeContext());
523 : DisallowHeapAllocation no_gc;
524 2169906 : 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 102208 : for (int src = 0; src < length; src += kEntryLength) {
531 188318 : if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
532 : optimized_code) {
533 2077 : BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
534 2077 : if (FLAG_trace_opt) {
535 : PrintF(
536 : "[evicting entry from native context optimizing code map (%s) for ",
537 0 : reason);
538 0 : ShortPrint();
539 : DCHECK(!osr.IsNone());
540 0 : 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 92082 : if (dst != src) {
547 10 : code_map->set(dst + kSharedOffset, code_map->get(src + kSharedOffset));
548 : code_map->set(dst + kCachedCodeOffset,
549 10 : code_map->get(src + kCachedCodeOffset));
550 : code_map->set(dst + kOsrAstIdOffset,
551 20 : code_map->get(src + kOsrAstIdOffset));
552 : }
553 92082 : dst += kEntryLength;
554 : }
555 8049 : if (dst != length) {
556 : // Always trim even when array is cleared because of heap verifier.
557 2077 : heap->RightTrimFixedArray(code_map, length - dst);
558 2077 : if (code_map->length() == 0) {
559 : ClearOptimizedCodeMap();
560 : }
561 : }
562 : }
563 :
564 23955 : void Context::ClearOptimizedCodeMap() {
565 : DCHECK(IsNativeContext());
566 25159 : FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
567 : set_osr_code_table(empty_fixed_array);
568 23955 : }
569 :
570 1479990 : 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 1479990 : if (!function->next_function_link()->IsUndefined(isolate)) {
598 2 : CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
599 2 : 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 1479990 : UPDATE_WEAK_WRITE_BARRIER);
606 1479989 : set(OPTIMIZED_FUNCTIONS_LIST, function, UPDATE_WEAK_WRITE_BARRIER);
607 1479989 : }
608 :
609 :
610 530 : 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 1062 : 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 532 : if (element_function == function) {
620 530 : if (prev == NULL) {
621 : set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link(),
622 528 : UPDATE_WEAK_WRITE_BARRIER);
623 : } else {
624 : prev->set_next_function_link(element_function->next_function_link(),
625 2 : UPDATE_WEAK_WRITE_BARRIER);
626 : }
627 530 : element_function->set_next_function_link(GetHeap()->undefined_value(),
628 530 : UPDATE_WEAK_WRITE_BARRIER);
629 530 : return;
630 : }
631 : prev = element_function;
632 : element = element_function->next_function_link();
633 : }
634 0 : UNREACHABLE();
635 : }
636 :
637 :
638 463047 : void Context::SetOptimizedFunctionsListHead(Object* head) {
639 : DCHECK(IsNativeContext());
640 463047 : set(OPTIMIZED_FUNCTIONS_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
641 463047 : }
642 :
643 :
644 98729 : Object* Context::OptimizedFunctionsListHead() {
645 : DCHECK(IsNativeContext());
646 98729 : return get(OPTIMIZED_FUNCTIONS_LIST);
647 : }
648 :
649 :
650 642048 : void Context::AddOptimizedCode(Code* code) {
651 : DCHECK(IsNativeContext());
652 : DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
653 : DCHECK(code->next_code_link()->IsUndefined(GetIsolate()));
654 642048 : code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
655 642048 : set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER);
656 642049 : }
657 :
658 :
659 416434 : void Context::SetOptimizedCodeListHead(Object* head) {
660 : DCHECK(IsNativeContext());
661 416434 : set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
662 416434 : }
663 :
664 :
665 109382 : Object* Context::OptimizedCodeListHead() {
666 : DCHECK(IsNativeContext());
667 109382 : return get(OPTIMIZED_CODE_LIST);
668 : }
669 :
670 :
671 422165 : void Context::SetDeoptimizedCodeListHead(Object* head) {
672 : DCHECK(IsNativeContext());
673 422165 : set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
674 422165 : }
675 :
676 :
677 546864 : Object* Context::DeoptimizedCodeListHead() {
678 : DCHECK(IsNativeContext());
679 546864 : return get(DEOPTIMIZED_CODE_LIST);
680 : }
681 :
682 :
683 48 : Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
684 : Isolate* isolate = GetIsolate();
685 : Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
686 48 : if (!result->IsUndefined(isolate)) return result;
687 : return isolate->factory()->NewStringFromStaticChars(
688 42 : "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 1501 : int Context::ImportedFieldIndexForName(Handle<String> string) {
696 26465 : NATIVE_CONTEXT_IMPORTED_FIELDS(COMPARE_NAME)
697 237 : return kNotFound;
698 : }
699 :
700 :
701 237 : int Context::IntrinsicIndexForName(Handle<String> string) {
702 4898 : NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
703 0 : 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 241926 : int Context::IntrinsicIndexForName(const unsigned char* unsigned_string,
712 : int length) {
713 : const char* string = reinterpret_cast<const char*>(unsigned_string);
714 241926 : NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
715 75 : 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 105618 : void Context::ResetErrorsThrown() {
744 : DCHECK(IsNativeContext());
745 : set_errors_thrown(Smi::FromInt(0));
746 105618 : }
747 :
748 1159401 : void Context::IncrementErrorsThrown() {
749 : DCHECK(IsNativeContext());
750 :
751 : int previous_value = errors_thrown()->value();
752 1159401 : set_errors_thrown(Smi::FromInt(previous_value + 1));
753 1159401 : }
754 :
755 :
756 130 : int Context::GetErrorsThrown() { return errors_thrown()->value(); }
757 :
758 : } // namespace internal
759 : } // namespace v8
|