scopeinfo.cc 15.7 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <stdlib.h>

#include "v8.h"

#include "scopeinfo.h"
#include "scopes.h"

35 36
#include "allocation-inl.h"

37 38
namespace v8 {
namespace internal {
39 40


41
Handle<ScopeInfo> ScopeInfo::Create(Scope* scope, Zone* zone) {
42
  // Collect stack and context locals.
43 44
  ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
  ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
45 46 47 48 49 50
  scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
  const int stack_local_count = stack_locals.length();
  const int context_local_count = context_locals.length();
  // Make sure we allocate the correct amount.
  ASSERT(scope->StackLocalCount() == stack_local_count);
  ASSERT(scope->ContextLocalCount() == context_local_count);
51

52 53 54 55
  // Determine use and location of the function variable if it is present.
  FunctionVariableInfo function_name_info;
  VariableMode function_variable_mode;
  if (scope->is_function_scope() && scope->function() != NULL) {
56
    Variable* var = scope->function()->proxy()->var();
57 58 59 60 61 62 63
    if (!var->is_used()) {
      function_name_info = UNUSED;
    } else if (var->IsContextSlot()) {
      function_name_info = CONTEXT;
    } else {
      ASSERT(var->IsStackLocal());
      function_name_info = STACK;
64
    }
65
    function_variable_mode = var->mode();
66
  } else {
67 68
    function_name_info = NONE;
    function_variable_mode = VAR;
69 70
  }

71 72 73 74 75 76 77 78 79 80 81
  const bool has_function_name = function_name_info != NONE;
  const int parameter_count = scope->num_parameters();
  const int length = kVariablePartIndex
      + parameter_count + stack_local_count + 2 * context_local_count
      + (has_function_name ? 2 : 0);

  Handle<ScopeInfo> scope_info = FACTORY->NewScopeInfo(length);

  // Encode the flags.
  int flags = TypeField::encode(scope->type()) |
      CallsEvalField::encode(scope->calls_eval()) |
82
      LanguageModeField::encode(scope->language_mode()) |
83 84 85 86 87 88 89 90 91 92 93 94
      FunctionVariableField::encode(function_name_info) |
      FunctionVariableMode::encode(function_variable_mode);
  scope_info->SetFlags(flags);
  scope_info->SetParameterCount(parameter_count);
  scope_info->SetStackLocalCount(stack_local_count);
  scope_info->SetContextLocalCount(context_local_count);

  int index = kVariablePartIndex;
  // Add parameters.
  ASSERT(index == scope_info->ParameterEntriesIndex());
  for (int i = 0; i < parameter_count; ++i) {
    scope_info->set(index++, *scope->parameter(i)->name());
95 96
  }

97 98 99 100 101 102 103 104
  // Add stack locals' names. We are assuming that the stack locals'
  // slots are allocated in increasing order, so we can simply add
  // them to the ScopeInfo object.
  ASSERT(index == scope_info->StackLocalEntriesIndex());
  for (int i = 0; i < stack_local_count; ++i) {
    ASSERT(stack_locals[i]->index() == i);
    scope_info->set(index++, *stack_locals[i]->name());
  }
105

106 107 108 109 110 111
  // Due to usage analysis, context-allocated locals are not necessarily in
  // increasing order: Some of them may be parameters which are allocated before
  // the non-parameter locals. When the non-parameter locals are sorted
  // according to usage, the allocated slot indices may not be in increasing
  // order with the variable list anymore. Thus, we first need to sort them by
  // context slot index before adding them to the ScopeInfo object.
112
  context_locals.Sort(&Variable::CompareIndex);
113 114 115 116 117 118

  // Add context locals' names.
  ASSERT(index == scope_info->ContextLocalNameEntriesIndex());
  for (int i = 0; i < context_local_count; ++i) {
    scope_info->set(index++, *context_locals[i]->name());
  }
119

120 121
  // Add context locals' info.
  ASSERT(index == scope_info->ContextLocalInfoEntriesIndex());
122
  for (int i = 0; i < context_local_count; ++i) {
123 124 125 126
    Variable* var = context_locals[i];
    uint32_t value = ContextLocalMode::encode(var->mode()) |
        ContextLocalInitFlag::encode(var->initialization_flag());
    scope_info->set(index++, Smi::FromInt(value));
127
  }
128

129 130 131
  // If present, add the function variable name and its index.
  ASSERT(index == scope_info->FunctionNameEntryIndex());
  if (has_function_name) {
132 133
    int var_index = scope->function()->proxy()->var()->index();
    scope_info->set(index++, *scope->function()->proxy()->name());
134 135 136 137 138 139 140
    scope_info->set(index++, Smi::FromInt(var_index));
    ASSERT(function_name_info != STACK ||
           (var_index == scope_info->StackLocalCount() &&
            var_index == scope_info->StackSlotCount() - 1));
    ASSERT(function_name_info != CONTEXT ||
           var_index == scope_info->ContextLength() - 1);
  }
141

142 143 144
  ASSERT(index == scope_info->length());
  ASSERT(scope->num_parameters() == scope_info->ParameterCount());
  ASSERT(scope->num_stack_slots() == scope_info->StackSlotCount());
145 146 147
  ASSERT(scope->num_heap_slots() == scope_info->ContextLength() ||
         (scope->num_heap_slots() == kVariablePartIndex &&
          scope_info->ContextLength() == 0));
148
  return scope_info;
149 150 151
}


152 153
ScopeInfo* ScopeInfo::Empty() {
  return reinterpret_cast<ScopeInfo*>(HEAP->empty_fixed_array());
154 155 156
}


157 158 159
ScopeType ScopeInfo::Type() {
  ASSERT(length() > 0);
  return TypeField::decode(Flags());
160 161 162
}


163 164
bool ScopeInfo::CallsEval() {
  return length() > 0 && CallsEvalField::decode(Flags());
165 166 167
}


168 169
LanguageMode ScopeInfo::language_mode() {
  return length() > 0 ? LanguageModeField::decode(Flags()) : CLASSIC_MODE;
170 171 172
}


173 174
int ScopeInfo::LocalCount() {
  return StackLocalCount() + ContextLocalCount();
175 176 177
}


178 179 180 181 182 183 184
int ScopeInfo::StackSlotCount() {
  if (length() > 0) {
    bool function_name_stack_slot =
        FunctionVariableField::decode(Flags()) == STACK;
    return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
  }
  return 0;
185 186 187
}


188 189 190 191 192 193 194 195
int ScopeInfo::ContextLength() {
  if (length() > 0) {
    int context_locals = ContextLocalCount();
    bool function_name_context_slot =
        FunctionVariableField::decode(Flags()) == CONTEXT;
    bool has_context = context_locals > 0 ||
        function_name_context_slot ||
        Type() == WITH_SCOPE ||
196 197
        (Type() == FUNCTION_SCOPE && CallsEval()) ||
        Type() == MODULE_SCOPE;
198 199 200 201
    if (has_context) {
      return Context::MIN_CONTEXT_SLOTS + context_locals +
          (function_name_context_slot ? 1 : 0);
    }
202
  }
203
  return 0;
204 205 206
}


207 208 209
bool ScopeInfo::HasFunctionName() {
  if (length() > 0) {
    return NONE != FunctionVariableField::decode(Flags());
210
  } else {
211
    return false;
212
  }
213 214 215
}


216 217 218 219 220
bool ScopeInfo::HasHeapAllocatedLocals() {
  if (length() > 0) {
    return ContextLocalCount() > 0;
  } else {
    return false;
221 222 223 224
  }
}


225
bool ScopeInfo::HasContext() {
226
  return ContextLength() > 0;
227 228 229
}


230 231 232
String* ScopeInfo::FunctionName() {
  ASSERT(HasFunctionName());
  return String::cast(get(FunctionNameEntryIndex()));
233 234 235
}


236 237 238 239
String* ScopeInfo::ParameterName(int var) {
  ASSERT(0 <= var && var < ParameterCount());
  int info_index = ParameterEntriesIndex() + var;
  return String::cast(get(info_index));
240 241 242
}


243 244 245 246 247 248
String* ScopeInfo::LocalName(int var) {
  ASSERT(0 <= var && var < LocalCount());
  ASSERT(StackLocalEntriesIndex() + StackLocalCount() ==
         ContextLocalNameEntriesIndex());
  int info_index = StackLocalEntriesIndex() + var;
  return String::cast(get(info_index));
249 250 251
}


252 253 254 255
String* ScopeInfo::StackLocalName(int var) {
  ASSERT(0 <= var && var < StackLocalCount());
  int info_index = StackLocalEntriesIndex() + var;
  return String::cast(get(info_index));
256 257 258
}


259 260 261 262
String* ScopeInfo::ContextLocalName(int var) {
  ASSERT(0 <= var && var < ContextLocalCount());
  int info_index = ContextLocalNameEntriesIndex() + var;
  return String::cast(get(info_index));
263 264 265
}


266 267
VariableMode ScopeInfo::ContextLocalMode(int var) {
  ASSERT(0 <= var && var < ContextLocalCount());
268 269 270 271 272 273 274 275 276 277 278
  int info_index = ContextLocalInfoEntriesIndex() + var;
  int value = Smi::cast(get(info_index))->value();
  return ContextLocalMode::decode(value);
}


InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
  ASSERT(0 <= var && var < ContextLocalCount());
  int info_index = ContextLocalInfoEntriesIndex() + var;
  int value = Smi::cast(get(info_index))->value();
  return ContextLocalInitFlag::decode(value);
279 280 281
}


282
int ScopeInfo::StackSlotIndex(String* name) {
283
  ASSERT(name->IsSymbol());
284
  if (length() > 0) {
285 286 287 288 289 290
    int start = StackLocalEntriesIndex();
    int end = StackLocalEntriesIndex() + StackLocalCount();
    for (int i = start; i < end; ++i) {
      if (name == get(i)) {
        return i - start;
      }
291 292 293 294 295
    }
  }
  return -1;
}

296

297 298 299
int ScopeInfo::ContextSlotIndex(String* name,
                                VariableMode* mode,
                                InitializationFlag* init_flag) {
300
  ASSERT(name->IsSymbol());
301
  ASSERT(mode != NULL);
302
  ASSERT(init_flag != NULL);
303
  if (length() > 0) {
304
    ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache();
305
    int result = context_slot_cache->Lookup(this, name, mode, init_flag);
306 307 308 309 310 311 312 313 314 315 316
    if (result != ContextSlotCache::kNotFound) {
      ASSERT(result < ContextLength());
      return result;
    }

    int start = ContextLocalNameEntriesIndex();
    int end = ContextLocalNameEntriesIndex() + ContextLocalCount();
    for (int i = start; i < end; ++i) {
      if (name == get(i)) {
        int var = i - start;
        *mode = ContextLocalMode(var);
317
        *init_flag = ContextLocalInitFlag(var);
318
        result = Context::MIN_CONTEXT_SLOTS + var;
319
        context_slot_cache->Update(this, name, *mode, *init_flag, result);
320
        ASSERT(result < ContextLength());
321
        return result;
322 323
      }
    }
324
    context_slot_cache->Update(this, name, INTERNAL, kNeedsInitialization, -1);
325 326 327 328 329
  }
  return -1;
}


330
int ScopeInfo::ParameterIndex(String* name) {
331
  ASSERT(name->IsSymbol());
332
  if (length() > 0) {
333 334 335 336 337
    // We must read parameters from the end since for
    // multiply declared parameters the value of the
    // last declaration of that parameter is used
    // inside a function (and thus we need to look
    // at the last index). Was bug# 1110337.
338 339 340 341 342 343
    int start = ParameterEntriesIndex();
    int end = ParameterEntriesIndex() + ParameterCount();
    for (int i = end - 1; i >= start; --i) {
      if (name == get(i)) {
        return i - start;
      }
344 345 346 347 348 349
    }
  }
  return -1;
}


350
int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
351
  ASSERT(name->IsSymbol());
352
  ASSERT(mode != NULL);
353
  if (length() > 0) {
354 355 356 357
    if (FunctionVariableField::decode(Flags()) == CONTEXT &&
        FunctionName() == name) {
      *mode = FunctionVariableMode::decode(Flags());
      return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
358 359 360 361 362 363
    }
  }
  return -1;
}


