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 <stdlib.h>
6
7#include "src/v8.h"
8
9#include "src/scopeinfo.h"
10#include "src/scopes.h"
11
12namespace v8 {
13namespace internal {
14
15
16Handle<ScopeInfo> ScopeInfo::Create(Scope* scope, Zone* zone) {
17  // Collect stack and context locals.
18  ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
19  ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
20  scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
21  const int stack_local_count = stack_locals.length();
22  const int context_local_count = context_locals.length();
23  // Make sure we allocate the correct amount.
24  DCHECK(scope->StackLocalCount() == stack_local_count);
25  DCHECK(scope->ContextLocalCount() == context_local_count);
26
27  // Determine use and location of the function variable if it is present.
28  FunctionVariableInfo function_name_info;
29  VariableMode function_variable_mode;
30  if (scope->is_function_scope() && scope->function() != NULL) {
31    Variable* var = scope->function()->proxy()->var();
32    if (!var->is_used()) {
33      function_name_info = UNUSED;
34    } else if (var->IsContextSlot()) {
35      function_name_info = CONTEXT;
36    } else {
37      DCHECK(var->IsStackLocal());
38      function_name_info = STACK;
39    }
40    function_variable_mode = var->mode();
41  } else {
42    function_name_info = NONE;
43    function_variable_mode = VAR;
44  }
45
46  const bool has_function_name = function_name_info != NONE;
47  const int parameter_count = scope->num_parameters();
48  const int length = kVariablePartIndex
49      + parameter_count + stack_local_count + 2 * context_local_count
50      + (has_function_name ? 2 : 0);
51
52  Factory* factory = zone->isolate()->factory();
53  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
54
55  // Encode the flags.
56  int flags = ScopeTypeField::encode(scope->scope_type()) |
57              CallsEvalField::encode(scope->calls_eval()) |
58              StrictModeField::encode(scope->strict_mode()) |
59              FunctionVariableField::encode(function_name_info) |
60              FunctionVariableMode::encode(function_variable_mode) |
61              AsmModuleField::encode(scope->asm_module()) |
62              AsmFunctionField::encode(scope->asm_function());
63  scope_info->SetFlags(flags);
64  scope_info->SetParameterCount(parameter_count);
65  scope_info->SetStackLocalCount(stack_local_count);
66  scope_info->SetContextLocalCount(context_local_count);
67
68  int index = kVariablePartIndex;
69  // Add parameters.
70  DCHECK(index == scope_info->ParameterEntriesIndex());
71  for (int i = 0; i < parameter_count; ++i) {
72    scope_info->set(index++, *scope->parameter(i)->name());
73  }
74
75  // Add stack locals' names. We are assuming that the stack locals'
76  // slots are allocated in increasing order, so we can simply add
77  // them to the ScopeInfo object.
78  DCHECK(index == scope_info->StackLocalEntriesIndex());
79  for (int i = 0; i < stack_local_count; ++i) {
80    DCHECK(stack_locals[i]->index() == i);
81    scope_info->set(index++, *stack_locals[i]->name());
82  }
83
84  // Due to usage analysis, context-allocated locals are not necessarily in
85  // increasing order: Some of them may be parameters which are allocated before
86  // the non-parameter locals. When the non-parameter locals are sorted
87  // according to usage, the allocated slot indices may not be in increasing
88  // order with the variable list anymore. Thus, we first need to sort them by
89  // context slot index before adding them to the ScopeInfo object.
90  context_locals.Sort(&Variable::CompareIndex);
91
92  // Add context locals' names.
93  DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
94  for (int i = 0; i < context_local_count; ++i) {
95    scope_info->set(index++, *context_locals[i]->name());
96  }
97
98  // Add context locals' info.
99  DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
100  for (int i = 0; i < context_local_count; ++i) {
101    Variable* var = context_locals[i];
102    uint32_t value =
103        ContextLocalMode::encode(var->mode()) |
104        ContextLocalInitFlag::encode(var->initialization_flag()) |
105        ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
106    scope_info->set(index++, Smi::FromInt(value));
107  }
108
109  // If present, add the function variable name and its index.
110  DCHECK(index == scope_info->FunctionNameEntryIndex());
111  if (has_function_name) {
112    int var_index = scope->function()->proxy()->var()->index();
113    scope_info->set(index++, *scope->function()->proxy()->name());
114    scope_info->set(index++, Smi::FromInt(var_index));
115    DCHECK(function_name_info != STACK ||
116           (var_index == scope_info->StackLocalCount() &&
117            var_index == scope_info->StackSlotCount() - 1));
118    DCHECK(function_name_info != CONTEXT ||
119           var_index == scope_info->ContextLength() - 1);
120  }
121
122  DCHECK(index == scope_info->length());
123  DCHECK(scope->num_parameters() == scope_info->ParameterCount());
124  DCHECK(scope->num_stack_slots() == scope_info->StackSlotCount());
125  DCHECK(scope->num_heap_slots() == scope_info->ContextLength() ||
126         (scope->num_heap_slots() == kVariablePartIndex &&
127          scope_info->ContextLength() == 0));
128  return scope_info;
129}
130
131
132ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
133  return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
134}
135
136
137ScopeType ScopeInfo::scope_type() {
138  DCHECK(length() > 0);
139  return ScopeTypeField::decode(Flags());
140}
141
142
143bool ScopeInfo::CallsEval() {
144  return length() > 0 && CallsEvalField::decode(Flags());
145}
146
147
148StrictMode ScopeInfo::strict_mode() {
149  return length() > 0 ? StrictModeField::decode(Flags()) : SLOPPY;
150}
151
152
153int ScopeInfo::LocalCount() {
154  return StackLocalCount() + ContextLocalCount();
155}
156
157
158int ScopeInfo::StackSlotCount() {
159  if (length() > 0) {
160    bool function_name_stack_slot =
161        FunctionVariableField::decode(Flags()) == STACK;
162    return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
163  }
164  return 0;
165}
166
167
168int ScopeInfo::ContextLength() {
169  if (length() > 0) {
170    int context_locals = ContextLocalCount();
171    bool function_name_context_slot =
172        FunctionVariableField::decode(Flags()) == CONTEXT;
173    bool has_context = context_locals > 0 ||
174        function_name_context_slot ||
175        scope_type() == WITH_SCOPE ||
176        (scope_type() == FUNCTION_SCOPE && CallsEval()) ||
177        scope_type() == MODULE_SCOPE;
178    if (has_context) {
179      return Context::MIN_CONTEXT_SLOTS + context_locals +
180          (function_name_context_slot ? 1 : 0);
181    }
182  }
183  return 0;
184}
185
186
187bool ScopeInfo::HasFunctionName() {
188  if (length() > 0) {
189    return NONE != FunctionVariableField::decode(Flags());
190  } else {
191    return false;
192  }
193}
194
195
196bool ScopeInfo::HasHeapAllocatedLocals() {
197  if (length() > 0) {
198    return ContextLocalCount() > 0;
199  } else {
200    return false;
201  }
202}
203
204
205bool ScopeInfo::HasContext() {
206  return ContextLength() > 0;
207}
208
209
210String* ScopeInfo::FunctionName() {
211  DCHECK(HasFunctionName());
212  return String::cast(get(FunctionNameEntryIndex()));
213}
214
215
216String* ScopeInfo::ParameterName(int var) {
217  DCHECK(0 <= var && var < ParameterCount());
218  int info_index = ParameterEntriesIndex() + var;
219  return String::cast(get(info_index));
220}
221
222
223String* ScopeInfo::LocalName(int var) {
224  DCHECK(0 <= var && var < LocalCount());
225  DCHECK(StackLocalEntriesIndex() + StackLocalCount() ==
226         ContextLocalNameEntriesIndex());
227  int info_index = StackLocalEntriesIndex() + var;
228  return String::cast(get(info_index));
229}
230
231
232String* ScopeInfo::StackLocalName(int var) {
233  DCHECK(0 <= var && var < StackLocalCount());
234  int info_index = StackLocalEntriesIndex() + var;
235  return String::cast(get(info_index));
236}
237
238
239String* ScopeInfo::ContextLocalName(int var) {
240  DCHECK(0 <= var && var < ContextLocalCount());
241  int info_index = ContextLocalNameEntriesIndex() + var;
242  return String::cast(get(info_index));
243}
244
245
246VariableMode ScopeInfo::ContextLocalMode(int var) {
247  DCHECK(0 <= var && var < ContextLocalCount());
248  int info_index = ContextLocalInfoEntriesIndex() + var;
249  int value = Smi::cast(get(info_index))->value();
250  return ContextLocalMode::decode(value);
251}
252
253
254InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
255  DCHECK(0 <= var && var < ContextLocalCount());
256  int info_index = ContextLocalInfoEntriesIndex() + var;
257  int value = Smi::cast(get(info_index))->value();
258  return ContextLocalInitFlag::decode(value);
259}
260
261
262MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
263  DCHECK(0 <= var && var < ContextLocalCount());
264  int info_index = ContextLocalInfoEntriesIndex() + var;
265  int value = Smi::cast(get(info_index))->value();
266  return ContextLocalMaybeAssignedFlag::decode(value);
267}
268
269
270bool ScopeInfo::LocalIsSynthetic(int var) {
271  DCHECK(0 <= var && var < LocalCount());
272  // There's currently no flag stored on the ScopeInfo to indicate that a
273  // variable is a compiler-introduced temporary. However, to avoid conflict
274  // with user declarations, the current temporaries like .generator_object and
275  // .result start with a dot, so we can use that as a flag. It's a hack!
276  Handle<String> name(LocalName(var));
277  return name->length() > 0 && name->Get(0) == '.';
278}
279
280
281int ScopeInfo::StackSlotIndex(String* name) {
282  DCHECK(name->IsInternalizedString());
283  if (length() > 0) {
284    int start = StackLocalEntriesIndex();
285    int end = StackLocalEntriesIndex() + StackLocalCount();
286    for (int i = start; i < end; ++i) {
287      if (name == get(i)) {
288        return i - start;
289      }
290    }
291  }
292  return -1;
293}
294
295
296int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
297                                Handle<String> name, VariableMode* mode,
298                                InitializationFlag* init_flag,
299                                MaybeAssignedFlag* maybe_assigned_flag) {
300  DCHECK(name->IsInternalizedString());
301  DCHECK(mode != NULL);
302  DCHECK(init_flag != NULL);
303  if (scope_info->length() > 0) {
304    ContextSlotCache* context_slot_cache =
305        scope_info->GetIsolate()->context_slot_cache();
306    int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
307                                            maybe_assigned_flag);
308    if (result != ContextSlotCache::kNotFound) {
309      DCHECK(result < scope_info->ContextLength());
310      return result;
311    }
312
313    int start = scope_info->ContextLocalNameEntriesIndex();
314    int end = scope_info->ContextLocalNameEntriesIndex() +
315        scope_info->ContextLocalCount();
316    for (int i = start; i < end; ++i) {
317      if (*name == scope_info->get(i)) {
318        int var = i - start;
319        *mode = scope_info->ContextLocalMode(var);
320        *init_flag = scope_info->ContextLocalInitFlag(var);
321        *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
322        result = Context::MIN_CONTEXT_SLOTS + var;
323        context_slot_cache->Update(scope_info, name, *mode, *init_flag,
324                                   *maybe_assigned_flag, result);
325        DCHECK(result < scope_info->ContextLength());
326        return result;
327      }
328    }
329    // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
330    context_slot_cache->Update(scope_info, name, INTERNAL, kNeedsInitialization,
331                               kNotAssigned, -1);
332  }
333  return -1;
334}
335
336
337int ScopeInfo::ParameterIndex(String* name) {
338  DCHECK(name->IsInternalizedString());
339  if (length() > 0) {
340    // We must read parameters from the end since for
341    // multiply declared parameters the value of the
342    // last declaration of that parameter is used
343    // inside a function (and thus we need to look
344    // at the last index). Was bug# 1110337.
345    int start = ParameterEntriesIndex();
346    int end = ParameterEntriesIndex() + ParameterCount();
347    for (int i = end - 1; i >= start; --i) {
348      if (name == get(i)) {
349        return i - start;
350      }
351    }
352  }
353  return -1;
354}
355
356
357int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
358  DCHECK(name->IsInternalizedString());
359  DCHECK(mode != NULL);
360  if (length() > 0) {
361    if (FunctionVariableField::decode(Flags()) == CONTEXT &&
362        FunctionName() == name) {
363      *mode = FunctionVariableMode::decode(Flags());
364      return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
365    }
366  }
367  return -1;
368}
369
370
371bool ScopeInfo::CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
372                                               Handle<Context> context,
373                                               Handle<JSObject> scope_object) {
374  Isolate* isolate = scope_info->GetIsolate();
375  int local_count = scope_info->ContextLocalCount();
376  if (local_count == 0) return true;
377  // Fill all context locals to the context extension.
378  int first_context_var = scope_info->StackLocalCount();
379  int start = scope_info->ContextLocalNameEntriesIndex();
380  for (int i = 0; i < local_count; ++i) {
381    if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
382    int context_index = Context::MIN_CONTEXT_SLOTS + i;
383    RETURN_ON_EXCEPTION_VALUE(
384        isolate,
385        Runtime::DefineObjectProperty(
386            scope_object,
387            Handle<String>(String::cast(scope_info->get(i + start))),
388            Handle<Object>(context->get(context_index), isolate),
389            ::NONE),
390        false);
391  }
392  return true;
393}
394
395
396int ScopeInfo::ParameterEntriesIndex() {
397  DCHECK(length() > 0);
398  return kVariablePartIndex;
399}
400
401
402int ScopeInfo::StackLocalEntriesIndex() {
403  return ParameterEntriesIndex() + ParameterCount();
404}
405
406
407int ScopeInfo::ContextLocalNameEntriesIndex() {
408  return StackLocalEntriesIndex() + StackLocalCount();
409}
410
411
412int ScopeInfo::ContextLocalInfoEntriesIndex() {
413  return ContextLocalNameEntriesIndex() + ContextLocalCount();
414}
415
416
417int ScopeInfo::FunctionNameEntryIndex() {
418  return ContextLocalInfoEntriesIndex() + ContextLocalCount();
419}
420
421
422int ContextSlotCache::Hash(Object* data, String* name) {
423  // Uses only lower 32 bits if pointers are larger.
424  uintptr_t addr_hash =
425      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
426  return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
427}
428
429
430int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
431                             InitializationFlag* init_flag,
432                             MaybeAssignedFlag* maybe_assigned_flag) {
433  int index = Hash(data, name);
434  Key& key = keys_[index];
435  if ((key.data == data) && key.name->Equals(name)) {
436    Value result(values_[index]);
437    if (mode != NULL) *mode = result.mode();
438    if (init_flag != NULL) *init_flag = result.initialization_flag();
439    if (maybe_assigned_flag != NULL)
440      *maybe_assigned_flag = result.maybe_assigned_flag();
441    return result.index() + kNotFound;
442  }
443  return kNotFound;
444}
445
446
447void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
448                              VariableMode mode, InitializationFlag init_flag,
449                              MaybeAssignedFlag maybe_assigned_flag,
450                              int slot_index) {
451  DisallowHeapAllocation no_gc;
452  Handle<String> internalized_name;
453  DCHECK(slot_index > kNotFound);
454  if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
455      ToHandle(&internalized_name)) {
456    int index = Hash(*data, *internalized_name);
457    Key& key = keys_[index];
458    key.data = *data;
459    key.name = *internalized_name;
460    // Please note value only takes a uint as index.
461    values_[index] = Value(mode, init_flag, maybe_assigned_flag,
462                           slot_index - kNotFound).raw();
463#ifdef DEBUG
464    ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
465#endif
466  }
467}
468
469
470void ContextSlotCache::Clear() {
471  for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
472}
473
474
475#ifdef DEBUG
476
477void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
478                                     VariableMode mode,
479                                     InitializationFlag init_flag,
480                                     MaybeAssignedFlag maybe_assigned_flag,
481                                     int slot_index) {
482  DisallowHeapAllocation no_gc;
483  Handle<String> internalized_name;
484  if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
485      ToHandle(&internalized_name)) {
486    int index = Hash(*data, *name);
487    Key& key = keys_[index];
488    DCHECK(key.data == *data);
489    DCHECK(key.name->Equals(*name));
490    Value result(values_[index]);
491    DCHECK(result.mode() == mode);
492    DCHECK(result.initialization_flag() == init_flag);
493    DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
494    DCHECK(result.index() + kNotFound == slot_index);
495  }
496}
497
498
499static void PrintList(const char* list_name,
500                      int nof_internal_slots,
501                      int start,
502                      int end,
503                      ScopeInfo* scope_info) {
504  if (start < end) {
505    PrintF("\n  // %s\n", list_name);
506    if (nof_internal_slots > 0) {
507      PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
508    }
509    for (int i = nof_internal_slots; start < end; ++i, ++start) {
510      PrintF("  %2d ", i);
511      String::cast(scope_info->get(start))->ShortPrint();
512      PrintF("\n");
513    }
514  }
515}
516
517
518void ScopeInfo::Print() {
519  PrintF("ScopeInfo ");
520  if (HasFunctionName()) {
521    FunctionName()->ShortPrint();
522  } else {
523    PrintF("/* no function name */");
524  }
525  PrintF("{");
526
527  PrintList("parameters", 0,
528            ParameterEntriesIndex(),
529            ParameterEntriesIndex() + ParameterCount(),
530            this);
531  PrintList("stack slots", 0,
532            StackLocalEntriesIndex(),
533            StackLocalEntriesIndex() + StackLocalCount(),
534            this);
535  PrintList("context slots",
536            Context::MIN_CONTEXT_SLOTS,
537            ContextLocalNameEntriesIndex(),
538            ContextLocalNameEntriesIndex() + ContextLocalCount(),
539            this);
540
541  PrintF("}\n");
542}
543#endif  // DEBUG
544
545
546//---------------------------------------------------------------------------
547// ModuleInfo.
548
549Handle<ModuleInfo> ModuleInfo::Create(
550    Isolate* isolate, Interface* interface, Scope* scope) {
551  Handle<ModuleInfo> info = Allocate(isolate, interface->Length());
552  info->set_host_index(interface->Index());
553  int i = 0;
554  for (Interface::Iterator it = interface->iterator();
555       !it.done(); it.Advance(), ++i) {
556    Variable* var = scope->LookupLocal(it.name());
557    info->set_name(i, *(it.name()->string()));
558    info->set_mode(i, var->mode());
559    DCHECK((var->mode() == MODULE) == (it.interface()->IsModule()));
560    if (var->mode() == MODULE) {
561      DCHECK(it.interface()->IsFrozen());
562      DCHECK(it.interface()->Index() >= 0);
563      info->set_index(i, it.interface()->Index());
564    } else {
565      DCHECK(var->index() >= 0);
566      info->set_index(i, var->index());
567    }
568  }
569  DCHECK(i == info->length());
570  return info;
571}
572
573} }  // namespace v8::internal
574