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/ast/scopeinfo.h"
6
7#include <stdlib.h>
8
9#include "src/ast/scopes.h"
10#include "src/bootstrapper.h"
11
12namespace v8 {
13namespace internal {
14
15
16Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
17                                    Scope* scope) {
18  // Collect stack and context locals.
19  ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
20  ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
21  ZoneList<Variable*> context_globals(scope->ContextGlobalCount(), zone);
22
23  scope->CollectStackAndContextLocals(&stack_locals, &context_locals,
24                                      &context_globals);
25  const int stack_local_count = stack_locals.length();
26  const int context_local_count = context_locals.length();
27  const int context_global_count = context_globals.length();
28  // Make sure we allocate the correct amount.
29  DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
30  DCHECK_EQ(scope->ContextGlobalCount(), context_global_count);
31
32  // Determine use and location of the "this" binding if it is present.
33  VariableAllocationInfo receiver_info;
34  if (scope->has_this_declaration()) {
35    Variable* var = scope->receiver();
36    if (!var->is_used()) {
37      receiver_info = UNUSED;
38    } else if (var->IsContextSlot()) {
39      receiver_info = CONTEXT;
40    } else {
41      DCHECK(var->IsParameter());
42      receiver_info = STACK;
43    }
44  } else {
45    receiver_info = NONE;
46  }
47
48  bool has_new_target = scope->new_target_var() != nullptr;
49
50  // Determine use and location of the function variable if it is present.
51  VariableAllocationInfo function_name_info;
52  VariableMode function_variable_mode;
53  if (scope->is_function_scope() && scope->function() != NULL) {
54    Variable* var = scope->function()->proxy()->var();
55    if (!var->is_used()) {
56      function_name_info = UNUSED;
57    } else if (var->IsContextSlot()) {
58      function_name_info = CONTEXT;
59    } else {
60      DCHECK(var->IsStackLocal());
61      function_name_info = STACK;
62    }
63    function_variable_mode = var->mode();
64  } else {
65    function_name_info = NONE;
66    function_variable_mode = VAR;
67  }
68  DCHECK(context_global_count == 0 || scope->scope_type() == SCRIPT_SCOPE);
69
70  const bool has_function_name = function_name_info != NONE;
71  const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
72  const int parameter_count = scope->num_parameters();
73  const int length = kVariablePartIndex + parameter_count +
74                     (1 + stack_local_count) + 2 * context_local_count +
75                     2 * context_global_count +
76                     (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
77
78  Factory* factory = isolate->factory();
79  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
80
81  bool has_simple_parameters =
82      scope->is_function_scope() && scope->has_simple_parameters();
83
84  // Encode the flags.
85  int flags = ScopeTypeField::encode(scope->scope_type()) |
86              CallsEvalField::encode(scope->calls_eval()) |
87              LanguageModeField::encode(scope->language_mode()) |
88              DeclarationScopeField::encode(scope->is_declaration_scope()) |
89              ReceiverVariableField::encode(receiver_info) |
90              HasNewTargetField::encode(has_new_target) |
91              FunctionVariableField::encode(function_name_info) |
92              FunctionVariableMode::encode(function_variable_mode) |
93              AsmModuleField::encode(scope->asm_module()) |
94              AsmFunctionField::encode(scope->asm_function()) |
95              HasSimpleParametersField::encode(has_simple_parameters) |
96              FunctionKindField::encode(scope->function_kind());
97  scope_info->SetFlags(flags);
98  scope_info->SetParameterCount(parameter_count);
99  scope_info->SetStackLocalCount(stack_local_count);
100  scope_info->SetContextLocalCount(context_local_count);
101  scope_info->SetContextGlobalCount(context_global_count);
102
103  int index = kVariablePartIndex;
104  // Add parameters.
105  DCHECK(index == scope_info->ParameterEntriesIndex());
106  for (int i = 0; i < parameter_count; ++i) {
107    scope_info->set(index++, *scope->parameter(i)->name());
108  }
109
110  // Add stack locals' names. We are assuming that the stack locals'
111  // slots are allocated in increasing order, so we can simply add
112  // them to the ScopeInfo object.
113  int first_slot_index;
114  if (stack_local_count > 0) {
115    first_slot_index = stack_locals[0]->index();
116  } else {
117    first_slot_index = 0;
118  }
119  DCHECK(index == scope_info->StackLocalFirstSlotIndex());
120  scope_info->set(index++, Smi::FromInt(first_slot_index));
121  DCHECK(index == scope_info->StackLocalEntriesIndex());
122  for (int i = 0; i < stack_local_count; ++i) {
123    DCHECK(stack_locals[i]->index() == first_slot_index + i);
124    scope_info->set(index++, *stack_locals[i]->name());
125  }
126
127  // Due to usage analysis, context-allocated locals are not necessarily in
128  // increasing order: Some of them may be parameters which are allocated before
129  // the non-parameter locals. When the non-parameter locals are sorted
130  // according to usage, the allocated slot indices may not be in increasing
131  // order with the variable list anymore. Thus, we first need to sort them by
132  // context slot index before adding them to the ScopeInfo object.
133  context_locals.Sort(&Variable::CompareIndex);
134
135  // Add context locals' names.
136  DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
137  for (int i = 0; i < context_local_count; ++i) {
138    scope_info->set(index++, *context_locals[i]->name());
139  }
140
141  // Add context globals' names.
142  DCHECK(index == scope_info->ContextGlobalNameEntriesIndex());
143  for (int i = 0; i < context_global_count; ++i) {
144    scope_info->set(index++, *context_globals[i]->name());
145  }
146
147  // Add context locals' info.
148  DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
149  for (int i = 0; i < context_local_count; ++i) {
150    Variable* var = context_locals[i];
151    uint32_t value =
152        ContextLocalMode::encode(var->mode()) |
153        ContextLocalInitFlag::encode(var->initialization_flag()) |
154        ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
155    scope_info->set(index++, Smi::FromInt(value));
156  }
157
158  // Add context globals' info.
159  DCHECK(index == scope_info->ContextGlobalInfoEntriesIndex());
160  for (int i = 0; i < context_global_count; ++i) {
161    Variable* var = context_globals[i];
162    // TODO(ishell): do we need this kind of info for globals here?
163    uint32_t value =
164        ContextLocalMode::encode(var->mode()) |
165        ContextLocalInitFlag::encode(var->initialization_flag()) |
166        ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
167    scope_info->set(index++, Smi::FromInt(value));
168  }
169
170  // If the receiver is allocated, add its index.
171  DCHECK(index == scope_info->ReceiverEntryIndex());
172  if (has_receiver) {
173    int var_index = scope->receiver()->index();
174    scope_info->set(index++, Smi::FromInt(var_index));
175    // ?? DCHECK(receiver_info != CONTEXT || var_index ==
176    // scope_info->ContextLength() - 1);
177  }
178
179  // If present, add the function variable name and its index.
180  DCHECK(index == scope_info->FunctionNameEntryIndex());
181  if (has_function_name) {
182    int var_index = scope->function()->proxy()->var()->index();
183    scope_info->set(index++, *scope->function()->proxy()->name());
184    scope_info->set(index++, Smi::FromInt(var_index));
185    DCHECK(function_name_info != CONTEXT ||
186           var_index == scope_info->ContextLength() - 1);
187  }
188
189  DCHECK(index == scope_info->length());
190  DCHECK(scope->num_parameters() == scope_info->ParameterCount());
191  DCHECK(scope->num_heap_slots() == scope_info->ContextLength() ||
192         (scope->num_heap_slots() == kVariablePartIndex &&
193          scope_info->ContextLength() == 0));
194  return scope_info;
195}
196
197
198Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
199  DCHECK(isolate->bootstrapper()->IsActive());
200
201  const int stack_local_count = 0;
202  const int context_local_count = 1;
203  const int context_global_count = 0;
204  const bool has_simple_parameters = true;
205  const VariableAllocationInfo receiver_info = CONTEXT;
206  const VariableAllocationInfo function_name_info = NONE;
207  const VariableMode function_variable_mode = VAR;
208  const bool has_function_name = false;
209  const bool has_receiver = true;
210  const int parameter_count = 0;
211  const int length = kVariablePartIndex + parameter_count +
212                     (1 + stack_local_count) + 2 * context_local_count +
213                     2 * context_global_count +
214                     (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
215
216  Factory* factory = isolate->factory();
217  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
218
219  // Encode the flags.
220  int flags = ScopeTypeField::encode(SCRIPT_SCOPE) |
221              CallsEvalField::encode(false) |
222              LanguageModeField::encode(SLOPPY) |
223              DeclarationScopeField::encode(true) |
224              ReceiverVariableField::encode(receiver_info) |
225              FunctionVariableField::encode(function_name_info) |
226              FunctionVariableMode::encode(function_variable_mode) |
227              AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
228              HasSimpleParametersField::encode(has_simple_parameters) |
229              FunctionKindField::encode(FunctionKind::kNormalFunction);
230  scope_info->SetFlags(flags);
231  scope_info->SetParameterCount(parameter_count);
232  scope_info->SetStackLocalCount(stack_local_count);
233  scope_info->SetContextLocalCount(context_local_count);
234  scope_info->SetContextGlobalCount(context_global_count);
235
236  int index = kVariablePartIndex;
237  const int first_slot_index = 0;
238  DCHECK(index == scope_info->StackLocalFirstSlotIndex());
239  scope_info->set(index++, Smi::FromInt(first_slot_index));
240  DCHECK(index == scope_info->StackLocalEntriesIndex());
241
242  // Here we add info for context-allocated "this".
243  DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
244  scope_info->set(index++, *isolate->factory()->this_string());
245  DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
246  const uint32_t value = ContextLocalMode::encode(CONST) |
247                         ContextLocalInitFlag::encode(kCreatedInitialized) |
248                         ContextLocalMaybeAssignedFlag::encode(kNotAssigned);
249  scope_info->set(index++, Smi::FromInt(value));
250
251  // And here we record that this scopeinfo binds a receiver.
252  DCHECK(index == scope_info->ReceiverEntryIndex());
253  const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
254  scope_info->set(index++, Smi::FromInt(receiver_index));
255
256  DCHECK(index == scope_info->FunctionNameEntryIndex());
257
258  DCHECK_EQ(index, scope_info->length());
259  DCHECK_EQ(scope_info->ParameterCount(), 0);
260  DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1);
261
262  return scope_info;
263}
264
265
266ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
267  return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
268}
269
270
271ScopeType ScopeInfo::scope_type() {
272  DCHECK(length() > 0);
273  return ScopeTypeField::decode(Flags());
274}
275
276
277bool ScopeInfo::CallsEval() {
278  return length() > 0 && CallsEvalField::decode(Flags());
279}
280
281
282LanguageMode ScopeInfo::language_mode() {
283  return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY;
284}
285
286
287bool ScopeInfo::is_declaration_scope() {
288  return DeclarationScopeField::decode(Flags());
289}
290
291
292int ScopeInfo::LocalCount() {
293  return StackLocalCount() + ContextLocalCount();
294}
295
296
297int ScopeInfo::StackSlotCount() {
298  if (length() > 0) {
299    bool function_name_stack_slot =
300        FunctionVariableField::decode(Flags()) == STACK;
301    return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
302  }
303  return 0;
304}
305
306
307int ScopeInfo::ContextLength() {
308  if (length() > 0) {
309    int context_locals = ContextLocalCount();
310    int context_globals = ContextGlobalCount();
311    bool function_name_context_slot =
312        FunctionVariableField::decode(Flags()) == CONTEXT;
313    bool has_context = context_locals > 0 || context_globals > 0 ||
314                       function_name_context_slot ||
315                       scope_type() == WITH_SCOPE ||
316                       (scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
317                           is_declaration_scope()) ||
318                       (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
319                       scope_type() == MODULE_SCOPE;
320
321    if (has_context) {
322      return Context::MIN_CONTEXT_SLOTS + context_locals + context_globals +
323             (function_name_context_slot ? 1 : 0);
324    }
325  }
326  return 0;
327}
328
329
330bool ScopeInfo::HasReceiver() {
331  if (length() > 0) {
332    return NONE != ReceiverVariableField::decode(Flags());
333  } else {
334    return false;
335  }
336}
337
338
339bool ScopeInfo::HasAllocatedReceiver() {
340  if (length() > 0) {
341    VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags());
342    return allocation == STACK || allocation == CONTEXT;
343  } else {
344    return false;
345  }
346}
347
348
349bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); }
350
351
352bool ScopeInfo::HasFunctionName() {
353  if (length() > 0) {
354    return NONE != FunctionVariableField::decode(Flags());
355  } else {
356    return false;
357  }
358}
359
360
361bool ScopeInfo::HasHeapAllocatedLocals() {
362  if (length() > 0) {
363    return ContextLocalCount() > 0;
364  } else {
365    return false;
366  }
367}
368
369
370bool ScopeInfo::HasContext() {
371  return ContextLength() > 0;
372}
373
374
375String* ScopeInfo::FunctionName() {
376  DCHECK(HasFunctionName());
377  return String::cast(get(FunctionNameEntryIndex()));
378}
379
380
381String* ScopeInfo::ParameterName(int var) {
382  DCHECK(0 <= var && var < ParameterCount());
383  int info_index = ParameterEntriesIndex() + var;
384  return String::cast(get(info_index));
385}
386
387
388String* ScopeInfo::LocalName(int var) {
389  DCHECK(0 <= var && var < LocalCount());
390  DCHECK(StackLocalEntriesIndex() + StackLocalCount() ==
391         ContextLocalNameEntriesIndex());
392  int info_index = StackLocalEntriesIndex() + var;
393  return String::cast(get(info_index));
394}
395
396
397String* ScopeInfo::StackLocalName(int var) {
398  DCHECK(0 <= var && var < StackLocalCount());
399  int info_index = StackLocalEntriesIndex() + var;
400  return String::cast(get(info_index));
401}
402
403
404int ScopeInfo::StackLocalIndex(int var) {
405  DCHECK(0 <= var && var < StackLocalCount());
406  int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
407  return first_slot_index + var;
408}
409
410
411String* ScopeInfo::ContextLocalName(int var) {
412  DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
413  int info_index = ContextLocalNameEntriesIndex() + var;
414  return String::cast(get(info_index));
415}
416
417
418VariableMode ScopeInfo::ContextLocalMode(int var) {
419  DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
420  int info_index = ContextLocalInfoEntriesIndex() + var;
421  int value = Smi::cast(get(info_index))->value();
422  return ContextLocalMode::decode(value);
423}
424
425
426InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
427  DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
428  int info_index = ContextLocalInfoEntriesIndex() + var;
429  int value = Smi::cast(get(info_index))->value();
430  return ContextLocalInitFlag::decode(value);
431}
432
433
434MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
435  DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
436  int info_index = ContextLocalInfoEntriesIndex() + var;
437  int value = Smi::cast(get(info_index))->value();
438  return ContextLocalMaybeAssignedFlag::decode(value);
439}
440
441bool ScopeInfo::VariableIsSynthetic(String* name) {
442  // There's currently no flag stored on the ScopeInfo to indicate that a
443  // variable is a compiler-introduced temporary. However, to avoid conflict
444  // with user declarations, the current temporaries like .generator_object and
445  // .result start with a dot, so we can use that as a flag. It's a hack!
446  return name->length() == 0 || name->Get(0) == '.' ||
447         name->Equals(name->GetHeap()->this_string());
448}
449
450
451int ScopeInfo::StackSlotIndex(String* name) {
452  DCHECK(name->IsInternalizedString());
453  if (length() > 0) {
454    int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
455    int start = StackLocalEntriesIndex();
456    int end = StackLocalEntriesIndex() + StackLocalCount();
457    for (int i = start; i < end; ++i) {
458      if (name == get(i)) {
459        return i - start + first_slot_index;
460      }
461    }
462  }
463  return -1;
464}
465
466
467int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
468                                Handle<String> name, VariableMode* mode,
469                                InitializationFlag* init_flag,
470                                MaybeAssignedFlag* maybe_assigned_flag) {
471  DCHECK(name->IsInternalizedString());
472  DCHECK(mode != NULL);
473  DCHECK(init_flag != NULL);
474  if (scope_info->length() > 0) {
475    ContextSlotCache* context_slot_cache =
476        scope_info->GetIsolate()->context_slot_cache();
477    int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
478                                            maybe_assigned_flag);
479    if (result != ContextSlotCache::kNotFound) {
480      DCHECK(result < scope_info->ContextLength());
481      return result;
482    }
483
484    int start = scope_info->ContextLocalNameEntriesIndex();
485    int end = scope_info->ContextLocalNameEntriesIndex() +
486              scope_info->ContextLocalCount();
487    for (int i = start; i < end; ++i) {
488      if (*name == scope_info->get(i)) {
489        int var = i - start;
490        *mode = scope_info->ContextLocalMode(var);
491        *init_flag = scope_info->ContextLocalInitFlag(var);
492        *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
493        result = Context::MIN_CONTEXT_SLOTS + var;
494
495        context_slot_cache->Update(scope_info, name, *mode, *init_flag,
496                                   *maybe_assigned_flag, result);
497        DCHECK(result < scope_info->ContextLength());
498        return result;
499      }
500    }
501    // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
502    context_slot_cache->Update(scope_info, name, TEMPORARY,
503                               kNeedsInitialization, kNotAssigned, -1);
504  }
505  return -1;
506}
507
508
509int ScopeInfo::ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info,
510                                      Handle<String> name, VariableMode* mode,
511                                      InitializationFlag* init_flag,
512                                      MaybeAssignedFlag* maybe_assigned_flag) {
513  DCHECK(name->IsInternalizedString());
514  DCHECK(mode != NULL);
515  DCHECK(init_flag != NULL);
516  if (scope_info->length() > 0) {
517    // This is to ensure that ContextLocalMode() and co. queries would work.
518    DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(),
519              scope_info->ContextLocalNameEntriesIndex() +
520                  scope_info->ContextLocalCount());
521    int base = scope_info->ContextLocalNameEntriesIndex();
522    int start = scope_info->ContextGlobalNameEntriesIndex();
523    int end = scope_info->ContextGlobalNameEntriesIndex() +
524              scope_info->ContextGlobalCount();
525    for (int i = start; i < end; ++i) {
526      if (*name == scope_info->get(i)) {
527        int var = i - base;
528        *mode = scope_info->ContextLocalMode(var);
529        *init_flag = scope_info->ContextLocalInitFlag(var);
530        *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
531        int result = Context::MIN_CONTEXT_SLOTS + var;
532        DCHECK(result < scope_info->ContextLength());
533        return result;
534      }
535    }
536  }
537  return -1;
538}
539
540
541String* ScopeInfo::ContextSlotName(int slot_index) {
542  int const var = slot_index - Context::MIN_CONTEXT_SLOTS;
543  DCHECK_LE(0, var);
544  DCHECK_LT(var, ContextLocalCount() + ContextGlobalCount());
545  return ContextLocalName(var);
546}
547
548
549int ScopeInfo::ParameterIndex(String* name) {
550  DCHECK(name->IsInternalizedString());
551  if (length() > 0) {
552    // We must read parameters from the end since for
553    // multiply declared parameters the value of the
554    // last declaration of that parameter is used
555    // inside a function (and thus we need to look
556    // at the last index). Was bug# 1110337.
557    int start = ParameterEntriesIndex();
558    int end = ParameterEntriesIndex() + ParameterCount();
559    for (int i = end - 1; i >= start; --i) {
560      if (name == get(i)) {
561        return i - start;
562      }
563    }
564  }
565  return -1;
566}
567
568
569int ScopeInfo::ReceiverContextSlotIndex() {
570  if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT)
571    return Smi::cast(get(ReceiverEntryIndex()))->value();
572  return -1;
573}
574
575
576int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
577  DCHECK(name->IsInternalizedString());
578  DCHECK(mode != NULL);
579  if (length() > 0) {
580    if (FunctionVariableField::decode(Flags()) == CONTEXT &&
581        FunctionName() == name) {
582      *mode = FunctionVariableMode::decode(Flags());
583      return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
584    }
585  }
586  return -1;
587}
588
589
590FunctionKind ScopeInfo::function_kind() {
591  return FunctionKindField::decode(Flags());
592}
593
594
595int ScopeInfo::ParameterEntriesIndex() {
596  DCHECK(length() > 0);
597  return kVariablePartIndex;
598}
599
600
601int ScopeInfo::StackLocalFirstSlotIndex() {
602  return ParameterEntriesIndex() + ParameterCount();
603}
604
605
606int ScopeInfo::StackLocalEntriesIndex() {
607  return StackLocalFirstSlotIndex() + 1;
608}
609
610
611int ScopeInfo::ContextLocalNameEntriesIndex() {
612  return StackLocalEntriesIndex() + StackLocalCount();
613}
614
615
616int ScopeInfo::ContextGlobalNameEntriesIndex() {
617  return ContextLocalNameEntriesIndex() + ContextLocalCount();
618}
619
620
621int ScopeInfo::ContextLocalInfoEntriesIndex() {
622  return ContextGlobalNameEntriesIndex() + ContextGlobalCount();
623}
624
625
626int ScopeInfo::ContextGlobalInfoEntriesIndex() {
627  return ContextLocalInfoEntriesIndex() + ContextLocalCount();
628}
629
630
631int ScopeInfo::ReceiverEntryIndex() {
632  return ContextGlobalInfoEntriesIndex() + ContextGlobalCount();
633}
634
635
636int ScopeInfo::FunctionNameEntryIndex() {
637  return ReceiverEntryIndex() + (HasAllocatedReceiver() ? 1 : 0);
638}
639
640
641int ContextSlotCache::Hash(Object* data, String* name) {
642  // Uses only lower 32 bits if pointers are larger.
643  uintptr_t addr_hash =
644      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
645  return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
646}
647
648
649int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
650                             InitializationFlag* init_flag,
651                             MaybeAssignedFlag* maybe_assigned_flag) {
652  int index = Hash(data, name);
653  Key& key = keys_[index];
654  if ((key.data == data) && key.name->Equals(name)) {
655    Value result(values_[index]);
656    if (mode != NULL) *mode = result.mode();
657    if (init_flag != NULL) *init_flag = result.initialization_flag();
658    if (maybe_assigned_flag != NULL)
659      *maybe_assigned_flag = result.maybe_assigned_flag();
660    return result.index() + kNotFound;
661  }
662  return kNotFound;
663}
664
665
666void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
667                              VariableMode mode, InitializationFlag init_flag,
668                              MaybeAssignedFlag maybe_assigned_flag,
669                              int slot_index) {
670  DisallowHeapAllocation no_gc;
671  Handle<String> internalized_name;
672  DCHECK(slot_index > kNotFound);
673  if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
674      ToHandle(&internalized_name)) {
675    int index = Hash(*data, *internalized_name);
676    Key& key = keys_[index];
677    key.data = *data;
678    key.name = *internalized_name;
679    // Please note value only takes a uint as index.
680    values_[index] = Value(mode, init_flag, maybe_assigned_flag,
681                           slot_index - kNotFound).raw();
682#ifdef DEBUG
683    ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
684#endif
685  }
686}
687
688
689void ContextSlotCache::Clear() {
690  for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
691}
692
693
694#ifdef DEBUG
695
696void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
697                                     VariableMode mode,
698                                     InitializationFlag init_flag,
699                                     MaybeAssignedFlag maybe_assigned_flag,
700                                     int slot_index) {
701  DisallowHeapAllocation no_gc;
702  Handle<String> internalized_name;
703  if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
704      ToHandle(&internalized_name)) {
705    int index = Hash(*data, *name);
706    Key& key = keys_[index];
707    DCHECK(key.data == *data);
708    DCHECK(key.name->Equals(*name));
709    Value result(values_[index]);
710    DCHECK(result.mode() == mode);
711    DCHECK(result.initialization_flag() == init_flag);
712    DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
713    DCHECK(result.index() + kNotFound == slot_index);
714  }
715}
716
717
718static void PrintList(const char* list_name,
719                      int nof_internal_slots,
720                      int start,
721                      int end,
722                      ScopeInfo* scope_info) {
723  if (start < end) {
724    PrintF("\n  // %s\n", list_name);
725    if (nof_internal_slots > 0) {
726      PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
727    }
728    for (int i = nof_internal_slots; start < end; ++i, ++start) {
729      PrintF("  %2d ", i);
730      String::cast(scope_info->get(start))->ShortPrint();
731      PrintF("\n");
732    }
733  }
734}
735
736
737void ScopeInfo::Print() {
738  PrintF("ScopeInfo ");
739  if (HasFunctionName()) {
740    FunctionName()->ShortPrint();
741  } else {
742    PrintF("/* no function name */");
743  }
744  PrintF("{");
745
746  if (length() > 0) {
747    PrintList("parameters", 0, ParameterEntriesIndex(),
748              ParameterEntriesIndex() + ParameterCount(), this);
749    PrintList("stack slots", 0, StackLocalEntriesIndex(),
750              StackLocalEntriesIndex() + StackLocalCount(), this);
751    PrintList("context slots", Context::MIN_CONTEXT_SLOTS,
752              ContextLocalNameEntriesIndex(),
753              ContextLocalNameEntriesIndex() + ContextLocalCount(), this);
754  }
755
756  PrintF("}\n");
757}
758#endif  // DEBUG
759
760
761//---------------------------------------------------------------------------
762// ModuleInfo.
763
764Handle<ModuleInfo> ModuleInfo::Create(Isolate* isolate,
765                                      ModuleDescriptor* descriptor,
766                                      Scope* scope) {
767  Handle<ModuleInfo> info = Allocate(isolate, descriptor->Length());
768  info->set_host_index(descriptor->Index());
769  int i = 0;
770  for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
771       it.Advance(), ++i) {
772    Variable* var = scope->LookupLocal(it.local_name());
773    info->set_name(i, *(it.export_name()->string()));
774    info->set_mode(i, var->mode());
775    DCHECK(var->index() >= 0);
776    info->set_index(i, var->index());
777  }
778  DCHECK(i == info->length());
779  return info;
780}
781
782}  // namespace internal
783}  // namespace v8
784