364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
int ScopeInfo::ParameterEntriesIndex() {
  ASSERT(length() > 0);
  return kVariablePartIndex;
}


int ScopeInfo::StackLocalEntriesIndex() {
  return ParameterEntriesIndex() + ParameterCount();
}


int ScopeInfo::ContextLocalNameEntriesIndex() {
  return StackLocalEntriesIndex() + StackLocalCount();
}


380
int ScopeInfo::ContextLocalInfoEntriesIndex() {
381 382 383 384 385
  return ContextLocalNameEntriesIndex() + ContextLocalCount();
}


int ScopeInfo::FunctionNameEntryIndex() {
386
  return ContextLocalInfoEntriesIndex() + ContextLocalCount();
387 388 389
}


390
int ContextSlotCache::Hash(Object* data, String* name) {
391 392
  // Uses only lower 32 bits if pointers are larger.
  uintptr_t addr_hash =
393
      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
394
  return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
395 396 397
}


398
int ContextSlotCache::Lookup(Object* data,
399
                             String* name,
400 401
                             VariableMode* mode,
                             InitializationFlag* init_flag) {
402
  int index = Hash(data, name);
403
  Key& key = keys_[index];
404
  if ((key.data == data) && key.name->Equals(name)) {
405 406
    Value result(values_[index]);
    if (mode != NULL) *mode = result.mode();
407
    if (init_flag != NULL) *init_flag = result.initialization_flag();
408 409 410 411 412 413
    return result.index() + kNotFound;
  }
  return kNotFound;
}


