Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame^] | 1 | // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 | // Redistribution and use in source and binary forms, with or without |
| 3 | // modification, are permitted provided that the following conditions are |
| 4 | // met: |
| 5 | // |
| 6 | // * Redistributions of source code must retain the above copyright |
| 7 | // notice, this list of conditions and the following disclaimer. |
| 8 | // * Redistributions in binary form must reproduce the above |
| 9 | // copyright notice, this list of conditions and the following |
| 10 | // disclaimer in the documentation and/or other materials provided |
| 11 | // with the distribution. |
| 12 | // * Neither the name of Google Inc. nor the names of its |
| 13 | // contributors may be used to endorse or promote products derived |
| 14 | // from this software without specific prior written permission. |
| 15 | // |
| 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | |
| 28 | #include <stdlib.h> |
| 29 | |
| 30 | #include "v8.h" |
| 31 | |
| 32 | #include "scopeinfo.h" |
| 33 | #include "scopes.h" |
| 34 | |
| 35 | namespace v8 { |
| 36 | namespace internal { |
| 37 | |
| 38 | |
| 39 | static int CompareLocal(Variable* const* v, Variable* const* w) { |
| 40 | Slot* s = (*v)->slot(); |
| 41 | Slot* t = (*w)->slot(); |
| 42 | // We may have rewritten parameters (that are in the arguments object) |
| 43 | // and which may have a NULL slot... - find a better solution... |
| 44 | int x = (s != NULL ? s->index() : 0); |
| 45 | int y = (t != NULL ? t->index() : 0); |
| 46 | // Consider sorting them according to type as well? |
| 47 | return x - y; |
| 48 | } |
| 49 | |
| 50 | |
| 51 | template<class Allocator> |
| 52 | ScopeInfo<Allocator>::ScopeInfo(Scope* scope) |
| 53 | : function_name_(Factory::empty_symbol()), |
| 54 | calls_eval_(scope->calls_eval()), |
| 55 | parameters_(scope->num_parameters()), |
| 56 | stack_slots_(scope->num_stack_slots()), |
| 57 | context_slots_(scope->num_heap_slots()), |
| 58 | context_modes_(scope->num_heap_slots()) { |
| 59 | // Add parameters. |
| 60 | for (int i = 0; i < scope->num_parameters(); i++) { |
| 61 | ASSERT(parameters_.length() == i); |
| 62 | parameters_.Add(scope->parameter(i)->name()); |
| 63 | } |
| 64 | |
| 65 | // Add stack locals and collect heap locals. |
| 66 | // We are assuming that the locals' slots are allocated in |
| 67 | // increasing order, so we can simply add them to the |
| 68 | // ScopeInfo lists. However, due to usage analysis, this is |
| 69 | // not true for context-allocated locals: Some of them |
| 70 | // may be parameters which are allocated before the |
| 71 | // non-parameter locals. When the non-parameter locals are |
| 72 | // sorted according to usage, the allocated slot indices may |
| 73 | // not be in increasing order with the variable list anymore. |
| 74 | // Thus, we first collect the context-allocated locals, and then |
| 75 | // sort them by context slot index before adding them to the |
| 76 | // ScopeInfo list. |
| 77 | List<Variable*, Allocator> locals(32); // 32 is a wild guess |
| 78 | ASSERT(locals.is_empty()); |
| 79 | scope->CollectUsedVariables(&locals); |
| 80 | locals.Sort(&CompareLocal); |
| 81 | |
| 82 | List<Variable*, Allocator> heap_locals(locals.length()); |
| 83 | for (int i = 0; i < locals.length(); i++) { |
| 84 | Variable* var = locals[i]; |
| 85 | if (var->var_uses()->is_used()) { |
| 86 | Slot* slot = var->slot(); |
| 87 | if (slot != NULL) { |
| 88 | switch (slot->type()) { |
| 89 | case Slot::PARAMETER: |
| 90 | // explicitly added to parameters_ above - ignore |
| 91 | break; |
| 92 | |
| 93 | case Slot::LOCAL: |
| 94 | ASSERT(stack_slots_.length() == slot->index()); |
| 95 | stack_slots_.Add(var->name()); |
| 96 | break; |
| 97 | |
| 98 | case Slot::CONTEXT: |
| 99 | heap_locals.Add(var); |
| 100 | break; |
| 101 | |
| 102 | case Slot::LOOKUP: |
| 103 | case Slot::GLOBAL: |
| 104 | // these are currently not used |
| 105 | UNREACHABLE(); |
| 106 | break; |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // Add heap locals. |
| 113 | if (scope->num_heap_slots() > 0) { |
| 114 | // Add user-defined slots. |
| 115 | for (int i = 0; i < heap_locals.length(); i++) { |
| 116 | ASSERT(heap_locals[i]->slot()->index() - Context::MIN_CONTEXT_SLOTS == |
| 117 | context_slots_.length()); |
| 118 | ASSERT(heap_locals[i]->slot()->index() - Context::MIN_CONTEXT_SLOTS == |
| 119 | context_modes_.length()); |
| 120 | context_slots_.Add(heap_locals[i]->name()); |
| 121 | context_modes_.Add(heap_locals[i]->mode()); |
| 122 | } |
| 123 | |
| 124 | } else { |
| 125 | ASSERT(heap_locals.length() == 0); |
| 126 | } |
| 127 | |
| 128 | // Add the function context slot, if present. |
| 129 | // For now, this must happen at the very end because of the |
| 130 | // ordering of the scope info slots and the respective slot indices. |
| 131 | if (scope->is_function_scope()) { |
| 132 | Variable* var = scope->function(); |
| 133 | if (var != NULL && |
| 134 | var->var_uses()->is_used() && |
| 135 | var->slot()->type() == Slot::CONTEXT) { |
| 136 | function_name_ = var->name(); |
| 137 | // Note that we must not find the function name in the context slot |
| 138 | // list - instead it must be handled separately in the |
| 139 | // Contexts::Lookup() function. Thus record an empty symbol here so we |
| 140 | // get the correct number of context slots. |
| 141 | ASSERT(var->slot()->index() - Context::MIN_CONTEXT_SLOTS == |
| 142 | context_slots_.length()); |
| 143 | ASSERT(var->slot()->index() - Context::MIN_CONTEXT_SLOTS == |
| 144 | context_modes_.length()); |
| 145 | context_slots_.Add(Factory::empty_symbol()); |
| 146 | context_modes_.Add(Variable::INTERNAL); |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | |
| 152 | // Encoding format in the Code object: |
| 153 | // |
| 154 | // - function name |
| 155 | // |
| 156 | // - number of variables in the context object (smi) (= function context |
| 157 | // slot index + 1) |
| 158 | // - list of pairs (name, Var mode) of context-allocated variables (starting |
| 159 | // with context slot 0) |
| 160 | // - NULL (sentinel) |
| 161 | // |
| 162 | // - number of parameters (smi) |
| 163 | // - list of parameter names (starting with parameter 0 first) |
| 164 | // - NULL (sentinel) |
| 165 | // |
| 166 | // - number of variables on the stack (smi) |
| 167 | // - list of names of stack-allocated variables (starting with stack slot 0) |
| 168 | // - NULL (sentinel) |
| 169 | |
| 170 | // The ScopeInfo representation could be simplified and the ScopeInfo |
| 171 | // re-implemented (with almost the same interface). Here is a |
| 172 | // suggestion for the new format: |
| 173 | // |
| 174 | // - have a single list with all variable names (parameters, stack locals, |
| 175 | // context locals), followed by a list of non-Object* values containing |
| 176 | // the variables information (what kind, index, attributes) |
| 177 | // - searching the linear list of names is fast and yields an index into the |
| 178 | // list if the variable name is found |
| 179 | // - that list index is then used to find the variable information in the |
| 180 | // subsequent list |
| 181 | // - the list entries don't have to be in any particular order, so all the |
| 182 | // current sorting business can go away |
| 183 | // - the ScopeInfo lookup routines can be reduced to perhaps a single lookup |
| 184 | // which returns all information at once |
| 185 | // - when gathering the information from a Scope, we only need to iterate |
| 186 | // through the local variables (parameters and context info is already |
| 187 | // present) |
| 188 | |
| 189 | |
| 190 | static inline Object** ReadInt(Object** p, int* x) { |
| 191 | *x = (reinterpret_cast<Smi*>(*p++))->value(); |
| 192 | return p; |
| 193 | } |
| 194 | |
| 195 | |
| 196 | static inline Object** ReadBool(Object** p, bool* x) { |
| 197 | *x = (reinterpret_cast<Smi*>(*p++))->value() != 0; |
| 198 | return p; |
| 199 | } |
| 200 | |
| 201 | |
| 202 | static inline Object** ReadSymbol(Object** p, Handle<String>* s) { |
| 203 | *s = Handle<String>(reinterpret_cast<String*>(*p++)); |
| 204 | return p; |
| 205 | } |
| 206 | |
| 207 | |
| 208 | static inline Object** ReadSentinel(Object** p) { |
| 209 | ASSERT(*p == NULL); |
| 210 | return p + 1; |
| 211 | } |
| 212 | |
| 213 | |
| 214 | template <class Allocator> |
| 215 | static Object** ReadList(Object** p, List<Handle<String>, Allocator >* list) { |
| 216 | ASSERT(list->is_empty()); |
| 217 | int n; |
| 218 | p = ReadInt(p, &n); |
| 219 | while (n-- > 0) { |
| 220 | Handle<String> s; |
| 221 | p = ReadSymbol(p, &s); |
| 222 | list->Add(s); |
| 223 | } |
| 224 | return ReadSentinel(p); |
| 225 | } |
| 226 | |
| 227 | |
| 228 | template <class Allocator> |
| 229 | static Object** ReadList(Object** p, |
| 230 | List<Handle<String>, Allocator>* list, |
| 231 | List<Variable::Mode, Allocator>* modes) { |
| 232 | ASSERT(list->is_empty()); |
| 233 | int n; |
| 234 | p = ReadInt(p, &n); |
| 235 | while (n-- > 0) { |
| 236 | Handle<String> s; |
| 237 | int m; |
| 238 | p = ReadSymbol(p, &s); |
| 239 | p = ReadInt(p, &m); |
| 240 | list->Add(s); |
| 241 | modes->Add(static_cast<Variable::Mode>(m)); |
| 242 | } |
| 243 | return ReadSentinel(p); |
| 244 | } |
| 245 | |
| 246 | |
| 247 | template<class Allocator> |
| 248 | ScopeInfo<Allocator>::ScopeInfo(Code* code) |
| 249 | : function_name_(Factory::empty_symbol()), |
| 250 | parameters_(4), |
| 251 | stack_slots_(8), |
| 252 | context_slots_(8), |
| 253 | context_modes_(8) { |
| 254 | if (code == NULL || code->sinfo_size() == 0) return; |
| 255 | |
| 256 | Object** p0 = &Memory::Object_at(code->sinfo_start()); |
| 257 | Object** p = p0; |
| 258 | p = ReadSymbol(p, &function_name_); |
| 259 | p = ReadBool(p, &calls_eval_); |
| 260 | p = ReadList<Allocator>(p, &context_slots_, &context_modes_); |
| 261 | p = ReadList<Allocator>(p, ¶meters_); |
| 262 | p = ReadList<Allocator>(p, &stack_slots_); |
| 263 | ASSERT((p - p0) * kPointerSize == code->sinfo_size()); |
| 264 | } |
| 265 | |
| 266 | |
| 267 | static inline Object** WriteInt(Object** p, int x) { |
| 268 | *p++ = Smi::FromInt(x); |
| 269 | return p; |
| 270 | } |
| 271 | |
| 272 | |
| 273 | static inline Object** WriteBool(Object** p, bool b) { |
| 274 | *p++ = Smi::FromInt(b ? 1 : 0); |
| 275 | return p; |
| 276 | } |
| 277 | |
| 278 | |
| 279 | static inline Object** WriteSymbol(Object** p, Handle<String> s) { |
| 280 | *p++ = *s; |
| 281 | return p; |
| 282 | } |
| 283 | |
| 284 | |
| 285 | static inline Object** WriteSentinel(Object** p) { |
| 286 | *p++ = NULL; |
| 287 | return p; |
| 288 | } |
| 289 | |
| 290 | |
| 291 | template <class Allocator> |
| 292 | static Object** WriteList(Object** p, List<Handle<String>, Allocator >* list) { |
| 293 | const int n = list->length(); |
| 294 | p = WriteInt(p, n); |
| 295 | for (int i = 0; i < n; i++) { |
| 296 | p = WriteSymbol(p, list->at(i)); |
| 297 | } |
| 298 | return WriteSentinel(p); |
| 299 | } |
| 300 | |
| 301 | |
| 302 | template <class Allocator> |
| 303 | static Object** WriteList(Object** p, |
| 304 | List<Handle<String>, Allocator>* list, |
| 305 | List<Variable::Mode, Allocator>* modes) { |
| 306 | const int n = list->length(); |
| 307 | p = WriteInt(p, n); |
| 308 | for (int i = 0; i < n; i++) { |
| 309 | p = WriteSymbol(p, list->at(i)); |
| 310 | p = WriteInt(p, modes->at(i)); |
| 311 | } |
| 312 | return WriteSentinel(p); |
| 313 | } |
| 314 | |
| 315 | |
| 316 | template<class Allocator> |
| 317 | int ScopeInfo<Allocator>::Serialize(Code* code) { |
| 318 | // function name, calls eval, length & sentinel for 3 tables: |
| 319 | const int extra_slots = 1 + 1 + 2 * 3; |
| 320 | int size = (extra_slots + |
| 321 | context_slots_.length() * 2 + |
| 322 | parameters_.length() + |
| 323 | stack_slots_.length()) * kPointerSize; |
| 324 | |
| 325 | if (code != NULL) { |
| 326 | CHECK(code->sinfo_size() == size); |
| 327 | Object** p0 = &Memory::Object_at(code->sinfo_start()); |
| 328 | Object** p = p0; |
| 329 | p = WriteSymbol(p, function_name_); |
| 330 | p = WriteBool(p, calls_eval_); |
| 331 | p = WriteList(p, &context_slots_, &context_modes_); |
| 332 | p = WriteList(p, ¶meters_); |
| 333 | p = WriteList(p, &stack_slots_); |
| 334 | ASSERT((p - p0) * kPointerSize == size); |
| 335 | } |
| 336 | |
| 337 | return size; |
| 338 | } |
| 339 | |
| 340 | |
| 341 | template<class Allocator> |
| 342 | void ScopeInfo<Allocator>::IterateScopeInfo(Code* code, ObjectVisitor* v) { |
| 343 | Object** start = &Memory::Object_at(code->sinfo_start()); |
| 344 | Object** end = &Memory::Object_at(code->sinfo_start() + code->sinfo_size()); |
| 345 | v->VisitPointers(start, end); |
| 346 | } |
| 347 | |
| 348 | |
| 349 | static Object** ContextEntriesAddr(Code* code) { |
| 350 | ASSERT(code->sinfo_size() > 0); |
| 351 | // +2 for function name and calls eval: |
| 352 | return &Memory::Object_at(code->sinfo_start()) + 2; |
| 353 | } |
| 354 | |
| 355 | |
| 356 | static Object** ParameterEntriesAddr(Code* code) { |
| 357 | ASSERT(code->sinfo_size() > 0); |
| 358 | Object** p = ContextEntriesAddr(code); |
| 359 | int n; // number of context slots; |
| 360 | p = ReadInt(p, &n); |
| 361 | return p + n*2 + 1; // *2 for pairs, +1 for sentinel |
| 362 | } |
| 363 | |
| 364 | |
| 365 | static Object** StackSlotEntriesAddr(Code* code) { |
| 366 | ASSERT(code->sinfo_size() > 0); |
| 367 | Object** p = ParameterEntriesAddr(code); |
| 368 | int n; // number of parameter slots; |
| 369 | p = ReadInt(p, &n); |
| 370 | return p + n + 1; // +1 for sentinel |
| 371 | } |
| 372 | |
| 373 | |
| 374 | template<class Allocator> |
| 375 | bool ScopeInfo<Allocator>::CallsEval(Code* code) { |
| 376 | if (code->sinfo_size() > 0) { |
| 377 | // +1 for function name: |
| 378 | Object** p = &Memory::Object_at(code->sinfo_start()) + 1; |
| 379 | bool calls_eval; |
| 380 | p = ReadBool(p, &calls_eval); |
| 381 | return calls_eval; |
| 382 | } |
| 383 | return true; |
| 384 | } |
| 385 | |
| 386 | |
| 387 | template<class Allocator> |
| 388 | int ScopeInfo<Allocator>::NumberOfStackSlots(Code* code) { |
| 389 | if (code->sinfo_size() > 0) { |
| 390 | Object** p = StackSlotEntriesAddr(code); |
| 391 | int n; // number of stack slots; |
| 392 | ReadInt(p, &n); |
| 393 | return n; |
| 394 | } |
| 395 | return 0; |
| 396 | } |
| 397 | |
| 398 | |
| 399 | template<class Allocator> |
| 400 | int ScopeInfo<Allocator>::NumberOfContextSlots(Code* code) { |
| 401 | if (code->sinfo_size() > 0) { |
| 402 | Object** p = ContextEntriesAddr(code); |
| 403 | int n; // number of context slots; |
| 404 | ReadInt(p, &n); |
| 405 | return n + Context::MIN_CONTEXT_SLOTS; |
| 406 | } |
| 407 | return 0; |
| 408 | } |
| 409 | |
| 410 | |
| 411 | template<class Allocator> |
| 412 | int ScopeInfo<Allocator>::StackSlotIndex(Code* code, String* name) { |
| 413 | ASSERT(name->IsSymbol()); |
| 414 | if (code->sinfo_size() > 0) { |
| 415 | // Loop below depends on the NULL sentinel after the stack slot names. |
| 416 | ASSERT(NumberOfStackSlots(code) > 0 || |
| 417 | *(StackSlotEntriesAddr(code) + 1) == NULL); |
| 418 | // slots start after length entry |
| 419 | Object** p0 = StackSlotEntriesAddr(code) + 1; |
| 420 | Object** p = p0; |
| 421 | while (*p != NULL) { |
| 422 | if (*p == name) return p - p0; |
| 423 | p++; |
| 424 | } |
| 425 | } |
| 426 | return -1; |
| 427 | } |
| 428 | |
| 429 | |
| 430 | template<class Allocator> |
| 431 | int ScopeInfo<Allocator>::ContextSlotIndex(Code* code, |
| 432 | String* name, |
| 433 | Variable::Mode* mode) { |
| 434 | ASSERT(name->IsSymbol()); |
| 435 | int result = ContextSlotCache::Lookup(code, name, mode); |
| 436 | if (result != ContextSlotCache::kNotFound) return result; |
| 437 | if (code->sinfo_size() > 0) { |
| 438 | // Loop below depends on the NULL sentinel after the context slot names. |
| 439 | ASSERT(NumberOfContextSlots(code) >= Context::MIN_CONTEXT_SLOTS || |
| 440 | *(ContextEntriesAddr(code) + 1) == NULL); |
| 441 | |
| 442 | // slots start after length entry |
| 443 | Object** p0 = ContextEntriesAddr(code) + 1; |
| 444 | Object** p = p0; |
| 445 | // contexts may have no variable slots (in the presence of eval()). |
| 446 | while (*p != NULL) { |
| 447 | if (*p == name) { |
| 448 | ASSERT(((p - p0) & 1) == 0); |
| 449 | int v; |
| 450 | ReadInt(p + 1, &v); |
| 451 | Variable::Mode mode_value = static_cast<Variable::Mode>(v); |
| 452 | if (mode != NULL) *mode = mode_value; |
| 453 | result = ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS; |
| 454 | ContextSlotCache::Update(code, name, mode_value, result); |
| 455 | return result; |
| 456 | } |
| 457 | p += 2; |
| 458 | } |
| 459 | } |
| 460 | ContextSlotCache::Update(code, name, Variable::INTERNAL, -1); |
| 461 | return -1; |
| 462 | } |
| 463 | |
| 464 | |
| 465 | template<class Allocator> |
| 466 | int ScopeInfo<Allocator>::ParameterIndex(Code* code, String* name) { |
| 467 | ASSERT(name->IsSymbol()); |
| 468 | if (code->sinfo_size() > 0) { |
| 469 | // We must read parameters from the end since for |
| 470 | // multiply declared parameters the value of the |
| 471 | // last declaration of that parameter is used |
| 472 | // inside a function (and thus we need to look |
| 473 | // at the last index). Was bug# 1110337. |
| 474 | // |
| 475 | // Eventually, we should only register such parameters |
| 476 | // once, with corresponding index. This requires a new |
| 477 | // implementation of the ScopeInfo code. See also other |
| 478 | // comments in this file regarding this. |
| 479 | Object** p = ParameterEntriesAddr(code); |
| 480 | int n; // number of parameters |
| 481 | Object** p0 = ReadInt(p, &n); |
| 482 | p = p0 + n; |
| 483 | while (p > p0) { |
| 484 | p--; |
| 485 | if (*p == name) return p - p0; |
| 486 | } |
| 487 | } |
| 488 | return -1; |
| 489 | } |
| 490 | |
| 491 | |
| 492 | template<class Allocator> |
| 493 | int ScopeInfo<Allocator>::FunctionContextSlotIndex(Code* code, String* name) { |
| 494 | ASSERT(name->IsSymbol()); |
| 495 | if (code->sinfo_size() > 0) { |
| 496 | Object** p = &Memory::Object_at(code->sinfo_start()); |
| 497 | if (*p == name) { |
| 498 | p = ContextEntriesAddr(code); |
| 499 | int n; // number of context slots |
| 500 | ReadInt(p, &n); |
| 501 | ASSERT(n != 0); |
| 502 | // The function context slot is the last entry. |
| 503 | return n + Context::MIN_CONTEXT_SLOTS - 1; |
| 504 | } |
| 505 | } |
| 506 | return -1; |
| 507 | } |
| 508 | |
| 509 | |
| 510 | template<class Allocator> |
| 511 | Handle<String> ScopeInfo<Allocator>::LocalName(int i) const { |
| 512 | // A local variable can be allocated either on the stack or in the context. |
| 513 | // For variables allocated in the context they are always preceded by the |
| 514 | // number Context::MIN_CONTEXT_SLOTS number of fixed allocated slots in the |
| 515 | // context. |
| 516 | if (i < number_of_stack_slots()) { |
| 517 | return stack_slot_name(i); |
| 518 | } else { |
| 519 | return context_slot_name(i - number_of_stack_slots() + |
| 520 | Context::MIN_CONTEXT_SLOTS); |
| 521 | } |
| 522 | } |
| 523 | |
| 524 | |
| 525 | template<class Allocator> |
| 526 | int ScopeInfo<Allocator>::NumberOfLocals() const { |
| 527 | int number_of_locals = number_of_stack_slots(); |
| 528 | if (number_of_context_slots() > 0) { |
| 529 | ASSERT(number_of_context_slots() >= Context::MIN_CONTEXT_SLOTS); |
| 530 | number_of_locals += number_of_context_slots() - Context::MIN_CONTEXT_SLOTS; |
| 531 | } |
| 532 | return number_of_locals; |
| 533 | } |
| 534 | |
| 535 | |
| 536 | int ContextSlotCache::Hash(Code* code, String* name) { |
| 537 | // Uses only lower 32 bits if pointers are larger. |
| 538 | uintptr_t addr_hash = |
| 539 | static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2; |
| 540 | return (addr_hash ^ name->Hash()) % kLength; |
| 541 | } |
| 542 | |
| 543 | |
| 544 | int ContextSlotCache::Lookup(Code* code, |
| 545 | String* name, |
| 546 | Variable::Mode* mode) { |
| 547 | int index = Hash(code, name); |
| 548 | Key& key = keys_[index]; |
| 549 | if ((key.code == code) && key.name->Equals(name)) { |
| 550 | Value result(values_[index]); |
| 551 | if (mode != NULL) *mode = result.mode(); |
| 552 | return result.index() + kNotFound; |
| 553 | } |
| 554 | return kNotFound; |
| 555 | } |
| 556 | |
| 557 | |
| 558 | void ContextSlotCache::Update(Code* code, |
| 559 | String* name, |
| 560 | Variable::Mode mode, |
| 561 | int slot_index) { |
| 562 | String* symbol; |
| 563 | ASSERT(slot_index > kNotFound); |
| 564 | if (Heap::LookupSymbolIfExists(name, &symbol)) { |
| 565 | int index = Hash(code, symbol); |
| 566 | Key& key = keys_[index]; |
| 567 | key.code = code; |
| 568 | key.name = symbol; |
| 569 | // Please note value only takes a uint as index. |
| 570 | values_[index] = Value(mode, slot_index - kNotFound).raw(); |
| 571 | #ifdef DEBUG |
| 572 | ValidateEntry(code, name, mode, slot_index); |
| 573 | #endif |
| 574 | } |
| 575 | } |
| 576 | |
| 577 | |
| 578 | void ContextSlotCache::Clear() { |
| 579 | for (int index = 0; index < kLength; index++) keys_[index].code = NULL; |
| 580 | } |
| 581 | |
| 582 | |
| 583 | ContextSlotCache::Key ContextSlotCache::keys_[ContextSlotCache::kLength]; |
| 584 | |
| 585 | |
| 586 | uint32_t ContextSlotCache::values_[ContextSlotCache::kLength]; |
| 587 | |
| 588 | |
| 589 | #ifdef DEBUG |
| 590 | |
| 591 | void ContextSlotCache::ValidateEntry(Code* code, |
| 592 | String* name, |
| 593 | Variable::Mode mode, |
| 594 | int slot_index) { |
| 595 | String* symbol; |
| 596 | if (Heap::LookupSymbolIfExists(name, &symbol)) { |
| 597 | int index = Hash(code, name); |
| 598 | Key& key = keys_[index]; |
| 599 | ASSERT(key.code == code); |
| 600 | ASSERT(key.name->Equals(name)); |
| 601 | Value result(values_[index]); |
| 602 | ASSERT(result.mode() == mode); |
| 603 | ASSERT(result.index() + kNotFound == slot_index); |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | |
| 608 | template <class Allocator> |
| 609 | static void PrintList(const char* list_name, |
| 610 | int nof_internal_slots, |
| 611 | List<Handle<String>, Allocator>& list) { |
| 612 | if (list.length() > 0) { |
| 613 | PrintF("\n // %s\n", list_name); |
| 614 | if (nof_internal_slots > 0) { |
| 615 | PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1); |
| 616 | } |
| 617 | for (int i = 0; i < list.length(); i++) { |
| 618 | PrintF(" %2d ", i + nof_internal_slots); |
| 619 | list[i]->ShortPrint(); |
| 620 | PrintF("\n"); |
| 621 | } |
| 622 | } |
| 623 | } |
| 624 | |
| 625 | |
| 626 | template<class Allocator> |
| 627 | void ScopeInfo<Allocator>::Print() { |
| 628 | PrintF("ScopeInfo "); |
| 629 | if (function_name_->length() > 0) |
| 630 | function_name_->ShortPrint(); |
| 631 | else |
| 632 | PrintF("/* no function name */"); |
| 633 | PrintF("{"); |
| 634 | |
| 635 | PrintList<Allocator>("parameters", 0, parameters_); |
| 636 | PrintList<Allocator>("stack slots", 0, stack_slots_); |
| 637 | PrintList<Allocator>("context slots", Context::MIN_CONTEXT_SLOTS, |
| 638 | context_slots_); |
| 639 | |
| 640 | PrintF("}\n"); |
| 641 | } |
| 642 | #endif // DEBUG |
| 643 | |
| 644 | |
| 645 | // Make sure the classes get instantiated by the template system. |
| 646 | template class ScopeInfo<FreeStoreAllocationPolicy>; |
| 647 | template class ScopeInfo<PreallocatedStorage>; |
| 648 | template class ScopeInfo<ZoneListAllocationPolicy>; |
| 649 | |
| 650 | } } // namespace v8::internal |