414
void ContextSlotCache::Update(Object* data,
415
                              String* name,
416
                              VariableMode mode,
417
                              InitializationFlag init_flag,
418 419 420
                              int slot_index) {
  String* symbol;
  ASSERT(slot_index > kNotFound);
421
  if (HEAP->LookupSymbolIfExists(name, &symbol)) {
422
    int index = Hash(data, symbol);
423
    Key& key = keys_[index];
424
    key.data = data;
425 426
    key.name = symbol;
    // Please note value only takes a uint as index.
427
    values_[index] = Value(mode, init_flag, slot_index - kNotFound).raw();
428
#ifdef DEBUG
429
    ValidateEntry(data, name, mode, init_flag, slot_index);
430 431 432 433 434 435
#endif
  }
}


void ContextSlotCache::Clear() {
436
  for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
437 438 439
}


440
#ifdef DEBUG
441

442
void ContextSlotCache::ValidateEntry(Object* data,
443
                                     String* name,
444
                                     VariableMode mode,
445
                                     InitializationFlag init_flag,
446 447
                                     int slot_index) {
  String* symbol;
448
  if (HEAP->LookupSymbolIfExists(name, &symbol)) {
449
    int index = Hash(data, name);
450
    Key& key = keys_[index];
451
    ASSERT(key.data == data);
452 453 454
    ASSERT(key.name->Equals(name));
    Value result(values_[index]);
    ASSERT(result.mode() == mode);
455
    ASSERT(result.initialization_flag() == init_flag);
456 457 458 459 460
    ASSERT(result.index() + kNotFound == slot_index);
  }
}


461 462
static void PrintList(const char* list_name,
                      int nof_internal_slots,
463 464 465 466
                      int start,
                      int end,
                      ScopeInfo* scope_info) {
  if (start < end) {
467 468 469 470
    PrintF("\n  // %s\n", list_name);
    if (nof_internal_slots > 0) {
      PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
    }
471 472 473
    for (int i = nof_internal_slots; start < end; ++i, ++start) {
      PrintF("  %2d ", i);
      String::cast(scope_info->get(start))->ShortPrint();
474 475 476 477 478 479
      PrintF("\n");
    }
  }
}


480
void ScopeInfo::Print() {
481
  PrintF("ScopeInfo ");
482 483 484
  if (HasFunctionName()) {
    FunctionName()->ShortPrint();
  } else {
485
    PrintF("/* no function name */");
486
  }
487 488
  PrintF("{");

489 490 491 492 493 494 495 496 497 498 499 500 501
  PrintList("parameters", 0,
            ParameterEntriesIndex(),
            ParameterEntriesIndex() + ParameterCount(),
            this);
  PrintList("stack slots", 0,
            StackLocalEntriesIndex(),
            StackLocalEntriesIndex() + StackLocalCount(),
            this);
  PrintList("context slots",
            Context::MIN_CONTEXT_SLOTS,
            ContextLocalNameEntriesIndex(),
            ContextLocalNameEntriesIndex() + ContextLocalCount(),
            this);
502 503 504 505 506 507

  PrintF("}\n");
}
#endif  // DEBUG

} }  // namespace v8::internal