1// Copyright 2012 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 "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "codegen.h"
34#include "debug.h"
35#include "deoptimizer.h"
36#include "date.h"
37#include "elements.h"
38#include "execution.h"
39#include "full-codegen.h"
40#include "hydrogen.h"
41#include "objects-inl.h"
42#include "objects-visiting.h"
43#include "objects-visiting-inl.h"
44#include "macro-assembler.h"
45#include "mark-compact.h"
46#include "safepoint-table.h"
47#include "string-stream.h"
48#include "utils.h"
49#include "vm-state-inl.h"
50
51#ifdef ENABLE_DISASSEMBLER
52#include "disasm.h"
53#include "disassembler.h"
54#endif
55
56namespace v8 {
57namespace internal {
58
59void PrintElementsKind(FILE* out, ElementsKind kind) {
60  ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
61  PrintF(out, "%s", accessor->name());
62}
63
64
65MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
66                                                  Object* value) {
67  Object* result;
68  { MaybeObject* maybe_result =
69        constructor->GetHeap()->AllocateJSObject(constructor);
70    if (!maybe_result->ToObject(&result)) return maybe_result;
71  }
72  JSValue::cast(result)->set_value(value);
73  return result;
74}
75
76
77MaybeObject* Object::ToObject(Context* global_context) {
78  if (IsNumber()) {
79    return CreateJSValue(global_context->number_function(), this);
80  } else if (IsBoolean()) {
81    return CreateJSValue(global_context->boolean_function(), this);
82  } else if (IsString()) {
83    return CreateJSValue(global_context->string_function(), this);
84  }
85  ASSERT(IsJSObject());
86  return this;
87}
88
89
90MaybeObject* Object::ToObject() {
91  if (IsJSReceiver()) {
92    return this;
93  } else if (IsNumber()) {
94    Isolate* isolate = Isolate::Current();
95    Context* global_context = isolate->context()->global_context();
96    return CreateJSValue(global_context->number_function(), this);
97  } else if (IsBoolean()) {
98    Isolate* isolate = HeapObject::cast(this)->GetIsolate();
99    Context* global_context = isolate->context()->global_context();
100    return CreateJSValue(global_context->boolean_function(), this);
101  } else if (IsString()) {
102    Isolate* isolate = HeapObject::cast(this)->GetIsolate();
103    Context* global_context = isolate->context()->global_context();
104    return CreateJSValue(global_context->string_function(), this);
105  }
106
107  // Throw a type error.
108  return Failure::InternalError();
109}
110
111
112Object* Object::ToBoolean() {
113  if (IsTrue()) return this;
114  if (IsFalse()) return this;
115  if (IsSmi()) {
116    return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
117  }
118  HeapObject* heap_object = HeapObject::cast(this);
119  if (heap_object->IsUndefined() || heap_object->IsNull()) {
120    return heap_object->GetHeap()->false_value();
121  }
122  // Undetectable object is false
123  if (heap_object->IsUndetectableObject()) {
124    return heap_object->GetHeap()->false_value();
125  }
126  if (heap_object->IsString()) {
127    return heap_object->GetHeap()->ToBoolean(
128        String::cast(this)->length() != 0);
129  }
130  if (heap_object->IsHeapNumber()) {
131    return HeapNumber::cast(this)->HeapNumberToBoolean();
132  }
133  return heap_object->GetHeap()->true_value();
134}
135
136
137void Object::Lookup(String* name, LookupResult* result) {
138  Object* holder = NULL;
139  if (IsJSReceiver()) {
140    holder = this;
141  } else {
142    Context* global_context = Isolate::Current()->context()->global_context();
143    if (IsNumber()) {
144      holder = global_context->number_function()->instance_prototype();
145    } else if (IsString()) {
146      holder = global_context->string_function()->instance_prototype();
147    } else if (IsBoolean()) {
148      holder = global_context->boolean_function()->instance_prototype();
149    }
150  }
151  ASSERT(holder != NULL);  // Cannot handle null or undefined.
152  JSReceiver::cast(holder)->Lookup(name, result);
153}
154
155
156MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
157                                             String* name,
158                                             PropertyAttributes* attributes) {
159  LookupResult result(name->GetIsolate());
160  Lookup(name, &result);
161  MaybeObject* value = GetProperty(receiver, &result, name, attributes);
162  ASSERT(*attributes <= ABSENT);
163  return value;
164}
165
166
167MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
168                                               Object* structure,
169                                               String* name) {
170  Isolate* isolate = name->GetIsolate();
171  // To accommodate both the old and the new api we switch on the
172  // data structure used to store the callbacks.  Eventually foreign
173  // callbacks should be phased out.
174  if (structure->IsForeign()) {
175    AccessorDescriptor* callback =
176        reinterpret_cast<AccessorDescriptor*>(
177            Foreign::cast(structure)->foreign_address());
178    MaybeObject* value = (callback->getter)(receiver, callback->data);
179    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
180    return value;
181  }
182
183  // api style callbacks.
184  if (structure->IsAccessorInfo()) {
185    AccessorInfo* data = AccessorInfo::cast(structure);
186    Object* fun_obj = data->getter();
187    v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
188    HandleScope scope(isolate);
189    JSObject* self = JSObject::cast(receiver);
190    Handle<String> key(name);
191    LOG(isolate, ApiNamedPropertyAccess("load", self, name));
192    CustomArguments args(isolate, data->data(), self, this);
193    v8::AccessorInfo info(args.end());
194    v8::Handle<v8::Value> result;
195    {
196      // Leaving JavaScript.
197      VMState state(isolate, EXTERNAL);
198      result = call_fun(v8::Utils::ToLocal(key), info);
199    }
200    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
201    if (result.IsEmpty()) {
202      return isolate->heap()->undefined_value();
203    }
204    return *v8::Utils::OpenHandle(*result);
205  }
206
207  // __defineGetter__ callback
208  if (structure->IsAccessorPair()) {
209    Object* getter = AccessorPair::cast(structure)->getter();
210    if (getter->IsSpecFunction()) {
211      // TODO(rossberg): nicer would be to cast to some JSCallable here...
212      return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
213    }
214    // Getter is not a function.
215    return isolate->heap()->undefined_value();
216  }
217
218  UNREACHABLE();
219  return NULL;
220}
221
222
223MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
224                                             String* name_raw) {
225  Isolate* isolate = GetIsolate();
226  HandleScope scope(isolate);
227  Handle<Object> receiver(receiver_raw);
228  Handle<Object> name(name_raw);
229
230  Handle<Object> args[] = { receiver, name };
231  Handle<Object> result = CallTrap(
232    "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
233  if (isolate->has_pending_exception()) return Failure::Exception();
234
235  return *result;
236}
237
238
239Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
240  Isolate* isolate = object->IsHeapObject()
241      ? Handle<HeapObject>::cast(object)->GetIsolate()
242      : Isolate::Current();
243  CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
244}
245
246
247MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
248                                            uint32_t index) {
249  String* name;
250  MaybeObject* maybe = GetHeap()->Uint32ToString(index);
251  if (!maybe->To<String>(&name)) return maybe;
252  return GetPropertyWithHandler(receiver, name);
253}
254
255
256MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
257                                            Object* value,
258                                            StrictModeFlag strict_mode) {
259  String* name;
260  MaybeObject* maybe = GetHeap()->Uint32ToString(index);
261  if (!maybe->To<String>(&name)) return maybe;
262  return SetPropertyWithHandler(name, value, NONE, strict_mode);
263}
264
265
266bool JSProxy::HasElementWithHandler(uint32_t index) {
267  String* name;
268  MaybeObject* maybe = GetHeap()->Uint32ToString(index);
269  if (!maybe->To<String>(&name)) return maybe;
270  return HasPropertyWithHandler(name);
271}
272
273
274MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
275                                                  JSReceiver* getter) {
276  HandleScope scope;
277  Handle<JSReceiver> fun(getter);
278  Handle<Object> self(receiver);
279#ifdef ENABLE_DEBUGGER_SUPPORT
280  Debug* debug = fun->GetHeap()->isolate()->debug();
281  // Handle stepping into a getter if step into is active.
282  // TODO(rossberg): should this apply to getters that are function proxies?
283  if (debug->StepInActive() && fun->IsJSFunction()) {
284    debug->HandleStepIn(
285        Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
286  }
287#endif
288
289  bool has_pending_exception;
290  Handle<Object> result =
291      Execution::Call(fun, self, 0, NULL, &has_pending_exception, true);
292  // Check for pending exception and return the result.
293  if (has_pending_exception) return Failure::Exception();
294  return *result;
295}
296
297
298// Only deal with CALLBACKS and INTERCEPTOR
299MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
300    Object* receiver,
301    LookupResult* result,
302    String* name,
303    PropertyAttributes* attributes) {
304  if (result->IsProperty()) {
305    switch (result->type()) {
306      case CALLBACKS: {
307        // Only allow API accessors.
308        Object* obj = result->GetCallbackObject();
309        if (obj->IsAccessorInfo()) {
310          AccessorInfo* info = AccessorInfo::cast(obj);
311          if (info->all_can_read()) {
312            *attributes = result->GetAttributes();
313            return result->holder()->GetPropertyWithCallback(
314                receiver, result->GetCallbackObject(), name);
315          }
316        }
317        break;
318      }
319      case NORMAL:
320      case FIELD:
321      case CONSTANT_FUNCTION: {
322        // Search ALL_CAN_READ accessors in prototype chain.
323        LookupResult r(GetIsolate());
324        result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
325        if (r.IsProperty()) {
326          return GetPropertyWithFailedAccessCheck(receiver,
327                                                  &r,
328                                                  name,
329                                                  attributes);
330        }
331        break;
332      }
333      case INTERCEPTOR: {
334        // If the object has an interceptor, try real named properties.
335        // No access check in GetPropertyAttributeWithInterceptor.
336        LookupResult r(GetIsolate());
337        result->holder()->LookupRealNamedProperty(name, &r);
338        if (r.IsProperty()) {
339          return GetPropertyWithFailedAccessCheck(receiver,
340                                                  &r,
341                                                  name,
342                                                  attributes);
343        }
344        break;
345      }
346      default:
347        UNREACHABLE();
348    }
349  }
350
351  // No accessible property found.
352  *attributes = ABSENT;
353  Heap* heap = name->GetHeap();
354  heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
355  return heap->undefined_value();
356}
357
358
359PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
360    Object* receiver,
361    LookupResult* result,
362    String* name,
363    bool continue_search) {
364  if (result->IsProperty()) {
365    switch (result->type()) {
366      case CALLBACKS: {
367        // Only allow API accessors.
368        Object* obj = result->GetCallbackObject();
369        if (obj->IsAccessorInfo()) {
370          AccessorInfo* info = AccessorInfo::cast(obj);
371          if (info->all_can_read()) {
372            return result->GetAttributes();
373          }
374        }
375        break;
376      }
377
378      case NORMAL:
379      case FIELD:
380      case CONSTANT_FUNCTION: {
381        if (!continue_search) break;
382        // Search ALL_CAN_READ accessors in prototype chain.
383        LookupResult r(GetIsolate());
384        result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
385        if (r.IsProperty()) {
386          return GetPropertyAttributeWithFailedAccessCheck(receiver,
387                                                           &r,
388                                                           name,
389                                                           continue_search);
390        }
391        break;
392      }
393
394      case INTERCEPTOR: {
395        // If the object has an interceptor, try real named properties.
396        // No access check in GetPropertyAttributeWithInterceptor.
397        LookupResult r(GetIsolate());
398        if (continue_search) {
399          result->holder()->LookupRealNamedProperty(name, &r);
400        } else {
401          result->holder()->LocalLookupRealNamedProperty(name, &r);
402        }
403        if (r.IsProperty()) {
404          return GetPropertyAttributeWithFailedAccessCheck(receiver,
405                                                           &r,
406                                                           name,
407                                                           continue_search);
408        }
409        break;
410      }
411
412      default:
413        UNREACHABLE();
414    }
415  }
416
417  GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
418  return ABSENT;
419}
420
421
422Object* JSObject::GetNormalizedProperty(LookupResult* result) {
423  ASSERT(!HasFastProperties());
424  Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
425  if (IsGlobalObject()) {
426    value = JSGlobalPropertyCell::cast(value)->value();
427  }
428  ASSERT(!value->IsJSGlobalPropertyCell());
429  return value;
430}
431
432
433Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
434  ASSERT(!HasFastProperties());
435  if (IsGlobalObject()) {
436    JSGlobalPropertyCell* cell =
437        JSGlobalPropertyCell::cast(
438            property_dictionary()->ValueAt(result->GetDictionaryEntry()));
439    cell->set_value(value);
440  } else {
441    property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
442  }
443  return value;
444}
445
446
447Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
448                                               Handle<String> key,
449                                               Handle<Object> value,
450                                               PropertyDetails details) {
451  CALL_HEAP_FUNCTION(object->GetIsolate(),
452                     object->SetNormalizedProperty(*key, *value, details),
453                     Object);
454}
455
456
457MaybeObject* JSObject::SetNormalizedProperty(String* name,
458                                             Object* value,
459                                             PropertyDetails details) {
460  ASSERT(!HasFastProperties());
461  int entry = property_dictionary()->FindEntry(name);
462  if (entry == StringDictionary::kNotFound) {
463    Object* store_value = value;
464    if (IsGlobalObject()) {
465      Heap* heap = name->GetHeap();
466      MaybeObject* maybe_store_value =
467          heap->AllocateJSGlobalPropertyCell(value);
468      if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
469    }
470    Object* dict;
471    { MaybeObject* maybe_dict =
472          property_dictionary()->Add(name, store_value, details);
473      if (!maybe_dict->ToObject(&dict)) return maybe_dict;
474    }
475    set_properties(StringDictionary::cast(dict));
476    return value;
477  }
478  // Preserve enumeration index.
479  details = PropertyDetails(details.attributes(),
480                            details.type(),
481                            property_dictionary()->DetailsAt(entry).index());
482  if (IsGlobalObject()) {
483    JSGlobalPropertyCell* cell =
484        JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
485    cell->set_value(value);
486    // Please note we have to update the property details.
487    property_dictionary()->DetailsAtPut(entry, details);
488  } else {
489    property_dictionary()->SetEntry(entry, name, value, details);
490  }
491  return value;
492}
493
494
495MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
496  ASSERT(!HasFastProperties());
497  StringDictionary* dictionary = property_dictionary();
498  int entry = dictionary->FindEntry(name);
499  if (entry != StringDictionary::kNotFound) {
500    // If we have a global object set the cell to the hole.
501    if (IsGlobalObject()) {
502      PropertyDetails details = dictionary->DetailsAt(entry);
503      if (details.IsDontDelete()) {
504        if (mode != FORCE_DELETION) return GetHeap()->false_value();
505        // When forced to delete global properties, we have to make a
506        // map change to invalidate any ICs that think they can load
507        // from the DontDelete cell without checking if it contains
508        // the hole value.
509        Object* new_map;
510        { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
511          if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
512        }
513        set_map(Map::cast(new_map));
514      }
515      JSGlobalPropertyCell* cell =
516          JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
517      cell->set_value(cell->GetHeap()->the_hole_value());
518      dictionary->DetailsAtPut(entry, details.AsDeleted());
519    } else {
520      Object* deleted = dictionary->DeleteProperty(entry, mode);
521      if (deleted == GetHeap()->true_value()) {
522        FixedArray* new_properties = NULL;
523        MaybeObject* maybe_properties = dictionary->Shrink(name);
524        if (!maybe_properties->To(&new_properties)) {
525          return maybe_properties;
526        }
527        set_properties(new_properties);
528      }
529      return deleted;
530    }
531  }
532  return GetHeap()->true_value();
533}
534
535
536bool JSObject::IsDirty() {
537  Object* cons_obj = map()->constructor();
538  if (!cons_obj->IsJSFunction())
539    return true;
540  JSFunction* fun = JSFunction::cast(cons_obj);
541  if (!fun->shared()->IsApiFunction())
542    return true;
543  // If the object is fully fast case and has the same map it was
544  // created with then no changes can have been made to it.
545  return map() != fun->initial_map()
546      || !HasFastElements()
547      || !HasFastProperties();
548}
549
550
551Handle<Object> Object::GetProperty(Handle<Object> object,
552                                   Handle<Object> receiver,
553                                   LookupResult* result,
554                                   Handle<String> key,
555                                   PropertyAttributes* attributes) {
556  Isolate* isolate = object->IsHeapObject()
557      ? Handle<HeapObject>::cast(object)->GetIsolate()
558      : Isolate::Current();
559  CALL_HEAP_FUNCTION(
560      isolate,
561      object->GetProperty(*receiver, result, *key, attributes),
562      Object);
563}
564
565
566MaybeObject* Object::GetProperty(Object* receiver,
567                                 LookupResult* result,
568                                 String* name,
569                                 PropertyAttributes* attributes) {
570  // Make sure that the top context does not change when doing
571  // callbacks or interceptor calls.
572  AssertNoContextChange ncc;
573  Heap* heap = name->GetHeap();
574
575  // Traverse the prototype chain from the current object (this) to
576  // the holder and check for access rights. This avoids traversing the
577  // objects more than once in case of interceptors, because the
578  // holder will always be the interceptor holder and the search may
579  // only continue with a current object just after the interceptor
580  // holder in the prototype chain.
581  // Proxy handlers do not use the proxy's prototype, so we can skip this.
582  if (!result->IsHandler()) {
583    Object* last = result->IsProperty()
584        ? result->holder()
585        : Object::cast(heap->null_value());
586    ASSERT(this != this->GetPrototype());
587    for (Object* current = this; true; current = current->GetPrototype()) {
588      if (current->IsAccessCheckNeeded()) {
589        // Check if we're allowed to read from the current object. Note
590        // that even though we may not actually end up loading the named
591        // property from the current object, we still check that we have
592        // access to it.
593        JSObject* checked = JSObject::cast(current);
594        if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
595          return checked->GetPropertyWithFailedAccessCheck(receiver,
596                                                           result,
597                                                           name,
598                                                           attributes);
599        }
600      }
601      // Stop traversing the chain once we reach the last object in the
602      // chain; either the holder of the result or null in case of an
603      // absent property.
604      if (current == last) break;
605    }
606  }
607
608  if (!result->IsProperty()) {
609    *attributes = ABSENT;
610    return heap->undefined_value();
611  }
612  *attributes = result->GetAttributes();
613  Object* value;
614  switch (result->type()) {
615    case NORMAL:
616      value = result->holder()->GetNormalizedProperty(result);
617      ASSERT(!value->IsTheHole() || result->IsReadOnly());
618      return value->IsTheHole() ? heap->undefined_value() : value;
619    case FIELD:
620      value = result->holder()->FastPropertyAt(result->GetFieldIndex());
621      ASSERT(!value->IsTheHole() || result->IsReadOnly());
622      return value->IsTheHole() ? heap->undefined_value() : value;
623    case CONSTANT_FUNCTION:
624      return result->GetConstantFunction();
625    case CALLBACKS:
626      return result->holder()->GetPropertyWithCallback(
627          receiver, result->GetCallbackObject(), name);
628    case HANDLER:
629      return result->proxy()->GetPropertyWithHandler(receiver, name);
630    case INTERCEPTOR: {
631      JSObject* recvr = JSObject::cast(receiver);
632      return result->holder()->GetPropertyWithInterceptor(
633          recvr, name, attributes);
634    }
635    case MAP_TRANSITION:
636    case ELEMENTS_TRANSITION:
637    case CONSTANT_TRANSITION:
638    case NULL_DESCRIPTOR:
639      break;
640  }
641  UNREACHABLE();
642  return NULL;
643}
644
645
646MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
647  Heap* heap = IsSmi()
648      ? Isolate::Current()->heap()
649      : HeapObject::cast(this)->GetHeap();
650  Object* holder = this;
651
652  // Iterate up the prototype chain until an element is found or the null
653  // prototype is encountered.
654  for (holder = this;
655       holder != heap->null_value();
656       holder = holder->GetPrototype()) {
657    if (!holder->IsJSObject()) {
658      Isolate* isolate = heap->isolate();
659      Context* global_context = isolate->context()->global_context();
660      if (holder->IsNumber()) {
661        holder = global_context->number_function()->instance_prototype();
662      } else if (holder->IsString()) {
663        holder = global_context->string_function()->instance_prototype();
664      } else if (holder->IsBoolean()) {
665        holder = global_context->boolean_function()->instance_prototype();
666      } else if (holder->IsJSProxy()) {
667        return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
668      } else {
669        // Undefined and null have no indexed properties.
670        ASSERT(holder->IsUndefined() || holder->IsNull());
671        return heap->undefined_value();
672      }
673    }
674
675    // Inline the case for JSObjects. Doing so significantly improves the
676    // performance of fetching elements where checking the prototype chain is
677    // necessary.
678    JSObject* js_object = JSObject::cast(holder);
679
680    // Check access rights if needed.
681    if (js_object->IsAccessCheckNeeded()) {
682      Isolate* isolate = heap->isolate();
683      if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
684        isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
685        return heap->undefined_value();
686      }
687    }
688
689    if (js_object->HasIndexedInterceptor()) {
690      return js_object->GetElementWithInterceptor(receiver, index);
691    }
692
693    if (js_object->elements() != heap->empty_fixed_array()) {
694      MaybeObject* result = js_object->GetElementsAccessor()->Get(
695          receiver, js_object, index);
696      if (result != heap->the_hole_value()) return result;
697    }
698  }
699
700  return heap->undefined_value();
701}
702
703
704Object* Object::GetPrototype() {
705  if (IsSmi()) {
706    Heap* heap = Isolate::Current()->heap();
707    Context* context = heap->isolate()->context()->global_context();
708    return context->number_function()->instance_prototype();
709  }
710
711  HeapObject* heap_object = HeapObject::cast(this);
712
713  // The object is either a number, a string, a boolean,
714  // a real JS object, or a Harmony proxy.
715  if (heap_object->IsJSReceiver()) {
716    return heap_object->map()->prototype();
717  }
718  Heap* heap = heap_object->GetHeap();
719  Context* context = heap->isolate()->context()->global_context();
720
721  if (heap_object->IsHeapNumber()) {
722    return context->number_function()->instance_prototype();
723  }
724  if (heap_object->IsString()) {
725    return context->string_function()->instance_prototype();
726  }
727  if (heap_object->IsBoolean()) {
728    return context->boolean_function()->instance_prototype();
729  } else {
730    return heap->null_value();
731  }
732}
733
734
735MaybeObject* Object::GetHash(CreationFlag flag) {
736  // The object is either a number, a string, an odd-ball,
737  // a real JS object, or a Harmony proxy.
738  if (IsNumber()) {
739    uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
740    return Smi::FromInt(hash & Smi::kMaxValue);
741  }
742  if (IsString()) {
743    uint32_t hash = String::cast(this)->Hash();
744    return Smi::FromInt(hash);
745  }
746  if (IsOddball()) {
747    uint32_t hash = Oddball::cast(this)->to_string()->Hash();
748    return Smi::FromInt(hash);
749  }
750  if (IsJSReceiver()) {
751    return JSReceiver::cast(this)->GetIdentityHash(flag);
752  }
753
754  UNREACHABLE();
755  return Smi::FromInt(0);
756}
757
758
759bool Object::SameValue(Object* other) {
760  if (other == this) return true;
761  if (!IsHeapObject() || !other->IsHeapObject()) return false;
762
763  // The object is either a number, a string, an odd-ball,
764  // a real JS object, or a Harmony proxy.
765  if (IsNumber() && other->IsNumber()) {
766    double this_value = Number();
767    double other_value = other->Number();
768    return (this_value == other_value) ||
769        (isnan(this_value) && isnan(other_value));
770  }
771  if (IsString() && other->IsString()) {
772    return String::cast(this)->Equals(String::cast(other));
773  }
774  return false;
775}
776
777
778void Object::ShortPrint(FILE* out) {
779  HeapStringAllocator allocator;
780  StringStream accumulator(&allocator);
781  ShortPrint(&accumulator);
782  accumulator.OutputToFile(out);
783}
784
785
786void Object::ShortPrint(StringStream* accumulator) {
787  if (IsSmi()) {
788    Smi::cast(this)->SmiPrint(accumulator);
789  } else if (IsFailure()) {
790    Failure::cast(this)->FailurePrint(accumulator);
791  } else {
792    HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
793  }
794}
795
796
797void Smi::SmiPrint(FILE* out) {
798  PrintF(out, "%d", value());
799}
800
801
802void Smi::SmiPrint(StringStream* accumulator) {
803  accumulator->Add("%d", value());
804}
805
806
807void Failure::FailurePrint(StringStream* accumulator) {
808  accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
809}
810
811
812void Failure::FailurePrint(FILE* out) {
813  PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
814}
815
816
817// Should a word be prefixed by 'a' or 'an' in order to read naturally in
818// English?  Returns false for non-ASCII or words that don't start with
819// a capital letter.  The a/an rule follows pronunciation in English.
820// We don't use the BBC's overcorrect "an historic occasion" though if
821// you speak a dialect you may well say "an 'istoric occasion".
822static bool AnWord(String* str) {
823  if (str->length() == 0) return false;  // A nothing.
824  int c0 = str->Get(0);
825  int c1 = str->length() > 1 ? str->Get(1) : 0;
826  if (c0 == 'U') {
827    if (c1 > 'Z') {
828      return true;  // An Umpire, but a UTF8String, a U.
829    }
830  } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
831    return true;    // An Ape, an ABCBook.
832  } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
833           (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
834            c0 == 'S' || c0 == 'X')) {
835    return true;    // An MP3File, an M.
836  }
837  return false;
838}
839
840
841MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
842#ifdef DEBUG
843  // Do not attempt to flatten in debug mode when allocation is not
844  // allowed.  This is to avoid an assertion failure when allocating.
845  // Flattening strings is the only case where we always allow
846  // allocation because no GC is performed if the allocation fails.
847  if (!HEAP->IsAllocationAllowed()) return this;
848#endif
849
850  Heap* heap = GetHeap();
851  switch (StringShape(this).representation_tag()) {
852    case kConsStringTag: {
853      ConsString* cs = ConsString::cast(this);
854      if (cs->second()->length() == 0) {
855        return cs->first();
856      }
857      // There's little point in putting the flat string in new space if the
858      // cons string is in old space.  It can never get GCed until there is
859      // an old space GC.
860      PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
861      int len = length();
862      Object* object;
863      String* result;
864      if (IsAsciiRepresentation()) {
865        { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
866          if (!maybe_object->ToObject(&object)) return maybe_object;
867        }
868        result = String::cast(object);
869        String* first = cs->first();
870        int first_length = first->length();
871        char* dest = SeqAsciiString::cast(result)->GetChars();
872        WriteToFlat(first, dest, 0, first_length);
873        String* second = cs->second();
874        WriteToFlat(second,
875                    dest + first_length,
876                    0,
877                    len - first_length);
878      } else {
879        { MaybeObject* maybe_object =
880              heap->AllocateRawTwoByteString(len, tenure);
881          if (!maybe_object->ToObject(&object)) return maybe_object;
882        }
883        result = String::cast(object);
884        uc16* dest = SeqTwoByteString::cast(result)->GetChars();
885        String* first = cs->first();
886        int first_length = first->length();
887        WriteToFlat(first, dest, 0, first_length);
888        String* second = cs->second();
889        WriteToFlat(second,
890                    dest + first_length,
891                    0,
892                    len - first_length);
893      }
894      cs->set_first(result);
895      cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
896      return result;
897    }
898    default:
899      return this;
900  }
901}
902
903
904bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
905  // Externalizing twice leaks the external resource, so it's
906  // prohibited by the API.
907  ASSERT(!this->IsExternalString());
908#ifdef DEBUG
909  if (FLAG_enable_slow_asserts) {
910    // Assert that the resource and the string are equivalent.
911    ASSERT(static_cast<size_t>(this->length()) == resource->length());
912    ScopedVector<uc16> smart_chars(this->length());
913    String::WriteToFlat(this, smart_chars.start(), 0, this->length());
914    ASSERT(memcmp(smart_chars.start(),
915                  resource->data(),
916                  resource->length() * sizeof(smart_chars[0])) == 0);
917  }
918#endif  // DEBUG
919  Heap* heap = GetHeap();
920  int size = this->Size();  // Byte size of the original string.
921  if (size < ExternalString::kShortSize) {
922    return false;
923  }
924  bool is_ascii = this->IsAsciiRepresentation();
925  bool is_symbol = this->IsSymbol();
926
927  // Morph the object to an external string by adjusting the map and
928  // reinitializing the fields.
929  if (size >= ExternalString::kSize) {
930    this->set_map_no_write_barrier(
931        is_symbol
932            ? (is_ascii ?  heap->external_symbol_with_ascii_data_map()
933                        :  heap->external_symbol_map())
934            : (is_ascii ?  heap->external_string_with_ascii_data_map()
935                        :  heap->external_string_map()));
936  } else {
937    this->set_map_no_write_barrier(
938        is_symbol
939            ? (is_ascii ?  heap->short_external_symbol_with_ascii_data_map()
940                        :  heap->short_external_symbol_map())
941            : (is_ascii ?  heap->short_external_string_with_ascii_data_map()
942                        :  heap->short_external_string_map()));
943  }
944  ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
945  self->set_resource(resource);
946  if (is_symbol) self->Hash();  // Force regeneration of the hash value.
947
948  // Fill the remainder of the string with dead wood.
949  int new_size = this->Size();  // Byte size of the external String object.
950  heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
951  if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
952    MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
953                                               new_size - size);
954  }
955  return true;
956}
957
958
959bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
960#ifdef DEBUG
961  if (FLAG_enable_slow_asserts) {
962    // Assert that the resource and the string are equivalent.
963    ASSERT(static_cast<size_t>(this->length()) == resource->length());
964    ScopedVector<char> smart_chars(this->length());
965    String::WriteToFlat(this, smart_chars.start(), 0, this->length());
966    ASSERT(memcmp(smart_chars.start(),
967                  resource->data(),
968                  resource->length() * sizeof(smart_chars[0])) == 0);
969  }
970#endif  // DEBUG
971  Heap* heap = GetHeap();
972  int size = this->Size();  // Byte size of the original string.
973  if (size < ExternalString::kShortSize) {
974    return false;
975  }
976  bool is_symbol = this->IsSymbol();
977
978  // Morph the object to an external string by adjusting the map and
979  // reinitializing the fields.  Use short version if space is limited.
980  if (size >= ExternalString::kSize) {
981    this->set_map_no_write_barrier(
982        is_symbol ? heap->external_ascii_symbol_map()
983                  : heap->external_ascii_string_map());
984  } else {
985    this->set_map_no_write_barrier(
986        is_symbol ? heap->short_external_ascii_symbol_map()
987                  : heap->short_external_ascii_string_map());
988  }
989  ExternalAsciiString* self = ExternalAsciiString::cast(this);
990  self->set_resource(resource);
991  if (is_symbol) self->Hash();  // Force regeneration of the hash value.
992
993  // Fill the remainder of the string with dead wood.
994  int new_size = this->Size();  // Byte size of the external String object.
995  heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
996  if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
997    MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
998                                               new_size - size);
999  }
1000  return true;
1001}
1002
1003
1004void String::StringShortPrint(StringStream* accumulator) {
1005  int len = length();
1006  if (len > kMaxShortPrintLength) {
1007    accumulator->Add("<Very long string[%u]>", len);
1008    return;
1009  }
1010
1011  if (!LooksValid()) {
1012    accumulator->Add("<Invalid String>");
1013    return;
1014  }
1015
1016  StringInputBuffer buf(this);
1017
1018  bool truncated = false;
1019  if (len > kMaxShortPrintLength) {
1020    len = kMaxShortPrintLength;
1021    truncated = true;
1022  }
1023  bool ascii = true;
1024  for (int i = 0; i < len; i++) {
1025    int c = buf.GetNext();
1026
1027    if (c < 32 || c >= 127) {
1028      ascii = false;
1029    }
1030  }
1031  buf.Reset(this);
1032  if (ascii) {
1033    accumulator->Add("<String[%u]: ", length());
1034    for (int i = 0; i < len; i++) {
1035      accumulator->Put(buf.GetNext());
1036    }
1037    accumulator->Put('>');
1038  } else {
1039    // Backslash indicates that the string contains control
1040    // characters and that backslashes are therefore escaped.
1041    accumulator->Add("<String[%u]\\: ", length());
1042    for (int i = 0; i < len; i++) {
1043      int c = buf.GetNext();
1044      if (c == '\n') {
1045        accumulator->Add("\\n");
1046      } else if (c == '\r') {
1047        accumulator->Add("\\r");
1048      } else if (c == '\\') {
1049        accumulator->Add("\\\\");
1050      } else if (c < 32 || c > 126) {
1051        accumulator->Add("\\x%02x", c);
1052      } else {
1053        accumulator->Put(c);
1054      }
1055    }
1056    if (truncated) {
1057      accumulator->Put('.');
1058      accumulator->Put('.');
1059      accumulator->Put('.');
1060    }
1061    accumulator->Put('>');
1062  }
1063  return;
1064}
1065
1066
1067void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1068  switch (map()->instance_type()) {
1069    case JS_ARRAY_TYPE: {
1070      double length = JSArray::cast(this)->length()->Number();
1071      accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
1072      break;
1073    }
1074    case JS_WEAK_MAP_TYPE: {
1075      accumulator->Add("<JS WeakMap>");
1076      break;
1077    }
1078    case JS_REGEXP_TYPE: {
1079      accumulator->Add("<JS RegExp>");
1080      break;
1081    }
1082    case JS_FUNCTION_TYPE: {
1083      Object* fun_name = JSFunction::cast(this)->shared()->name();
1084      bool printed = false;
1085      if (fun_name->IsString()) {
1086        String* str = String::cast(fun_name);
1087        if (str->length() > 0) {
1088          accumulator->Add("<JS Function ");
1089          accumulator->Put(str);
1090          accumulator->Put('>');
1091          printed = true;
1092        }
1093      }
1094      if (!printed) {
1095        accumulator->Add("<JS Function>");
1096      }
1097      break;
1098    }
1099    // All other JSObjects are rather similar to each other (JSObject,
1100    // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1101    default: {
1102      Map* map_of_this = map();
1103      Heap* heap = GetHeap();
1104      Object* constructor = map_of_this->constructor();
1105      bool printed = false;
1106      if (constructor->IsHeapObject() &&
1107          !heap->Contains(HeapObject::cast(constructor))) {
1108        accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1109      } else {
1110        bool global_object = IsJSGlobalProxy();
1111        if (constructor->IsJSFunction()) {
1112          if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
1113            accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1114          } else {
1115            Object* constructor_name =
1116                JSFunction::cast(constructor)->shared()->name();
1117            if (constructor_name->IsString()) {
1118              String* str = String::cast(constructor_name);
1119              if (str->length() > 0) {
1120                bool vowel = AnWord(str);
1121                accumulator->Add("<%sa%s ",
1122                       global_object ? "Global Object: " : "",
1123                       vowel ? "n" : "");
1124                accumulator->Put(str);
1125                printed = true;
1126              }
1127            }
1128          }
1129        }
1130        if (!printed) {
1131          accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1132        }
1133      }
1134      if (IsJSValue()) {
1135        accumulator->Add(" value = ");
1136        JSValue::cast(this)->value()->ShortPrint(accumulator);
1137      }
1138      accumulator->Put('>');
1139      break;
1140    }
1141  }
1142}
1143
1144
1145void JSObject::PrintElementsTransition(
1146    FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1147    ElementsKind to_kind, FixedArrayBase* to_elements) {
1148  if (from_kind != to_kind) {
1149    PrintF(file, "elements transition [");
1150    PrintElementsKind(file, from_kind);
1151    PrintF(file, " -> ");
1152    PrintElementsKind(file, to_kind);
1153    PrintF(file, "] in ");
1154    JavaScriptFrame::PrintTop(file, false, true);
1155    PrintF(file, " for ");
1156    ShortPrint(file);
1157    PrintF(file, " from ");
1158    from_elements->ShortPrint(file);
1159    PrintF(file, " to ");
1160    to_elements->ShortPrint(file);
1161    PrintF(file, "\n");
1162  }
1163}
1164
1165
1166void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
1167  Heap* heap = GetHeap();
1168  if (!heap->Contains(this)) {
1169    accumulator->Add("!!!INVALID POINTER!!!");
1170    return;
1171  }
1172  if (!heap->Contains(map())) {
1173    accumulator->Add("!!!INVALID MAP!!!");
1174    return;
1175  }
1176
1177  accumulator->Add("%p ", this);
1178
1179  if (IsString()) {
1180    String::cast(this)->StringShortPrint(accumulator);
1181    return;
1182  }
1183  if (IsJSObject()) {
1184    JSObject::cast(this)->JSObjectShortPrint(accumulator);
1185    return;
1186  }
1187  switch (map()->instance_type()) {
1188    case MAP_TYPE:
1189      accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
1190      break;
1191    case FIXED_ARRAY_TYPE:
1192      accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1193      break;
1194    case FIXED_DOUBLE_ARRAY_TYPE:
1195      accumulator->Add("<FixedDoubleArray[%u]>",
1196                       FixedDoubleArray::cast(this)->length());
1197      break;
1198    case BYTE_ARRAY_TYPE:
1199      accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1200      break;
1201    case FREE_SPACE_TYPE:
1202      accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1203      break;
1204    case EXTERNAL_PIXEL_ARRAY_TYPE:
1205      accumulator->Add("<ExternalPixelArray[%u]>",
1206                       ExternalPixelArray::cast(this)->length());
1207      break;
1208    case EXTERNAL_BYTE_ARRAY_TYPE:
1209      accumulator->Add("<ExternalByteArray[%u]>",
1210                       ExternalByteArray::cast(this)->length());
1211      break;
1212    case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1213      accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1214                       ExternalUnsignedByteArray::cast(this)->length());
1215      break;
1216    case EXTERNAL_SHORT_ARRAY_TYPE:
1217      accumulator->Add("<ExternalShortArray[%u]>",
1218                       ExternalShortArray::cast(this)->length());
1219      break;
1220    case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1221      accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1222                       ExternalUnsignedShortArray::cast(this)->length());
1223      break;
1224    case EXTERNAL_INT_ARRAY_TYPE:
1225      accumulator->Add("<ExternalIntArray[%u]>",
1226                       ExternalIntArray::cast(this)->length());
1227      break;
1228    case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1229      accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1230                       ExternalUnsignedIntArray::cast(this)->length());
1231      break;
1232    case EXTERNAL_FLOAT_ARRAY_TYPE:
1233      accumulator->Add("<ExternalFloatArray[%u]>",
1234                       ExternalFloatArray::cast(this)->length());
1235      break;
1236    case EXTERNAL_DOUBLE_ARRAY_TYPE:
1237      accumulator->Add("<ExternalDoubleArray[%u]>",
1238                       ExternalDoubleArray::cast(this)->length());
1239      break;
1240    case SHARED_FUNCTION_INFO_TYPE:
1241      accumulator->Add("<SharedFunctionInfo>");
1242      break;
1243    case JS_MESSAGE_OBJECT_TYPE:
1244      accumulator->Add("<JSMessageObject>");
1245      break;
1246#define MAKE_STRUCT_CASE(NAME, Name, name) \
1247  case NAME##_TYPE:                        \
1248    accumulator->Put('<');                 \
1249    accumulator->Add(#Name);               \
1250    accumulator->Put('>');                 \
1251    break;
1252  STRUCT_LIST(MAKE_STRUCT_CASE)
1253#undef MAKE_STRUCT_CASE
1254    case CODE_TYPE:
1255      accumulator->Add("<Code>");
1256      break;
1257    case ODDBALL_TYPE: {
1258      if (IsUndefined())
1259        accumulator->Add("<undefined>");
1260      else if (IsTheHole())
1261        accumulator->Add("<the hole>");
1262      else if (IsNull())
1263        accumulator->Add("<null>");
1264      else if (IsTrue())
1265        accumulator->Add("<true>");
1266      else if (IsFalse())
1267        accumulator->Add("<false>");
1268      else
1269        accumulator->Add("<Odd Oddball>");
1270      break;
1271    }
1272    case HEAP_NUMBER_TYPE:
1273      accumulator->Add("<Number: ");
1274      HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1275      accumulator->Put('>');
1276      break;
1277    case JS_PROXY_TYPE:
1278      accumulator->Add("<JSProxy>");
1279      break;
1280    case JS_FUNCTION_PROXY_TYPE:
1281      accumulator->Add("<JSFunctionProxy>");
1282      break;
1283    case FOREIGN_TYPE:
1284      accumulator->Add("<Foreign>");
1285      break;
1286    case JS_GLOBAL_PROPERTY_CELL_TYPE:
1287      accumulator->Add("Cell for ");
1288      JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1289      break;
1290    default:
1291      accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1292      break;
1293  }
1294}
1295
1296
1297void HeapObject::Iterate(ObjectVisitor* v) {
1298  // Handle header
1299  IteratePointer(v, kMapOffset);
1300  // Handle object body
1301  Map* m = map();
1302  IterateBody(m->instance_type(), SizeFromMap(m), v);
1303}
1304
1305
1306void HeapObject::IterateBody(InstanceType type, int object_size,
1307                             ObjectVisitor* v) {
1308  // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1309  // During GC, the map pointer field is encoded.
1310  if (type < FIRST_NONSTRING_TYPE) {
1311    switch (type & kStringRepresentationMask) {
1312      case kSeqStringTag:
1313        break;
1314      case kConsStringTag:
1315        ConsString::BodyDescriptor::IterateBody(this, v);
1316        break;
1317      case kSlicedStringTag:
1318        SlicedString::BodyDescriptor::IterateBody(this, v);
1319        break;
1320      case kExternalStringTag:
1321        if ((type & kStringEncodingMask) == kAsciiStringTag) {
1322          reinterpret_cast<ExternalAsciiString*>(this)->
1323              ExternalAsciiStringIterateBody(v);
1324        } else {
1325          reinterpret_cast<ExternalTwoByteString*>(this)->
1326              ExternalTwoByteStringIterateBody(v);
1327        }
1328        break;
1329    }
1330    return;
1331  }
1332
1333  switch (type) {
1334    case FIXED_ARRAY_TYPE:
1335      FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
1336      break;
1337    case FIXED_DOUBLE_ARRAY_TYPE:
1338      break;
1339    case JS_OBJECT_TYPE:
1340    case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1341    case JS_VALUE_TYPE:
1342    case JS_DATE_TYPE:
1343    case JS_ARRAY_TYPE:
1344    case JS_SET_TYPE:
1345    case JS_MAP_TYPE:
1346    case JS_WEAK_MAP_TYPE:
1347    case JS_REGEXP_TYPE:
1348    case JS_GLOBAL_PROXY_TYPE:
1349    case JS_GLOBAL_OBJECT_TYPE:
1350    case JS_BUILTINS_OBJECT_TYPE:
1351    case JS_MESSAGE_OBJECT_TYPE:
1352      JSObject::BodyDescriptor::IterateBody(this, object_size, v);
1353      break;
1354    case JS_FUNCTION_TYPE:
1355      reinterpret_cast<JSFunction*>(this)
1356          ->JSFunctionIterateBody(object_size, v);
1357      break;
1358    case ODDBALL_TYPE:
1359      Oddball::BodyDescriptor::IterateBody(this, v);
1360      break;
1361    case JS_PROXY_TYPE:
1362      JSProxy::BodyDescriptor::IterateBody(this, v);
1363      break;
1364    case JS_FUNCTION_PROXY_TYPE:
1365      JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1366      break;
1367    case FOREIGN_TYPE:
1368      reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
1369      break;
1370    case MAP_TYPE:
1371      Map::BodyDescriptor::IterateBody(this, v);
1372      break;
1373    case CODE_TYPE:
1374      reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1375      break;
1376    case JS_GLOBAL_PROPERTY_CELL_TYPE:
1377      JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
1378      break;
1379    case HEAP_NUMBER_TYPE:
1380    case FILLER_TYPE:
1381    case BYTE_ARRAY_TYPE:
1382    case FREE_SPACE_TYPE:
1383    case EXTERNAL_PIXEL_ARRAY_TYPE:
1384    case EXTERNAL_BYTE_ARRAY_TYPE:
1385    case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1386    case EXTERNAL_SHORT_ARRAY_TYPE:
1387    case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1388    case EXTERNAL_INT_ARRAY_TYPE:
1389    case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1390    case EXTERNAL_FLOAT_ARRAY_TYPE:
1391    case EXTERNAL_DOUBLE_ARRAY_TYPE:
1392      break;
1393    case SHARED_FUNCTION_INFO_TYPE: {
1394      SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
1395      shared->SharedFunctionInfoIterateBody(v);
1396      break;
1397    }
1398
1399#define MAKE_STRUCT_CASE(NAME, Name, name) \
1400        case NAME##_TYPE:
1401      STRUCT_LIST(MAKE_STRUCT_CASE)
1402#undef MAKE_STRUCT_CASE
1403      StructBodyDescriptor::IterateBody(this, object_size, v);
1404      break;
1405    default:
1406      PrintF("Unknown type: %d\n", type);
1407      UNREACHABLE();
1408  }
1409}
1410
1411
1412Object* HeapNumber::HeapNumberToBoolean() {
1413  // NaN, +0, and -0 should return the false object
1414#if __BYTE_ORDER == __LITTLE_ENDIAN
1415  union IeeeDoubleLittleEndianArchType u;
1416#elif __BYTE_ORDER == __BIG_ENDIAN
1417  union IeeeDoubleBigEndianArchType u;
1418#endif
1419  u.d = value();
1420  if (u.bits.exp == 2047) {
1421    // Detect NaN for IEEE double precision floating point.
1422    if ((u.bits.man_low | u.bits.man_high) != 0)
1423      return GetHeap()->false_value();
1424  }
1425  if (u.bits.exp == 0) {
1426    // Detect +0, and -0 for IEEE double precision floating point.
1427    if ((u.bits.man_low | u.bits.man_high) == 0)
1428      return GetHeap()->false_value();
1429  }
1430  return GetHeap()->true_value();
1431}
1432
1433
1434void HeapNumber::HeapNumberPrint(FILE* out) {
1435  PrintF(out, "%.16g", Number());
1436}
1437
1438
1439void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1440  // The Windows version of vsnprintf can allocate when printing a %g string
1441  // into a buffer that may not be big enough.  We don't want random memory
1442  // allocation when producing post-crash stack traces, so we print into a
1443  // buffer that is plenty big enough for any floating point number, then
1444  // print that using vsnprintf (which may truncate but never allocate if
1445  // there is no more space in the buffer).
1446  EmbeddedVector<char, 100> buffer;
1447  OS::SNPrintF(buffer, "%.16g", Number());
1448  accumulator->Add("%s", buffer.start());
1449}
1450
1451
1452String* JSReceiver::class_name() {
1453  if (IsJSFunction() && IsJSFunctionProxy()) {
1454    return GetHeap()->function_class_symbol();
1455  }
1456  if (map()->constructor()->IsJSFunction()) {
1457    JSFunction* constructor = JSFunction::cast(map()->constructor());
1458    return String::cast(constructor->shared()->instance_class_name());
1459  }
1460  // If the constructor is not present, return "Object".
1461  return GetHeap()->Object_symbol();
1462}
1463
1464
1465String* JSReceiver::constructor_name() {
1466  if (map()->constructor()->IsJSFunction()) {
1467    JSFunction* constructor = JSFunction::cast(map()->constructor());
1468    String* name = String::cast(constructor->shared()->name());
1469    if (name->length() > 0) return name;
1470    String* inferred_name = constructor->shared()->inferred_name();
1471    if (inferred_name->length() > 0) return inferred_name;
1472    Object* proto = GetPrototype();
1473    if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
1474  }
1475  // TODO(rossberg): what about proxies?
1476  // If the constructor is not present, return "Object".
1477  return GetHeap()->Object_symbol();
1478}
1479
1480
1481MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1482                                               String* name,
1483                                               Object* value) {
1484  int index = new_map->PropertyIndexFor(name);
1485  if (map()->unused_property_fields() == 0) {
1486    ASSERT(map()->unused_property_fields() == 0);
1487    int new_unused = new_map->unused_property_fields();
1488    Object* values;
1489    { MaybeObject* maybe_values =
1490          properties()->CopySize(properties()->length() + new_unused + 1);
1491      if (!maybe_values->ToObject(&values)) return maybe_values;
1492    }
1493    set_properties(FixedArray::cast(values));
1494  }
1495  set_map(new_map);
1496  return FastPropertyAtPut(index, value);
1497}
1498
1499
1500static bool IsIdentifier(UnicodeCache* cache,
1501                         unibrow::CharacterStream* buffer) {
1502  // Checks whether the buffer contains an identifier (no escape).
1503  if (!buffer->has_more()) return false;
1504  if (!cache->IsIdentifierStart(buffer->GetNext())) {
1505    return false;
1506  }
1507  while (buffer->has_more()) {
1508    if (!cache->IsIdentifierPart(buffer->GetNext())) {
1509      return false;
1510    }
1511  }
1512  return true;
1513}
1514
1515
1516MaybeObject* JSObject::AddFastProperty(String* name,
1517                                       Object* value,
1518                                       PropertyAttributes attributes) {
1519  ASSERT(!IsJSGlobalProxy());
1520
1521  // Normalize the object if the name is an actual string (not the
1522  // hidden symbols) and is not a real identifier.
1523  Isolate* isolate = GetHeap()->isolate();
1524  StringInputBuffer buffer(name);
1525  if (!IsIdentifier(isolate->unicode_cache(), &buffer)
1526      && name != isolate->heap()->hidden_symbol()) {
1527    Object* obj;
1528    { MaybeObject* maybe_obj =
1529          NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1530      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1531    }
1532    return AddSlowProperty(name, value, attributes);
1533  }
1534
1535  DescriptorArray* old_descriptors = map()->instance_descriptors();
1536  // Compute the new index for new field.
1537  int index = map()->NextFreePropertyIndex();
1538
1539  // Allocate new instance descriptors with (name, index) added
1540  FieldDescriptor new_field(name, index, attributes);
1541  Object* new_descriptors;
1542  { MaybeObject* maybe_new_descriptors =
1543        old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1544    if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1545      return maybe_new_descriptors;
1546    }
1547  }
1548
1549  // Only allow map transition if the object isn't the global object and there
1550  // is not a transition for the name, or there's a transition for the name but
1551  // it's unrelated to properties.
1552  int descriptor_index = old_descriptors->Search(name);
1553
1554  // Element transitions are stored in the descriptor for property "", which is
1555  // not a identifier and should have forced a switch to slow properties above.
1556  ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1557      old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
1558  bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1559      old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
1560  bool allow_map_transition =
1561      can_insert_transition &&
1562      (isolate->context()->global_context()->object_function()->map() != map());
1563
1564  ASSERT(index < map()->inobject_properties() ||
1565         (index - map()->inobject_properties()) < properties()->length() ||
1566         map()->unused_property_fields() == 0);
1567  // Allocate a new map for the object.
1568  Object* r;
1569  { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1570    if (!maybe_r->ToObject(&r)) return maybe_r;
1571  }
1572  Map* new_map = Map::cast(r);
1573  if (allow_map_transition) {
1574    // Allocate new instance descriptors for the old map with map transition.
1575    MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
1576    Object* r;
1577    { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1578      if (!maybe_r->ToObject(&r)) return maybe_r;
1579    }
1580    old_descriptors = DescriptorArray::cast(r);
1581  }
1582
1583  if (map()->unused_property_fields() == 0) {
1584    if (properties()->length() > MaxFastProperties()) {
1585      Object* obj;
1586      { MaybeObject* maybe_obj =
1587            NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1588        if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1589      }
1590      return AddSlowProperty(name, value, attributes);
1591    }
1592    // Make room for the new value
1593    Object* values;
1594    { MaybeObject* maybe_values =
1595          properties()->CopySize(properties()->length() + kFieldsAdded);
1596      if (!maybe_values->ToObject(&values)) return maybe_values;
1597    }
1598    set_properties(FixedArray::cast(values));
1599    new_map->set_unused_property_fields(kFieldsAdded - 1);
1600  } else {
1601    new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1602  }
1603  // We have now allocated all the necessary objects.
1604  // All the changes can be applied at once, so they are atomic.
1605  map()->set_instance_descriptors(old_descriptors);
1606  new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1607  set_map(new_map);
1608  return FastPropertyAtPut(index, value);
1609}
1610
1611
1612MaybeObject* JSObject::AddConstantFunctionProperty(
1613    String* name,
1614    JSFunction* function,
1615    PropertyAttributes attributes) {
1616  // Allocate new instance descriptors with (name, function) added
1617  ConstantFunctionDescriptor d(name, function, attributes);
1618  Object* new_descriptors;
1619  { MaybeObject* maybe_new_descriptors =
1620        map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1621    if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1622      return maybe_new_descriptors;
1623    }
1624  }
1625
1626  // Allocate a new map for the object.
1627  Object* new_map;
1628  { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1629    if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1630  }
1631
1632  DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1633  Map::cast(new_map)->set_instance_descriptors(descriptors);
1634  Map* old_map = map();
1635  set_map(Map::cast(new_map));
1636
1637  // If the old map is the global object map (from new Object()),
1638  // then transitions are not added to it, so we are done.
1639  Heap* heap = GetHeap();
1640  if (old_map == heap->isolate()->context()->global_context()->
1641      object_function()->map()) {
1642    return function;
1643  }
1644
1645  // Do not add CONSTANT_TRANSITIONS to global objects
1646  if (IsGlobalObject()) {
1647    return function;
1648  }
1649
1650  // Add a CONSTANT_TRANSITION descriptor to the old map,
1651  // so future assignments to this property on other objects
1652  // of the same type will create a normal field, not a constant function.
1653  // Don't do this for special properties, with non-trival attributes.
1654  if (attributes != NONE) {
1655    return function;
1656  }
1657  ConstTransitionDescriptor mark(name, Map::cast(new_map));
1658  { MaybeObject* maybe_new_descriptors =
1659        old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1660    if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1661      // We have accomplished the main goal, so return success.
1662      return function;
1663    }
1664  }
1665  old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1666
1667  return function;
1668}
1669
1670
1671// Add property in slow mode
1672MaybeObject* JSObject::AddSlowProperty(String* name,
1673                                       Object* value,
1674                                       PropertyAttributes attributes) {
1675  ASSERT(!HasFastProperties());
1676  StringDictionary* dict = property_dictionary();
1677  Object* store_value = value;
1678  if (IsGlobalObject()) {
1679    // In case name is an orphaned property reuse the cell.
1680    int entry = dict->FindEntry(name);
1681    if (entry != StringDictionary::kNotFound) {
1682      store_value = dict->ValueAt(entry);
1683      JSGlobalPropertyCell::cast(store_value)->set_value(value);
1684      // Assign an enumeration index to the property and update
1685      // SetNextEnumerationIndex.
1686      int index = dict->NextEnumerationIndex();
1687      PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1688      dict->SetNextEnumerationIndex(index + 1);
1689      dict->SetEntry(entry, name, store_value, details);
1690      return value;
1691    }
1692    Heap* heap = GetHeap();
1693    { MaybeObject* maybe_store_value =
1694          heap->AllocateJSGlobalPropertyCell(value);
1695      if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1696    }
1697    JSGlobalPropertyCell::cast(store_value)->set_value(value);
1698  }
1699  PropertyDetails details = PropertyDetails(attributes, NORMAL);
1700  Object* result;
1701  { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1702    if (!maybe_result->ToObject(&result)) return maybe_result;
1703  }
1704  if (dict != result) set_properties(StringDictionary::cast(result));
1705  return value;
1706}
1707
1708
1709MaybeObject* JSObject::AddProperty(String* name,
1710                                   Object* value,
1711                                   PropertyAttributes attributes,
1712                                   StrictModeFlag strict_mode) {
1713  ASSERT(!IsJSGlobalProxy());
1714  Map* map_of_this = map();
1715  Heap* heap = GetHeap();
1716  if (!map_of_this->is_extensible()) {
1717    if (strict_mode == kNonStrictMode) {
1718      return value;
1719    } else {
1720      Handle<Object> args[1] = {Handle<String>(name)};
1721      return heap->isolate()->Throw(
1722          *FACTORY->NewTypeError("object_not_extensible",
1723                                 HandleVector(args, 1)));
1724    }
1725  }
1726  if (HasFastProperties()) {
1727    // Ensure the descriptor array does not get too big.
1728    if (map_of_this->instance_descriptors()->number_of_descriptors() <
1729        DescriptorArray::kMaxNumberOfDescriptors) {
1730      if (value->IsJSFunction()) {
1731        return AddConstantFunctionProperty(name,
1732                                           JSFunction::cast(value),
1733                                           attributes);
1734      } else {
1735        return AddFastProperty(name, value, attributes);
1736      }
1737    } else {
1738      // Normalize the object to prevent very large instance descriptors.
1739      // This eliminates unwanted N^2 allocation and lookup behavior.
1740      Object* obj;
1741      { MaybeObject* maybe_obj =
1742            NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1743        if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1744      }
1745    }
1746  }
1747  return AddSlowProperty(name, value, attributes);
1748}
1749
1750
1751MaybeObject* JSObject::SetPropertyPostInterceptor(
1752    String* name,
1753    Object* value,
1754    PropertyAttributes attributes,
1755    StrictModeFlag strict_mode) {
1756  // Check local property, ignore interceptor.
1757  LookupResult result(GetIsolate());
1758  LocalLookupRealNamedProperty(name, &result);
1759  if (result.IsFound()) {
1760    // An existing property, a map transition or a null descriptor was
1761    // found.  Use set property to handle all these cases.
1762    return SetProperty(&result, name, value, attributes, strict_mode);
1763  }
1764  bool found = false;
1765  MaybeObject* result_object;
1766  result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1767                                                            value,
1768                                                            attributes,
1769                                                            &found,
1770                                                            strict_mode);
1771  if (found) return result_object;
1772  // Add a new real property.
1773  return AddProperty(name, value, attributes, strict_mode);
1774}
1775
1776
1777MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1778                                           Object* value,
1779                                           PropertyAttributes attributes) {
1780  StringDictionary* dictionary = property_dictionary();
1781  int old_index = dictionary->FindEntry(name);
1782  int new_enumeration_index = 0;  // 0 means "Use the next available index."
1783  if (old_index != -1) {
1784    // All calls to ReplaceSlowProperty have had all transitions removed.
1785    ASSERT(!dictionary->ContainsTransition(old_index));
1786    new_enumeration_index = dictionary->DetailsAt(old_index).index();
1787  }
1788
1789  PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1790  return SetNormalizedProperty(name, value, new_details);
1791}
1792
1793
1794MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
1795    String* name,
1796    Object* new_value,
1797    PropertyAttributes attributes) {
1798  Map* old_map = map();
1799  Object* result;
1800  { MaybeObject* maybe_result =
1801        ConvertDescriptorToField(name, new_value, attributes);
1802    if (!maybe_result->ToObject(&result)) return maybe_result;
1803  }
1804  // If we get to this point we have succeeded - do not return failure
1805  // after this point.  Later stuff is optional.
1806  if (!HasFastProperties()) {
1807    return result;
1808  }
1809  // Do not add transitions to the map of "new Object()".
1810  if (map() == GetIsolate()->context()->global_context()->
1811      object_function()->map()) {
1812    return result;
1813  }
1814
1815  MapTransitionDescriptor transition(name,
1816                                     map(),
1817                                     attributes);
1818  Object* new_descriptors;
1819  { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1820        CopyInsert(&transition, KEEP_TRANSITIONS);
1821    if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1822      return result;  // Yes, return _result_.
1823    }
1824  }
1825  old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1826  return result;
1827}
1828
1829
1830MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1831                                                Object* new_value,
1832                                                PropertyAttributes attributes) {
1833  if (map()->unused_property_fields() == 0 &&
1834      properties()->length() > MaxFastProperties()) {
1835    Object* obj;
1836    { MaybeObject* maybe_obj =
1837          NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1838      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1839    }
1840    return ReplaceSlowProperty(name, new_value, attributes);
1841  }
1842
1843  int index = map()->NextFreePropertyIndex();
1844  FieldDescriptor new_field(name, index, attributes);
1845  // Make a new DescriptorArray replacing an entry with FieldDescriptor.
1846  Object* descriptors_unchecked;
1847  { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1848                                  CopyInsert(&new_field, REMOVE_TRANSITIONS);
1849    if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1850      return maybe_descriptors_unchecked;
1851    }
1852  }
1853  DescriptorArray* new_descriptors =
1854      DescriptorArray::cast(descriptors_unchecked);
1855
1856  // Make a new map for the object.
1857  Object* new_map_unchecked;
1858  { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1859    if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1860      return maybe_new_map_unchecked;
1861    }
1862  }
1863  Map* new_map = Map::cast(new_map_unchecked);
1864  new_map->set_instance_descriptors(new_descriptors);
1865
1866  // Make new properties array if necessary.
1867  FixedArray* new_properties = 0;  // Will always be NULL or a valid pointer.
1868  int new_unused_property_fields = map()->unused_property_fields() - 1;
1869  if (map()->unused_property_fields() == 0) {
1870    new_unused_property_fields = kFieldsAdded - 1;
1871    Object* new_properties_object;
1872    { MaybeObject* maybe_new_properties_object =
1873          properties()->CopySize(properties()->length() + kFieldsAdded);
1874      if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1875        return maybe_new_properties_object;
1876      }
1877    }
1878    new_properties = FixedArray::cast(new_properties_object);
1879  }
1880
1881  // Update pointers to commit changes.
1882  // Object points to the new map.
1883  new_map->set_unused_property_fields(new_unused_property_fields);
1884  set_map(new_map);
1885  if (new_properties) {
1886    set_properties(FixedArray::cast(new_properties));
1887  }
1888  return FastPropertyAtPut(index, new_value);
1889}
1890
1891
1892
1893MaybeObject* JSObject::SetPropertyWithInterceptor(
1894    String* name,
1895    Object* value,
1896    PropertyAttributes attributes,
1897    StrictModeFlag strict_mode) {
1898  Isolate* isolate = GetIsolate();
1899  HandleScope scope(isolate);
1900  Handle<JSObject> this_handle(this);
1901  Handle<String> name_handle(name);
1902  Handle<Object> value_handle(value, isolate);
1903  Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1904  if (!interceptor->setter()->IsUndefined()) {
1905    LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1906    CustomArguments args(isolate, interceptor->data(), this, this);
1907    v8::AccessorInfo info(args.end());
1908    v8::NamedPropertySetter setter =
1909        v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1910    v8::Handle<v8::Value> result;
1911    {
1912      // Leaving JavaScript.
1913      VMState state(isolate, EXTERNAL);
1914      Handle<Object> value_unhole(value->IsTheHole() ?
1915                                  isolate->heap()->undefined_value() :
1916                                  value,
1917                                  isolate);
1918      result = setter(v8::Utils::ToLocal(name_handle),
1919                      v8::Utils::ToLocal(value_unhole),
1920                      info);
1921    }
1922    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1923    if (!result.IsEmpty()) return *value_handle;
1924  }
1925  MaybeObject* raw_result =
1926      this_handle->SetPropertyPostInterceptor(*name_handle,
1927                                              *value_handle,
1928                                              attributes,
1929                                              strict_mode);
1930  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1931  return raw_result;
1932}
1933
1934
1935Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1936                                       Handle<String> key,
1937                                       Handle<Object> value,
1938                                       PropertyAttributes attributes,
1939                                       StrictModeFlag strict_mode) {
1940  CALL_HEAP_FUNCTION(object->GetIsolate(),
1941                     object->SetProperty(*key, *value, attributes, strict_mode),
1942                     Object);
1943}
1944
1945
1946MaybeObject* JSReceiver::SetProperty(String* name,
1947                                     Object* value,
1948                                     PropertyAttributes attributes,
1949                                     StrictModeFlag strict_mode) {
1950  LookupResult result(GetIsolate());
1951  LocalLookup(name, &result);
1952  return SetProperty(&result, name, value, attributes, strict_mode);
1953}
1954
1955
1956MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1957                                               String* name,
1958                                               Object* value,
1959                                               JSObject* holder,
1960                                               StrictModeFlag strict_mode) {
1961  Isolate* isolate = GetIsolate();
1962  HandleScope scope(isolate);
1963
1964  // We should never get here to initialize a const with the hole
1965  // value since a const declaration would conflict with the setter.
1966  ASSERT(!value->IsTheHole());
1967  Handle<Object> value_handle(value, isolate);
1968
1969  // To accommodate both the old and the new api we switch on the
1970  // data structure used to store the callbacks.  Eventually foreign
1971  // callbacks should be phased out.
1972  if (structure->IsForeign()) {
1973    AccessorDescriptor* callback =
1974        reinterpret_cast<AccessorDescriptor*>(
1975            Foreign::cast(structure)->foreign_address());
1976    MaybeObject* obj = (callback->setter)(this,  value, callback->data);
1977    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1978    if (obj->IsFailure()) return obj;
1979    return *value_handle;
1980  }
1981
1982  if (structure->IsAccessorInfo()) {
1983    // api style callbacks
1984    AccessorInfo* data = AccessorInfo::cast(structure);
1985    Object* call_obj = data->setter();
1986    v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1987    if (call_fun == NULL) return value;
1988    Handle<String> key(name);
1989    LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1990    CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
1991    v8::AccessorInfo info(args.end());
1992    {
1993      // Leaving JavaScript.
1994      VMState state(isolate, EXTERNAL);
1995      call_fun(v8::Utils::ToLocal(key),
1996               v8::Utils::ToLocal(value_handle),
1997               info);
1998    }
1999    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
2000    return *value_handle;
2001  }
2002
2003  if (structure->IsAccessorPair()) {
2004    Object* setter = AccessorPair::cast(structure)->setter();
2005    if (setter->IsSpecFunction()) {
2006      // TODO(rossberg): nicer would be to cast to some JSCallable here...
2007     return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
2008    } else {
2009      if (strict_mode == kNonStrictMode) {
2010        return value;
2011      }
2012      Handle<String> key(name);
2013      Handle<Object> holder_handle(holder, isolate);
2014      Handle<Object> args[2] = { key, holder_handle };
2015      return isolate->Throw(
2016          *isolate->factory()->NewTypeError("no_setter_in_callback",
2017                                            HandleVector(args, 2)));
2018    }
2019  }
2020
2021  UNREACHABLE();
2022  return NULL;
2023}
2024
2025
2026MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2027                                                      Object* value) {
2028  Isolate* isolate = GetIsolate();
2029  Handle<Object> value_handle(value, isolate);
2030  Handle<JSReceiver> fun(setter, isolate);
2031  Handle<JSReceiver> self(this, isolate);
2032#ifdef ENABLE_DEBUGGER_SUPPORT
2033  Debug* debug = isolate->debug();
2034  // Handle stepping into a setter if step into is active.
2035  // TODO(rossberg): should this apply to getters that are function proxies?
2036  if (debug->StepInActive() && fun->IsJSFunction()) {
2037    debug->HandleStepIn(
2038        Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
2039  }
2040#endif
2041  bool has_pending_exception;
2042  Handle<Object> argv[] = { value_handle };
2043  Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
2044  // Check for pending exception and return the result.
2045  if (has_pending_exception) return Failure::Exception();
2046  return *value_handle;
2047}
2048
2049
2050void JSObject::LookupCallbackSetterInPrototypes(String* name,
2051                                                LookupResult* result) {
2052  Heap* heap = GetHeap();
2053  for (Object* pt = GetPrototype();
2054       pt != heap->null_value();
2055       pt = pt->GetPrototype()) {
2056    if (pt->IsJSProxy()) {
2057      return result->HandlerResult(JSProxy::cast(pt));
2058    }
2059    JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
2060    if (result->IsProperty()) {
2061      if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2062      // Found non-callback or read-only callback, stop looking.
2063      break;
2064    }
2065  }
2066  result->NotFound();
2067}
2068
2069
2070MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2071    uint32_t index,
2072    Object* value,
2073    bool* found,
2074    StrictModeFlag strict_mode) {
2075  Heap* heap = GetHeap();
2076  for (Object* pt = GetPrototype();
2077       pt != heap->null_value();
2078       pt = pt->GetPrototype()) {
2079    if (pt->IsJSProxy()) {
2080      String* name;
2081      MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2082      if (!maybe->To<String>(&name)) {
2083        *found = true;  // Force abort
2084        return maybe;
2085      }
2086      return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2087          name, value, NONE, strict_mode, found);
2088    }
2089    if (!JSObject::cast(pt)->HasDictionaryElements()) {
2090      continue;
2091    }
2092    SeededNumberDictionary* dictionary =
2093        JSObject::cast(pt)->element_dictionary();
2094    int entry = dictionary->FindEntry(index);
2095    if (entry != SeededNumberDictionary::kNotFound) {
2096      PropertyDetails details = dictionary->DetailsAt(entry);
2097      if (details.type() == CALLBACKS) {
2098        *found = true;
2099        return SetElementWithCallback(dictionary->ValueAt(entry),
2100                                      index,
2101                                      value,
2102                                      JSObject::cast(pt),
2103                                      strict_mode);
2104      }
2105    }
2106  }
2107  *found = false;
2108  return heap->the_hole_value();
2109}
2110
2111MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2112    String* name,
2113    Object* value,
2114    PropertyAttributes attributes,
2115    bool* found,
2116    StrictModeFlag strict_mode) {
2117  Heap* heap = GetHeap();
2118  // We could not find a local property so let's check whether there is an
2119  // accessor that wants to handle the property.
2120  LookupResult accessor_result(heap->isolate());
2121  LookupCallbackSetterInPrototypes(name, &accessor_result);
2122  if (accessor_result.IsFound()) {
2123    *found = true;
2124    if (accessor_result.type() == CALLBACKS) {
2125      return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2126                                     name,
2127                                     value,
2128                                     accessor_result.holder(),
2129                                     strict_mode);
2130    } else if (accessor_result.type() == HANDLER) {
2131      // There is a proxy in the prototype chain. Invoke its
2132      // getPropertyDescriptor trap.
2133      bool found = false;
2134      // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2135      // make sure to use the handlified references after calling
2136      // the function.
2137      Handle<JSObject> self(this);
2138      Handle<String> hname(name);
2139      Handle<Object> hvalue(value);
2140      MaybeObject* result =
2141          accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2142              name, value, attributes, strict_mode, &found);
2143      if (found) return result;
2144      // The proxy does not define the property as an accessor.
2145      // Consequently, it has no effect on setting the receiver.
2146      return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
2147    }
2148  }
2149  *found = false;
2150  return heap->the_hole_value();
2151}
2152
2153
2154void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2155  DescriptorArray* descriptors = map()->instance_descriptors();
2156  int number = descriptors->SearchWithCache(name);
2157  if (number != DescriptorArray::kNotFound) {
2158    result->DescriptorResult(this, descriptors->GetDetails(number), number);
2159  } else {
2160    result->NotFound();
2161  }
2162}
2163
2164
2165void Map::LookupInDescriptors(JSObject* holder,
2166                              String* name,
2167                              LookupResult* result) {
2168  DescriptorArray* descriptors = instance_descriptors();
2169  DescriptorLookupCache* cache =
2170      GetHeap()->isolate()->descriptor_lookup_cache();
2171  int number = cache->Lookup(descriptors, name);
2172  if (number == DescriptorLookupCache::kAbsent) {
2173    number = descriptors->Search(name);
2174    cache->Update(descriptors, name, number);
2175  }
2176  if (number != DescriptorArray::kNotFound) {
2177    result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2178  } else {
2179    result->NotFound();
2180  }
2181}
2182
2183
2184static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2185  ASSERT(!map.is_null());
2186  for (int i = 0; i < maps->length(); ++i) {
2187    if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2188  }
2189  return false;
2190}
2191
2192
2193template <class T>
2194static Handle<T> MaybeNull(T* p) {
2195  if (p == NULL) return Handle<T>::null();
2196  return Handle<T>(p);
2197}
2198
2199
2200Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2201  ElementsKind elms_kind = elements_kind();
2202  if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2203    bool dummy = true;
2204    Handle<Map> fast_map =
2205        MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2206    if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2207      return fast_map;
2208    }
2209    return Handle<Map>::null();
2210  }
2211  if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2212    bool dummy = true;
2213    Handle<Map> double_map =
2214        MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2215    // In the current implementation, if the DOUBLE map doesn't exist, the
2216    // FAST map can't exist either.
2217    if (double_map.is_null()) return Handle<Map>::null();
2218    Handle<Map> fast_map =
2219        MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2220                                                          &dummy));
2221    if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2222      return fast_map;
2223    }
2224    if (ContainsMap(candidates, double_map)) return double_map;
2225  }
2226  return Handle<Map>::null();
2227}
2228
2229static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2230                                                   ElementsKind elements_kind) {
2231  if (descriptor_contents->IsMap()) {
2232    Map* map = Map::cast(descriptor_contents);
2233    if (map->elements_kind() == elements_kind) {
2234      return map;
2235    }
2236    return NULL;
2237  }
2238
2239  FixedArray* map_array = FixedArray::cast(descriptor_contents);
2240  for (int i = 0; i < map_array->length(); ++i) {
2241    Object* current = map_array->get(i);
2242    // Skip undefined slots, they are sentinels for reclaimed maps.
2243    if (!current->IsUndefined()) {
2244      Map* current_map = Map::cast(map_array->get(i));
2245      if (current_map->elements_kind() == elements_kind) {
2246        return current_map;
2247      }
2248    }
2249  }
2250
2251  return NULL;
2252}
2253
2254
2255static MaybeObject* AddElementsTransitionMapToDescriptor(
2256    Object* descriptor_contents,
2257    Map* new_map) {
2258  // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2259  // simply add the map.
2260  if (descriptor_contents == NULL) {
2261    return new_map;
2262  }
2263
2264  // There was already a map in the descriptor, create a 2-element FixedArray
2265  // to contain the existing map plus the new one.
2266  FixedArray* new_array;
2267  Heap* heap = new_map->GetHeap();
2268  if (descriptor_contents->IsMap()) {
2269    // Must tenure, DescriptorArray expects no new-space objects.
2270    MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2271    if (!maybe_new_array->To<FixedArray>(&new_array)) {
2272      return maybe_new_array;
2273    }
2274    new_array->set(0, descriptor_contents);
2275    new_array->set(1, new_map);
2276    return new_array;
2277  }
2278
2279  // The descriptor already contained a list of maps for different ElementKinds
2280  // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2281  // slot, and if that's not available, create a FixedArray to hold the existing
2282  // maps plus the new one and fill it in.
2283  FixedArray* array = FixedArray::cast(descriptor_contents);
2284  for (int i = 0; i < array->length(); ++i) {
2285    if (array->get(i)->IsUndefined()) {
2286      array->set(i, new_map);
2287      return array;
2288    }
2289  }
2290
2291  // Must tenure, DescriptorArray expects no new-space objects.
2292  MaybeObject* maybe_new_array =
2293      heap->AllocateFixedArray(array->length() + 1, TENURED);
2294  if (!maybe_new_array->To<FixedArray>(&new_array)) {
2295    return maybe_new_array;
2296  }
2297  int i = 0;
2298  while (i < array->length()) {
2299    new_array->set(i, array->get(i));
2300    ++i;
2301  }
2302  new_array->set(i, new_map);
2303  return new_array;
2304}
2305
2306
2307String* Map::elements_transition_sentinel_name() {
2308  return GetHeap()->empty_symbol();
2309}
2310
2311
2312Object* Map::GetDescriptorContents(String* sentinel_name,
2313                                   bool* safe_to_add_transition) {
2314  // Get the cached index for the descriptors lookup, or find and cache it.
2315  DescriptorArray* descriptors = instance_descriptors();
2316  DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2317  int index = cache->Lookup(descriptors, sentinel_name);
2318  if (index == DescriptorLookupCache::kAbsent) {
2319    index = descriptors->Search(sentinel_name);
2320    cache->Update(descriptors, sentinel_name, index);
2321  }
2322  // If the transition already exists, return its descriptor.
2323  if (index != DescriptorArray::kNotFound) {
2324    PropertyDetails details(descriptors->GetDetails(index));
2325    if (details.type() == ELEMENTS_TRANSITION) {
2326      return descriptors->GetValue(index);
2327    } else {
2328      if (safe_to_add_transition != NULL) {
2329        *safe_to_add_transition = false;
2330      }
2331    }
2332  }
2333  return NULL;
2334}
2335
2336
2337Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2338                                      bool* safe_to_add_transition) {
2339  // Special case: indirect SMI->FAST transition (cf. comment in
2340  // AddElementsTransition()).
2341  if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2342      elements_kind == FAST_ELEMENTS) {
2343    Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2344                                                        safe_to_add_transition);
2345    if (double_map == NULL) return double_map;
2346    return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2347                                                   safe_to_add_transition);
2348  }
2349  Object* descriptor_contents = GetDescriptorContents(
2350      elements_transition_sentinel_name(), safe_to_add_transition);
2351  if (descriptor_contents != NULL) {
2352    Map* maybe_transition_map =
2353        GetElementsTransitionMapFromDescriptor(descriptor_contents,
2354                                               elements_kind);
2355    ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2356    return maybe_transition_map;
2357  }
2358  return NULL;
2359}
2360
2361
2362MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2363                                        Map* transitioned_map) {
2364  // The map transition graph should be a tree, therefore the transition
2365  // from SMI to FAST elements is not done directly, but by going through
2366  // DOUBLE elements first.
2367  if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2368      elements_kind == FAST_ELEMENTS) {
2369    bool safe_to_add = true;
2370    Map* double_map = this->LookupElementsTransitionMap(
2371        FAST_DOUBLE_ELEMENTS, &safe_to_add);
2372    // This method is only called when safe_to_add_transition has been found
2373    // to be true earlier.
2374    ASSERT(safe_to_add);
2375
2376    if (double_map == NULL) {
2377      MaybeObject* maybe_map = this->CopyDropTransitions();
2378      if (!maybe_map->To(&double_map)) return maybe_map;
2379      double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2380      MaybeObject* maybe_double_transition = this->AddElementsTransition(
2381          FAST_DOUBLE_ELEMENTS, double_map);
2382      if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2383    }
2384    return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2385  }
2386
2387  bool safe_to_add_transition = true;
2388  Object* descriptor_contents = GetDescriptorContents(
2389      elements_transition_sentinel_name(), &safe_to_add_transition);
2390  // This method is only called when safe_to_add_transition has been found
2391  // to be true earlier.
2392  ASSERT(safe_to_add_transition);
2393  MaybeObject* maybe_new_contents =
2394      AddElementsTransitionMapToDescriptor(descriptor_contents,
2395                                           transitioned_map);
2396  Object* new_contents;
2397  if (!maybe_new_contents->ToObject(&new_contents)) {
2398    return maybe_new_contents;
2399  }
2400
2401  ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2402                                    new_contents);
2403  Object* new_descriptors;
2404  MaybeObject* maybe_new_descriptors =
2405      instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2406  if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2407    return maybe_new_descriptors;
2408  }
2409  set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2410  return this;
2411}
2412
2413
2414Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2415                                               ElementsKind to_kind) {
2416  Isolate* isolate = object->GetIsolate();
2417  CALL_HEAP_FUNCTION(isolate,
2418                     object->GetElementsTransitionMap(isolate, to_kind),
2419                     Map);
2420}
2421
2422
2423MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
2424  Map* current_map = map();
2425  ElementsKind from_kind = current_map->elements_kind();
2426
2427  if (from_kind == to_kind) return current_map;
2428
2429  // Only objects with FastProperties can have DescriptorArrays and can track
2430  // element-related maps. Also don't add descriptors to maps that are shared.
2431  bool safe_to_add_transition = HasFastProperties() &&
2432      !current_map->IsUndefined() &&
2433      !current_map->is_shared();
2434
2435  // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2436  // with elements that switch back and forth between dictionary and fast
2437  // element mode.
2438  if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2439    safe_to_add_transition = false;
2440  }
2441
2442  if (safe_to_add_transition) {
2443    // It's only safe to manipulate the descriptor array if it would be
2444    // safe to add a transition.
2445    Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2446        to_kind, &safe_to_add_transition);
2447    if (maybe_transition_map != NULL) {
2448      return maybe_transition_map;
2449    }
2450  }
2451
2452  Map* new_map = NULL;
2453
2454  // No transition to an existing map for the given ElementsKind. Make a new
2455  // one.
2456  { MaybeObject* maybe_map = current_map->CopyDropTransitions();
2457    if (!maybe_map->To(&new_map)) return maybe_map;
2458  }
2459
2460  new_map->set_elements_kind(to_kind);
2461
2462  // Only remember the map transition if the object's map is NOT equal to the
2463  // global object_function's map and there is not an already existing
2464  // non-matching element transition.
2465  Context* global_context = GetIsolate()->context()->global_context();
2466  bool allow_map_transition = safe_to_add_transition &&
2467      (global_context->object_function()->map() != map());
2468  if (allow_map_transition) {
2469    MaybeObject* maybe_transition =
2470        current_map->AddElementsTransition(to_kind, new_map);
2471    if (maybe_transition->IsFailure()) return maybe_transition;
2472  }
2473  return new_map;
2474}
2475
2476
2477void JSObject::LocalLookupRealNamedProperty(String* name,
2478                                            LookupResult* result) {
2479  if (IsJSGlobalProxy()) {
2480    Object* proto = GetPrototype();
2481    if (proto->IsNull()) return result->NotFound();
2482    ASSERT(proto->IsJSGlobalObject());
2483    // A GlobalProxy's prototype should always be a proper JSObject.
2484    return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2485  }
2486
2487  if (HasFastProperties()) {
2488    LookupInDescriptor(name, result);
2489    if (result->IsFound()) {
2490      // A property, a map transition or a null descriptor was found.
2491      // We return all of these result types because
2492      // LocalLookupRealNamedProperty is used when setting properties
2493      // where map transitions and null descriptors are handled.
2494      ASSERT(result->holder() == this && result->type() != NORMAL);
2495      // Disallow caching for uninitialized constants. These can only
2496      // occur as fields.
2497      if (result->IsReadOnly() && result->type() == FIELD &&
2498          FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2499        result->DisallowCaching();
2500      }
2501      return;
2502    }
2503  } else {
2504    int entry = property_dictionary()->FindEntry(name);
2505    if (entry != StringDictionary::kNotFound) {
2506      Object* value = property_dictionary()->ValueAt(entry);
2507      if (IsGlobalObject()) {
2508        PropertyDetails d = property_dictionary()->DetailsAt(entry);
2509        if (d.IsDeleted()) {
2510          result->NotFound();
2511          return;
2512        }
2513        value = JSGlobalPropertyCell::cast(value)->value();
2514      }
2515      // Make sure to disallow caching for uninitialized constants
2516      // found in the dictionary-mode objects.
2517      if (value->IsTheHole()) result->DisallowCaching();
2518      result->DictionaryResult(this, entry);
2519      return;
2520    }
2521  }
2522  result->NotFound();
2523}
2524
2525
2526void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2527  LocalLookupRealNamedProperty(name, result);
2528  if (result->IsProperty()) return;
2529
2530  LookupRealNamedPropertyInPrototypes(name, result);
2531}
2532
2533
2534void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2535                                                   LookupResult* result) {
2536  Heap* heap = GetHeap();
2537  for (Object* pt = GetPrototype();
2538       pt != heap->null_value();
2539       pt = JSObject::cast(pt)->GetPrototype()) {
2540    JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
2541    if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
2542  }
2543  result->NotFound();
2544}
2545
2546
2547// We only need to deal with CALLBACKS and INTERCEPTORS
2548MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2549    LookupResult* result,
2550    String* name,
2551    Object* value,
2552    bool check_prototype,
2553    StrictModeFlag strict_mode) {
2554  if (check_prototype && !result->IsProperty()) {
2555    LookupCallbackSetterInPrototypes(name, result);
2556  }
2557
2558  if (result->IsProperty()) {
2559    if (!result->IsReadOnly()) {
2560      switch (result->type()) {
2561        case CALLBACKS: {
2562          Object* obj = result->GetCallbackObject();
2563          if (obj->IsAccessorInfo()) {
2564            AccessorInfo* info = AccessorInfo::cast(obj);
2565            if (info->all_can_write()) {
2566              return SetPropertyWithCallback(result->GetCallbackObject(),
2567                                             name,
2568                                             value,
2569                                             result->holder(),
2570                                             strict_mode);
2571            }
2572          }
2573          break;
2574        }
2575        case INTERCEPTOR: {
2576          // Try lookup real named properties. Note that only property can be
2577          // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2578          LookupResult r(GetIsolate());
2579          LookupRealNamedProperty(name, &r);
2580          if (r.IsProperty()) {
2581            return SetPropertyWithFailedAccessCheck(&r,
2582                                                    name,
2583                                                    value,
2584                                                    check_prototype,
2585                                                    strict_mode);
2586          }
2587          break;
2588        }
2589        default: {
2590          break;
2591        }
2592      }
2593    }
2594  }
2595
2596  Isolate* isolate = GetIsolate();
2597  HandleScope scope(isolate);
2598  Handle<Object> value_handle(value);
2599  isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
2600  return *value_handle;
2601}
2602
2603
2604MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2605                                     String* key,
2606                                     Object* value,
2607                                     PropertyAttributes attributes,
2608                                     StrictModeFlag strict_mode) {
2609  if (result->IsFound() && result->type() == HANDLER) {
2610    return result->proxy()->SetPropertyWithHandler(
2611        key, value, attributes, strict_mode);
2612  } else {
2613    return JSObject::cast(this)->SetPropertyForResult(
2614        result, key, value, attributes, strict_mode);
2615  }
2616}
2617
2618
2619bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2620  Isolate* isolate = GetIsolate();
2621  HandleScope scope(isolate);
2622  Handle<Object> receiver(this);
2623  Handle<Object> name(name_raw);
2624
2625  Handle<Object> args[] = { name };
2626  Handle<Object> result = CallTrap(
2627    "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
2628  if (isolate->has_pending_exception()) return Failure::Exception();
2629
2630  return result->ToBoolean()->IsTrue();
2631}
2632
2633
2634MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2635    String* name_raw,
2636    Object* value_raw,
2637    PropertyAttributes attributes,
2638    StrictModeFlag strict_mode) {
2639  Isolate* isolate = GetIsolate();
2640  HandleScope scope(isolate);
2641  Handle<Object> receiver(this);
2642  Handle<Object> name(name_raw);
2643  Handle<Object> value(value_raw);
2644
2645  Handle<Object> args[] = { receiver, name, value };
2646  CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
2647  if (isolate->has_pending_exception()) return Failure::Exception();
2648
2649  return *value;
2650}
2651
2652
2653MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2654    String* name_raw,
2655    Object* value_raw,
2656    PropertyAttributes attributes,
2657    StrictModeFlag strict_mode,
2658    bool* found) {
2659  *found = true;  // except where defined otherwise...
2660  Isolate* isolate = GetHeap()->isolate();
2661  Handle<JSProxy> proxy(this);
2662  Handle<Object> handler(this->handler());  // Trap might morph proxy.
2663  Handle<String> name(name_raw);
2664  Handle<Object> value(value_raw);
2665  Handle<Object> args[] = { name };
2666  Handle<Object> result = proxy->CallTrap(
2667      "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2668  if (isolate->has_pending_exception()) return Failure::Exception();
2669
2670  if (!result->IsUndefined()) {
2671    // The proxy handler cares about this property.
2672    // Check whether it is virtualized as an accessor.
2673    // Emulate [[GetProperty]] semantics for proxies.
2674    bool has_pending_exception;
2675    Handle<Object> argv[] = { result };
2676    Handle<Object> desc =
2677        Execution::Call(isolate->to_complete_property_descriptor(), result,
2678                        ARRAY_SIZE(argv), argv, &has_pending_exception);
2679    if (has_pending_exception) return Failure::Exception();
2680
2681    Handle<String> conf_name =
2682        isolate->factory()->LookupAsciiSymbol("configurable_");
2683    Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2684    ASSERT(!isolate->has_pending_exception());
2685    if (configurable->IsFalse()) {
2686      Handle<String> trap =
2687          isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2688      Handle<Object> args[] = { handler, trap, name };
2689      Handle<Object> error = isolate->factory()->NewTypeError(
2690          "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2691      return isolate->Throw(*error);
2692    }
2693    ASSERT(configurable->IsTrue());
2694
2695    // Check for AccessorDescriptor.
2696    Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2697    Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2698    ASSERT(!isolate->has_pending_exception());
2699    if (!setter->IsUndefined()) {
2700      // We have a setter -- invoke it.
2701      // TODO(rossberg): nicer would be to cast to some JSCallable here...
2702      return proxy->SetPropertyWithDefinedSetter(
2703          JSReceiver::cast(*setter), *value);
2704    } else {
2705      Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2706      Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2707      ASSERT(!isolate->has_pending_exception());
2708      if (!getter->IsUndefined()) {
2709        // We have a getter but no setter -- the property may not be
2710        // written. In strict mode, throw an error.
2711        if (strict_mode == kNonStrictMode) return *value;
2712        Handle<Object> args[] = { name, proxy };
2713        Handle<Object> error = isolate->factory()->NewTypeError(
2714            "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2715        return isolate->Throw(*error);
2716      }
2717    }
2718    // Fall-through.
2719  }
2720
2721  // The proxy does not define the property as an accessor.
2722  *found = false;
2723  return *value;
2724}
2725
2726
2727MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2728    String* name_raw, DeleteMode mode) {
2729  Isolate* isolate = GetIsolate();
2730  HandleScope scope(isolate);
2731  Handle<Object> receiver(this);
2732  Handle<Object> name(name_raw);
2733
2734  Handle<Object> args[] = { name };
2735  Handle<Object> result = CallTrap(
2736    "delete", Handle<Object>(), ARRAY_SIZE(args), args);
2737  if (isolate->has_pending_exception()) return Failure::Exception();
2738
2739  Object* bool_result = result->ToBoolean();
2740  if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2741    Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2742    Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
2743    Handle<Object> error = isolate->factory()->NewTypeError(
2744        "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2745    isolate->Throw(*error);
2746    return Failure::Exception();
2747  }
2748  return bool_result;
2749}
2750
2751
2752MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2753    uint32_t index,
2754    DeleteMode mode) {
2755  Isolate* isolate = GetIsolate();
2756  HandleScope scope(isolate);
2757  Handle<String> name = isolate->factory()->Uint32ToString(index);
2758  return JSProxy::DeletePropertyWithHandler(*name, mode);
2759}
2760
2761
2762MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2763    JSReceiver* receiver_raw,
2764    String* name_raw) {
2765  Isolate* isolate = GetIsolate();
2766  HandleScope scope(isolate);
2767  Handle<JSProxy> proxy(this);
2768  Handle<Object> handler(this->handler());  // Trap might morph proxy.
2769  Handle<JSReceiver> receiver(receiver_raw);
2770  Handle<Object> name(name_raw);
2771
2772  Handle<Object> args[] = { name };
2773  Handle<Object> result = CallTrap(
2774    "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2775  if (isolate->has_pending_exception()) return NONE;
2776
2777  if (result->IsUndefined()) return ABSENT;
2778
2779  bool has_pending_exception;
2780  Handle<Object> argv[] = { result };
2781  Handle<Object> desc =
2782      Execution::Call(isolate->to_complete_property_descriptor(), result,
2783                      ARRAY_SIZE(argv), argv, &has_pending_exception);
2784  if (has_pending_exception) return NONE;
2785
2786  // Convert result to PropertyAttributes.
2787  Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2788  Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2789  if (isolate->has_pending_exception()) return NONE;
2790  Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2791  Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2792  if (isolate->has_pending_exception()) return NONE;
2793  Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2794  Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2795  if (isolate->has_pending_exception()) return NONE;
2796
2797  if (configurable->IsFalse()) {
2798    Handle<String> trap =
2799        isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2800    Handle<Object> args[] = { handler, trap, name };
2801    Handle<Object> error = isolate->factory()->NewTypeError(
2802        "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2803    isolate->Throw(*error);
2804    return NONE;
2805  }
2806
2807  int attributes = NONE;
2808  if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2809  if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2810  if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2811  return static_cast<PropertyAttributes>(attributes);
2812}
2813
2814
2815MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2816    JSReceiver* receiver,
2817    uint32_t index) {
2818  Isolate* isolate = GetIsolate();
2819  HandleScope scope(isolate);
2820  Handle<String> name = isolate->factory()->Uint32ToString(index);
2821  return GetPropertyAttributeWithHandler(receiver, *name);
2822}
2823
2824
2825void JSProxy::Fix() {
2826  Isolate* isolate = GetIsolate();
2827  HandleScope scope(isolate);
2828  Handle<JSProxy> self(this);
2829
2830  // Save identity hash.
2831  MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2832
2833  if (IsJSFunctionProxy()) {
2834    isolate->factory()->BecomeJSFunction(self);
2835    // Code will be set on the JavaScript side.
2836  } else {
2837    isolate->factory()->BecomeJSObject(self);
2838  }
2839  ASSERT(self->IsJSObject());
2840
2841  // Inherit identity, if it was present.
2842  Object* hash;
2843  if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2844    Handle<JSObject> new_self(JSObject::cast(*self));
2845    isolate->factory()->SetIdentityHash(new_self, hash);
2846  }
2847}
2848
2849
2850MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2851                                                 Handle<Object> derived,
2852                                                 int argc,
2853                                                 Handle<Object> argv[]) {
2854  Isolate* isolate = GetIsolate();
2855  Handle<Object> handler(this->handler());
2856
2857  Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2858  Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2859  if (isolate->has_pending_exception()) return trap;
2860
2861  if (trap->IsUndefined()) {
2862    if (derived.is_null()) {
2863      Handle<Object> args[] = { handler, trap_name };
2864      Handle<Object> error = isolate->factory()->NewTypeError(
2865        "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2866      isolate->Throw(*error);
2867      return Handle<Object>();
2868    }
2869    trap = Handle<Object>(derived);
2870  }
2871
2872  bool threw;
2873  return Execution::Call(trap, handler, argc, argv, &threw);
2874}
2875
2876
2877MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2878                                            String* name,
2879                                            Object* value,
2880                                            PropertyAttributes attributes,
2881                                            StrictModeFlag strict_mode) {
2882  Heap* heap = GetHeap();
2883  // Make sure that the top context does not change when doing callbacks or
2884  // interceptor calls.
2885  AssertNoContextChange ncc;
2886
2887  // Optimization for 2-byte strings often used as keys in a decompression
2888  // dictionary.  We make these short keys into symbols to avoid constantly
2889  // reallocating them.
2890  if (!name->IsSymbol() && name->length() <= 2) {
2891    Object* symbol_version;
2892    { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
2893      if (maybe_symbol_version->ToObject(&symbol_version)) {
2894        name = String::cast(symbol_version);
2895      }
2896    }
2897  }
2898
2899  // Check access rights if needed.
2900  if (IsAccessCheckNeeded()) {
2901    if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2902      return SetPropertyWithFailedAccessCheck(
2903          result, name, value, true, strict_mode);
2904    }
2905  }
2906
2907  if (IsJSGlobalProxy()) {
2908    Object* proto = GetPrototype();
2909    if (proto->IsNull()) return value;
2910    ASSERT(proto->IsJSGlobalObject());
2911    return JSObject::cast(proto)->SetPropertyForResult(
2912        result, name, value, attributes, strict_mode);
2913  }
2914
2915  if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2916    bool found = false;
2917    MaybeObject* result_object;
2918    result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2919                                                              value,
2920                                                              attributes,
2921                                                              &found,
2922                                                              strict_mode);
2923    if (found) return result_object;
2924  }
2925
2926  // At this point, no GC should have happened, as this would invalidate
2927  // 'result', which we cannot handlify!
2928
2929  if (!result->IsFound()) {
2930    // Neither properties nor transitions found.
2931    return AddProperty(name, value, attributes, strict_mode);
2932  }
2933  if (result->IsReadOnly() && result->IsProperty()) {
2934    if (strict_mode == kStrictMode) {
2935      Handle<JSObject> self(this);
2936      Handle<String> hname(name);
2937      Handle<Object> args[] = { hname, self };
2938      return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2939          "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
2940    } else {
2941      return value;
2942    }
2943  }
2944  // This is a real property that is not read-only, or it is a
2945  // transition or null descriptor and there are no setters in the prototypes.
2946  switch (result->type()) {
2947    case NORMAL:
2948      return SetNormalizedProperty(result, value);
2949    case FIELD:
2950      return FastPropertyAtPut(result->GetFieldIndex(), value);
2951    case MAP_TRANSITION:
2952      if (attributes == result->GetAttributes()) {
2953        // Only use map transition if the attributes match.
2954        return AddFastPropertyUsingMap(result->GetTransitionMap(),
2955                                       name,
2956                                       value);
2957      }
2958      return ConvertDescriptorToField(name, value, attributes);
2959    case CONSTANT_FUNCTION:
2960      // Only replace the function if necessary.
2961      if (value == result->GetConstantFunction()) return value;
2962      // Preserve the attributes of this existing property.
2963      attributes = result->GetAttributes();
2964      return ConvertDescriptorToField(name, value, attributes);
2965    case CALLBACKS:
2966      return SetPropertyWithCallback(result->GetCallbackObject(),
2967                                     name,
2968                                     value,
2969                                     result->holder(),
2970                                     strict_mode);
2971    case INTERCEPTOR:
2972      return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
2973    case CONSTANT_TRANSITION: {
2974      // If the same constant function is being added we can simply
2975      // transition to the target map.
2976      Map* target_map = result->GetTransitionMap();
2977      DescriptorArray* target_descriptors = target_map->instance_descriptors();
2978      int number = target_descriptors->SearchWithCache(name);
2979      ASSERT(number != DescriptorArray::kNotFound);
2980      ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2981      JSFunction* function =
2982          JSFunction::cast(target_descriptors->GetValue(number));
2983      if (value == function) {
2984        set_map(target_map);
2985        return value;
2986      }
2987      // Otherwise, replace with a MAP_TRANSITION to a new map with a
2988      // FIELD, even if the value is a constant function.
2989      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2990    }
2991    case NULL_DESCRIPTOR:
2992    case ELEMENTS_TRANSITION:
2993      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2994    case HANDLER:
2995      UNREACHABLE();
2996      return value;
2997  }
2998  UNREACHABLE();  // keep the compiler happy
2999  return value;
3000}
3001
3002
3003// Set a real local property, even if it is READ_ONLY.  If the property is not
3004// present, add it with attributes NONE.  This code is an exact clone of
3005// SetProperty, with the check for IsReadOnly and the check for a
3006// callback setter removed.  The two lines looking up the LookupResult
3007// result are also added.  If one of the functions is changed, the other
3008// should be.
3009// Note that this method cannot be used to set the prototype of a function
3010// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3011// doesn't handle function prototypes correctly.
3012Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3013    Handle<JSObject> object,
3014    Handle<String> key,
3015    Handle<Object> value,
3016    PropertyAttributes attributes) {
3017  CALL_HEAP_FUNCTION(
3018    object->GetIsolate(),
3019    object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3020    Object);
3021}
3022
3023
3024MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
3025    String* name,
3026    Object* value,
3027    PropertyAttributes attributes) {
3028
3029  // Make sure that the top context does not change when doing callbacks or
3030  // interceptor calls.
3031  AssertNoContextChange ncc;
3032  Isolate* isolate = GetIsolate();
3033  LookupResult result(isolate);
3034  LocalLookup(name, &result);
3035  // Check access rights if needed.
3036  if (IsAccessCheckNeeded()) {
3037    if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3038      return SetPropertyWithFailedAccessCheck(&result,
3039                                              name,
3040                                              value,
3041                                              false,
3042                                              kNonStrictMode);
3043    }
3044  }
3045
3046  if (IsJSGlobalProxy()) {
3047    Object* proto = GetPrototype();
3048    if (proto->IsNull()) return value;
3049    ASSERT(proto->IsJSGlobalObject());
3050    return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
3051        name,
3052        value,
3053        attributes);
3054  }
3055
3056  // Check for accessor in prototype chain removed here in clone.
3057  if (!result.IsFound()) {
3058    // Neither properties nor transitions found.
3059    return AddProperty(name, value, attributes, kNonStrictMode);
3060  }
3061
3062  PropertyDetails details = PropertyDetails(attributes, NORMAL);
3063
3064  // Check of IsReadOnly removed from here in clone.
3065  switch (result.type()) {
3066    case NORMAL:
3067      return SetNormalizedProperty(name, value, details);
3068    case FIELD:
3069      return FastPropertyAtPut(result.GetFieldIndex(), value);
3070    case MAP_TRANSITION:
3071      if (attributes == result.GetAttributes()) {
3072        // Only use map transition if the attributes match.
3073        return AddFastPropertyUsingMap(result.GetTransitionMap(),
3074                                       name,
3075                                       value);
3076      }
3077      return ConvertDescriptorToField(name, value, attributes);
3078    case CONSTANT_FUNCTION:
3079      // Only replace the function if necessary.
3080      if (value == result.GetConstantFunction()) return value;
3081      // Preserve the attributes of this existing property.
3082      attributes = result.GetAttributes();
3083      return ConvertDescriptorToField(name, value, attributes);
3084    case CALLBACKS:
3085    case INTERCEPTOR:
3086      // Override callback in clone
3087      return ConvertDescriptorToField(name, value, attributes);
3088    case CONSTANT_TRANSITION:
3089      // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3090      // if the value is a function.
3091      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3092    case NULL_DESCRIPTOR:
3093    case ELEMENTS_TRANSITION:
3094      return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3095    case HANDLER:
3096      UNREACHABLE();
3097      return value;
3098  }
3099  UNREACHABLE();  // keep the compiler happy
3100  return value;
3101}
3102
3103
3104PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3105      JSObject* receiver,
3106      String* name,
3107      bool continue_search) {
3108  // Check local property, ignore interceptor.
3109  LookupResult result(GetIsolate());
3110  LocalLookupRealNamedProperty(name, &result);
3111  if (result.IsProperty()) return result.GetAttributes();
3112
3113  if (continue_search) {
3114    // Continue searching via the prototype chain.
3115    Object* pt = GetPrototype();
3116    if (!pt->IsNull()) {
3117      return JSObject::cast(pt)->
3118        GetPropertyAttributeWithReceiver(receiver, name);
3119    }
3120  }
3121  return ABSENT;
3122}
3123
3124
3125PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3126      JSObject* receiver,
3127      String* name,
3128      bool continue_search) {
3129  Isolate* isolate = GetIsolate();
3130
3131  // Make sure that the top context does not change when doing
3132  // callbacks or interceptor calls.
3133  AssertNoContextChange ncc;
3134
3135  HandleScope scope(isolate);
3136  Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3137  Handle<JSObject> receiver_handle(receiver);
3138  Handle<JSObject> holder_handle(this);
3139  Handle<String> name_handle(name);
3140  CustomArguments args(isolate, interceptor->data(), receiver, this);
3141  v8::AccessorInfo info(args.end());
3142  if (!interceptor->query()->IsUndefined()) {
3143    v8::NamedPropertyQuery query =
3144        v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
3145    LOG(isolate,
3146        ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
3147    v8::Handle<v8::Integer> result;
3148    {
3149      // Leaving JavaScript.
3150      VMState state(isolate, EXTERNAL);
3151      result = query(v8::Utils::ToLocal(name_handle), info);
3152    }
3153    if (!result.IsEmpty()) {
3154      ASSERT(result->IsInt32());
3155      return static_cast<PropertyAttributes>(result->Int32Value());
3156    }
3157  } else if (!interceptor->getter()->IsUndefined()) {
3158    v8::NamedPropertyGetter getter =
3159        v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
3160    LOG(isolate,
3161        ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
3162    v8::Handle<v8::Value> result;
3163    {
3164      // Leaving JavaScript.
3165      VMState state(isolate, EXTERNAL);
3166      result = getter(v8::Utils::ToLocal(name_handle), info);
3167    }
3168    if (!result.IsEmpty()) return DONT_ENUM;
3169  }
3170  return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3171                                                            *name_handle,
3172                                                            continue_search);
3173}
3174
3175
3176PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3177      JSReceiver* receiver,
3178      String* key) {
3179  uint32_t index = 0;
3180  if (IsJSObject() && key->AsArrayIndex(&index)) {
3181    return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3182        ? NONE : ABSENT;
3183  }
3184  // Named property.
3185  LookupResult result(GetIsolate());
3186  Lookup(key, &result);
3187  return GetPropertyAttribute(receiver, &result, key, true);
3188}
3189
3190
3191PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3192                                                    LookupResult* result,
3193                                                    String* name,
3194                                                    bool continue_search) {
3195  // Check access rights if needed.
3196  if (IsAccessCheckNeeded()) {
3197    JSObject* this_obj = JSObject::cast(this);
3198    Heap* heap = GetHeap();
3199    if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3200      return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3201          receiver, result, name, continue_search);
3202    }
3203  }
3204  if (result->IsProperty()) {
3205    switch (result->type()) {
3206      case NORMAL:  // fall through
3207      case FIELD:
3208      case CONSTANT_FUNCTION:
3209      case CALLBACKS:
3210        return result->GetAttributes();
3211      case HANDLER: {
3212        return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3213            receiver, name);
3214      }
3215      case INTERCEPTOR:
3216        return result->holder()->GetPropertyAttributeWithInterceptor(
3217            JSObject::cast(receiver), name, continue_search);
3218      default:
3219        UNREACHABLE();
3220    }
3221  }
3222  return ABSENT;
3223}
3224
3225
3226PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
3227  // Check whether the name is an array index.
3228  uint32_t index = 0;
3229  if (IsJSObject() && name->AsArrayIndex(&index)) {
3230    if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
3231    return ABSENT;
3232  }
3233  // Named property.
3234  LookupResult result(GetIsolate());
3235  LocalLookup(name, &result);
3236  return GetPropertyAttribute(this, &result, name, false);
3237}
3238
3239
3240MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3241                                     PropertyNormalizationMode mode) {
3242  Isolate* isolate = obj->GetIsolate();
3243  Map* fast = obj->map();
3244  int index = fast->Hash() % kEntries;
3245  Object* result = get(index);
3246  if (result->IsMap() &&
3247      Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
3248#ifdef DEBUG
3249    if (FLAG_verify_heap) {
3250      Map::cast(result)->SharedMapVerify();
3251    }
3252    if (FLAG_enable_slow_asserts) {
3253      // The cached map should match newly created normalized map bit-by-bit.
3254      Object* fresh;
3255      { MaybeObject* maybe_fresh =
3256            fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3257        if (maybe_fresh->ToObject(&fresh)) {
3258          ASSERT(memcmp(Map::cast(fresh)->address(),
3259                        Map::cast(result)->address(),
3260                        Map::kSize) == 0);
3261        }
3262      }
3263    }
3264#endif
3265    return result;
3266  }
3267
3268  { MaybeObject* maybe_result =
3269        fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3270    if (!maybe_result->ToObject(&result)) return maybe_result;
3271  }
3272  set(index, result);
3273  isolate->counters()->normalized_maps()->Increment();
3274
3275  return result;
3276}
3277
3278
3279void NormalizedMapCache::Clear() {
3280  int entries = length();
3281  for (int i = 0; i != entries; i++) {
3282    set_undefined(i);
3283  }
3284}
3285
3286
3287void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3288                                  Handle<String> name,
3289                                  Handle<Code> code) {
3290  Isolate* isolate = object->GetIsolate();
3291  CALL_HEAP_FUNCTION_VOID(isolate,
3292                          object->UpdateMapCodeCache(*name, *code));
3293}
3294
3295
3296MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
3297  if (map()->is_shared()) {
3298    // Fast case maps are never marked as shared.
3299    ASSERT(!HasFastProperties());
3300    // Replace the map with an identical copy that can be safely modified.
3301    Object* obj;
3302    { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3303                                                     UNIQUE_NORMALIZED_MAP);
3304      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3305    }
3306    GetIsolate()->counters()->normalized_maps()->Increment();
3307
3308    set_map(Map::cast(obj));
3309  }
3310  return map()->UpdateCodeCache(name, code);
3311}
3312
3313
3314void JSObject::NormalizeProperties(Handle<JSObject> object,
3315                                   PropertyNormalizationMode mode,
3316                                   int expected_additional_properties) {
3317  CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3318                          object->NormalizeProperties(
3319                              mode, expected_additional_properties));
3320}
3321
3322
3323MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3324                                           int expected_additional_properties) {
3325  if (!HasFastProperties()) return this;
3326
3327  // The global object is always normalized.
3328  ASSERT(!IsGlobalObject());
3329  // JSGlobalProxy must never be normalized
3330  ASSERT(!IsJSGlobalProxy());
3331
3332  Map* map_of_this = map();
3333
3334  // Allocate new content.
3335  int property_count = map_of_this->NumberOfDescribedProperties();
3336  if (expected_additional_properties > 0) {
3337    property_count += expected_additional_properties;
3338  } else {
3339    property_count += 2;  // Make space for two more properties.
3340  }
3341  StringDictionary* dictionary;
3342  { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count);
3343    if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3344  }
3345
3346  DescriptorArray* descs = map_of_this->instance_descriptors();
3347  for (int i = 0; i < descs->number_of_descriptors(); i++) {
3348    PropertyDetails details(descs->GetDetails(i));
3349    switch (details.type()) {
3350      case CONSTANT_FUNCTION: {
3351        PropertyDetails d =
3352            PropertyDetails(details.attributes(), NORMAL, details.index());
3353        Object* value = descs->GetConstantFunction(i);
3354        MaybeObject* maybe_dictionary =
3355            dictionary->Add(descs->GetKey(i), value, d);
3356        if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3357        break;
3358      }
3359      case FIELD: {
3360        PropertyDetails d =
3361            PropertyDetails(details.attributes(), NORMAL, details.index());
3362        Object* value = FastPropertyAt(descs->GetFieldIndex(i));
3363        MaybeObject* maybe_dictionary =
3364            dictionary->Add(descs->GetKey(i), value, d);
3365        if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3366        break;
3367      }
3368      case CALLBACKS: {
3369        if (!descs->IsProperty(i)) break;
3370        Object* value = descs->GetCallbacksObject(i);
3371        if (value->IsAccessorPair()) {
3372          MaybeObject* maybe_copy =
3373              AccessorPair::cast(value)->CopyWithoutTransitions();
3374          if (!maybe_copy->To(&value)) return maybe_copy;
3375        }
3376        MaybeObject* maybe_dictionary =
3377            dictionary->Add(descs->GetKey(i), value, details);
3378        if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3379        break;
3380      }
3381      case MAP_TRANSITION:
3382      case CONSTANT_TRANSITION:
3383      case NULL_DESCRIPTOR:
3384      case INTERCEPTOR:
3385      case ELEMENTS_TRANSITION:
3386        break;
3387      case HANDLER:
3388      case NORMAL:
3389        UNREACHABLE();
3390        break;
3391    }
3392  }
3393
3394  Heap* current_heap = GetHeap();
3395
3396  // Copy the next enumeration index from instance descriptor.
3397  int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
3398  dictionary->SetNextEnumerationIndex(index);
3399
3400  Map* new_map;
3401  { MaybeObject* maybe_map =
3402        current_heap->isolate()->context()->global_context()->
3403        normalized_map_cache()->Get(this, mode);
3404    if (!maybe_map->To(&new_map)) return maybe_map;
3405  }
3406
3407  // We have now successfully allocated all the necessary objects.
3408  // Changes can now be made with the guarantee that all of them take effect.
3409
3410  // Resize the object in the heap if necessary.
3411  int new_instance_size = new_map->instance_size();
3412  int instance_size_delta = map_of_this->instance_size() - new_instance_size;
3413  ASSERT(instance_size_delta >= 0);
3414  current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3415                                     instance_size_delta);
3416  if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
3417    MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3418                                               -instance_size_delta);
3419  }
3420
3421
3422  set_map(new_map);
3423  new_map->clear_instance_descriptors();
3424
3425  set_properties(dictionary);
3426
3427  current_heap->isolate()->counters()->props_to_dictionary()->Increment();
3428
3429#ifdef DEBUG
3430  if (FLAG_trace_normalization) {
3431    PrintF("Object properties have been normalized:\n");
3432    Print();
3433  }
3434#endif
3435  return this;
3436}
3437
3438
3439void JSObject::TransformToFastProperties(Handle<JSObject> object,
3440                                         int unused_property_fields) {
3441  CALL_HEAP_FUNCTION_VOID(
3442      object->GetIsolate(),
3443      object->TransformToFastProperties(unused_property_fields));
3444}
3445
3446
3447MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
3448  if (HasFastProperties()) return this;
3449  ASSERT(!IsGlobalObject());
3450  return property_dictionary()->
3451      TransformPropertiesToFastFor(this, unused_property_fields);
3452}
3453
3454
3455Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3456    Handle<JSObject> object) {
3457  CALL_HEAP_FUNCTION(object->GetIsolate(),
3458                     object->NormalizeElements(),
3459                     SeededNumberDictionary);
3460}
3461
3462
3463MaybeObject* JSObject::NormalizeElements() {
3464  ASSERT(!HasExternalArrayElements());
3465
3466  // Find the backing store.
3467  FixedArrayBase* array = FixedArrayBase::cast(elements());
3468  Map* old_map = array->map();
3469  bool is_arguments =
3470      (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
3471  if (is_arguments) {
3472    array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
3473  }
3474  if (array->IsDictionary()) return array;
3475
3476  ASSERT(HasFastElements() ||
3477         HasFastSmiOnlyElements() ||
3478         HasFastDoubleElements() ||
3479         HasFastArgumentsElements());
3480  // Compute the effective length and allocate a new backing store.
3481  int length = IsJSArray()
3482      ? Smi::cast(JSArray::cast(this)->length())->value()
3483      : array->length();
3484  int old_capacity = 0;
3485  int used_elements = 0;
3486  GetElementsCapacityAndUsage(&old_capacity, &used_elements);
3487  SeededNumberDictionary* dictionary = NULL;
3488  { Object* object;
3489    MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
3490    if (!maybe->ToObject(&object)) return maybe;
3491    dictionary = SeededNumberDictionary::cast(object);
3492  }
3493
3494  // Copy the elements to the new backing store.
3495  bool has_double_elements = array->IsFixedDoubleArray();
3496  for (int i = 0; i < length; i++) {
3497    Object* value = NULL;
3498    if (has_double_elements) {
3499      FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3500      if (double_array->is_the_hole(i)) {
3501        value = GetIsolate()->heap()->the_hole_value();
3502      } else {
3503        // Objects must be allocated in the old object space, since the
3504        // overall number of HeapNumbers needed for the conversion might
3505        // exceed the capacity of new space, and we would fail repeatedly
3506        // trying to convert the FixedDoubleArray.
3507        MaybeObject* maybe_value_object =
3508            GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
3509        if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
3510      }
3511    } else {
3512      ASSERT(old_map->has_fast_elements() ||
3513             old_map->has_fast_smi_only_elements());
3514      value = FixedArray::cast(array)->get(i);
3515    }
3516    PropertyDetails details = PropertyDetails(NONE, NORMAL);
3517    if (!value->IsTheHole()) {
3518      Object* result;
3519      MaybeObject* maybe_result =
3520          dictionary->AddNumberEntry(i, value, details);
3521      if (!maybe_result->ToObject(&result)) return maybe_result;
3522      dictionary = SeededNumberDictionary::cast(result);
3523    }
3524  }
3525
3526  // Switch to using the dictionary as the backing storage for elements.
3527  if (is_arguments) {
3528    FixedArray::cast(elements())->set(1, dictionary);
3529  } else {
3530    // Set the new map first to satify the elements type assert in
3531    // set_elements().
3532    Object* new_map;
3533    MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
3534                                                  DICTIONARY_ELEMENTS);
3535    if (!maybe->ToObject(&new_map)) return maybe;
3536    set_map(Map::cast(new_map));
3537    set_elements(dictionary);
3538  }
3539
3540  old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3541      Increment();
3542
3543#ifdef DEBUG
3544  if (FLAG_trace_normalization) {
3545    PrintF("Object elements have been normalized:\n");
3546    Print();
3547  }
3548#endif
3549
3550  ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3551  return dictionary;
3552}
3553
3554
3555Smi* JSReceiver::GenerateIdentityHash() {
3556  Isolate* isolate = GetIsolate();
3557
3558  int hash_value;
3559  int attempts = 0;
3560  do {
3561    // Generate a random 32-bit hash value but limit range to fit
3562    // within a smi.
3563    hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
3564    attempts++;
3565  } while (hash_value == 0 && attempts < 30);
3566  hash_value = hash_value != 0 ? hash_value : 1;  // never return 0
3567
3568  return Smi::FromInt(hash_value);
3569}
3570
3571
3572MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3573  MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3574                                         hash);
3575  if (maybe->IsFailure()) return maybe;
3576  return this;
3577}
3578
3579
3580int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3581  CALL_AND_RETRY(obj->GetIsolate(),
3582                 obj->GetIdentityHash(ALLOW_CREATION),
3583                 return Smi::cast(__object__)->value(),
3584                 return 0);
3585}
3586
3587
3588MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3589  Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3590  if (stored_value->IsSmi()) return stored_value;
3591
3592  // Do not generate permanent identity hash code if not requested.
3593  if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3594
3595  Smi* hash = GenerateIdentityHash();
3596  MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3597                                          hash);
3598  if (result->IsFailure()) return result;
3599  if (result->ToObjectUnchecked()->IsUndefined()) {
3600    // Trying to get hash of detached proxy.
3601    return Smi::FromInt(0);
3602  }
3603  return hash;
3604}
3605
3606
3607MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3608  Object* hash = this->hash();
3609  if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3610    hash = GenerateIdentityHash();
3611    set_hash(hash);
3612  }
3613  return hash;
3614}
3615
3616
3617Object* JSObject::GetHiddenProperty(String* key) {
3618  if (IsJSGlobalProxy()) {
3619    // For a proxy, use the prototype as target object.
3620    Object* proxy_parent = GetPrototype();
3621    // If the proxy is detached, return undefined.
3622    if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3623    ASSERT(proxy_parent->IsJSGlobalObject());
3624    return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3625  }
3626  ASSERT(!IsJSGlobalProxy());
3627  MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3628  ASSERT(!hidden_lookup->IsFailure());  // No failure when passing false as arg.
3629  if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3630    return GetHeap()->undefined_value();
3631  }
3632  StringDictionary* dictionary =
3633      StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3634  int entry = dictionary->FindEntry(key);
3635  if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3636  return dictionary->ValueAt(entry);
3637}
3638
3639
3640Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3641                                 Handle<String> key,
3642                                 Handle<Object> value) {
3643  CALL_HEAP_FUNCTION(obj->GetIsolate(),
3644                     obj->SetHiddenProperty(*key, *value),
3645                     Object);
3646}
3647
3648
3649MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3650  if (IsJSGlobalProxy()) {
3651    // For a proxy, use the prototype as target object.
3652    Object* proxy_parent = GetPrototype();
3653    // If the proxy is detached, return undefined.
3654    if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3655    ASSERT(proxy_parent->IsJSGlobalObject());
3656    return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3657  }
3658  ASSERT(!IsJSGlobalProxy());
3659  MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3660  StringDictionary* dictionary;
3661  if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3662
3663  // If it was found, check if the key is already in the dictionary.
3664  int entry = dictionary->FindEntry(key);
3665  if (entry != StringDictionary::kNotFound) {
3666    // If key was found, just update the value.
3667    dictionary->ValueAtPut(entry, value);
3668    return this;
3669  }
3670  // Key was not already in the dictionary, so add the entry.
3671  MaybeObject* insert_result = dictionary->Add(key,
3672                                               value,
3673                                               PropertyDetails(NONE, NORMAL));
3674  StringDictionary* new_dict;
3675  if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3676  if (new_dict != dictionary) {
3677    // If adding the key expanded the dictionary (i.e., Add returned a new
3678    // dictionary), store it back to the object.
3679    MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3680    if (store_result->IsFailure()) return store_result;
3681  }
3682  // Return this to mark success.
3683  return this;
3684}
3685
3686
3687void JSObject::DeleteHiddenProperty(String* key) {
3688  if (IsJSGlobalProxy()) {
3689    // For a proxy, use the prototype as target object.
3690    Object* proxy_parent = GetPrototype();
3691    // If the proxy is detached, return immediately.
3692    if (proxy_parent->IsNull()) return;
3693    ASSERT(proxy_parent->IsJSGlobalObject());
3694    JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3695    return;
3696  }
3697  MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3698  ASSERT(!hidden_lookup->IsFailure());  // No failure when passing false as arg.
3699  if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3700  StringDictionary* dictionary =
3701      StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3702  int entry = dictionary->FindEntry(key);
3703  if (entry == StringDictionary::kNotFound) {
3704    // Key wasn't in dictionary. Deletion is a success.
3705    return;
3706  }
3707  // Key was in the dictionary. Remove it.
3708  dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3709}
3710
3711
3712bool JSObject::HasHiddenProperties() {
3713  return GetPropertyAttributePostInterceptor(this,
3714                                             GetHeap()->hidden_symbol(),
3715                                             false) != ABSENT;
3716}
3717
3718
3719MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3720  ASSERT(!IsJSGlobalProxy());
3721  if (HasFastProperties()) {
3722    // If the object has fast properties, check whether the first slot
3723    // in the descriptor array matches the hidden symbol. Since the
3724    // hidden symbols hash code is zero (and no other string has hash
3725    // code zero) it will always occupy the first entry if present.
3726    DescriptorArray* descriptors = this->map()->instance_descriptors();
3727    if ((descriptors->number_of_descriptors() > 0) &&
3728        (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3729      if (descriptors->GetType(0) == FIELD) {
3730        Object* hidden_store =
3731            this->FastPropertyAt(descriptors->GetFieldIndex(0));
3732        return StringDictionary::cast(hidden_store);
3733      } else {
3734        ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3735               descriptors->GetType(0) == MAP_TRANSITION);
3736      }
3737    }
3738  } else {
3739    PropertyAttributes attributes;
3740    // You can't install a getter on a property indexed by the hidden symbol,
3741    // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3742    // object.
3743    Object* lookup =
3744        GetLocalPropertyPostInterceptor(this,
3745                                        GetHeap()->hidden_symbol(),
3746                                        &attributes)->ToObjectUnchecked();
3747    if (!lookup->IsUndefined()) {
3748      return StringDictionary::cast(lookup);
3749    }
3750  }
3751  if (!create_if_absent) return GetHeap()->undefined_value();
3752  const int kInitialSize = 5;
3753  MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3754  StringDictionary* dictionary;
3755  if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3756  MaybeObject* store_result =
3757      SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3758                                 dictionary,
3759                                 DONT_ENUM,
3760                                 kNonStrictMode);
3761  if (store_result->IsFailure()) return store_result;
3762  return dictionary;
3763}
3764
3765
3766MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3767    StringDictionary* dictionary) {
3768  ASSERT(!IsJSGlobalProxy());
3769  ASSERT(HasHiddenProperties());
3770  if (HasFastProperties()) {
3771    // If the object has fast properties, check whether the first slot
3772    // in the descriptor array matches the hidden symbol. Since the
3773    // hidden symbols hash code is zero (and no other string has hash
3774    // code zero) it will always occupy the first entry if present.
3775    DescriptorArray* descriptors = this->map()->instance_descriptors();
3776    if ((descriptors->number_of_descriptors() > 0) &&
3777        (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3778      if (descriptors->GetType(0) == FIELD) {
3779        this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3780        return this;
3781      } else {
3782        ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3783               descriptors->GetType(0) == MAP_TRANSITION);
3784      }
3785    }
3786  }
3787  MaybeObject* store_result =
3788      SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3789                                 dictionary,
3790                                 DONT_ENUM,
3791                                 kNonStrictMode);
3792  if (store_result->IsFailure()) return store_result;
3793  return this;
3794}
3795
3796
3797MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3798                                                     DeleteMode mode) {
3799  // Check local property, ignore interceptor.
3800  LookupResult result(GetIsolate());
3801  LocalLookupRealNamedProperty(name, &result);
3802  if (!result.IsProperty()) return GetHeap()->true_value();
3803
3804  // Normalize object if needed.
3805  Object* obj;
3806  { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3807    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3808  }
3809
3810  return DeleteNormalizedProperty(name, mode);
3811}
3812
3813
3814MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
3815  Isolate* isolate = GetIsolate();
3816  HandleScope scope(isolate);
3817  Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3818  Handle<String> name_handle(name);
3819  Handle<JSObject> this_handle(this);
3820  if (!interceptor->deleter()->IsUndefined()) {
3821    v8::NamedPropertyDeleter deleter =
3822        v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
3823    LOG(isolate,
3824        ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3825    CustomArguments args(isolate, interceptor->data(), this, this);
3826    v8::AccessorInfo info(args.end());
3827    v8::Handle<v8::Boolean> result;
3828    {
3829      // Leaving JavaScript.
3830      VMState state(isolate, EXTERNAL);
3831      result = deleter(v8::Utils::ToLocal(name_handle), info);
3832    }
3833    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3834    if (!result.IsEmpty()) {
3835      ASSERT(result->IsBoolean());
3836      return *v8::Utils::OpenHandle(*result);
3837    }
3838  }
3839  MaybeObject* raw_result =
3840      this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
3841  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3842  return raw_result;
3843}
3844
3845
3846MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
3847  Isolate* isolate = GetIsolate();
3848  Heap* heap = isolate->heap();
3849  // Make sure that the top context does not change when doing
3850  // callbacks or interceptor calls.
3851  AssertNoContextChange ncc;
3852  HandleScope scope(isolate);
3853  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
3854  if (interceptor->deleter()->IsUndefined()) return heap->false_value();
3855  v8::IndexedPropertyDeleter deleter =
3856      v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3857  Handle<JSObject> this_handle(this);
3858  LOG(isolate,
3859      ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3860  CustomArguments args(isolate, interceptor->data(), this, this);
3861  v8::AccessorInfo info(args.end());
3862  v8::Handle<v8::Boolean> result;
3863  {
3864    // Leaving JavaScript.
3865    VMState state(isolate, EXTERNAL);
3866    result = deleter(index, info);
3867  }
3868  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3869  if (!result.IsEmpty()) {
3870    ASSERT(result->IsBoolean());
3871    return *v8::Utils::OpenHandle(*result);
3872  }
3873  MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3874      *this_handle,
3875      index,
3876      NORMAL_DELETION);
3877  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3878  return raw_result;
3879}
3880
3881
3882Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3883                                       uint32_t index) {
3884  CALL_HEAP_FUNCTION(obj->GetIsolate(),
3885                     obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3886                     Object);
3887}
3888
3889
3890MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
3891  Isolate* isolate = GetIsolate();
3892  // Check access rights if needed.
3893  if (IsAccessCheckNeeded() &&
3894      !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3895    isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3896    return isolate->heap()->false_value();
3897  }
3898
3899  if (IsJSGlobalProxy()) {
3900    Object* proto = GetPrototype();
3901    if (proto->IsNull()) return isolate->heap()->false_value();
3902    ASSERT(proto->IsJSGlobalObject());
3903    return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3904  }
3905
3906  if (HasIndexedInterceptor()) {
3907    // Skip interceptor if forcing deletion.
3908    if (mode != FORCE_DELETION) {
3909      return DeleteElementWithInterceptor(index);
3910    }
3911    mode = JSReceiver::FORCE_DELETION;
3912  }
3913
3914  return GetElementsAccessor()->Delete(this, index, mode);
3915}
3916
3917
3918Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3919                              Handle<String> prop) {
3920  CALL_HEAP_FUNCTION(obj->GetIsolate(),
3921                     obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3922                     Object);
3923}
3924
3925
3926MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
3927  Isolate* isolate = GetIsolate();
3928  // ECMA-262, 3rd, 8.6.2.5
3929  ASSERT(name->IsString());
3930
3931  // Check access rights if needed.
3932  if (IsAccessCheckNeeded() &&
3933      !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3934    isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3935    return isolate->heap()->false_value();
3936  }
3937
3938  if (IsJSGlobalProxy()) {
3939    Object* proto = GetPrototype();
3940    if (proto->IsNull()) return isolate->heap()->false_value();
3941    ASSERT(proto->IsJSGlobalObject());
3942    return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3943  }
3944
3945  uint32_t index = 0;
3946  if (name->AsArrayIndex(&index)) {
3947    return DeleteElement(index, mode);
3948  } else {
3949    LookupResult result(isolate);
3950    LocalLookup(name, &result);
3951    if (!result.IsProperty()) return isolate->heap()->true_value();
3952    // Ignore attributes if forcing a deletion.
3953    if (result.IsDontDelete() && mode != FORCE_DELETION) {
3954      if (mode == STRICT_DELETION) {
3955        // Deleting a non-configurable property in strict mode.
3956        HandleScope scope(isolate);
3957        Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
3958        return isolate->Throw(*isolate->factory()->NewTypeError(
3959            "strict_delete_property", HandleVector(args, 2)));
3960      }
3961      return isolate->heap()->false_value();
3962    }
3963    // Check for interceptor.
3964    if (result.type() == INTERCEPTOR) {
3965      // Skip interceptor if forcing a deletion.
3966      if (mode == FORCE_DELETION) {
3967        return DeletePropertyPostInterceptor(name, mode);
3968      }
3969      return DeletePropertyWithInterceptor(name);
3970    }
3971    // Normalize object if needed.
3972    Object* obj;
3973    { MaybeObject* maybe_obj =
3974          NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3975      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3976    }
3977    // Make sure the properties are normalized before removing the entry.
3978    return DeleteNormalizedProperty(name, mode);
3979  }
3980}
3981
3982
3983MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
3984  if (IsJSProxy()) {
3985    return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
3986  }
3987  return JSObject::cast(this)->DeleteElement(index, mode);
3988}
3989
3990
3991MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3992  if (IsJSProxy()) {
3993    return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3994  }
3995  return JSObject::cast(this)->DeleteProperty(name, mode);
3996}
3997
3998
3999bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
4000                                            ElementsKind kind,
4001                                            Object* object) {
4002  ASSERT(kind == FAST_ELEMENTS ||
4003         kind == DICTIONARY_ELEMENTS);
4004  if (kind == FAST_ELEMENTS) {
4005    int length = IsJSArray()
4006        ? Smi::cast(JSArray::cast(this)->length())->value()
4007        : elements->length();
4008    for (int i = 0; i < length; ++i) {
4009      Object* element = elements->get(i);
4010      if (!element->IsTheHole() && element == object) return true;
4011    }
4012  } else {
4013    Object* key =
4014        SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
4015    if (!key->IsUndefined()) return true;
4016  }
4017  return false;
4018}
4019
4020
4021// Check whether this object references another object.
4022bool JSObject::ReferencesObject(Object* obj) {
4023  Map* map_of_this = map();
4024  Heap* heap = GetHeap();
4025  AssertNoAllocation no_alloc;
4026
4027  // Is the object the constructor for this object?
4028  if (map_of_this->constructor() == obj) {
4029    return true;
4030  }
4031
4032  // Is the object the prototype for this object?
4033  if (map_of_this->prototype() == obj) {
4034    return true;
4035  }
4036
4037  // Check if the object is among the named properties.
4038  Object* key = SlowReverseLookup(obj);
4039  if (!key->IsUndefined()) {
4040    return true;
4041  }
4042
4043  // Check if the object is among the indexed properties.
4044  ElementsKind kind = GetElementsKind();
4045  switch (kind) {
4046    case EXTERNAL_PIXEL_ELEMENTS:
4047    case EXTERNAL_BYTE_ELEMENTS:
4048    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4049    case EXTERNAL_SHORT_ELEMENTS:
4050    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4051    case EXTERNAL_INT_ELEMENTS:
4052    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4053    case EXTERNAL_FLOAT_ELEMENTS:
4054    case EXTERNAL_DOUBLE_ELEMENTS:
4055    case FAST_DOUBLE_ELEMENTS:
4056      // Raw pixels and external arrays do not reference other
4057      // objects.
4058      break;
4059    case FAST_SMI_ONLY_ELEMENTS:
4060      break;
4061    case FAST_ELEMENTS:
4062    case DICTIONARY_ELEMENTS: {
4063      FixedArray* elements = FixedArray::cast(this->elements());
4064      if (ReferencesObjectFromElements(elements, kind, obj)) return true;
4065      break;
4066    }
4067    case NON_STRICT_ARGUMENTS_ELEMENTS: {
4068      FixedArray* parameter_map = FixedArray::cast(elements());
4069      // Check the mapped parameters.
4070      int length = parameter_map->length();
4071      for (int i = 2; i < length; ++i) {
4072        Object* value = parameter_map->get(i);
4073        if (!value->IsTheHole() && value == obj) return true;
4074      }
4075      // Check the arguments.
4076      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4077      kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4078      if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
4079      break;
4080    }
4081  }
4082
4083  // For functions check the context.
4084  if (IsJSFunction()) {
4085    // Get the constructor function for arguments array.
4086    JSObject* arguments_boilerplate =
4087        heap->isolate()->context()->global_context()->
4088            arguments_boilerplate();
4089    JSFunction* arguments_function =
4090        JSFunction::cast(arguments_boilerplate->map()->constructor());
4091
4092    // Get the context and don't check if it is the global context.
4093    JSFunction* f = JSFunction::cast(this);
4094    Context* context = f->context();
4095    if (context->IsGlobalContext()) {
4096      return false;
4097    }
4098
4099    // Check the non-special context slots.
4100    for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4101      // Only check JS objects.
4102      if (context->get(i)->IsJSObject()) {
4103        JSObject* ctxobj = JSObject::cast(context->get(i));
4104        // If it is an arguments array check the content.
4105        if (ctxobj->map()->constructor() == arguments_function) {
4106          if (ctxobj->ReferencesObject(obj)) {
4107            return true;
4108          }
4109        } else if (ctxobj == obj) {
4110          return true;
4111        }
4112      }
4113    }
4114
4115    // Check the context extension (if any) if it can have references.
4116    if (context->has_extension() && !context->IsCatchContext()) {
4117      return JSObject::cast(context->extension())->ReferencesObject(obj);
4118    }
4119  }
4120
4121  // No references to object.
4122  return false;
4123}
4124
4125
4126Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
4127  CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
4128}
4129
4130
4131MaybeObject* JSObject::PreventExtensions() {
4132  Isolate* isolate = GetIsolate();
4133  if (IsAccessCheckNeeded() &&
4134      !isolate->MayNamedAccess(this,
4135                               isolate->heap()->undefined_value(),
4136                               v8::ACCESS_KEYS)) {
4137    isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4138    return isolate->heap()->false_value();
4139  }
4140
4141  if (IsJSGlobalProxy()) {
4142    Object* proto = GetPrototype();
4143    if (proto->IsNull()) return this;
4144    ASSERT(proto->IsJSGlobalObject());
4145    return JSObject::cast(proto)->PreventExtensions();
4146  }
4147
4148  // It's not possible to seal objects with external array elements
4149  if (HasExternalArrayElements()) {
4150    HandleScope scope(isolate);
4151    Handle<Object> object(this);
4152    Handle<Object> error  =
4153        isolate->factory()->NewTypeError(
4154            "cant_prevent_ext_external_array_elements",
4155            HandleVector(&object, 1));
4156    return isolate->Throw(*error);
4157  }
4158
4159  // If there are fast elements we normalize.
4160  SeededNumberDictionary* dictionary = NULL;
4161  { MaybeObject* maybe = NormalizeElements();
4162    if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
4163  }
4164  ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4165  // Make sure that we never go back to fast case.
4166  dictionary->set_requires_slow_elements();
4167
4168  // Do a map transition, other objects with this map may still
4169  // be extensible.
4170  Map* new_map;
4171  { MaybeObject* maybe = map()->CopyDropTransitions();
4172    if (!maybe->To<Map>(&new_map)) return maybe;
4173  }
4174  new_map->set_is_extensible(false);
4175  set_map(new_map);
4176  ASSERT(!map()->is_extensible());
4177  return new_map;
4178}
4179
4180
4181// Tests for the fast common case for property enumeration:
4182// - This object and all prototypes has an enum cache (which means that
4183//   it is no proxy, has no interceptors and needs no access checks).
4184// - This object has no elements.
4185// - No prototype has enumerable properties/elements.
4186bool JSReceiver::IsSimpleEnum() {
4187  Heap* heap = GetHeap();
4188  for (Object* o = this;
4189       o != heap->null_value();
4190       o = JSObject::cast(o)->GetPrototype()) {
4191    if (!o->IsJSObject()) return false;
4192    JSObject* curr = JSObject::cast(o);
4193    if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
4194    ASSERT(!curr->HasNamedInterceptor());
4195    ASSERT(!curr->HasIndexedInterceptor());
4196    ASSERT(!curr->IsAccessCheckNeeded());
4197    if (curr->NumberOfEnumElements() > 0) return false;
4198    if (curr != this) {
4199      FixedArray* curr_fixed_array =
4200          FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
4201      if (curr_fixed_array->length() > 0) return false;
4202    }
4203  }
4204  return true;
4205}
4206
4207
4208int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
4209  int result = 0;
4210  DescriptorArray* descs = instance_descriptors();
4211  for (int i = 0; i < descs->number_of_descriptors(); i++) {
4212    PropertyDetails details(descs->GetDetails(i));
4213    if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
4214      result++;
4215    }
4216  }
4217  return result;
4218}
4219
4220
4221int Map::PropertyIndexFor(String* name) {
4222  DescriptorArray* descs = instance_descriptors();
4223  for (int i = 0; i < descs->number_of_descriptors(); i++) {
4224    if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4225      return descs->GetFieldIndex(i);
4226    }
4227  }
4228  return -1;
4229}
4230
4231
4232int Map::NextFreePropertyIndex() {
4233  int max_index = -1;
4234  DescriptorArray* descs = instance_descriptors();
4235  for (int i = 0; i < descs->number_of_descriptors(); i++) {
4236    if (descs->GetType(i) == FIELD) {
4237      int current_index = descs->GetFieldIndex(i);
4238      if (current_index > max_index) max_index = current_index;
4239    }
4240  }
4241  return max_index + 1;
4242}
4243
4244
4245AccessorDescriptor* Map::FindAccessor(String* name) {
4246  DescriptorArray* descs = instance_descriptors();
4247  for (int i = 0; i < descs->number_of_descriptors(); i++) {
4248    if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4249      return descs->GetCallbacks(i);
4250    }
4251  }
4252  return NULL;
4253}
4254
4255
4256void JSReceiver::LocalLookup(String* name, LookupResult* result) {
4257  ASSERT(name->IsString());
4258
4259  Heap* heap = GetHeap();
4260
4261  if (IsJSGlobalProxy()) {
4262    Object* proto = GetPrototype();
4263    if (proto->IsNull()) return result->NotFound();
4264    ASSERT(proto->IsJSGlobalObject());
4265    return JSReceiver::cast(proto)->LocalLookup(name, result);
4266  }
4267
4268  if (IsJSProxy()) {
4269    result->HandlerResult(JSProxy::cast(this));
4270    return;
4271  }
4272
4273  // Do not use inline caching if the object is a non-global object
4274  // that requires access checks.
4275  if (IsAccessCheckNeeded()) {
4276    result->DisallowCaching();
4277  }
4278
4279  JSObject* js_object = JSObject::cast(this);
4280
4281  // Check __proto__ before interceptor.
4282  if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
4283    result->ConstantResult(js_object);
4284    return;
4285  }
4286
4287  // Check for lookup interceptor except when bootstrapping.
4288  if (js_object->HasNamedInterceptor() &&
4289      !heap->isolate()->bootstrapper()->IsActive()) {
4290    result->InterceptorResult(js_object);
4291    return;
4292  }
4293
4294  js_object->LocalLookupRealNamedProperty(name, result);
4295}
4296
4297
4298void JSReceiver::Lookup(String* name, LookupResult* result) {
4299  // Ecma-262 3rd 8.6.2.4
4300  Heap* heap = GetHeap();
4301  for (Object* current = this;
4302       current != heap->null_value();
4303       current = JSObject::cast(current)->GetPrototype()) {
4304    JSReceiver::cast(current)->LocalLookup(name, result);
4305    if (result->IsProperty()) return;
4306  }
4307  result->NotFound();
4308}
4309
4310
4311// Search object and it's prototype chain for callback properties.
4312void JSObject::LookupCallback(String* name, LookupResult* result) {
4313  Heap* heap = GetHeap();
4314  for (Object* current = this;
4315       current != heap->null_value() && current->IsJSObject();
4316       current = JSObject::cast(current)->GetPrototype()) {
4317    JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
4318    if (result->IsFound() && result->type() == CALLBACKS) return;
4319  }
4320  result->NotFound();
4321}
4322
4323
4324// Try to update an accessor in an elements dictionary. Return true if the
4325// update succeeded, and false otherwise.
4326static bool UpdateGetterSetterInDictionary(
4327    SeededNumberDictionary* dictionary,
4328    uint32_t index,
4329    Object* getter,
4330    Object* setter,
4331    PropertyAttributes attributes) {
4332  int entry = dictionary->FindEntry(index);
4333  if (entry != SeededNumberDictionary::kNotFound) {
4334    Object* result = dictionary->ValueAt(entry);
4335    PropertyDetails details = dictionary->DetailsAt(entry);
4336    if (details.type() == CALLBACKS && result->IsAccessorPair()) {
4337      ASSERT(!details.IsDontDelete());
4338      if (details.attributes() != attributes) {
4339        dictionary->DetailsAtPut(entry,
4340                                 PropertyDetails(attributes, CALLBACKS, index));
4341      }
4342      AccessorPair::cast(result)->SetComponents(getter, setter);
4343      return true;
4344    }
4345  }
4346  return false;
4347}
4348
4349
4350MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
4351                                             Object* getter,
4352                                             Object* setter,
4353                                             PropertyAttributes attributes) {
4354  switch (GetElementsKind()) {
4355    case FAST_SMI_ONLY_ELEMENTS:
4356    case FAST_ELEMENTS:
4357    case FAST_DOUBLE_ELEMENTS:
4358      break;
4359    case EXTERNAL_PIXEL_ELEMENTS:
4360    case EXTERNAL_BYTE_ELEMENTS:
4361    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4362    case EXTERNAL_SHORT_ELEMENTS:
4363    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4364    case EXTERNAL_INT_ELEMENTS:
4365    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4366    case EXTERNAL_FLOAT_ELEMENTS:
4367    case EXTERNAL_DOUBLE_ELEMENTS:
4368      // Ignore getters and setters on pixel and external array elements.
4369      return GetHeap()->undefined_value();
4370    case DICTIONARY_ELEMENTS:
4371      if (UpdateGetterSetterInDictionary(element_dictionary(),
4372                                         index,
4373                                         getter,
4374                                         setter,
4375                                         attributes)) {
4376        return GetHeap()->undefined_value();
4377      }
4378      break;
4379    case NON_STRICT_ARGUMENTS_ELEMENTS: {
4380      // Ascertain whether we have read-only properties or an existing
4381      // getter/setter pair in an arguments elements dictionary backing
4382      // store.
4383      FixedArray* parameter_map = FixedArray::cast(elements());
4384      uint32_t length = parameter_map->length();
4385      Object* probe =
4386          index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4387      if (probe == NULL || probe->IsTheHole()) {
4388        FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4389        if (arguments->IsDictionary()) {
4390          SeededNumberDictionary* dictionary =
4391              SeededNumberDictionary::cast(arguments);
4392          if (UpdateGetterSetterInDictionary(dictionary,
4393                                             index,
4394                                             getter,
4395                                             setter,
4396                                             attributes)) {
4397            return GetHeap()->undefined_value();
4398          }
4399        }
4400      }
4401      break;
4402    }
4403  }
4404
4405  AccessorPair* accessors;
4406  { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4407    if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4408  }
4409  accessors->SetComponents(getter, setter);
4410
4411  return SetElementCallback(index, accessors, attributes);
4412}
4413
4414
4415MaybeObject* JSObject::DefinePropertyAccessor(String* name,
4416                                              Object* getter,
4417                                              Object* setter,
4418                                              PropertyAttributes attributes) {
4419  // Lookup the name.
4420  LookupResult result(GetHeap()->isolate());
4421  LocalLookupRealNamedProperty(name, &result);
4422  if (result.IsFound()) {
4423    if (result.type() == CALLBACKS) {
4424      ASSERT(!result.IsDontDelete());
4425      Object* obj = result.GetCallbackObject();
4426      // Need to preserve old getters/setters.
4427      if (obj->IsAccessorPair()) {
4428        AccessorPair* copy;
4429        { MaybeObject* maybe_copy =
4430              AccessorPair::cast(obj)->CopyWithoutTransitions();
4431          if (!maybe_copy->To(&copy)) return maybe_copy;
4432        }
4433        copy->SetComponents(getter, setter);
4434        // Use set to update attributes.
4435        return SetPropertyCallback(name, copy, attributes);
4436      }
4437    }
4438  }
4439
4440  AccessorPair* accessors;
4441  { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4442    if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4443  }
4444  accessors->SetComponents(getter, setter);
4445
4446  return SetPropertyCallback(name, accessors, attributes);
4447}
4448
4449
4450bool JSObject::CanSetCallback(String* name) {
4451  ASSERT(!IsAccessCheckNeeded() ||
4452         GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
4453
4454  // Check if there is an API defined callback object which prohibits
4455  // callback overwriting in this object or it's prototype chain.
4456  // This mechanism is needed for instance in a browser setting, where
4457  // certain accessors such as window.location should not be allowed
4458  // to be overwritten because allowing overwriting could potentially
4459  // cause security problems.
4460  LookupResult callback_result(GetIsolate());
4461  LookupCallback(name, &callback_result);
4462  if (callback_result.IsProperty()) {
4463    Object* obj = callback_result.GetCallbackObject();
4464    if (obj->IsAccessorInfo() &&
4465        AccessorInfo::cast(obj)->prohibits_overwriting()) {
4466      return false;
4467    }
4468  }
4469
4470  return true;
4471}
4472
4473
4474MaybeObject* JSObject::SetElementCallback(uint32_t index,
4475                                          Object* structure,
4476                                          PropertyAttributes attributes) {
4477  PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4478
4479  // Normalize elements to make this operation simple.
4480  SeededNumberDictionary* dictionary;
4481  { MaybeObject* maybe_dictionary = NormalizeElements();
4482    if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
4483  }
4484  ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4485
4486  // Update the dictionary with the new CALLBACKS property.
4487  { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
4488    if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
4489  }
4490
4491  dictionary->set_requires_slow_elements();
4492  // Update the dictionary backing store on the object.
4493  if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4494    // Also delete any parameter alias.
4495    //
4496    // TODO(kmillikin): when deleting the last parameter alias we could
4497    // switch to a direct backing store without the parameter map.  This
4498    // would allow GC of the context.
4499    FixedArray* parameter_map = FixedArray::cast(elements());
4500    if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
4501      parameter_map->set(index + 2, GetHeap()->the_hole_value());
4502    }
4503    parameter_map->set(1, dictionary);
4504  } else {
4505    set_elements(dictionary);
4506  }
4507
4508  return GetHeap()->undefined_value();
4509}
4510
4511
4512MaybeObject* JSObject::SetPropertyCallback(String* name,
4513                                           Object* structure,
4514                                           PropertyAttributes attributes) {
4515  // Normalize object to make this operation simple.
4516  { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4517    if (maybe_ok->IsFailure()) return maybe_ok;
4518  }
4519
4520  // For the global object allocate a new map to invalidate the global inline
4521  // caches which have a global property cell reference directly in the code.
4522  if (IsGlobalObject()) {
4523    Map* new_map;
4524    { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
4525      if (!maybe_new_map->To(&new_map)) return maybe_new_map;
4526    }
4527    set_map(new_map);
4528    // When running crankshaft, changing the map is not enough. We
4529    // need to deoptimize all functions that rely on this global
4530    // object.
4531    Deoptimizer::DeoptimizeGlobalObject(this);
4532  }
4533
4534  // Update the dictionary with the new CALLBACKS property.
4535  PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4536  { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details);
4537    if (maybe_ok->IsFailure()) return maybe_ok;
4538  }
4539
4540  return GetHeap()->undefined_value();
4541}
4542
4543
4544void JSObject::DefineAccessor(Handle<JSObject> object,
4545                              Handle<String> name,
4546                              Handle<Object> getter,
4547                              Handle<Object> setter,
4548                              PropertyAttributes attributes) {
4549  CALL_HEAP_FUNCTION_VOID(
4550      object->GetIsolate(),
4551      object->DefineAccessor(*name, *getter, *setter, attributes));
4552}
4553
4554MaybeObject* JSObject::DefineAccessor(String* name,
4555                                      Object* getter,
4556                                      Object* setter,
4557                                      PropertyAttributes attributes) {
4558  Isolate* isolate = GetIsolate();
4559  // Check access rights if needed.
4560  if (IsAccessCheckNeeded() &&
4561      !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4562    isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4563    return isolate->heap()->undefined_value();
4564  }
4565
4566  if (IsJSGlobalProxy()) {
4567    Object* proto = GetPrototype();
4568    if (proto->IsNull()) return this;
4569    ASSERT(proto->IsJSGlobalObject());
4570    return JSObject::cast(proto)->DefineAccessor(
4571        name, getter, setter, attributes);
4572  }
4573
4574  // Make sure that the top context does not change when doing callbacks or
4575  // interceptor calls.
4576  AssertNoContextChange ncc;
4577
4578  // Try to flatten before operating on the string.
4579  name->TryFlatten();
4580
4581  if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4582
4583  uint32_t index = 0;
4584  return name->AsArrayIndex(&index) ?
4585      DefineElementAccessor(index, getter, setter, attributes) :
4586      DefinePropertyAccessor(name, getter, setter, attributes);
4587}
4588
4589
4590MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
4591  Isolate* isolate = GetIsolate();
4592  String* name = String::cast(info->name());
4593  // Check access rights if needed.
4594  if (IsAccessCheckNeeded() &&
4595      !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4596    isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4597    return isolate->heap()->undefined_value();
4598  }
4599
4600  if (IsJSGlobalProxy()) {
4601    Object* proto = GetPrototype();
4602    if (proto->IsNull()) return this;
4603    ASSERT(proto->IsJSGlobalObject());
4604    return JSObject::cast(proto)->DefineAccessor(info);
4605  }
4606
4607  // Make sure that the top context does not change when doing callbacks or
4608  // interceptor calls.
4609  AssertNoContextChange ncc;
4610
4611  // Try to flatten before operating on the string.
4612  name->TryFlatten();
4613
4614  if (!CanSetCallback(name)) {
4615    return isolate->heap()->undefined_value();
4616  }
4617
4618  uint32_t index = 0;
4619  bool is_element = name->AsArrayIndex(&index);
4620
4621  if (is_element) {
4622    if (IsJSArray()) return isolate->heap()->undefined_value();
4623
4624    // Accessors overwrite previous callbacks (cf. with getters/setters).
4625    switch (GetElementsKind()) {
4626      case FAST_SMI_ONLY_ELEMENTS:
4627      case FAST_ELEMENTS:
4628      case FAST_DOUBLE_ELEMENTS:
4629        break;
4630      case EXTERNAL_PIXEL_ELEMENTS:
4631      case EXTERNAL_BYTE_ELEMENTS:
4632      case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4633      case EXTERNAL_SHORT_ELEMENTS:
4634      case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4635      case EXTERNAL_INT_ELEMENTS:
4636      case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4637      case EXTERNAL_FLOAT_ELEMENTS:
4638      case EXTERNAL_DOUBLE_ELEMENTS:
4639        // Ignore getters and setters on pixel and external array
4640        // elements.
4641        return isolate->heap()->undefined_value();
4642      case DICTIONARY_ELEMENTS:
4643        break;
4644      case NON_STRICT_ARGUMENTS_ELEMENTS:
4645        UNIMPLEMENTED();
4646        break;
4647    }
4648
4649    { MaybeObject* maybe_ok =
4650          SetElementCallback(index, info, info->property_attributes());
4651      if (maybe_ok->IsFailure()) return maybe_ok;
4652    }
4653  } else {
4654    // Lookup the name.
4655    LookupResult result(isolate);
4656    LocalLookup(name, &result);
4657    // ES5 forbids turning a property into an accessor if it's not
4658    // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4659    if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
4660      return isolate->heap()->undefined_value();
4661    }
4662    { MaybeObject* maybe_ok =
4663          SetPropertyCallback(name, info, info->property_attributes());
4664      if (maybe_ok->IsFailure()) return maybe_ok;
4665    }
4666  }
4667
4668  return this;
4669}
4670
4671
4672Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
4673  Heap* heap = GetHeap();
4674
4675  // Make sure that the top context does not change when doing callbacks or
4676  // interceptor calls.
4677  AssertNoContextChange ncc;
4678
4679  // Check access rights if needed.
4680  if (IsAccessCheckNeeded() &&
4681      !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4682    heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4683    return heap->undefined_value();
4684  }
4685
4686  // Make the lookup and include prototypes.
4687  uint32_t index = 0;
4688  if (name->AsArrayIndex(&index)) {
4689    for (Object* obj = this;
4690         obj != heap->null_value();
4691         obj = JSObject::cast(obj)->GetPrototype()) {
4692      JSObject* js_object = JSObject::cast(obj);
4693      if (js_object->HasDictionaryElements()) {
4694        SeededNumberDictionary* dictionary = js_object->element_dictionary();
4695        int entry = dictionary->FindEntry(index);
4696        if (entry != SeededNumberDictionary::kNotFound) {
4697          Object* element = dictionary->ValueAt(entry);
4698          if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
4699              element->IsAccessorPair()) {
4700            return AccessorPair::cast(element)->GetComponent(component);
4701          }
4702        }
4703      }
4704    }
4705  } else {
4706    for (Object* obj = this;
4707         obj != heap->null_value();
4708         obj = JSObject::cast(obj)->GetPrototype()) {
4709      LookupResult result(heap->isolate());
4710      JSObject::cast(obj)->LocalLookup(name, &result);
4711      if (result.IsProperty()) {
4712        if (result.IsReadOnly()) return heap->undefined_value();
4713        if (result.type() == CALLBACKS) {
4714          Object* obj = result.GetCallbackObject();
4715          if (obj->IsAccessorPair()) {
4716            return AccessorPair::cast(obj)->GetComponent(component);
4717          }
4718        }
4719      }
4720    }
4721  }
4722  return heap->undefined_value();
4723}
4724
4725
4726Object* JSObject::SlowReverseLookup(Object* value) {
4727  if (HasFastProperties()) {
4728    DescriptorArray* descs = map()->instance_descriptors();
4729    for (int i = 0; i < descs->number_of_descriptors(); i++) {
4730      if (descs->GetType(i) == FIELD) {
4731        if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4732          return descs->GetKey(i);
4733        }
4734      } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4735        if (descs->GetConstantFunction(i) == value) {
4736          return descs->GetKey(i);
4737        }
4738      }
4739    }
4740    return GetHeap()->undefined_value();
4741  } else {
4742    return property_dictionary()->SlowReverseLookup(value);
4743  }
4744}
4745
4746
4747MaybeObject* Map::CopyDropDescriptors() {
4748  Heap* heap = GetHeap();
4749  Object* result;
4750  { MaybeObject* maybe_result =
4751        heap->AllocateMap(instance_type(), instance_size());
4752    if (!maybe_result->ToObject(&result)) return maybe_result;
4753  }
4754  Map::cast(result)->set_prototype(prototype());
4755  Map::cast(result)->set_constructor(constructor());
4756  // Don't copy descriptors, so map transitions always remain a forest.
4757  // If we retained the same descriptors we would have two maps
4758  // pointing to the same transition which is bad because the garbage
4759  // collector relies on being able to reverse pointers from transitions
4760  // to maps.  If properties need to be retained use CopyDropTransitions.
4761  Map::cast(result)->clear_instance_descriptors();
4762  // Please note instance_type and instance_size are set when allocated.
4763  Map::cast(result)->set_inobject_properties(inobject_properties());
4764  Map::cast(result)->set_unused_property_fields(unused_property_fields());
4765
4766  // If the map has pre-allocated properties always start out with a descriptor
4767  // array describing these properties.
4768  if (pre_allocated_property_fields() > 0) {
4769    ASSERT(constructor()->IsJSFunction());
4770    JSFunction* ctor = JSFunction::cast(constructor());
4771    Object* descriptors;
4772    { MaybeObject* maybe_descriptors =
4773          ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4774      if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4775    }
4776    Map::cast(result)->set_instance_descriptors(
4777        DescriptorArray::cast(descriptors));
4778    Map::cast(result)->set_pre_allocated_property_fields(
4779        pre_allocated_property_fields());
4780  }
4781  Map::cast(result)->set_bit_field(bit_field());
4782  Map::cast(result)->set_bit_field2(bit_field2());
4783  Map::cast(result)->set_bit_field3(bit_field3());
4784  Map::cast(result)->set_is_shared(false);
4785  Map::cast(result)->ClearCodeCache(heap);
4786  return result;
4787}
4788
4789
4790MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4791                                 NormalizedMapSharingMode sharing) {
4792  int new_instance_size = instance_size();
4793  if (mode == CLEAR_INOBJECT_PROPERTIES) {
4794    new_instance_size -= inobject_properties() * kPointerSize;
4795  }
4796
4797  Object* result;
4798  { MaybeObject* maybe_result =
4799        GetHeap()->AllocateMap(instance_type(), new_instance_size);
4800    if (!maybe_result->ToObject(&result)) return maybe_result;
4801  }
4802
4803  if (mode != CLEAR_INOBJECT_PROPERTIES) {
4804    Map::cast(result)->set_inobject_properties(inobject_properties());
4805  }
4806
4807  Map::cast(result)->set_prototype(prototype());
4808  Map::cast(result)->set_constructor(constructor());
4809
4810  Map::cast(result)->set_bit_field(bit_field());
4811  Map::cast(result)->set_bit_field2(bit_field2());
4812  Map::cast(result)->set_bit_field3(bit_field3());
4813
4814  Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4815
4816#ifdef DEBUG
4817  if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
4818    Map::cast(result)->SharedMapVerify();
4819  }
4820#endif
4821
4822  return result;
4823}
4824
4825
4826MaybeObject* Map::CopyDropTransitions() {
4827  Object* new_map;
4828  { MaybeObject* maybe_new_map = CopyDropDescriptors();
4829    if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4830  }
4831  Object* descriptors;
4832  { MaybeObject* maybe_descriptors =
4833        instance_descriptors()->RemoveTransitions();
4834    if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4835  }
4836  cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
4837  return new_map;
4838}
4839
4840void Map::UpdateCodeCache(Handle<Map> map,
4841                          Handle<String> name,
4842                          Handle<Code> code) {
4843  Isolate* isolate = map->GetIsolate();
4844  CALL_HEAP_FUNCTION_VOID(isolate,
4845                          map->UpdateCodeCache(*name, *code));
4846}
4847
4848MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
4849  // Allocate the code cache if not present.
4850  if (code_cache()->IsFixedArray()) {
4851    Object* result;
4852    { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
4853      if (!maybe_result->ToObject(&result)) return maybe_result;
4854    }
4855    set_code_cache(result);
4856  }
4857
4858  // Update the code cache.
4859  return CodeCache::cast(code_cache())->Update(name, code);
4860}
4861
4862
4863Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4864  // Do a lookup if a code cache exists.
4865  if (!code_cache()->IsFixedArray()) {
4866    return CodeCache::cast(code_cache())->Lookup(name, flags);
4867  } else {
4868    return GetHeap()->undefined_value();
4869  }
4870}
4871
4872
4873int Map::IndexInCodeCache(Object* name, Code* code) {
4874  // Get the internal index if a code cache exists.
4875  if (!code_cache()->IsFixedArray()) {
4876    return CodeCache::cast(code_cache())->GetIndex(name, code);
4877  }
4878  return -1;
4879}
4880
4881
4882void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4883  // No GC is supposed to happen between a call to IndexInCodeCache and
4884  // RemoveFromCodeCache so the code cache must be there.
4885  ASSERT(!code_cache()->IsFixedArray());
4886  CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4887}
4888
4889
4890// An iterator over all map transitions in an descriptor array, reusing the map
4891// field of the contens array while it is running.
4892class IntrusiveMapTransitionIterator {
4893 public:
4894  explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
4895      : descriptor_array_(descriptor_array) { }
4896
4897  void Start() {
4898    ASSERT(!IsIterating());
4899    if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
4900  }
4901
4902  bool IsIterating() {
4903    return HasContentArray() && (*ContentHeader())->IsSmi();
4904  }
4905
4906  Map* Next() {
4907    ASSERT(IsIterating());
4908    FixedArray* contents = ContentArray();
4909    // Attention, tricky index manipulation ahead: Every entry in the contents
4910    // array consists of a value/details pair, so the index is typically even.
4911    // An exception is made for CALLBACKS entries: An even index means we look
4912    // at its getter, and an odd index means we look at its setter.
4913    int index = Smi::cast(*ContentHeader())->value();
4914    while (index < contents->length()) {
4915      PropertyDetails details(Smi::cast(contents->get(index | 1)));
4916      switch (details.type()) {
4917        case MAP_TRANSITION:
4918        case CONSTANT_TRANSITION:
4919        case ELEMENTS_TRANSITION:
4920          // We definitely have a map transition.
4921          *ContentHeader() = Smi::FromInt(index + 2);
4922          return static_cast<Map*>(contents->get(index));
4923        case CALLBACKS: {
4924          // We might have a map transition in a getter or in a setter.
4925          AccessorPair* accessors =
4926              static_cast<AccessorPair*>(contents->get(index & ~1));
4927          Object* accessor =
4928              ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4929          index++;
4930          if (accessor->IsMap()) {
4931            *ContentHeader() = Smi::FromInt(index);
4932            return static_cast<Map*>(accessor);
4933          }
4934          break;
4935        }
4936        case NORMAL:
4937        case FIELD:
4938        case CONSTANT_FUNCTION:
4939        case HANDLER:
4940        case INTERCEPTOR:
4941        case NULL_DESCRIPTOR:
4942          // We definitely have no map transition.
4943          index += 2;
4944          break;
4945      }
4946    }
4947    *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4948    return NULL;
4949  }
4950
4951 private:
4952  bool HasContentArray() {
4953    return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
4954  }
4955
4956  FixedArray* ContentArray() {
4957    Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
4958    return static_cast<FixedArray*>(array);
4959  }
4960
4961  Object** ContentHeader() {
4962    return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
4963  }
4964
4965  DescriptorArray* descriptor_array_;
4966};
4967
4968
4969// An iterator over all prototype transitions, reusing the map field of the
4970// underlying array while it is running.
4971class IntrusivePrototypeTransitionIterator {
4972 public:
4973  explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
4974      : proto_trans_(proto_trans) { }
4975
4976  void Start() {
4977    ASSERT(!IsIterating());
4978    if (HasTransitions()) *Header() = Smi::FromInt(0);
4979  }
4980
4981  bool IsIterating() {
4982    return HasTransitions() && (*Header())->IsSmi();
4983  }
4984
4985  Map* Next() {
4986    ASSERT(IsIterating());
4987    int transitionNumber = Smi::cast(*Header())->value();
4988    if (transitionNumber < NumberOfTransitions()) {
4989      *Header() = Smi::FromInt(transitionNumber + 1);
4990      return GetTransition(transitionNumber);
4991    }
4992    *Header() = proto_trans_->GetHeap()->fixed_array_map();
4993    return NULL;
4994  }
4995
4996 private:
4997  bool HasTransitions() {
4998    return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
4999  }
5000
5001  Object** Header() {
5002    return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
5003  }
5004
5005  int NumberOfTransitions() {
5006    Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5007    return Smi::cast(num)->value();
5008  }
5009
5010  Map* GetTransition(int transitionNumber) {
5011    return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5012  }
5013
5014  int IndexFor(int transitionNumber) {
5015    return Map::kProtoTransitionHeaderSize +
5016        Map::kProtoTransitionMapOffset +
5017        transitionNumber * Map::kProtoTransitionElementsPerEntry;
5018  }
5019
5020  FixedArray* proto_trans_;
5021};
5022
5023
5024// To traverse the transition tree iteratively, we have to store two kinds of
5025// information in a map: The parent map in the traversal and which children of a
5026// node have already been visited. To do this without additional memory, we
5027// temporarily reuse two maps with known values:
5028//
5029//  (1) The map of the map temporarily holds the parent, and is restored to the
5030//      meta map afterwards.
5031//
5032//  (2) The info which children have already been visited depends on which part
5033//      of the map we currently iterate:
5034//
5035//    (a) If we currently follow normal map transitions, we temporarily store
5036//        the current index in the map of the FixedArray of the desciptor
5037//        array's contents, and restore it to the fixed array map afterwards.
5038//        Note that a single descriptor can have 0, 1, or 2 transitions.
5039//
5040//    (b) If we currently follow prototype transitions, we temporarily store
5041//        the current index in the map of the FixedArray holding the prototype
5042//        transitions, and restore it to the fixed array map afterwards.
5043//
5044// Note that the child iterator is just a concatenation of two iterators: One
5045// iterating over map transitions and one iterating over prototype transisitons.
5046class TraversableMap : public Map {
5047 public:
5048  // Record the parent in the traversal within this map. Note that this destroys
5049  // this map's map!
5050  void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5051
5052  // Reset the current map's map, returning the parent previously stored in it.
5053  TraversableMap* GetAndResetParent() {
5054    TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5055    set_map_no_write_barrier(GetHeap()->meta_map());
5056    return old_parent;
5057  }
5058
5059  // Start iterating over this map's children, possibly destroying a FixedArray
5060  // map (see explanation above).
5061  void ChildIteratorStart() {
5062    IntrusiveMapTransitionIterator(instance_descriptors()).Start();
5063    IntrusivePrototypeTransitionIterator(
5064        unchecked_prototype_transitions()).Start();
5065  }
5066
5067  // If we have an unvisited child map, return that one and advance. If we have
5068  // none, return NULL and reset any destroyed FixedArray maps.
5069  TraversableMap* ChildIteratorNext() {
5070    IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5071    if (descriptor_iterator.IsIterating()) {
5072      Map* next = descriptor_iterator.Next();
5073      if (next != NULL) return static_cast<TraversableMap*>(next);
5074    }
5075    IntrusivePrototypeTransitionIterator
5076        proto_iterator(unchecked_prototype_transitions());
5077    if (proto_iterator.IsIterating()) {
5078      Map* next = proto_iterator.Next();
5079      if (next != NULL) return static_cast<TraversableMap*>(next);
5080    }
5081    return NULL;
5082  }
5083};
5084
5085
5086// Traverse the transition tree in postorder without using the C++ stack by
5087// doing pointer reversal.
5088void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
5089  TraversableMap* current = static_cast<TraversableMap*>(this);
5090  current->ChildIteratorStart();
5091  while (true) {
5092    TraversableMap* child = current->ChildIteratorNext();
5093    if (child != NULL) {
5094      child->ChildIteratorStart();
5095      child->SetParent(current);
5096      current = child;
5097    } else {
5098      TraversableMap* parent = current->GetAndResetParent();
5099      callback(current, data);
5100      if (current == this) break;
5101      current = parent;
5102    }
5103  }
5104}
5105
5106
5107MaybeObject* CodeCache::Update(String* name, Code* code) {
5108  // The number of monomorphic stubs for normal load/store/call IC's can grow to
5109  // a large number and therefore they need to go into a hash table. They are
5110  // used to load global properties from cells.
5111  if (code->type() == NORMAL) {
5112    // Make sure that a hash table is allocated for the normal load code cache.
5113    if (normal_type_cache()->IsUndefined()) {
5114      Object* result;
5115      { MaybeObject* maybe_result =
5116            CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
5117        if (!maybe_result->ToObject(&result)) return maybe_result;
5118      }
5119      set_normal_type_cache(result);
5120    }
5121    return UpdateNormalTypeCache(name, code);
5122  } else {
5123    ASSERT(default_cache()->IsFixedArray());
5124    return UpdateDefaultCache(name, code);
5125  }
5126}
5127
5128
5129MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
5130  // When updating the default code cache we disregard the type encoded in the
5131  // flags. This allows call constant stubs to overwrite call field
5132  // stubs, etc.
5133  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
5134
5135  // First check whether we can update existing code cache without
5136  // extending it.
5137  FixedArray* cache = default_cache();
5138  int length = cache->length();
5139  int deleted_index = -1;
5140  for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5141    Object* key = cache->get(i);
5142    if (key->IsNull()) {
5143      if (deleted_index < 0) deleted_index = i;
5144      continue;
5145    }
5146    if (key->IsUndefined()) {
5147      if (deleted_index >= 0) i = deleted_index;
5148      cache->set(i + kCodeCacheEntryNameOffset, name);
5149      cache->set(i + kCodeCacheEntryCodeOffset, code);
5150      return this;
5151    }
5152    if (name->Equals(String::cast(key))) {
5153      Code::Flags found =
5154          Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
5155      if (Code::RemoveTypeFromFlags(found) == flags) {
5156        cache->set(i + kCodeCacheEntryCodeOffset, code);
5157        return this;
5158      }
5159    }
5160  }
5161
5162  // Reached the end of the code cache.  If there were deleted
5163  // elements, reuse the space for the first of them.
5164  if (deleted_index >= 0) {
5165    cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
5166    cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
5167    return this;
5168  }
5169
5170  // Extend the code cache with some new entries (at least one). Must be a
5171  // multiple of the entry size.
5172  int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
5173  new_length = new_length - new_length % kCodeCacheEntrySize;
5174  ASSERT((new_length % kCodeCacheEntrySize) == 0);
5175  Object* result;
5176  { MaybeObject* maybe_result = cache->CopySize(new_length);
5177    if (!maybe_result->ToObject(&result)) return maybe_result;
5178  }
5179
5180  // Add the (name, code) pair to the new cache.
5181  cache = FixedArray::cast(result);
5182  cache->set(length + kCodeCacheEntryNameOffset, name);
5183  cache->set(length + kCodeCacheEntryCodeOffset, code);
5184  set_default_cache(cache);
5185  return this;
5186}
5187
5188
5189MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
5190  // Adding a new entry can cause a new cache to be allocated.
5191  CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5192  Object* new_cache;
5193  { MaybeObject* maybe_new_cache = cache->Put(name, code);
5194    if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5195  }
5196  set_normal_type_cache(new_cache);
5197  return this;
5198}
5199
5200
5201Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5202  if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5203    return LookupNormalTypeCache(name, flags);
5204  } else {
5205    return LookupDefaultCache(name, flags);
5206  }
5207}
5208
5209
5210Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5211  FixedArray* cache = default_cache();
5212  int length = cache->length();
5213  for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5214    Object* key = cache->get(i + kCodeCacheEntryNameOffset);
5215    // Skip deleted elements.
5216    if (key->IsNull()) continue;
5217    if (key->IsUndefined()) return key;
5218    if (name->Equals(String::cast(key))) {
5219      Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5220      if (code->flags() == flags) {
5221        return code;
5222      }
5223    }
5224  }
5225  return GetHeap()->undefined_value();
5226}
5227
5228
5229Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5230  if (!normal_type_cache()->IsUndefined()) {
5231    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5232    return cache->Lookup(name, flags);
5233  } else {
5234    return GetHeap()->undefined_value();
5235  }
5236}
5237
5238
5239int CodeCache::GetIndex(Object* name, Code* code) {
5240  if (code->type() == NORMAL) {
5241    if (normal_type_cache()->IsUndefined()) return -1;
5242    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5243    return cache->GetIndex(String::cast(name), code->flags());
5244  }
5245
5246  FixedArray* array = default_cache();
5247  int len = array->length();
5248  for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5249    if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
5250  }
5251  return -1;
5252}
5253
5254
5255void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
5256  if (code->type() == NORMAL) {
5257    ASSERT(!normal_type_cache()->IsUndefined());
5258    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5259    ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
5260    cache->RemoveByIndex(index);
5261  } else {
5262    FixedArray* array = default_cache();
5263    ASSERT(array->length() >= index && array->get(index)->IsCode());
5264    // Use null instead of undefined for deleted elements to distinguish
5265    // deleted elements from unused elements.  This distinction is used
5266    // when looking up in the cache and when updating the cache.
5267    ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5268    array->set_null(index - 1);  // Name.
5269    array->set_null(index);  // Code.
5270  }
5271}
5272
5273
5274// The key in the code cache hash table consists of the property name and the
5275// code object. The actual match is on the name and the code flags. If a key
5276// is created using the flags and not a code object it can only be used for
5277// lookup not to create a new entry.
5278class CodeCacheHashTableKey : public HashTableKey {
5279 public:
5280  CodeCacheHashTableKey(String* name, Code::Flags flags)
5281      : name_(name), flags_(flags), code_(NULL) { }
5282
5283  CodeCacheHashTableKey(String* name, Code* code)
5284      : name_(name),
5285        flags_(code->flags()),
5286        code_(code) { }
5287
5288
5289  bool IsMatch(Object* other) {
5290    if (!other->IsFixedArray()) return false;
5291    FixedArray* pair = FixedArray::cast(other);
5292    String* name = String::cast(pair->get(0));
5293    Code::Flags flags = Code::cast(pair->get(1))->flags();
5294    if (flags != flags_) {
5295      return false;
5296    }
5297    return name_->Equals(name);
5298  }
5299
5300  static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5301    return name->Hash() ^ flags;
5302  }
5303
5304  uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5305
5306  uint32_t HashForObject(Object* obj) {
5307    FixedArray* pair = FixedArray::cast(obj);
5308    String* name = String::cast(pair->get(0));
5309    Code* code = Code::cast(pair->get(1));
5310    return NameFlagsHashHelper(name, code->flags());
5311  }
5312
5313  MUST_USE_RESULT MaybeObject* AsObject() {
5314    ASSERT(code_ != NULL);
5315    Object* obj;
5316    { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
5317      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5318    }
5319    FixedArray* pair = FixedArray::cast(obj);
5320    pair->set(0, name_);
5321    pair->set(1, code_);
5322    return pair;
5323  }
5324
5325 private:
5326  String* name_;
5327  Code::Flags flags_;
5328  // TODO(jkummerow): We should be able to get by without this.
5329  Code* code_;
5330};
5331
5332
5333Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5334  CodeCacheHashTableKey key(name, flags);
5335  int entry = FindEntry(&key);
5336  if (entry == kNotFound) return GetHeap()->undefined_value();
5337  return get(EntryToIndex(entry) + 1);
5338}
5339
5340
5341MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
5342  CodeCacheHashTableKey key(name, code);
5343  Object* obj;
5344  { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5345    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5346  }
5347
5348  // Don't use |this|, as the table might have grown.
5349  CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5350
5351  int entry = cache->FindInsertionEntry(key.Hash());
5352  Object* k;
5353  { MaybeObject* maybe_k = key.AsObject();
5354    if (!maybe_k->ToObject(&k)) return maybe_k;
5355  }
5356
5357  cache->set(EntryToIndex(entry), k);
5358  cache->set(EntryToIndex(entry) + 1, code);
5359  cache->ElementAdded();
5360  return cache;
5361}
5362
5363
5364int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5365  CodeCacheHashTableKey key(name, flags);
5366  int entry = FindEntry(&key);
5367  return (entry == kNotFound) ? -1 : entry;
5368}
5369
5370
5371void CodeCacheHashTable::RemoveByIndex(int index) {
5372  ASSERT(index >= 0);
5373  Heap* heap = GetHeap();
5374  set(EntryToIndex(index), heap->the_hole_value());
5375  set(EntryToIndex(index) + 1, heap->the_hole_value());
5376  ElementRemoved();
5377}
5378
5379
5380void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5381                                  MapHandleList* maps,
5382                                  Code::Flags flags,
5383                                  Handle<Code> code) {
5384  Isolate* isolate = cache->GetIsolate();
5385  CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5386}
5387
5388
5389MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
5390                                          Code::Flags flags,
5391                                          Code* code) {
5392  // Initialize cache if necessary.
5393  if (cache()->IsUndefined()) {
5394    Object* result;
5395    { MaybeObject* maybe_result =
5396          PolymorphicCodeCacheHashTable::Allocate(
5397              PolymorphicCodeCacheHashTable::kInitialSize);
5398      if (!maybe_result->ToObject(&result)) return maybe_result;
5399    }
5400    set_cache(result);
5401  } else {
5402    // This entry shouldn't be contained in the cache yet.
5403    ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5404               ->Lookup(maps, flags)->IsUndefined());
5405  }
5406  PolymorphicCodeCacheHashTable* hash_table =
5407      PolymorphicCodeCacheHashTable::cast(cache());
5408  Object* new_cache;
5409  { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5410    if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5411  }
5412  set_cache(new_cache);
5413  return this;
5414}
5415
5416
5417Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5418                                            Code::Flags flags) {
5419  if (!cache()->IsUndefined()) {
5420    PolymorphicCodeCacheHashTable* hash_table =
5421        PolymorphicCodeCacheHashTable::cast(cache());
5422    return Handle<Object>(hash_table->Lookup(maps, flags));
5423  } else {
5424    return GetIsolate()->factory()->undefined_value();
5425  }
5426}
5427
5428
5429// Despite their name, object of this class are not stored in the actual
5430// hash table; instead they're temporarily used for lookups. It is therefore
5431// safe to have a weak (non-owning) pointer to a MapList as a member field.
5432class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5433 public:
5434  // Callers must ensure that |maps| outlives the newly constructed object.
5435  PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
5436      : maps_(maps),
5437        code_flags_(code_flags) {}
5438
5439  bool IsMatch(Object* other) {
5440    MapHandleList other_maps(kDefaultListAllocationSize);
5441    int other_flags;
5442    FromObject(other, &other_flags, &other_maps);
5443    if (code_flags_ != other_flags) return false;
5444    if (maps_->length() != other_maps.length()) return false;
5445    // Compare just the hashes first because it's faster.
5446    int this_hash = MapsHashHelper(maps_, code_flags_);
5447    int other_hash = MapsHashHelper(&other_maps, other_flags);
5448    if (this_hash != other_hash) return false;
5449
5450    // Full comparison: for each map in maps_, look for an equivalent map in
5451    // other_maps. This implementation is slow, but probably good enough for
5452    // now because the lists are short (<= 4 elements currently).
5453    for (int i = 0; i < maps_->length(); ++i) {
5454      bool match_found = false;
5455      for (int j = 0; j < other_maps.length(); ++j) {
5456        if (*(maps_->at(i)) == *(other_maps.at(j))) {
5457          match_found = true;
5458          break;
5459        }
5460      }
5461      if (!match_found) return false;
5462    }
5463    return true;
5464  }
5465
5466  static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
5467    uint32_t hash = code_flags;
5468    for (int i = 0; i < maps->length(); ++i) {
5469      hash ^= maps->at(i)->Hash();
5470    }
5471    return hash;
5472  }
5473
5474  uint32_t Hash() {
5475    return MapsHashHelper(maps_, code_flags_);
5476  }
5477
5478  uint32_t HashForObject(Object* obj) {
5479    MapHandleList other_maps(kDefaultListAllocationSize);
5480    int other_flags;
5481    FromObject(obj, &other_flags, &other_maps);
5482    return MapsHashHelper(&other_maps, other_flags);
5483  }
5484
5485  MUST_USE_RESULT MaybeObject* AsObject() {
5486    Object* obj;
5487    // The maps in |maps_| must be copied to a newly allocated FixedArray,
5488    // both because the referenced MapList is short-lived, and because C++
5489    // objects can't be stored in the heap anyway.
5490    { MaybeObject* maybe_obj =
5491        HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5492      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5493    }
5494    FixedArray* list = FixedArray::cast(obj);
5495    list->set(0, Smi::FromInt(code_flags_));
5496    for (int i = 0; i < maps_->length(); ++i) {
5497      list->set(i + 1, *maps_->at(i));
5498    }
5499    return list;
5500  }
5501
5502 private:
5503  static MapHandleList* FromObject(Object* obj,
5504                                   int* code_flags,
5505                                   MapHandleList* maps) {
5506    FixedArray* list = FixedArray::cast(obj);
5507    maps->Rewind(0);
5508    *code_flags = Smi::cast(list->get(0))->value();
5509    for (int i = 1; i < list->length(); ++i) {
5510      maps->Add(Handle<Map>(Map::cast(list->get(i))));
5511    }
5512    return maps;
5513  }
5514
5515  MapHandleList* maps_;  // weak.
5516  int code_flags_;
5517  static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
5518};
5519
5520
5521Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5522                                              int code_flags) {
5523  PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5524  int entry = FindEntry(&key);
5525  if (entry == kNotFound) return GetHeap()->undefined_value();
5526  return get(EntryToIndex(entry) + 1);
5527}
5528
5529
5530MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
5531                                                int code_flags,
5532                                                Code* code) {
5533  PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5534  Object* obj;
5535  { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5536    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5537  }
5538  PolymorphicCodeCacheHashTable* cache =
5539      reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5540  int entry = cache->FindInsertionEntry(key.Hash());
5541  { MaybeObject* maybe_obj = key.AsObject();
5542    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5543  }
5544  cache->set(EntryToIndex(entry), obj);
5545  cache->set(EntryToIndex(entry) + 1, code);
5546  cache->ElementAdded();
5547  return cache;
5548}
5549
5550
5551MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
5552  ElementsAccessor* accessor = array->GetElementsAccessor();
5553  MaybeObject* maybe_result =
5554      accessor->AddElementsToFixedArray(array, array, this);
5555  FixedArray* result;
5556  if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5557#ifdef DEBUG
5558  if (FLAG_enable_slow_asserts) {
5559    for (int i = 0; i < result->length(); i++) {
5560      Object* current = result->get(i);
5561      ASSERT(current->IsNumber() || current->IsString());
5562    }
5563  }
5564#endif
5565  return result;
5566}
5567
5568
5569MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
5570  ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5571  MaybeObject* maybe_result =
5572      accessor->AddElementsToFixedArray(NULL, NULL, this, other);
5573  FixedArray* result;
5574  if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5575#ifdef DEBUG
5576  if (FLAG_enable_slow_asserts) {
5577    for (int i = 0; i < result->length(); i++) {
5578      Object* current = result->get(i);
5579      ASSERT(current->IsNumber() || current->IsString());
5580    }
5581  }
5582#endif
5583  return result;
5584}
5585
5586
5587MaybeObject* FixedArray::CopySize(int new_length) {
5588  Heap* heap = GetHeap();
5589  if (new_length == 0) return heap->empty_fixed_array();
5590  Object* obj;
5591  { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
5592    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5593  }
5594  FixedArray* result = FixedArray::cast(obj);
5595  // Copy the content
5596  AssertNoAllocation no_gc;
5597  int len = length();
5598  if (new_length < len) len = new_length;
5599  // We are taking the map from the old fixed array so the map is sure to
5600  // be an immortal immutable object.
5601  result->set_map_no_write_barrier(map());
5602  WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
5603  for (int i = 0; i < len; i++) {
5604    result->set(i, get(i), mode);
5605  }
5606  return result;
5607}
5608
5609
5610void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
5611  AssertNoAllocation no_gc;
5612  WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
5613  for (int index = 0; index < len; index++) {
5614    dest->set(dest_pos+index, get(pos+index), mode);
5615  }
5616}
5617
5618
5619#ifdef DEBUG
5620bool FixedArray::IsEqualTo(FixedArray* other) {
5621  if (length() != other->length()) return false;
5622  for (int i = 0 ; i < length(); ++i) {
5623    if (get(i) != other->get(i)) return false;
5624  }
5625  return true;
5626}
5627#endif
5628
5629
5630MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
5631  Heap* heap = Isolate::Current()->heap();
5632  if (number_of_descriptors == 0) {
5633    return heap->empty_descriptor_array();
5634  }
5635  // Allocate the array of keys.
5636  Object* array;
5637  { MaybeObject* maybe_array =
5638        heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
5639    if (!maybe_array->ToObject(&array)) return maybe_array;
5640  }
5641  // Do not use DescriptorArray::cast on incomplete object.
5642  FixedArray* result = FixedArray::cast(array);
5643
5644  // Allocate the content array and set it in the descriptor array.
5645  { MaybeObject* maybe_array =
5646        heap->AllocateFixedArray(number_of_descriptors << 1);
5647    if (!maybe_array->ToObject(&array)) return maybe_array;
5648  }
5649  result->set(kBitField3StorageIndex, Smi::FromInt(0));
5650  result->set(kContentArrayIndex, array);
5651  result->set(kEnumerationIndexIndex,
5652              Smi::FromInt(PropertyDetails::kInitialIndex));
5653  return result;
5654}
5655
5656
5657void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
5658                                   FixedArray* new_cache,
5659                                   Object* new_index_cache) {
5660  ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
5661  ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
5662  if (HasEnumCache()) {
5663    FixedArray::cast(get(kEnumerationIndexIndex))->
5664      set(kEnumCacheBridgeCacheIndex, new_cache);
5665    FixedArray::cast(get(kEnumerationIndexIndex))->
5666      set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
5667  } else {
5668    if (IsEmpty()) return;  // Do nothing for empty descriptor array.
5669    FixedArray::cast(bridge_storage)->
5670      set(kEnumCacheBridgeCacheIndex, new_cache);
5671    FixedArray::cast(bridge_storage)->
5672      set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
5673    NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5674                      kEnumCacheBridgeEnumIndex,
5675                      get(kEnumerationIndexIndex));
5676    set(kEnumerationIndexIndex, bridge_storage);
5677  }
5678}
5679
5680
5681static bool InsertionPointFound(String* key1, String* key2) {
5682  return key1->Hash() > key2->Hash() || key1 == key2;
5683}
5684
5685
5686void DescriptorArray::CopyFrom(Handle<DescriptorArray> dst,
5687                               int dst_index,
5688                               Handle<DescriptorArray> src,
5689                               int src_index,
5690                               const WhitenessWitness& witness) {
5691  CALL_HEAP_FUNCTION_VOID(dst->GetIsolate(),
5692                          dst->CopyFrom(dst_index, *src, src_index, witness));
5693}
5694
5695
5696MaybeObject* DescriptorArray::CopyFrom(int dst_index,
5697                                       DescriptorArray* src,
5698                                       int src_index,
5699                                       const WhitenessWitness& witness) {
5700  Object* value = src->GetValue(src_index);
5701  PropertyDetails details(src->GetDetails(src_index));
5702  if (details.type() == CALLBACKS && value->IsAccessorPair()) {
5703    MaybeObject* maybe_copy =
5704        AccessorPair::cast(value)->CopyWithoutTransitions();
5705    if (!maybe_copy->To(&value)) return maybe_copy;
5706  }
5707  Descriptor desc(src->GetKey(src_index), value, details);
5708  Set(dst_index, &desc, witness);
5709  return this;
5710}
5711
5712
5713MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5714                                         TransitionFlag transition_flag) {
5715  // Transitions are only kept when inserting another transition.
5716  // This precondition is not required by this function's implementation, but
5717  // is currently required by the semantics of maps, so we check it.
5718  // Conversely, we filter after replacing, so replacing a transition and
5719  // removing all other transitions is not supported.
5720  bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
5721  ASSERT(remove_transitions == !descriptor->ContainsTransition());
5722  ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
5723
5724  // Ensure the key is a symbol.
5725  { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5726    if (maybe_result->IsFailure()) return maybe_result;
5727  }
5728
5729  int new_size = 0;
5730  for (int i = 0; i < number_of_descriptors(); i++) {
5731    if (IsNullDescriptor(i)) continue;
5732    if (remove_transitions && IsTransitionOnly(i)) continue;
5733    new_size++;
5734  }
5735
5736  // If key is in descriptor, we replace it in-place when filtering.
5737  // Count a null descriptor for key as inserted, not replaced.
5738  int index = Search(descriptor->GetKey());
5739  const bool replacing = (index != kNotFound);
5740  bool keep_enumeration_index = false;
5741  if (replacing) {
5742    // We are replacing an existing descriptor.  We keep the enumeration
5743    // index of a visible property.
5744    PropertyType t = PropertyDetails(GetDetails(index)).type();
5745    if (t == CONSTANT_FUNCTION ||
5746        t == FIELD ||
5747        t == CALLBACKS ||
5748        t == INTERCEPTOR) {
5749      keep_enumeration_index = true;
5750    } else if (remove_transitions) {
5751     // Replaced descriptor has been counted as removed if it is
5752     // a transition that will be replaced.  Adjust count in this case.
5753      ++new_size;
5754    }
5755  } else {
5756    ++new_size;
5757  }
5758
5759  DescriptorArray* new_descriptors;
5760  { MaybeObject* maybe_result = Allocate(new_size);
5761    if (!maybe_result->To(&new_descriptors)) return maybe_result;
5762  }
5763
5764  DescriptorArray::WhitenessWitness witness(new_descriptors);
5765
5766  // Set the enumeration index in the descriptors and set the enumeration index
5767  // in the result.
5768  int enumeration_index = NextEnumerationIndex();
5769  if (!descriptor->ContainsTransition()) {
5770    if (keep_enumeration_index) {
5771      descriptor->SetEnumerationIndex(
5772          PropertyDetails(GetDetails(index)).index());
5773    } else {
5774      descriptor->SetEnumerationIndex(enumeration_index);
5775      ++enumeration_index;
5776    }
5777  }
5778  new_descriptors->SetNextEnumerationIndex(enumeration_index);
5779
5780  // Copy the descriptors, filtering out transitions and null descriptors,
5781  // and inserting or replacing a descriptor.
5782  int to_index = 0;
5783  int insertion_index = -1;
5784  int from_index = 0;
5785  while (from_index < number_of_descriptors()) {
5786    if (insertion_index < 0 &&
5787        InsertionPointFound(GetKey(from_index), descriptor->GetKey())) {
5788      insertion_index = to_index++;
5789      if (replacing) from_index++;
5790    } else {
5791      if (!(IsNullDescriptor(from_index) ||
5792            (remove_transitions && IsTransitionOnly(from_index)))) {
5793        MaybeObject* copy_result =
5794            new_descriptors->CopyFrom(to_index++, this, from_index, witness);
5795        if (copy_result->IsFailure()) return copy_result;
5796      }
5797      from_index++;
5798    }
5799  }
5800  if (insertion_index < 0) insertion_index = to_index++;
5801  new_descriptors->Set(insertion_index, descriptor, witness);
5802
5803  ASSERT(to_index == new_descriptors->number_of_descriptors());
5804  SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5805
5806  return new_descriptors;
5807}
5808
5809
5810MaybeObject* DescriptorArray::RemoveTransitions() {
5811  // Allocate the new descriptor array.
5812  int new_number_of_descriptors = 0;
5813  for (int i = 0; i < number_of_descriptors(); i++) {
5814    if (IsProperty(i)) new_number_of_descriptors++;
5815  }
5816  DescriptorArray* new_descriptors;
5817  { MaybeObject* maybe_result = Allocate(new_number_of_descriptors);
5818    if (!maybe_result->To(&new_descriptors)) return maybe_result;
5819  }
5820
5821  // Copy the content.
5822  DescriptorArray::WhitenessWitness witness(new_descriptors);
5823  int next_descriptor = 0;
5824  for (int i = 0; i < number_of_descriptors(); i++) {
5825    if (IsProperty(i)) {
5826      MaybeObject* copy_result =
5827          new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5828      if (copy_result->IsFailure()) return copy_result;
5829    }
5830  }
5831  ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5832
5833  return new_descriptors;
5834}
5835
5836
5837void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
5838  // In-place heap sort.
5839  int len = number_of_descriptors();
5840
5841  // Bottom-up max-heap construction.
5842  // Index of the last node with children
5843  const int max_parent_index = (len / 2) - 1;
5844  for (int i = max_parent_index; i >= 0; --i) {
5845    int parent_index = i;
5846    const uint32_t parent_hash = GetKey(i)->Hash();
5847    while (parent_index <= max_parent_index) {
5848      int child_index = 2 * parent_index + 1;
5849      uint32_t child_hash = GetKey(child_index)->Hash();
5850      if (child_index + 1 < len) {
5851        uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5852        if (right_child_hash > child_hash) {
5853          child_index++;
5854          child_hash = right_child_hash;
5855        }
5856      }
5857      if (child_hash <= parent_hash) break;
5858      NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
5859      // Now element at child_index could be < its children.
5860      parent_index = child_index;  // parent_hash remains correct.
5861    }
5862  }
5863
5864  // Extract elements and create sorted array.
5865  for (int i = len - 1; i > 0; --i) {
5866    // Put max element at the back of the array.
5867    NoIncrementalWriteBarrierSwapDescriptors(0, i);
5868    // Shift down the new top element.
5869    int parent_index = 0;
5870    const uint32_t parent_hash = GetKey(parent_index)->Hash();
5871    const int max_parent_index = (i / 2) - 1;
5872    while (parent_index <= max_parent_index) {
5873      int child_index = parent_index * 2 + 1;
5874      uint32_t child_hash = GetKey(child_index)->Hash();
5875      if (child_index + 1 < i) {
5876        uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5877        if (right_child_hash > child_hash) {
5878          child_index++;
5879          child_hash = right_child_hash;
5880        }
5881      }
5882      if (child_hash <= parent_hash) break;
5883      NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
5884      parent_index = child_index;
5885    }
5886  }
5887}
5888
5889
5890void DescriptorArray::Sort(const WhitenessWitness& witness) {
5891  SortUnchecked(witness);
5892  SLOW_ASSERT(IsSortedNoDuplicates());
5893}
5894
5895
5896int DescriptorArray::BinarySearch(String* name, int low, int high) {
5897  uint32_t hash = name->Hash();
5898
5899  while (low <= high) {
5900    int mid = (low + high) / 2;
5901    String* mid_name = GetKey(mid);
5902    uint32_t mid_hash = mid_name->Hash();
5903
5904    if (mid_hash > hash) {
5905      high = mid - 1;
5906      continue;
5907    }
5908    if (mid_hash < hash) {
5909      low = mid + 1;
5910      continue;
5911    }
5912    // Found an element with the same hash-code.
5913    ASSERT(hash == mid_hash);
5914    // There might be more, so we find the first one and
5915    // check them all to see if we have a match.
5916    if (name == mid_name  && !is_null_descriptor(mid)) return mid;
5917    while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5918    for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
5919      if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
5920    }
5921    break;
5922  }
5923  return kNotFound;
5924}
5925
5926
5927int DescriptorArray::LinearSearch(String* name, int len) {
5928  uint32_t hash = name->Hash();
5929  for (int number = 0; number < len; number++) {
5930    String* entry = GetKey(number);
5931    if ((entry->Hash() == hash) &&
5932        name->Equals(entry) &&
5933        !is_null_descriptor(number)) {
5934      return number;
5935    }
5936  }
5937  return kNotFound;
5938}
5939
5940
5941MaybeObject* AccessorPair::CopyWithoutTransitions() {
5942  Heap* heap = GetHeap();
5943  AccessorPair* copy;
5944  { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5945    if (!maybe_copy->To(&copy)) return maybe_copy;
5946  }
5947  copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
5948  copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
5949  return copy;
5950}
5951
5952
5953Object* AccessorPair::GetComponent(AccessorComponent component) {
5954    Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter();
5955    return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
5956}
5957
5958
5959MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5960                                               PretenureFlag pretenure) {
5961  ASSERT(deopt_entry_count > 0);
5962  return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
5963                                  pretenure);
5964}
5965
5966
5967MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5968                                                PretenureFlag pretenure) {
5969  if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5970  return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
5971                                  pretenure);
5972}
5973
5974
5975#ifdef DEBUG
5976bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5977  if (IsEmpty()) return other->IsEmpty();
5978  if (other->IsEmpty()) return false;
5979  if (length() != other->length()) return false;
5980  for (int i = 0; i < length(); ++i) {
5981    if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5982  }
5983  return GetContentArray()->IsEqualTo(other->GetContentArray());
5984}
5985#endif
5986
5987
5988bool String::LooksValid() {
5989  if (!Isolate::Current()->heap()->Contains(this)) return false;
5990  return true;
5991}
5992
5993
5994String::FlatContent String::GetFlatContent() {
5995  int length = this->length();
5996  StringShape shape(this);
5997  String* string = this;
5998  int offset = 0;
5999  if (shape.representation_tag() == kConsStringTag) {
6000    ConsString* cons = ConsString::cast(string);
6001    if (cons->second()->length() != 0) {
6002      return FlatContent();
6003    }
6004    string = cons->first();
6005    shape = StringShape(string);
6006  }
6007  if (shape.representation_tag() == kSlicedStringTag) {
6008    SlicedString* slice = SlicedString::cast(string);
6009    offset = slice->offset();
6010    string = slice->parent();
6011    shape = StringShape(string);
6012    ASSERT(shape.representation_tag() != kConsStringTag &&
6013           shape.representation_tag() != kSlicedStringTag);
6014  }
6015  if (shape.encoding_tag() == kAsciiStringTag) {
6016    const char* start;
6017    if (shape.representation_tag() == kSeqStringTag) {
6018      start = SeqAsciiString::cast(string)->GetChars();
6019    } else {
6020      start = ExternalAsciiString::cast(string)->GetChars();
6021    }
6022    return FlatContent(Vector<const char>(start + offset, length));
6023  } else {
6024    ASSERT(shape.encoding_tag() == kTwoByteStringTag);
6025    const uc16* start;
6026    if (shape.representation_tag() == kSeqStringTag) {
6027      start = SeqTwoByteString::cast(string)->GetChars();
6028    } else {
6029      start = ExternalTwoByteString::cast(string)->GetChars();
6030    }
6031    return FlatContent(Vector<const uc16>(start + offset, length));
6032  }
6033}
6034
6035
6036SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6037                                          RobustnessFlag robust_flag,
6038                                          int offset,
6039                                          int length,
6040                                          int* length_return) {
6041  if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
6042    return SmartArrayPointer<char>(NULL);
6043  }
6044  Heap* heap = GetHeap();
6045
6046  // Negative length means the to the end of the string.
6047  if (length < 0) length = kMaxInt - offset;
6048
6049  // Compute the size of the UTF-8 string. Start at the specified offset.
6050  Access<StringInputBuffer> buffer(
6051      heap->isolate()->objects_string_input_buffer());
6052  buffer->Reset(offset, this);
6053  int character_position = offset;
6054  int utf8_bytes = 0;
6055  int last = unibrow::Utf16::kNoPreviousCharacter;
6056  while (buffer->has_more() && character_position++ < offset + length) {
6057    uint16_t character = buffer->GetNext();
6058    utf8_bytes += unibrow::Utf8::Length(character, last);
6059    last = character;
6060  }
6061
6062  if (length_return) {
6063    *length_return = utf8_bytes;
6064  }
6065
6066  char* result = NewArray<char>(utf8_bytes + 1);
6067
6068  // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
6069  buffer->Rewind();
6070  buffer->Seek(offset);
6071  character_position = offset;
6072  int utf8_byte_position = 0;
6073  last = unibrow::Utf16::kNoPreviousCharacter;
6074  while (buffer->has_more() && character_position++ < offset + length) {
6075    uint16_t character = buffer->GetNext();
6076    if (allow_nulls == DISALLOW_NULLS && character == 0) {
6077      character = ' ';
6078    }
6079    utf8_byte_position +=
6080        unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
6081    last = character;
6082  }
6083  result[utf8_byte_position] = 0;
6084  return SmartArrayPointer<char>(result);
6085}
6086
6087
6088SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6089                                          RobustnessFlag robust_flag,
6090                                          int* length_return) {
6091  return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6092}
6093
6094
6095const uc16* String::GetTwoByteData() {
6096  return GetTwoByteData(0);
6097}
6098
6099
6100const uc16* String::GetTwoByteData(unsigned start) {
6101  ASSERT(!IsAsciiRepresentationUnderneath());
6102  switch (StringShape(this).representation_tag()) {
6103    case kSeqStringTag:
6104      return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
6105    case kExternalStringTag:
6106      return ExternalTwoByteString::cast(this)->
6107        ExternalTwoByteStringGetData(start);
6108    case kSlicedStringTag: {
6109      SlicedString* slice = SlicedString::cast(this);
6110      return slice->parent()->GetTwoByteData(start + slice->offset());
6111    }
6112    case kConsStringTag:
6113      UNREACHABLE();
6114      return NULL;
6115  }
6116  UNREACHABLE();
6117  return NULL;
6118}
6119
6120
6121SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
6122  if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
6123    return SmartArrayPointer<uc16>();
6124  }
6125  Heap* heap = GetHeap();
6126
6127  Access<StringInputBuffer> buffer(
6128      heap->isolate()->objects_string_input_buffer());
6129  buffer->Reset(this);
6130
6131  uc16* result = NewArray<uc16>(length() + 1);
6132
6133  int i = 0;
6134  while (buffer->has_more()) {
6135    uint16_t character = buffer->GetNext();
6136    result[i++] = character;
6137  }
6138  result[i] = 0;
6139  return SmartArrayPointer<uc16>(result);
6140}
6141
6142
6143const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
6144  return reinterpret_cast<uc16*>(
6145      reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6146}
6147
6148
6149void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6150                                                           unsigned* offset_ptr,
6151                                                           unsigned max_chars) {
6152  unsigned chars_read = 0;
6153  unsigned offset = *offset_ptr;
6154  while (chars_read < max_chars) {
6155    uint16_t c = *reinterpret_cast<uint16_t*>(
6156        reinterpret_cast<char*>(this) -
6157            kHeapObjectTag + kHeaderSize + offset * kShortSize);
6158    if (c <= kMaxAsciiCharCode) {
6159      // Fast case for ASCII characters.   Cursor is an input output argument.
6160      if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6161                                                          rbb->util_buffer,
6162                                                          rbb->capacity,
6163                                                          rbb->cursor)) {
6164        break;
6165      }
6166    } else {
6167      if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6168                                                             rbb->util_buffer,
6169                                                             rbb->capacity,
6170                                                             rbb->cursor)) {
6171        break;
6172      }
6173    }
6174    offset++;
6175    chars_read++;
6176  }
6177  *offset_ptr = offset;
6178  rbb->remaining += chars_read;
6179}
6180
6181
6182const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6183    unsigned* remaining,
6184    unsigned* offset_ptr,
6185    unsigned max_chars) {
6186  const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6187      kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6188  *remaining = max_chars;
6189  *offset_ptr += max_chars;
6190  return b;
6191}
6192
6193
6194// This will iterate unless the block of string data spans two 'halves' of
6195// a ConsString, in which case it will recurse.  Since the block of string
6196// data to be read has a maximum size this limits the maximum recursion
6197// depth to something sane.  Since C++ does not have tail call recursion
6198// elimination, the iteration must be explicit. Since this is not an
6199// -IntoBuffer method it can delegate to one of the efficient
6200// *AsciiStringReadBlock routines.
6201const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6202                                                     unsigned* offset_ptr,
6203                                                     unsigned max_chars) {
6204  ConsString* current = this;
6205  unsigned offset = *offset_ptr;
6206  int offset_correction = 0;
6207
6208  while (true) {
6209    String* left = current->first();
6210    unsigned left_length = (unsigned)left->length();
6211    if (left_length > offset &&
6212        (max_chars <= left_length - offset ||
6213         (rbb->capacity <= left_length - offset &&
6214          (max_chars = left_length - offset, true)))) {  // comma operator!
6215      // Left hand side only - iterate unless we have reached the bottom of
6216      // the cons tree.  The assignment on the left of the comma operator is
6217      // in order to make use of the fact that the -IntoBuffer routines can
6218      // produce at most 'capacity' characters.  This enables us to postpone
6219      // the point where we switch to the -IntoBuffer routines (below) in order
6220      // to maximize the chances of delegating a big chunk of work to the
6221      // efficient *AsciiStringReadBlock routines.
6222      if (StringShape(left).IsCons()) {
6223        current = ConsString::cast(left);
6224        continue;
6225      } else {
6226        const unibrow::byte* answer =
6227            String::ReadBlock(left, rbb, &offset, max_chars);
6228        *offset_ptr = offset + offset_correction;
6229        return answer;
6230      }
6231    } else if (left_length <= offset) {
6232      // Right hand side only - iterate unless we have reached the bottom of
6233      // the cons tree.
6234      String* right = current->second();
6235      offset -= left_length;
6236      offset_correction += left_length;
6237      if (StringShape(right).IsCons()) {
6238        current = ConsString::cast(right);
6239        continue;
6240      } else {
6241        const unibrow::byte* answer =
6242            String::ReadBlock(right, rbb, &offset, max_chars);
6243        *offset_ptr = offset + offset_correction;
6244        return answer;
6245      }
6246    } else {
6247      // The block to be read spans two sides of the ConsString, so we call the
6248      // -IntoBuffer version, which will recurse.  The -IntoBuffer methods
6249      // are able to assemble data from several part strings because they use
6250      // the util_buffer to store their data and never return direct pointers
6251      // to their storage.  We don't try to read more than the buffer capacity
6252      // here or we can get too much recursion.
6253      ASSERT(rbb->remaining == 0);
6254      ASSERT(rbb->cursor == 0);
6255      current->ConsStringReadBlockIntoBuffer(
6256          rbb,
6257          &offset,
6258          max_chars > rbb->capacity ? rbb->capacity : max_chars);
6259      *offset_ptr = offset + offset_correction;
6260      return rbb->util_buffer;
6261    }
6262  }
6263}
6264
6265
6266const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6267      unsigned* remaining,
6268      unsigned* offset_ptr,
6269      unsigned max_chars) {
6270  // Cast const char* to unibrow::byte* (signedness difference).
6271  const unibrow::byte* b =
6272      reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
6273  *remaining = max_chars;
6274  *offset_ptr += max_chars;
6275  return b;
6276}
6277
6278
6279void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6280      ReadBlockBuffer* rbb,
6281      unsigned* offset_ptr,
6282      unsigned max_chars) {
6283  unsigned chars_read = 0;
6284  unsigned offset = *offset_ptr;
6285  const uint16_t* data = GetChars();
6286  while (chars_read < max_chars) {
6287    uint16_t c = data[offset];
6288    if (c <= kMaxAsciiCharCode) {
6289      // Fast case for ASCII characters. Cursor is an input output argument.
6290      if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6291                                                          rbb->util_buffer,
6292                                                          rbb->capacity,
6293                                                          rbb->cursor))
6294        break;
6295    } else {
6296      if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6297                                                             rbb->util_buffer,
6298                                                             rbb->capacity,
6299                                                             rbb->cursor))
6300        break;
6301    }
6302    offset++;
6303    chars_read++;
6304  }
6305  *offset_ptr = offset;
6306  rbb->remaining += chars_read;
6307}
6308
6309
6310void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6311                                                 unsigned* offset_ptr,
6312                                                 unsigned max_chars) {
6313  unsigned capacity = rbb->capacity - rbb->cursor;
6314  if (max_chars > capacity) max_chars = capacity;
6315  memcpy(rbb->util_buffer + rbb->cursor,
6316         reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6317             *offset_ptr * kCharSize,
6318         max_chars);
6319  rbb->remaining += max_chars;
6320  *offset_ptr += max_chars;
6321  rbb->cursor += max_chars;
6322}
6323
6324
6325void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6326      ReadBlockBuffer* rbb,
6327      unsigned* offset_ptr,
6328      unsigned max_chars) {
6329  unsigned capacity = rbb->capacity - rbb->cursor;
6330  if (max_chars > capacity) max_chars = capacity;
6331  memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
6332  rbb->remaining += max_chars;
6333  *offset_ptr += max_chars;
6334  rbb->cursor += max_chars;
6335}
6336
6337
6338// This method determines the type of string involved and then copies
6339// a whole chunk of characters into a buffer, or returns a pointer to a buffer
6340// where they can be found.  The pointer is not necessarily valid across a GC
6341// (see AsciiStringReadBlock).
6342const unibrow::byte* String::ReadBlock(String* input,
6343                                       ReadBlockBuffer* rbb,
6344                                       unsigned* offset_ptr,
6345                                       unsigned max_chars) {
6346  ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6347  if (max_chars == 0) {
6348    rbb->remaining = 0;
6349    return NULL;
6350  }
6351  switch (StringShape(input).representation_tag()) {
6352    case kSeqStringTag:
6353      if (input->IsAsciiRepresentation()) {
6354        SeqAsciiString* str = SeqAsciiString::cast(input);
6355        return str->SeqAsciiStringReadBlock(&rbb->remaining,
6356                                            offset_ptr,
6357                                            max_chars);
6358      } else {
6359        SeqTwoByteString* str = SeqTwoByteString::cast(input);
6360        str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6361                                                 offset_ptr,
6362                                                 max_chars);
6363        return rbb->util_buffer;
6364      }
6365    case kConsStringTag:
6366      return ConsString::cast(input)->ConsStringReadBlock(rbb,
6367                                                          offset_ptr,
6368                                                          max_chars);
6369    case kExternalStringTag:
6370      if (input->IsAsciiRepresentation()) {
6371        return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6372            &rbb->remaining,
6373            offset_ptr,
6374            max_chars);
6375      } else {
6376        ExternalTwoByteString::cast(input)->
6377            ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6378                                                     offset_ptr,
6379                                                     max_chars);
6380        return rbb->util_buffer;
6381      }
6382    case kSlicedStringTag:
6383      return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6384                                                              offset_ptr,
6385                                                              max_chars);
6386    default:
6387      break;
6388  }
6389
6390  UNREACHABLE();
6391  return 0;
6392}
6393
6394
6395void Relocatable::PostGarbageCollectionProcessing() {
6396  Isolate* isolate = Isolate::Current();
6397  Relocatable* current = isolate->relocatable_top();
6398  while (current != NULL) {
6399    current->PostGarbageCollection();
6400    current = current->prev_;
6401  }
6402}
6403
6404
6405// Reserve space for statics needing saving and restoring.
6406int Relocatable::ArchiveSpacePerThread() {
6407  return sizeof(Isolate::Current()->relocatable_top());
6408}
6409
6410
6411// Archive statics that are thread local.
6412char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
6413  *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6414  isolate->set_relocatable_top(NULL);
6415  return to + ArchiveSpacePerThread();
6416}
6417
6418
6419// Restore statics that are thread local.
6420char* Relocatable::RestoreState(Isolate* isolate, char* from) {
6421  isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
6422  return from + ArchiveSpacePerThread();
6423}
6424
6425
6426char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6427  Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6428  Iterate(v, top);
6429  return thread_storage + ArchiveSpacePerThread();
6430}
6431
6432
6433void Relocatable::Iterate(ObjectVisitor* v) {
6434  Isolate* isolate = Isolate::Current();
6435  Iterate(v, isolate->relocatable_top());
6436}
6437
6438
6439void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6440  Relocatable* current = top;
6441  while (current != NULL) {
6442    current->IterateInstance(v);
6443    current = current->prev_;
6444  }
6445}
6446
6447
6448FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6449    : Relocatable(isolate),
6450      str_(str.location()),
6451      length_(str->length()) {
6452  PostGarbageCollection();
6453}
6454
6455
6456FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6457    : Relocatable(isolate),
6458      str_(0),
6459      is_ascii_(true),
6460      length_(input.length()),
6461      start_(input.start()) { }
6462
6463
6464void FlatStringReader::PostGarbageCollection() {
6465  if (str_ == NULL) return;
6466  Handle<String> str(str_);
6467  ASSERT(str->IsFlat());
6468  String::FlatContent content = str->GetFlatContent();
6469  ASSERT(content.IsFlat());
6470  is_ascii_ = content.IsAscii();
6471  if (is_ascii_) {
6472    start_ = content.ToAsciiVector().start();
6473  } else {
6474    start_ = content.ToUC16Vector().start();
6475  }
6476}
6477
6478
6479void StringInputBuffer::Seek(unsigned pos) {
6480  Reset(pos, input_);
6481}
6482
6483
6484void SafeStringInputBuffer::Seek(unsigned pos) {
6485  Reset(pos, input_);
6486}
6487
6488
6489// This method determines the type of string involved and then copies
6490// a whole chunk of characters into a buffer.  It can be used with strings
6491// that have been glued together to form a ConsString and which must cooperate
6492// to fill up a buffer.
6493void String::ReadBlockIntoBuffer(String* input,
6494                                 ReadBlockBuffer* rbb,
6495                                 unsigned* offset_ptr,
6496                                 unsigned max_chars) {
6497  ASSERT(*offset_ptr <= (unsigned)input->length());
6498  if (max_chars == 0) return;
6499
6500  switch (StringShape(input).representation_tag()) {
6501    case kSeqStringTag:
6502      if (input->IsAsciiRepresentation()) {
6503        SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
6504                                                                 offset_ptr,
6505                                                                 max_chars);
6506        return;
6507      } else {
6508        SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6509                                                                     offset_ptr,
6510                                                                     max_chars);
6511        return;
6512      }
6513    case kConsStringTag:
6514      ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6515                                                             offset_ptr,
6516                                                             max_chars);
6517      return;
6518    case kExternalStringTag:
6519      if (input->IsAsciiRepresentation()) {
6520        ExternalAsciiString::cast(input)->
6521            ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6522      } else {
6523        ExternalTwoByteString::cast(input)->
6524            ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6525                                                     offset_ptr,
6526                                                     max_chars);
6527       }
6528       return;
6529    case kSlicedStringTag:
6530      SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6531                                                                 offset_ptr,
6532                                                                 max_chars);
6533      return;
6534    default:
6535      break;
6536  }
6537
6538  UNREACHABLE();
6539  return;
6540}
6541
6542
6543const unibrow::byte* String::ReadBlock(String* input,
6544                                       unibrow::byte* util_buffer,
6545                                       unsigned capacity,
6546                                       unsigned* remaining,
6547                                       unsigned* offset_ptr) {
6548  ASSERT(*offset_ptr <= (unsigned)input->length());
6549  unsigned chars = input->length() - *offset_ptr;
6550  ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6551  const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
6552  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6553  *remaining = rbb.remaining;
6554  return answer;
6555}
6556
6557
6558const unibrow::byte* String::ReadBlock(String** raw_input,
6559                                       unibrow::byte* util_buffer,
6560                                       unsigned capacity,
6561                                       unsigned* remaining,
6562                                       unsigned* offset_ptr) {
6563  Handle<String> input(raw_input);
6564  ASSERT(*offset_ptr <= (unsigned)input->length());
6565  unsigned chars = input->length() - *offset_ptr;
6566  if (chars > capacity) chars = capacity;
6567  ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6568  ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
6569  ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6570  *remaining = rbb.remaining;
6571  return rbb.util_buffer;
6572}
6573
6574
6575// This will iterate unless the block of string data spans two 'halves' of
6576// a ConsString, in which case it will recurse.  Since the block of string
6577// data to be read has a maximum size this limits the maximum recursion
6578// depth to something sane.  Since C++ does not have tail call recursion
6579// elimination, the iteration must be explicit.
6580void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6581                                               unsigned* offset_ptr,
6582                                               unsigned max_chars) {
6583  ConsString* current = this;
6584  unsigned offset = *offset_ptr;
6585  int offset_correction = 0;
6586
6587  while (true) {
6588    String* left = current->first();
6589    unsigned left_length = (unsigned)left->length();
6590    if (left_length > offset &&
6591      max_chars <= left_length - offset) {
6592      // Left hand side only - iterate unless we have reached the bottom of
6593      // the cons tree.
6594      if (StringShape(left).IsCons()) {
6595        current = ConsString::cast(left);
6596        continue;
6597      } else {
6598        String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6599        *offset_ptr = offset + offset_correction;
6600        return;
6601      }
6602    } else if (left_length <= offset) {
6603      // Right hand side only - iterate unless we have reached the bottom of
6604      // the cons tree.
6605      offset -= left_length;
6606      offset_correction += left_length;
6607      String* right = current->second();
6608      if (StringShape(right).IsCons()) {
6609        current = ConsString::cast(right);
6610        continue;
6611      } else {
6612        String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6613        *offset_ptr = offset + offset_correction;
6614        return;
6615      }
6616    } else {
6617      // The block to be read spans two sides of the ConsString, so we recurse.
6618      // First recurse on the left.
6619      max_chars -= left_length - offset;
6620      String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6621      // We may have reached the max or there may not have been enough space
6622      // in the buffer for the characters in the left hand side.
6623      if (offset == left_length) {
6624        // Recurse on the right.
6625        String* right = String::cast(current->second());
6626        offset -= left_length;
6627        offset_correction += left_length;
6628        String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6629      }
6630      *offset_ptr = offset + offset_correction;
6631      return;
6632    }
6633  }
6634}
6635
6636
6637uint16_t ConsString::ConsStringGet(int index) {
6638  ASSERT(index >= 0 && index < this->length());
6639
6640  // Check for a flattened cons string
6641  if (second()->length() == 0) {
6642    String* left = first();
6643    return left->Get(index);
6644  }
6645
6646  String* string = String::cast(this);
6647
6648  while (true) {
6649    if (StringShape(string).IsCons()) {
6650      ConsString* cons_string = ConsString::cast(string);
6651      String* left = cons_string->first();
6652      if (left->length() > index) {
6653        string = left;
6654      } else {
6655        index -= left->length();
6656        string = cons_string->second();
6657      }
6658    } else {
6659      return string->Get(index);
6660    }
6661  }
6662
6663  UNREACHABLE();
6664  return 0;
6665}
6666
6667
6668uint16_t SlicedString::SlicedStringGet(int index) {
6669  return parent()->Get(offset() + index);
6670}
6671
6672
6673const unibrow::byte* SlicedString::SlicedStringReadBlock(
6674    ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6675  unsigned offset = this->offset();
6676  *offset_ptr += offset;
6677  const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6678                                                  buffer, offset_ptr, chars);
6679  *offset_ptr -= offset;
6680  return answer;
6681}
6682
6683
6684void SlicedString::SlicedStringReadBlockIntoBuffer(
6685    ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6686  unsigned offset = this->offset();
6687  *offset_ptr += offset;
6688  String::ReadBlockIntoBuffer(String::cast(parent()),
6689                              buffer, offset_ptr, chars);
6690  *offset_ptr -= offset;
6691}
6692
6693template <typename sinkchar>
6694void String::WriteToFlat(String* src,
6695                         sinkchar* sink,
6696                         int f,
6697                         int t) {
6698  String* source = src;
6699  int from = f;
6700  int to = t;
6701  while (true) {
6702    ASSERT(0 <= from && from <= to && to <= source->length());
6703    switch (StringShape(source).full_representation_tag()) {
6704      case kAsciiStringTag | kExternalStringTag: {
6705        CopyChars(sink,
6706                  ExternalAsciiString::cast(source)->GetChars() + from,
6707                  to - from);
6708        return;
6709      }
6710      case kTwoByteStringTag | kExternalStringTag: {
6711        const uc16* data =
6712            ExternalTwoByteString::cast(source)->GetChars();
6713        CopyChars(sink,
6714                  data + from,
6715                  to - from);
6716        return;
6717      }
6718      case kAsciiStringTag | kSeqStringTag: {
6719        CopyChars(sink,
6720                  SeqAsciiString::cast(source)->GetChars() + from,
6721                  to - from);
6722        return;
6723      }
6724      case kTwoByteStringTag | kSeqStringTag: {
6725        CopyChars(sink,
6726                  SeqTwoByteString::cast(source)->GetChars() + from,
6727                  to - from);
6728        return;
6729      }
6730      case kAsciiStringTag | kConsStringTag:
6731      case kTwoByteStringTag | kConsStringTag: {
6732        ConsString* cons_string = ConsString::cast(source);
6733        String* first = cons_string->first();
6734        int boundary = first->length();
6735        if (to - boundary >= boundary - from) {
6736          // Right hand side is longer.  Recurse over left.
6737          if (from < boundary) {
6738            WriteToFlat(first, sink, from, boundary);
6739            sink += boundary - from;
6740            from = 0;
6741          } else {
6742            from -= boundary;
6743          }
6744          to -= boundary;
6745          source = cons_string->second();
6746        } else {
6747          // Left hand side is longer.  Recurse over right.
6748          if (to > boundary) {
6749            String* second = cons_string->second();
6750            // When repeatedly appending to a string, we get a cons string that
6751            // is unbalanced to the left, a list, essentially.  We inline the
6752            // common case of sequential ascii right child.
6753            if (to - boundary == 1) {
6754              sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
6755            } else if (second->IsSeqAsciiString()) {
6756              CopyChars(sink + boundary - from,
6757                        SeqAsciiString::cast(second)->GetChars(),
6758                        to - boundary);
6759            } else {
6760              WriteToFlat(second,
6761                          sink + boundary - from,
6762                          0,
6763                          to - boundary);
6764            }
6765            to = boundary;
6766          }
6767          source = first;
6768        }
6769        break;
6770      }
6771      case kAsciiStringTag | kSlicedStringTag:
6772      case kTwoByteStringTag | kSlicedStringTag: {
6773        SlicedString* slice = SlicedString::cast(source);
6774        unsigned offset = slice->offset();
6775        WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6776        return;
6777      }
6778    }
6779  }
6780}
6781
6782
6783template <typename IteratorA, typename IteratorB>
6784static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6785  // General slow case check.  We know that the ia and ib iterators
6786  // have the same length.
6787  while (ia->has_more()) {
6788    uint32_t ca = ia->GetNext();
6789    uint32_t cb = ib->GetNext();
6790    ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6791    ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6792    if (ca != cb)
6793      return false;
6794  }
6795  return true;
6796}
6797
6798
6799// Compares the contents of two strings by reading and comparing
6800// int-sized blocks of characters.
6801template <typename Char>
6802static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6803  int length = a.length();
6804  ASSERT_EQ(length, b.length());
6805  const Char* pa = a.start();
6806  const Char* pb = b.start();
6807  int i = 0;
6808#ifndef V8_HOST_CAN_READ_UNALIGNED
6809  // If this architecture isn't comfortable reading unaligned ints
6810  // then we have to check that the strings are aligned before
6811  // comparing them blockwise.
6812  const int kAlignmentMask = sizeof(uint32_t) - 1;  // NOLINT
6813  uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6814  uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
6815  if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
6816#endif
6817    const int kStepSize = sizeof(int) / sizeof(Char);  // NOLINT
6818    int endpoint = length - kStepSize;
6819    // Compare blocks until we reach near the end of the string.
6820    for (; i <= endpoint; i += kStepSize) {
6821      uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6822      uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6823      if (wa != wb) {
6824        return false;
6825      }
6826    }
6827#ifndef V8_HOST_CAN_READ_UNALIGNED
6828  }
6829#endif
6830  // Compare the remaining characters that didn't fit into a block.
6831  for (; i < length; i++) {
6832    if (a[i] != b[i]) {
6833      return false;
6834    }
6835  }
6836  return true;
6837}
6838
6839
6840template <typename IteratorA>
6841static inline bool CompareStringContentsPartial(Isolate* isolate,
6842                                                IteratorA* ia,
6843                                                String* b) {
6844  String::FlatContent content = b->GetFlatContent();
6845  if (content.IsFlat()) {
6846    if (content.IsAscii()) {
6847      VectorIterator<char> ib(content.ToAsciiVector());
6848      return CompareStringContents(ia, &ib);
6849    } else {
6850      VectorIterator<uc16> ib(content.ToUC16Vector());
6851      return CompareStringContents(ia, &ib);
6852    }
6853  } else {
6854    isolate->objects_string_compare_buffer_b()->Reset(0, b);
6855    return CompareStringContents(ia,
6856                                 isolate->objects_string_compare_buffer_b());
6857  }
6858}
6859
6860
6861bool String::SlowEquals(String* other) {
6862  // Fast check: negative check with lengths.
6863  int len = length();
6864  if (len != other->length()) return false;
6865  if (len == 0) return true;
6866
6867  // Fast check: if hash code is computed for both strings
6868  // a fast negative check can be performed.
6869  if (HasHashCode() && other->HasHashCode()) {
6870#ifdef DEBUG
6871    if (FLAG_enable_slow_asserts) {
6872      if (Hash() != other->Hash()) {
6873        bool found_difference = false;
6874        for (int i = 0; i < len; i++) {
6875          if (Get(i) != other->Get(i)) {
6876            found_difference = true;
6877            break;
6878          }
6879        }
6880        ASSERT(found_difference);
6881      }
6882    }
6883#endif
6884    if (Hash() != other->Hash()) return false;
6885  }
6886
6887  // We know the strings are both non-empty. Compare the first chars
6888  // before we try to flatten the strings.
6889  if (this->Get(0) != other->Get(0)) return false;
6890
6891  String* lhs = this->TryFlattenGetString();
6892  String* rhs = other->TryFlattenGetString();
6893
6894  if (StringShape(lhs).IsSequentialAscii() &&
6895      StringShape(rhs).IsSequentialAscii()) {
6896    const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6897    const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
6898    return CompareRawStringContents(Vector<const char>(str1, len),
6899                                    Vector<const char>(str2, len));
6900  }
6901
6902  Isolate* isolate = GetIsolate();
6903  String::FlatContent lhs_content = lhs->GetFlatContent();
6904  String::FlatContent rhs_content = rhs->GetFlatContent();
6905  if (lhs_content.IsFlat()) {
6906    if (lhs_content.IsAscii()) {
6907      Vector<const char> vec1 = lhs_content.ToAsciiVector();
6908      if (rhs_content.IsFlat()) {
6909        if (rhs_content.IsAscii()) {
6910          Vector<const char> vec2 = rhs_content.ToAsciiVector();
6911          return CompareRawStringContents(vec1, vec2);
6912        } else {
6913          VectorIterator<char> buf1(vec1);
6914          VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
6915          return CompareStringContents(&buf1, &ib);
6916        }
6917      } else {
6918        VectorIterator<char> buf1(vec1);
6919        isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6920        return CompareStringContents(&buf1,
6921            isolate->objects_string_compare_buffer_b());
6922      }
6923    } else {
6924      Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6925      if (rhs_content.IsFlat()) {
6926        if (rhs_content.IsAscii()) {
6927          VectorIterator<uc16> buf1(vec1);
6928          VectorIterator<char> ib(rhs_content.ToAsciiVector());
6929          return CompareStringContents(&buf1, &ib);
6930        } else {
6931          Vector<const uc16> vec2(rhs_content.ToUC16Vector());
6932          return CompareRawStringContents(vec1, vec2);
6933        }
6934      } else {
6935        VectorIterator<uc16> buf1(vec1);
6936        isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6937        return CompareStringContents(&buf1,
6938            isolate->objects_string_compare_buffer_b());
6939      }
6940    }
6941  } else {
6942    isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6943    return CompareStringContentsPartial(isolate,
6944        isolate->objects_string_compare_buffer_a(), rhs);
6945  }
6946}
6947
6948
6949bool String::MarkAsUndetectable() {
6950  if (StringShape(this).IsSymbol()) return false;
6951
6952  Map* map = this->map();
6953  Heap* heap = GetHeap();
6954  if (map == heap->string_map()) {
6955    this->set_map(heap->undetectable_string_map());
6956    return true;
6957  } else if (map == heap->ascii_string_map()) {
6958    this->set_map(heap->undetectable_ascii_string_map());
6959    return true;
6960  }
6961  // Rest cannot be marked as undetectable
6962  return false;
6963}
6964
6965
6966bool String::IsEqualTo(Vector<const char> str) {
6967  Isolate* isolate = GetIsolate();
6968  int slen = length();
6969  Access<UnicodeCache::Utf8Decoder>
6970      decoder(isolate->unicode_cache()->utf8_decoder());
6971  decoder->Reset(str.start(), str.length());
6972  int i;
6973  for (i = 0; i < slen && decoder->has_more(); i++) {
6974    uint32_t r = decoder->GetNext();
6975    if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
6976      if (i > slen - 1) return false;
6977      if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
6978      if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
6979    } else {
6980      if (Get(i) != r) return false;
6981    }
6982  }
6983  return i == slen && !decoder->has_more();
6984}
6985
6986
6987bool String::IsAsciiEqualTo(Vector<const char> str) {
6988  int slen = length();
6989  if (str.length() != slen) return false;
6990  FlatContent content = GetFlatContent();
6991  if (content.IsAscii()) {
6992    return CompareChars(content.ToAsciiVector().start(),
6993                        str.start(), slen) == 0;
6994  }
6995  for (int i = 0; i < slen; i++) {
6996    if (Get(i) != static_cast<uint16_t>(str[i])) return false;
6997  }
6998  return true;
6999}
7000
7001
7002bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
7003  int slen = length();
7004  if (str.length() != slen) return false;
7005  FlatContent content = GetFlatContent();
7006  if (content.IsTwoByte()) {
7007    return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
7008  }
7009  for (int i = 0; i < slen; i++) {
7010    if (Get(i) != str[i]) return false;
7011  }
7012  return true;
7013}
7014
7015
7016uint32_t String::ComputeAndSetHash() {
7017  // Should only be called if hash code has not yet been computed.
7018  ASSERT(!HasHashCode());
7019
7020  const int len = length();
7021
7022  // Compute the hash code.
7023  uint32_t field = 0;
7024  if (StringShape(this).IsSequentialAscii()) {
7025    field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
7026                                 len,
7027                                 GetHeap()->HashSeed());
7028  } else if (StringShape(this).IsSequentialTwoByte()) {
7029    field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
7030                                 len,
7031                                 GetHeap()->HashSeed());
7032  } else {
7033    StringInputBuffer buffer(this);
7034    field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
7035  }
7036
7037  // Store the hash code in the object.
7038  set_hash_field(field);
7039
7040  // Check the hash code is there.
7041  ASSERT(HasHashCode());
7042  uint32_t result = field >> kHashShift;
7043  ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
7044  return result;
7045}
7046
7047
7048bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
7049                               uint32_t* index,
7050                               int length) {
7051  if (length == 0 || length > kMaxArrayIndexSize) return false;
7052  uc32 ch = buffer->GetNext();
7053
7054  // If the string begins with a '0' character, it must only consist
7055  // of it to be a legal array index.
7056  if (ch == '0') {
7057    *index = 0;
7058    return length == 1;
7059  }
7060
7061  // Convert string to uint32 array index; character by character.
7062  int d = ch - '0';
7063  if (d < 0 || d > 9) return false;
7064  uint32_t result = d;
7065  while (buffer->has_more()) {
7066    d = buffer->GetNext() - '0';
7067    if (d < 0 || d > 9) return false;
7068    // Check that the new result is below the 32 bit limit.
7069    if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7070    result = (result * 10) + d;
7071  }
7072
7073  *index = result;
7074  return true;
7075}
7076
7077
7078bool String::SlowAsArrayIndex(uint32_t* index) {
7079  if (length() <= kMaxCachedArrayIndexLength) {
7080    Hash();  // force computation of hash code
7081    uint32_t field = hash_field();
7082    if ((field & kIsNotArrayIndexMask) != 0) return false;
7083    // Isolate the array index form the full hash field.
7084    *index = (kArrayIndexHashMask & field) >> kHashShift;
7085    return true;
7086  } else {
7087    StringInputBuffer buffer(this);
7088    return ComputeArrayIndex(&buffer, index, length());
7089  }
7090}
7091
7092
7093uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
7094  // For array indexes mix the length into the hash as an array index could
7095  // be zero.
7096  ASSERT(length > 0);
7097  ASSERT(length <= String::kMaxArrayIndexSize);
7098  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7099         (1 << String::kArrayIndexValueBits));
7100
7101  value <<= String::kHashShift;
7102  value |= length << String::kArrayIndexHashLengthShift;
7103
7104  ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7105  ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7106         (value & String::kContainsCachedArrayIndexMask) == 0);
7107  return value;
7108}
7109
7110
7111void StringHasher::AddSurrogatePair(uc32 c) {
7112  uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7113  AddCharacter(lead);
7114  uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7115  AddCharacter(trail);
7116}
7117
7118
7119void StringHasher::AddSurrogatePairNoIndex(uc32 c) {
7120  uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7121  AddCharacterNoIndex(lead);
7122  uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7123  AddCharacterNoIndex(trail);
7124}
7125
7126
7127uint32_t StringHasher::GetHashField() {
7128  ASSERT(is_valid());
7129  if (length_ <= String::kMaxHashCalcLength) {
7130    if (is_array_index()) {
7131      return MakeArrayIndexHash(array_index(), length_);
7132    }
7133    return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
7134  } else {
7135    return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
7136  }
7137}
7138
7139
7140uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
7141                                  int length,
7142                                  uint32_t seed) {
7143  StringHasher hasher(length, seed);
7144
7145  // Very long strings have a trivial hash that doesn't inspect the
7146  // string contents.
7147  if (hasher.has_trivial_hash()) {
7148    return hasher.GetHashField();
7149  }
7150
7151  // Do the iterative array index computation as long as there is a
7152  // chance this is an array index.
7153  while (buffer->has_more() && hasher.is_array_index()) {
7154    hasher.AddCharacter(buffer->GetNext());
7155  }
7156
7157  // Process the remaining characters without updating the array
7158  // index.
7159  while (buffer->has_more()) {
7160    hasher.AddCharacterNoIndex(buffer->GetNext());
7161  }
7162
7163  return hasher.GetHashField();
7164}
7165
7166
7167MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
7168  Heap* heap = GetHeap();
7169  if (start == 0 && end == length()) return this;
7170  MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
7171  return result;
7172}
7173
7174
7175void String::PrintOn(FILE* file) {
7176  int length = this->length();
7177  for (int i = 0; i < length; i++) {
7178    fprintf(file, "%c", Get(i));
7179  }
7180}
7181
7182
7183void Map::CreateOneBackPointer(Object* transition_target) {
7184  if (!transition_target->IsMap()) return;
7185  Map* target = Map::cast(transition_target);
7186#ifdef DEBUG
7187  // Verify target.
7188  Object* source_prototype = prototype();
7189  Object* target_prototype = target->prototype();
7190  ASSERT(source_prototype->IsJSReceiver() ||
7191         source_prototype->IsMap() ||
7192         source_prototype->IsNull());
7193  ASSERT(target_prototype->IsJSReceiver() ||
7194         target_prototype->IsNull());
7195  ASSERT(source_prototype->IsMap() ||
7196         source_prototype == target_prototype);
7197#endif
7198  // Point target back to source.  set_prototype() will not let us set
7199  // the prototype to a map, as we do here.
7200  *RawField(target, kPrototypeOffset) = this;
7201}
7202
7203
7204void Map::CreateBackPointers() {
7205  DescriptorArray* descriptors = instance_descriptors();
7206  for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
7207    switch (descriptors->GetType(i)) {
7208      case MAP_TRANSITION:
7209      case CONSTANT_TRANSITION:
7210        CreateOneBackPointer(descriptors->GetValue(i));
7211        break;
7212      case ELEMENTS_TRANSITION: {
7213        Object* object = descriptors->GetValue(i);
7214        if (object->IsMap()) {
7215          CreateOneBackPointer(object);
7216        } else {
7217          FixedArray* array = FixedArray::cast(object);
7218          for (int i = 0; i < array->length(); ++i) {
7219            CreateOneBackPointer(array->get(i));
7220          }
7221        }
7222        break;
7223      }
7224      case CALLBACKS: {
7225        Object* object = descriptors->GetValue(i);
7226        if (object->IsAccessorPair()) {
7227          AccessorPair* accessors = AccessorPair::cast(object);
7228          CreateOneBackPointer(accessors->getter());
7229          CreateOneBackPointer(accessors->setter());
7230        }
7231        break;
7232      }
7233      case NORMAL:
7234      case FIELD:
7235      case CONSTANT_FUNCTION:
7236      case HANDLER:
7237      case INTERCEPTOR:
7238      case NULL_DESCRIPTOR:
7239        break;
7240    }
7241  }
7242}
7243
7244
7245bool Map::RestoreOneBackPointer(Object* object,
7246                                Object* real_prototype,
7247                                bool* keep_entry) {
7248  if (!object->IsMap()) return false;
7249  Map* map = Map::cast(object);
7250  if (Marking::MarkBitFrom(map).Get()) {
7251    *keep_entry = true;
7252    return false;
7253  }
7254  ASSERT(map->prototype() == this || map->prototype() == real_prototype);
7255  // Getter prototype() is read-only, set_prototype() has side effects.
7256  *RawField(map, Map::kPrototypeOffset) = real_prototype;
7257  return true;
7258}
7259
7260
7261void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
7262  DescriptorArray* d = DescriptorArray::cast(
7263      *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7264  if (d->IsEmpty()) return;
7265  Smi* NullDescriptorDetails =
7266    PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
7267  FixedArray* contents = FixedArray::cast(
7268      d->get(DescriptorArray::kContentArrayIndex));
7269  ASSERT(contents->length() >= 2);
7270  for (int i = 0; i < contents->length(); i += 2) {
7271    // If the pair (value, details) is a map transition, check if the target is
7272    // live. If not, null the descriptor. Also drop the back pointer for that
7273    // map transition, so that this map is not reached again by following a back
7274    // pointer from a non-live object.
7275    bool keep_entry = false;
7276    PropertyDetails details(Smi::cast(contents->get(i + 1)));
7277    switch (details.type()) {
7278      case MAP_TRANSITION:
7279      case CONSTANT_TRANSITION:
7280        RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
7281        break;
7282      case ELEMENTS_TRANSITION: {
7283        Object* object = contents->get(i);
7284        if (object->IsMap()) {
7285          RestoreOneBackPointer(object, real_prototype, &keep_entry);
7286        } else {
7287          FixedArray* array = FixedArray::cast(object);
7288          for (int j = 0; j < array->length(); ++j) {
7289            if (RestoreOneBackPointer(array->get(j),
7290                                      real_prototype,
7291                                      &keep_entry)) {
7292              array->set_undefined(j);
7293            }
7294          }
7295        }
7296        break;
7297      }
7298      case CALLBACKS: {
7299        Object* object = contents->get(i);
7300        if (object->IsAccessorPair()) {
7301          AccessorPair* accessors = AccessorPair::cast(object);
7302          if (RestoreOneBackPointer(accessors->getter(),
7303                                    real_prototype,
7304                                    &keep_entry)) {
7305            accessors->set_getter(heap->the_hole_value());
7306          }
7307          if (RestoreOneBackPointer(accessors->setter(),
7308                                    real_prototype,
7309                                    &keep_entry)) {
7310            accessors->set_setter(heap->the_hole_value());
7311          }
7312        } else {
7313          keep_entry = true;
7314        }
7315        break;
7316      }
7317      case NORMAL:
7318      case FIELD:
7319      case CONSTANT_FUNCTION:
7320      case HANDLER:
7321      case INTERCEPTOR:
7322      case NULL_DESCRIPTOR:
7323        keep_entry = true;
7324        break;
7325    }
7326    // Make sure that an entry containing only dead transitions gets collected.
7327    // What we *really* want to do here is removing this entry completely, but
7328    // for technical reasons we can't do this, so we zero it out instead.
7329    if (!keep_entry) {
7330      contents->set_unchecked(i + 1, NullDescriptorDetails);
7331      contents->set_null_unchecked(heap, i);
7332    }
7333  }
7334}
7335
7336
7337int Map::Hash() {
7338  // For performance reasons we only hash the 3 most variable fields of a map:
7339  // constructor, prototype and bit_field2.
7340
7341  // Shift away the tag.
7342  int hash = (static_cast<uint32_t>(
7343        reinterpret_cast<uintptr_t>(constructor())) >> 2);
7344
7345  // XOR-ing the prototype and constructor directly yields too many zero bits
7346  // when the two pointers are close (which is fairly common).
7347  // To avoid this we shift the prototype 4 bits relatively to the constructor.
7348  hash ^= (static_cast<uint32_t>(
7349        reinterpret_cast<uintptr_t>(prototype())) << 2);
7350
7351  return hash ^ (hash >> 16) ^ bit_field2();
7352}
7353
7354
7355bool Map::EquivalentToForNormalization(Map* other,
7356                                       PropertyNormalizationMode mode) {
7357  return
7358    constructor() == other->constructor() &&
7359    prototype() == other->prototype() &&
7360    inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7361                              0 :
7362                              other->inobject_properties()) &&
7363    instance_type() == other->instance_type() &&
7364    bit_field() == other->bit_field() &&
7365    bit_field2() == other->bit_field2() &&
7366    (bit_field3() & ~(1<<Map::kIsShared)) ==
7367        (other->bit_field3() & ~(1<<Map::kIsShared));
7368}
7369
7370
7371void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7372  // Iterate over all fields in the body but take care in dealing with
7373  // the code entry.
7374  IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7375  v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7376  IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7377}
7378
7379
7380void JSFunction::MarkForLazyRecompilation() {
7381  ASSERT(is_compiled() && !IsOptimized());
7382  ASSERT(shared()->allows_lazy_compilation() ||
7383         code()->optimizable());
7384  Builtins* builtins = GetIsolate()->builtins();
7385  ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
7386}
7387
7388
7389bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7390                                        ClearExceptionFlag flag) {
7391  return shared->is_compiled() || CompileLazy(shared, flag);
7392}
7393
7394
7395static bool CompileLazyHelper(CompilationInfo* info,
7396                              ClearExceptionFlag flag) {
7397  // Compile the source information to a code object.
7398  ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7399  ASSERT(!info->isolate()->has_pending_exception());
7400  bool result = Compiler::CompileLazy(info);
7401  ASSERT(result != Isolate::Current()->has_pending_exception());
7402  if (!result && flag == CLEAR_EXCEPTION) {
7403    info->isolate()->clear_pending_exception();
7404  }
7405  return result;
7406}
7407
7408
7409bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7410                                     ClearExceptionFlag flag) {
7411  CompilationInfo info(shared);
7412  return CompileLazyHelper(&info, flag);
7413}
7414
7415
7416bool JSFunction::CompileLazy(Handle<JSFunction> function,
7417                             ClearExceptionFlag flag) {
7418  bool result = true;
7419  if (function->shared()->is_compiled()) {
7420    function->ReplaceCode(function->shared()->code());
7421    function->shared()->set_code_age(0);
7422  } else {
7423    CompilationInfo info(function);
7424    result = CompileLazyHelper(&info, flag);
7425    ASSERT(!result || function->is_compiled());
7426  }
7427  return result;
7428}
7429
7430
7431bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7432                                  int osr_ast_id,
7433                                  ClearExceptionFlag flag) {
7434  CompilationInfo info(function);
7435  info.SetOptimizing(osr_ast_id);
7436  return CompileLazyHelper(&info, flag);
7437}
7438
7439
7440bool JSFunction::IsInlineable() {
7441  if (IsBuiltin()) return false;
7442  SharedFunctionInfo* shared_info = shared();
7443  // Check that the function has a script associated with it.
7444  if (!shared_info->script()->IsScript()) return false;
7445  if (shared_info->optimization_disabled()) return false;
7446  Code* code = shared_info->code();
7447  if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7448  // If we never ran this (unlikely) then lets try to optimize it.
7449  if (code->kind() != Code::FUNCTION) return true;
7450  return code->optimizable();
7451}
7452
7453
7454MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
7455  ASSERT(value->IsJSReceiver());
7456  Heap* heap = GetHeap();
7457  if (has_initial_map()) {
7458    // If the function has allocated the initial map
7459    // replace it with a copy containing the new prototype.
7460    Map* new_map;
7461    MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
7462    if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7463    new_map->set_prototype(value);
7464    MaybeObject* maybe_object =
7465        set_initial_map_and_cache_transitions(new_map);
7466    if (maybe_object->IsFailure()) return maybe_object;
7467  } else {
7468    // Put the value in the initial map field until an initial map is
7469    // needed.  At that point, a new initial map is created and the
7470    // prototype is put into the initial map where it belongs.
7471    set_prototype_or_initial_map(value);
7472  }
7473  heap->ClearInstanceofCache();
7474  return value;
7475}
7476
7477
7478MaybeObject* JSFunction::SetPrototype(Object* value) {
7479  ASSERT(should_have_prototype());
7480  Object* construct_prototype = value;
7481
7482  // If the value is not a JSReceiver, store the value in the map's
7483  // constructor field so it can be accessed.  Also, set the prototype
7484  // used for constructing objects to the original object prototype.
7485  // See ECMA-262 13.2.2.
7486  if (!value->IsJSReceiver()) {
7487    // Copy the map so this does not affect unrelated functions.
7488    // Remove map transitions because they point to maps with a
7489    // different prototype.
7490    Map* new_map;
7491    { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
7492      if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7493    }
7494    Heap* heap = new_map->GetHeap();
7495    set_map(new_map);
7496    new_map->set_constructor(value);
7497    new_map->set_non_instance_prototype(true);
7498    construct_prototype =
7499        heap->isolate()->context()->global_context()->
7500            initial_object_prototype();
7501  } else {
7502    map()->set_non_instance_prototype(false);
7503  }
7504
7505  return SetInstancePrototype(construct_prototype);
7506}
7507
7508
7509Object* JSFunction::RemovePrototype() {
7510  Context* global_context = context()->global_context();
7511  Map* no_prototype_map = shared()->is_classic_mode()
7512      ? global_context->function_without_prototype_map()
7513      : global_context->strict_mode_function_without_prototype_map();
7514
7515  if (map() == no_prototype_map) {
7516    // Be idempotent.
7517    return this;
7518  }
7519
7520  ASSERT(map() == (shared()->is_classic_mode()
7521                   ? global_context->function_map()
7522                   : global_context->strict_mode_function_map()));
7523
7524  set_map(no_prototype_map);
7525  set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
7526  return this;
7527}
7528
7529
7530Object* JSFunction::SetInstanceClassName(String* name) {
7531  shared()->set_instance_class_name(name);
7532  return this;
7533}
7534
7535
7536void JSFunction::PrintName(FILE* out) {
7537  SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
7538  PrintF(out, "%s", *name);
7539}
7540
7541
7542Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7543  return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7544}
7545
7546
7547MaybeObject* Oddball::Initialize(const char* to_string,
7548                                 Object* to_number,
7549                                 byte kind) {
7550  String* symbol;
7551  { MaybeObject* maybe_symbol =
7552        Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
7553    if (!maybe_symbol->To(&symbol)) return maybe_symbol;
7554  }
7555  set_to_string(symbol);
7556  set_to_number(to_number);
7557  set_kind(kind);
7558  return this;
7559}
7560
7561
7562String* SharedFunctionInfo::DebugName() {
7563  Object* n = name();
7564  if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7565  return String::cast(n);
7566}
7567
7568
7569bool SharedFunctionInfo::HasSourceCode() {
7570  return !script()->IsUndefined() &&
7571         !reinterpret_cast<Script*>(script())->source()->IsUndefined();
7572}
7573
7574
7575Handle<Object> SharedFunctionInfo::GetSourceCode() {
7576  if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
7577  Handle<String> source(String::cast(Script::cast(script())->source()));
7578  return SubString(source, start_position(), end_position());
7579}
7580
7581
7582int SharedFunctionInfo::SourceSize() {
7583  return end_position() - start_position();
7584}
7585
7586
7587int SharedFunctionInfo::CalculateInstanceSize() {
7588  int instance_size =
7589      JSObject::kHeaderSize +
7590      expected_nof_properties() * kPointerSize;
7591  if (instance_size > JSObject::kMaxInstanceSize) {
7592    instance_size = JSObject::kMaxInstanceSize;
7593  }
7594  return instance_size;
7595}
7596
7597
7598int SharedFunctionInfo::CalculateInObjectProperties() {
7599  return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7600}
7601
7602
7603bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7604  // Check the basic conditions for generating inline constructor code.
7605  if (!FLAG_inline_new
7606      || !has_only_simple_this_property_assignments()
7607      || this_property_assignments_count() == 0) {
7608    return false;
7609  }
7610
7611  // If the prototype is null inline constructors cause no problems.
7612  if (!prototype->IsJSObject()) {
7613    ASSERT(prototype->IsNull());
7614    return true;
7615  }
7616
7617  Heap* heap = GetHeap();
7618
7619  // Traverse the proposed prototype chain looking for setters for properties of
7620  // the same names as are set by the inline constructor.
7621  for (Object* obj = prototype;
7622       obj != heap->null_value();
7623       obj = obj->GetPrototype()) {
7624    JSObject* js_object = JSObject::cast(obj);
7625    for (int i = 0; i < this_property_assignments_count(); i++) {
7626      LookupResult result(heap->isolate());
7627      String* name = GetThisPropertyAssignmentName(i);
7628      js_object->LocalLookupRealNamedProperty(name, &result);
7629      if (result.IsFound() && result.type() == CALLBACKS) {
7630        return false;
7631      }
7632    }
7633  }
7634
7635  return true;
7636}
7637
7638
7639void SharedFunctionInfo::ForbidInlineConstructor() {
7640  set_compiler_hints(BooleanBit::set(compiler_hints(),
7641                                     kHasOnlySimpleThisPropertyAssignments,
7642                                     false));
7643}
7644
7645
7646void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
7647    bool only_simple_this_property_assignments,
7648    FixedArray* assignments) {
7649  set_compiler_hints(BooleanBit::set(compiler_hints(),
7650                                     kHasOnlySimpleThisPropertyAssignments,
7651                                     only_simple_this_property_assignments));
7652  set_this_property_assignments(assignments);
7653  set_this_property_assignments_count(assignments->length() / 3);
7654}
7655
7656
7657void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
7658  Heap* heap = GetHeap();
7659  set_compiler_hints(BooleanBit::set(compiler_hints(),
7660                                     kHasOnlySimpleThisPropertyAssignments,
7661                                     false));
7662  set_this_property_assignments(heap->undefined_value());
7663  set_this_property_assignments_count(0);
7664}
7665
7666
7667String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7668  Object* obj = this_property_assignments();
7669  ASSERT(obj->IsFixedArray());
7670  ASSERT(index < this_property_assignments_count());
7671  obj = FixedArray::cast(obj)->get(index * 3);
7672  ASSERT(obj->IsString());
7673  return String::cast(obj);
7674}
7675
7676
7677bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7678  Object* obj = this_property_assignments();
7679  ASSERT(obj->IsFixedArray());
7680  ASSERT(index < this_property_assignments_count());
7681  obj = FixedArray::cast(obj)->get(index * 3 + 1);
7682  return Smi::cast(obj)->value() != -1;
7683}
7684
7685
7686int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7687  ASSERT(IsThisPropertyAssignmentArgument(index));
7688  Object* obj =
7689      FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7690  return Smi::cast(obj)->value();
7691}
7692
7693
7694Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7695  ASSERT(!IsThisPropertyAssignmentArgument(index));
7696  Object* obj =
7697      FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7698  return obj;
7699}
7700
7701
7702// Support function for printing the source code to a StringStream
7703// without any allocation in the heap.
7704void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7705                                         int max_length) {
7706  // For some native functions there is no source.
7707  if (!HasSourceCode()) {
7708    accumulator->Add("<No Source>");
7709    return;
7710  }
7711
7712  // Get the source for the script which this function came from.
7713  // Don't use String::cast because we don't want more assertion errors while
7714  // we are already creating a stack dump.
7715  String* script_source =
7716      reinterpret_cast<String*>(Script::cast(script())->source());
7717
7718  if (!script_source->LooksValid()) {
7719    accumulator->Add("<Invalid Source>");
7720    return;
7721  }
7722
7723  if (!is_toplevel()) {
7724    accumulator->Add("function ");
7725    Object* name = this->name();
7726    if (name->IsString() && String::cast(name)->length() > 0) {
7727      accumulator->PrintName(name);
7728    }
7729  }
7730
7731  int len = end_position() - start_position();
7732  if (len <= max_length || max_length < 0) {
7733    accumulator->Put(script_source, start_position(), end_position());
7734  } else {
7735    accumulator->Put(script_source,
7736                     start_position(),
7737                     start_position() + max_length);
7738    accumulator->Add("...\n");
7739  }
7740}
7741
7742
7743static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7744  if (code->instruction_size() != recompiled->instruction_size()) return false;
7745  ByteArray* code_relocation = code->relocation_info();
7746  ByteArray* recompiled_relocation = recompiled->relocation_info();
7747  int length = code_relocation->length();
7748  if (length != recompiled_relocation->length()) return false;
7749  int compare = memcmp(code_relocation->GetDataStartAddress(),
7750                       recompiled_relocation->GetDataStartAddress(),
7751                       length);
7752  return compare == 0;
7753}
7754
7755
7756void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7757  ASSERT(!has_deoptimization_support());
7758  AssertNoAllocation no_allocation;
7759  Code* code = this->code();
7760  if (IsCodeEquivalent(code, recompiled)) {
7761    // Copy the deoptimization data from the recompiled code.
7762    code->set_deoptimization_data(recompiled->deoptimization_data());
7763    code->set_has_deoptimization_support(true);
7764  } else {
7765    // TODO(3025757): In case the recompiled isn't equivalent to the
7766    // old code, we have to replace it. We should try to avoid this
7767    // altogether because it flushes valuable type feedback by
7768    // effectively resetting all IC state.
7769    set_code(recompiled);
7770  }
7771  ASSERT(has_deoptimization_support());
7772}
7773
7774
7775void SharedFunctionInfo::DisableOptimization() {
7776  // Disable optimization for the shared function info and mark the
7777  // code as non-optimizable. The marker on the shared function info
7778  // is there because we flush non-optimized code thereby loosing the
7779  // non-optimizable information for the code. When the code is
7780  // regenerated and set on the shared function info it is marked as
7781  // non-optimizable if optimization is disabled for the shared
7782  // function info.
7783  set_optimization_disabled(true);
7784  // Code should be the lazy compilation stub or else unoptimized.  If the
7785  // latter, disable optimization for the code too.
7786  ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7787  if (code()->kind() == Code::FUNCTION) {
7788    code()->set_optimizable(false);
7789  }
7790  if (FLAG_trace_opt) {
7791    PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
7792  }
7793}
7794
7795
7796bool SharedFunctionInfo::VerifyBailoutId(int id) {
7797  ASSERT(id != AstNode::kNoNumber);
7798  Code* unoptimized = code();
7799  DeoptimizationOutputData* data =
7800      DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7801  unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7802  USE(ignore);
7803  return true;  // Return true if there was no ASSERT.
7804}
7805
7806
7807void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7808  ASSERT(!IsInobjectSlackTrackingInProgress());
7809
7810  if (!FLAG_clever_optimizations) return;
7811
7812  // Only initiate the tracking the first time.
7813  if (live_objects_may_exist()) return;
7814  set_live_objects_may_exist(true);
7815
7816  // No tracking during the snapshot construction phase.
7817  if (Serializer::enabled()) return;
7818
7819  if (map->unused_property_fields() == 0) return;
7820
7821  // Nonzero counter is a leftover from the previous attempt interrupted
7822  // by GC, keep it.
7823  if (construction_count() == 0) {
7824    set_construction_count(kGenerousAllocationCount);
7825  }
7826  set_initial_map(map);
7827  Builtins* builtins = map->GetHeap()->isolate()->builtins();
7828  ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
7829            construct_stub());
7830  set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
7831}
7832
7833
7834// Called from GC, hence reinterpret_cast and unchecked accessors.
7835void SharedFunctionInfo::DetachInitialMap() {
7836  Map* map = reinterpret_cast<Map*>(initial_map());
7837
7838  // Make the map remember to restore the link if it survives the GC.
7839  map->set_bit_field2(
7840      map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7841
7842  // Undo state changes made by StartInobjectTracking (except the
7843  // construction_count). This way if the initial map does not survive the GC
7844  // then StartInobjectTracking will be called again the next time the
7845  // constructor is called. The countdown will continue and (possibly after
7846  // several more GCs) CompleteInobjectSlackTracking will eventually be called.
7847  Heap* heap = map->GetHeap();
7848  set_initial_map(heap->raw_unchecked_undefined_value());
7849  Builtins* builtins = heap->isolate()->builtins();
7850  ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
7851            *RawField(this, kConstructStubOffset));
7852  set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
7853  // It is safe to clear the flag: it will be set again if the map is live.
7854  set_live_objects_may_exist(false);
7855}
7856
7857
7858// Called from GC, hence reinterpret_cast and unchecked accessors.
7859void SharedFunctionInfo::AttachInitialMap(Map* map) {
7860  map->set_bit_field2(
7861      map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7862
7863  // Resume inobject slack tracking.
7864  set_initial_map(map);
7865  Builtins* builtins = map->GetHeap()->isolate()->builtins();
7866  ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
7867            *RawField(this, kConstructStubOffset));
7868  set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
7869  // The map survived the gc, so there may be objects referencing it.
7870  set_live_objects_may_exist(true);
7871}
7872
7873
7874void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
7875  code()->ClearInlineCaches();
7876  set_ic_age(new_ic_age);
7877  if (code()->kind() == Code::FUNCTION) {
7878    code()->set_profiler_ticks(0);
7879    if (optimization_disabled() &&
7880        opt_count() >= Compiler::kDefaultMaxOptCount) {
7881      // Re-enable optimizations if they were disabled due to opt_count limit.
7882      set_optimization_disabled(false);
7883      code()->set_optimizable(true);
7884    }
7885    set_opt_count(0);
7886  }
7887}
7888
7889
7890static void GetMinInobjectSlack(Map* map, void* data) {
7891  int slack = map->unused_property_fields();
7892  if (*reinterpret_cast<int*>(data) > slack) {
7893    *reinterpret_cast<int*>(data) = slack;
7894  }
7895}
7896
7897
7898static void ShrinkInstanceSize(Map* map, void* data) {
7899  int slack = *reinterpret_cast<int*>(data);
7900  map->set_inobject_properties(map->inobject_properties() - slack);
7901  map->set_unused_property_fields(map->unused_property_fields() - slack);
7902  map->set_instance_size(map->instance_size() - slack * kPointerSize);
7903
7904  // Visitor id might depend on the instance size, recalculate it.
7905  map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7906}
7907
7908
7909void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7910  ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7911  Map* map = Map::cast(initial_map());
7912
7913  Heap* heap = map->GetHeap();
7914  set_initial_map(heap->undefined_value());
7915  Builtins* builtins = heap->isolate()->builtins();
7916  ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
7917            construct_stub());
7918  set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
7919
7920  int slack = map->unused_property_fields();
7921  map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7922  if (slack != 0) {
7923    // Resize the initial map and all maps in its transition tree.
7924    map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
7925
7926    // Give the correct expected_nof_properties to initial maps created later.
7927    ASSERT(expected_nof_properties() >= slack);
7928    set_expected_nof_properties(expected_nof_properties() - slack);
7929  }
7930}
7931
7932
7933void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
7934  v->VisitSharedFunctionInfo(this);
7935  SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
7936}
7937
7938
7939#define DECLARE_TAG(ignore1, name, ignore2) name,
7940const char* const VisitorSynchronization::kTags[
7941    VisitorSynchronization::kNumberOfSyncTags] = {
7942  VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7943};
7944#undef DECLARE_TAG
7945
7946
7947#define DECLARE_TAG(ignore1, ignore2, name) name,
7948const char* const VisitorSynchronization::kTagNames[
7949    VisitorSynchronization::kNumberOfSyncTags] = {
7950  VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7951};
7952#undef DECLARE_TAG
7953
7954
7955void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
7956  ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
7957  Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7958  Object* old_target = target;
7959  VisitPointer(&target);
7960  CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
7961}
7962
7963
7964void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7965  Object* code = Code::GetObjectFromEntryAddress(entry_address);
7966  Object* old_code = code;
7967  VisitPointer(&code);
7968  if (code != old_code) {
7969    Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7970  }
7971}
7972
7973
7974void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7975  ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7976  Object* cell = rinfo->target_cell();
7977  Object* old_cell = cell;
7978  VisitPointer(&cell);
7979  if (cell != old_cell) {
7980    rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7981  }
7982}
7983
7984
7985void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
7986  ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
7987          rinfo->IsPatchedReturnSequence()) ||
7988         (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
7989          rinfo->IsPatchedDebugBreakSlotSequence()));
7990  Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
7991  Object* old_target = target;
7992  VisitPointer(&target);
7993  CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
7994}
7995
7996void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
7997  ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
7998  VisitPointer(rinfo->target_object_address());
7999}
8000
8001void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
8002  Address* p = rinfo->target_reference_address();
8003  VisitExternalReferences(p, p + 1);
8004}
8005
8006void Code::InvalidateRelocation() {
8007  set_relocation_info(GetHeap()->empty_byte_array());
8008}
8009
8010
8011void Code::Relocate(intptr_t delta) {
8012  for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
8013    it.rinfo()->apply(delta);
8014  }
8015  CPU::FlushICache(instruction_start(), instruction_size());
8016}
8017
8018
8019void Code::CopyFrom(const CodeDesc& desc) {
8020  ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
8021
8022  // copy code
8023  memmove(instruction_start(), desc.buffer, desc.instr_size);
8024
8025  // copy reloc info
8026  memmove(relocation_start(),
8027          desc.buffer + desc.buffer_size - desc.reloc_size,
8028          desc.reloc_size);
8029
8030  // unbox handles and relocate
8031  intptr_t delta = instruction_start() - desc.buffer;
8032  int mode_mask = RelocInfo::kCodeTargetMask |
8033                  RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
8034                  RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
8035                  RelocInfo::kApplyMask;
8036  Assembler* origin = desc.origin;  // Needed to find target_object on X64.
8037  for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
8038    RelocInfo::Mode mode = it.rinfo()->rmode();
8039    if (mode == RelocInfo::EMBEDDED_OBJECT) {
8040      Handle<Object> p = it.rinfo()->target_object_handle(origin);
8041      it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
8042    } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
8043      Handle<JSGlobalPropertyCell> cell  = it.rinfo()->target_cell_handle();
8044      it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
8045    } else if (RelocInfo::IsCodeTarget(mode)) {
8046      // rewrite code handles in inline cache targets to direct
8047      // pointers to the first instruction in the code object
8048      Handle<Object> p = it.rinfo()->target_object_handle(origin);
8049      Code* code = Code::cast(*p);
8050      it.rinfo()->set_target_address(code->instruction_start(),
8051                                     SKIP_WRITE_BARRIER);
8052    } else {
8053      it.rinfo()->apply(delta);
8054    }
8055  }
8056  CPU::FlushICache(instruction_start(), instruction_size());
8057}
8058
8059
8060// Locate the source position which is closest to the address in the code. This
8061// is using the source position information embedded in the relocation info.
8062// The position returned is relative to the beginning of the script where the
8063// source for this function is found.
8064int Code::SourcePosition(Address pc) {
8065  int distance = kMaxInt;
8066  int position = RelocInfo::kNoPosition;  // Initially no position found.
8067  // Run through all the relocation info to find the best matching source
8068  // position. All the code needs to be considered as the sequence of the
8069  // instructions in the code does not necessarily follow the same order as the
8070  // source.
8071  RelocIterator it(this, RelocInfo::kPositionMask);
8072  while (!it.done()) {
8073    // Only look at positions after the current pc.
8074    if (it.rinfo()->pc() < pc) {
8075      // Get position and distance.
8076
8077      int dist = static_cast<int>(pc - it.rinfo()->pc());
8078      int pos = static_cast<int>(it.rinfo()->data());
8079      // If this position is closer than the current candidate or if it has the
8080      // same distance as the current candidate and the position is higher then
8081      // this position is the new candidate.
8082      if ((dist < distance) ||
8083          (dist == distance && pos > position)) {
8084        position = pos;
8085        distance = dist;
8086      }
8087    }
8088    it.next();
8089  }
8090  return position;
8091}
8092
8093
8094// Same as Code::SourcePosition above except it only looks for statement
8095// positions.
8096int Code::SourceStatementPosition(Address pc) {
8097  // First find the position as close as possible using all position
8098  // information.
8099  int position = SourcePosition(pc);
8100  // Now find the closest statement position before the position.
8101  int statement_position = 0;
8102  RelocIterator it(this, RelocInfo::kPositionMask);
8103  while (!it.done()) {
8104    if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
8105      int p = static_cast<int>(it.rinfo()->data());
8106      if (statement_position < p && p <= position) {
8107        statement_position = p;
8108      }
8109    }
8110    it.next();
8111  }
8112  return statement_position;
8113}
8114
8115
8116SafepointEntry Code::GetSafepointEntry(Address pc) {
8117  SafepointTable table(this);
8118  return table.FindEntry(pc);
8119}
8120
8121
8122void Code::SetNoStackCheckTable() {
8123  // Indicate the absence of a stack-check table by a table start after the
8124  // end of the instructions.  Table start must be aligned, so round up.
8125  set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
8126}
8127
8128
8129Map* Code::FindFirstMap() {
8130  ASSERT(is_inline_cache_stub());
8131  AssertNoAllocation no_allocation;
8132  int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8133  for (RelocIterator it(this, mask); !it.done(); it.next()) {
8134    RelocInfo* info = it.rinfo();
8135    Object* object = info->target_object();
8136    if (object->IsMap()) return Map::cast(object);
8137  }
8138  return NULL;
8139}
8140
8141
8142void Code::ClearInlineCaches() {
8143  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
8144             RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
8145             RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
8146             RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
8147  for (RelocIterator it(this, mask); !it.done(); it.next()) {
8148    RelocInfo* info = it.rinfo();
8149    Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
8150    if (target->is_inline_cache_stub()) {
8151      IC::Clear(info->pc());
8152    }
8153  }
8154}
8155
8156
8157#ifdef ENABLE_DISASSEMBLER
8158
8159void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
8160  disasm::NameConverter converter;
8161  int deopt_count = DeoptCount();
8162  PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
8163  if (0 == deopt_count) return;
8164
8165  PrintF(out, "%6s  %6s  %6s %6s %12s\n", "index", "ast id", "argc", "pc",
8166         FLAG_print_code_verbose ? "commands" : "");
8167  for (int i = 0; i < deopt_count; i++) {
8168    PrintF(out, "%6d  %6d  %6d %6d",
8169           i,
8170           AstId(i)->value(),
8171           ArgumentsStackHeight(i)->value(),
8172           Pc(i)->value());
8173
8174    if (!FLAG_print_code_verbose) {
8175      PrintF(out, "\n");
8176      continue;
8177    }
8178    // Print details of the frame translation.
8179    int translation_index = TranslationIndex(i)->value();
8180    TranslationIterator iterator(TranslationByteArray(), translation_index);
8181    Translation::Opcode opcode =
8182        static_cast<Translation::Opcode>(iterator.Next());
8183    ASSERT(Translation::BEGIN == opcode);
8184    int frame_count = iterator.Next();
8185    int jsframe_count = iterator.Next();
8186    PrintF(out, "  %s {frame count=%d, js frame count=%d}\n",
8187           Translation::StringFor(opcode),
8188           frame_count,
8189           jsframe_count);
8190
8191    while (iterator.HasNext() &&
8192           Translation::BEGIN !=
8193           (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8194      PrintF(out, "%24s    %s ", "", Translation::StringFor(opcode));
8195
8196      switch (opcode) {
8197        case Translation::BEGIN:
8198          UNREACHABLE();
8199          break;
8200
8201        case Translation::JS_FRAME: {
8202          int ast_id = iterator.Next();
8203          int function_id = iterator.Next();
8204          JSFunction* function =
8205              JSFunction::cast(LiteralArray()->get(function_id));
8206          unsigned height = iterator.Next();
8207          PrintF(out, "{ast_id=%d, function=", ast_id);
8208          function->PrintName(out);
8209          PrintF(out, ", height=%u}", height);
8210          break;
8211        }
8212
8213        case Translation::ARGUMENTS_ADAPTOR_FRAME:
8214        case Translation::CONSTRUCT_STUB_FRAME: {
8215          int function_id = iterator.Next();
8216          JSFunction* function =
8217              JSFunction::cast(LiteralArray()->get(function_id));
8218          unsigned height = iterator.Next();
8219          PrintF(out, "{function=");
8220          function->PrintName(out);
8221          PrintF(out, ", height=%u}", height);
8222          break;
8223        }
8224
8225        case Translation::DUPLICATE:
8226          break;
8227
8228        case Translation::REGISTER: {
8229          int reg_code = iterator.Next();
8230            PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8231          break;
8232        }
8233
8234        case Translation::INT32_REGISTER: {
8235          int reg_code = iterator.Next();
8236          PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8237          break;
8238        }
8239
8240        case Translation::DOUBLE_REGISTER: {
8241          int reg_code = iterator.Next();
8242          PrintF(out, "{input=%s}",
8243                 DoubleRegister::AllocationIndexToString(reg_code));
8244          break;
8245        }
8246
8247        case Translation::STACK_SLOT: {
8248          int input_slot_index = iterator.Next();
8249          PrintF(out, "{input=%d}", input_slot_index);
8250          break;
8251        }
8252
8253        case Translation::INT32_STACK_SLOT: {
8254          int input_slot_index = iterator.Next();
8255          PrintF(out, "{input=%d}", input_slot_index);
8256          break;
8257        }
8258
8259        case Translation::DOUBLE_STACK_SLOT: {
8260          int input_slot_index = iterator.Next();
8261          PrintF(out, "{input=%d}", input_slot_index);
8262          break;
8263        }
8264
8265        case Translation::LITERAL: {
8266          unsigned literal_index = iterator.Next();
8267          PrintF(out, "{literal_id=%u}", literal_index);
8268          break;
8269        }
8270
8271        case Translation::ARGUMENTS_OBJECT:
8272          break;
8273      }
8274      PrintF(out, "\n");
8275    }
8276  }
8277}
8278
8279
8280void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8281  PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
8282         this->DeoptPoints());
8283  if (this->DeoptPoints() == 0) return;
8284
8285  PrintF("%6s  %8s  %s\n", "ast id", "pc", "state");
8286  for (int i = 0; i < this->DeoptPoints(); i++) {
8287    int pc_and_state = this->PcAndState(i)->value();
8288    PrintF("%6d  %8d  %s\n",
8289           this->AstId(i)->value(),
8290           FullCodeGenerator::PcField::decode(pc_and_state),
8291           FullCodeGenerator::State2String(
8292               FullCodeGenerator::StateField::decode(pc_and_state)));
8293  }
8294}
8295
8296
8297// Identify kind of code.
8298const char* Code::Kind2String(Kind kind) {
8299  switch (kind) {
8300    case FUNCTION: return "FUNCTION";
8301    case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
8302    case STUB: return "STUB";
8303    case BUILTIN: return "BUILTIN";
8304    case LOAD_IC: return "LOAD_IC";
8305    case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8306    case STORE_IC: return "STORE_IC";
8307    case KEYED_STORE_IC: return "KEYED_STORE_IC";
8308    case CALL_IC: return "CALL_IC";
8309    case KEYED_CALL_IC: return "KEYED_CALL_IC";
8310    case UNARY_OP_IC: return "UNARY_OP_IC";
8311    case BINARY_OP_IC: return "BINARY_OP_IC";
8312    case COMPARE_IC: return "COMPARE_IC";
8313    case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
8314  }
8315  UNREACHABLE();
8316  return NULL;
8317}
8318
8319
8320const char* Code::ICState2String(InlineCacheState state) {
8321  switch (state) {
8322    case UNINITIALIZED: return "UNINITIALIZED";
8323    case PREMONOMORPHIC: return "PREMONOMORPHIC";
8324    case MONOMORPHIC: return "MONOMORPHIC";
8325    case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8326    case MEGAMORPHIC: return "MEGAMORPHIC";
8327    case DEBUG_BREAK: return "DEBUG_BREAK";
8328    case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8329  }
8330  UNREACHABLE();
8331  return NULL;
8332}
8333
8334
8335const char* Code::PropertyType2String(PropertyType type) {
8336  switch (type) {
8337    case NORMAL: return "NORMAL";
8338    case FIELD: return "FIELD";
8339    case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8340    case CALLBACKS: return "CALLBACKS";
8341    case HANDLER: return "HANDLER";
8342    case INTERCEPTOR: return "INTERCEPTOR";
8343    case MAP_TRANSITION: return "MAP_TRANSITION";
8344    case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
8345    case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8346    case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8347  }
8348  UNREACHABLE();  // keep the compiler happy
8349  return NULL;
8350}
8351
8352
8353void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8354  const char* name = NULL;
8355  switch (kind) {
8356    case CALL_IC:
8357      if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8358        name = "STRING_INDEX_OUT_OF_BOUNDS";
8359      }
8360      break;
8361    case STORE_IC:
8362    case KEYED_STORE_IC:
8363      if (extra == kStrictMode) {
8364        name = "STRICT";
8365      }
8366      break;
8367    default:
8368      break;
8369  }
8370  if (name != NULL) {
8371    PrintF(out, "extra_ic_state = %s\n", name);
8372  } else {
8373    PrintF(out, "extra_ic_state = %d\n", extra);
8374  }
8375}
8376
8377
8378void Code::Disassemble(const char* name, FILE* out) {
8379  PrintF(out, "kind = %s\n", Kind2String(kind()));
8380  if (is_inline_cache_stub()) {
8381    PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
8382    PrintExtraICState(out, kind(), extra_ic_state());
8383    if (ic_state() == MONOMORPHIC) {
8384      PrintF(out, "type = %s\n", PropertyType2String(type()));
8385    }
8386    if (is_call_stub() || is_keyed_call_stub()) {
8387      PrintF(out, "argc = %d\n", arguments_count());
8388    }
8389  }
8390  if ((name != NULL) && (name[0] != '\0')) {
8391    PrintF(out, "name = %s\n", name);
8392  }
8393  if (kind() == OPTIMIZED_FUNCTION) {
8394    PrintF(out, "stack_slots = %d\n", stack_slots());
8395  }
8396
8397  PrintF(out, "Instructions (size = %d)\n", instruction_size());
8398  Disassembler::Decode(out, this);
8399  PrintF(out, "\n");
8400
8401  if (kind() == FUNCTION) {
8402    DeoptimizationOutputData* data =
8403        DeoptimizationOutputData::cast(this->deoptimization_data());
8404    data->DeoptimizationOutputDataPrint(out);
8405  } else if (kind() == OPTIMIZED_FUNCTION) {
8406    DeoptimizationInputData* data =
8407        DeoptimizationInputData::cast(this->deoptimization_data());
8408    data->DeoptimizationInputDataPrint(out);
8409  }
8410  PrintF("\n");
8411
8412  if (kind() == OPTIMIZED_FUNCTION) {
8413    SafepointTable table(this);
8414    PrintF(out, "Safepoints (size = %u)\n", table.size());
8415    for (unsigned i = 0; i < table.length(); i++) {
8416      unsigned pc_offset = table.GetPcOffset(i);
8417      PrintF(out, "%p  %4d  ", (instruction_start() + pc_offset), pc_offset);
8418      table.PrintEntry(i);
8419      PrintF(out, " (sp -> fp)");
8420      SafepointEntry entry = table.GetEntry(i);
8421      if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8422        PrintF(out, "  %6d", entry.deoptimization_index());
8423      } else {
8424        PrintF(out, "  <none>");
8425      }
8426      if (entry.argument_count() > 0) {
8427        PrintF(out, " argc: %d", entry.argument_count());
8428      }
8429      PrintF(out, "\n");
8430    }
8431    PrintF(out, "\n");
8432  } else if (kind() == FUNCTION) {
8433    unsigned offset = stack_check_table_offset();
8434    // If there is no stack check table, the "table start" will at or after
8435    // (due to alignment) the end of the instruction stream.
8436    if (static_cast<int>(offset) < instruction_size()) {
8437      unsigned* address =
8438          reinterpret_cast<unsigned*>(instruction_start() + offset);
8439      unsigned length = address[0];
8440      PrintF(out, "Stack checks (size = %u)\n", length);
8441      PrintF(out, "ast_id  pc_offset\n");
8442      for (unsigned i = 0; i < length; ++i) {
8443        unsigned index = (2 * i) + 1;
8444        PrintF(out, "%6u  %9u\n", address[index], address[index + 1]);
8445      }
8446      PrintF(out, "\n");
8447    }
8448  }
8449
8450  PrintF("RelocInfo (size = %d)\n", relocation_size());
8451  for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8452  PrintF(out, "\n");
8453}
8454#endif  // ENABLE_DISASSEMBLER
8455
8456
8457MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8458    int capacity,
8459    int length,
8460    SetFastElementsCapacityMode set_capacity_mode) {
8461  Heap* heap = GetHeap();
8462  // We should never end in here with a pixel or external array.
8463  ASSERT(!HasExternalArrayElements());
8464
8465  // Allocate a new fast elements backing store.
8466  FixedArray* new_elements;
8467  { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8468    if (!maybe->To(&new_elements)) return maybe;
8469  }
8470
8471  // Find the new map to use for this object if there is a map change.
8472  Map* new_map = NULL;
8473  if (elements()->map() != heap->non_strict_arguments_elements_map()) {
8474    // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8475    // it, or if it's allowed and the old elements array contained only SMIs.
8476    bool has_fast_smi_only_elements =
8477        (set_capacity_mode == kForceSmiOnlyElements) ||
8478        ((set_capacity_mode == kAllowSmiOnlyElements) &&
8479         (elements()->map()->has_fast_smi_only_elements() ||
8480          elements() == heap->empty_fixed_array()));
8481    ElementsKind elements_kind = has_fast_smi_only_elements
8482        ? FAST_SMI_ONLY_ELEMENTS
8483        : FAST_ELEMENTS;
8484    MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
8485    if (!maybe->To(&new_map)) return maybe;
8486  }
8487
8488  FixedArrayBase* old_elements = elements();
8489  ElementsKind elements_kind = GetElementsKind();
8490  ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8491  ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
8492      ? FAST_SMI_ONLY_ELEMENTS
8493      : FAST_ELEMENTS;
8494  //  int copy_size = Min(old_elements_raw->length(), new_elements->length());
8495  accessor->CopyElements(this, new_elements, to_kind);
8496  if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8497    set_map_and_elements(new_map, new_elements);
8498  } else {
8499    FixedArray* parameter_map = FixedArray::cast(old_elements);
8500    parameter_map->set(1, new_elements);
8501  }
8502
8503  if (FLAG_trace_elements_transitions) {
8504    PrintElementsTransition(stdout, elements_kind, old_elements,
8505                            GetElementsKind(), new_elements);
8506  }
8507
8508  // Update the length if necessary.
8509  if (IsJSArray()) {
8510    JSArray::cast(this)->set_length(Smi::FromInt(length));
8511  }
8512
8513  return new_elements;
8514}
8515
8516
8517MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8518    int capacity,
8519    int length) {
8520  Heap* heap = GetHeap();
8521  // We should never end in here with a pixel or external array.
8522  ASSERT(!HasExternalArrayElements());
8523
8524  FixedArrayBase* elems;
8525  { MaybeObject* maybe_obj =
8526        heap->AllocateUninitializedFixedDoubleArray(capacity);
8527    if (!maybe_obj->To(&elems)) return maybe_obj;
8528  }
8529
8530  Map* new_map;
8531  { MaybeObject* maybe_obj =
8532        GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
8533    if (!maybe_obj->To(&new_map)) return maybe_obj;
8534  }
8535
8536  FixedArrayBase* old_elements = elements();
8537  ElementsKind elements_kind = GetElementsKind();
8538  ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8539  accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
8540  if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8541    set_map_and_elements(new_map, elems);
8542  } else {
8543    FixedArray* parameter_map = FixedArray::cast(old_elements);
8544    parameter_map->set(1, elems);
8545  }
8546
8547  if (FLAG_trace_elements_transitions) {
8548    PrintElementsTransition(stdout, elements_kind, old_elements,
8549                            FAST_DOUBLE_ELEMENTS, elems);
8550  }
8551
8552  if (IsJSArray()) {
8553    JSArray::cast(this)->set_length(Smi::FromInt(length));
8554  }
8555
8556  return this;
8557}
8558
8559
8560MaybeObject* JSArray::Initialize(int capacity) {
8561  Heap* heap = GetHeap();
8562  ASSERT(capacity >= 0);
8563  set_length(Smi::FromInt(0));
8564  FixedArray* new_elements;
8565  if (capacity == 0) {
8566    new_elements = heap->empty_fixed_array();
8567  } else {
8568    MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
8569    if (!maybe_obj->To(&new_elements)) return maybe_obj;
8570  }
8571  set_elements(new_elements);
8572  return this;
8573}
8574
8575
8576void JSArray::Expand(int required_size) {
8577  GetIsolate()->factory()->SetElementsCapacityAndLength(
8578      Handle<JSArray>(this), required_size, required_size);
8579}
8580
8581
8582MaybeObject* JSArray::SetElementsLength(Object* len) {
8583  // We should never end in here with a pixel or external array.
8584  ASSERT(AllowsSetElementsLength());
8585  return GetElementsAccessor()->SetLength(this, len);
8586}
8587
8588
8589Object* Map::GetPrototypeTransition(Object* prototype) {
8590  FixedArray* cache = prototype_transitions();
8591  int number_of_transitions = NumberOfProtoTransitions();
8592  const int proto_offset =
8593      kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8594  const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8595  const int step = kProtoTransitionElementsPerEntry;
8596  for (int i = 0; i < number_of_transitions; i++) {
8597    if (cache->get(proto_offset + i * step) == prototype) {
8598      Object* map = cache->get(map_offset + i * step);
8599      ASSERT(map->IsMap());
8600      return map;
8601    }
8602  }
8603  return NULL;
8604}
8605
8606
8607MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
8608  ASSERT(map->IsMap());
8609  ASSERT(HeapObject::cast(prototype)->map()->IsMap());
8610  // Don't cache prototype transition if this map is shared.
8611  if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8612
8613  FixedArray* cache = prototype_transitions();
8614
8615  const int step = kProtoTransitionElementsPerEntry;
8616  const int header = kProtoTransitionHeaderSize;
8617
8618  int capacity = (cache->length() - header) / step;
8619
8620  int transitions = NumberOfProtoTransitions() + 1;
8621
8622  if (transitions > capacity) {
8623    if (capacity > kMaxCachedPrototypeTransitions) return this;
8624
8625    FixedArray* new_cache;
8626    // Grow array by factor 2 over and above what we need.
8627    { MaybeObject* maybe_cache =
8628          GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
8629      if (!maybe_cache->To(&new_cache)) return maybe_cache;
8630    }
8631
8632    for (int i = 0; i < capacity * step; i++) {
8633      new_cache->set(i + header, cache->get(i + header));
8634    }
8635    cache = new_cache;
8636    set_prototype_transitions(cache);
8637  }
8638
8639  int last = transitions - 1;
8640
8641  cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8642  cache->set(header + last * step + kProtoTransitionMapOffset, map);
8643  SetNumberOfProtoTransitions(transitions);
8644
8645  return cache;
8646}
8647
8648
8649MaybeObject* JSReceiver::SetPrototype(Object* value,
8650                                      bool skip_hidden_prototypes) {
8651#ifdef DEBUG
8652  int size = Size();
8653#endif
8654
8655  Heap* heap = GetHeap();
8656  // Silently ignore the change if value is not a JSObject or null.
8657  // SpiderMonkey behaves this way.
8658  if (!value->IsJSReceiver() && !value->IsNull()) return value;
8659
8660  // From 8.6.2 Object Internal Methods
8661  // ...
8662  // In addition, if [[Extensible]] is false the value of the [[Class]] and
8663  // [[Prototype]] internal properties of the object may not be modified.
8664  // ...
8665  // Implementation specific extensions that modify [[Class]], [[Prototype]]
8666  // or [[Extensible]] must not violate the invariants defined in the preceding
8667  // paragraph.
8668  if (!this->map()->is_extensible()) {
8669    HandleScope scope(heap->isolate());
8670    Handle<Object> handle(this, heap->isolate());
8671    return heap->isolate()->Throw(
8672        *FACTORY->NewTypeError("non_extensible_proto",
8673                               HandleVector<Object>(&handle, 1)));
8674  }
8675
8676  // Before we can set the prototype we need to be sure
8677  // prototype cycles are prevented.
8678  // It is sufficient to validate that the receiver is not in the new prototype
8679  // chain.
8680  for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
8681    if (JSReceiver::cast(pt) == this) {
8682      // Cycle detected.
8683      HandleScope scope(heap->isolate());
8684      return heap->isolate()->Throw(
8685          *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
8686    }
8687  }
8688
8689  JSReceiver* real_receiver = this;
8690
8691  if (skip_hidden_prototypes) {
8692    // Find the first object in the chain whose prototype object is not
8693    // hidden and set the new prototype on that object.
8694    Object* current_proto = real_receiver->GetPrototype();
8695    while (current_proto->IsJSObject() &&
8696          JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8697      real_receiver = JSReceiver::cast(current_proto);
8698      current_proto = current_proto->GetPrototype();
8699    }
8700  }
8701
8702  // Set the new prototype of the object.
8703  Map* map = real_receiver->map();
8704
8705  // Nothing to do if prototype is already set.
8706  if (map->prototype() == value) return value;
8707
8708  Object* new_map = map->GetPrototypeTransition(value);
8709  if (new_map == NULL) {
8710    { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8711      if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8712    }
8713
8714    { MaybeObject* maybe_new_cache =
8715          map->PutPrototypeTransition(value, Map::cast(new_map));
8716      if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8717    }
8718
8719    Map::cast(new_map)->set_prototype(value);
8720  }
8721  ASSERT(Map::cast(new_map)->prototype() == value);
8722  real_receiver->set_map(Map::cast(new_map));
8723
8724  heap->ClearInstanceofCache();
8725  ASSERT(size == Size());
8726  return value;
8727}
8728
8729
8730MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8731                                                uint32_t first_arg,
8732                                                uint32_t arg_count,
8733                                                EnsureElementsMode mode) {
8734  // Elements in |Arguments| are ordered backwards (because they're on the
8735  // stack), but the method that's called here iterates over them in forward
8736  // direction.
8737  return EnsureCanContainElements(
8738      args->arguments() - first_arg - (arg_count - 1),
8739      arg_count, mode);
8740}
8741
8742
8743bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
8744  Isolate* isolate = GetIsolate();
8745  // Make sure that the top context does not change when doing
8746  // callbacks or interceptor calls.
8747  AssertNoContextChange ncc;
8748  HandleScope scope(isolate);
8749  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8750  Handle<JSReceiver> receiver_handle(receiver);
8751  Handle<JSObject> holder_handle(this);
8752  CustomArguments args(isolate, interceptor->data(), receiver, this);
8753  v8::AccessorInfo info(args.end());
8754  if (!interceptor->query()->IsUndefined()) {
8755    v8::IndexedPropertyQuery query =
8756        v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
8757    LOG(isolate,
8758        ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
8759    v8::Handle<v8::Integer> result;
8760    {
8761      // Leaving JavaScript.
8762      VMState state(isolate, EXTERNAL);
8763      result = query(index, info);
8764    }
8765    if (!result.IsEmpty()) {
8766      ASSERT(result->IsInt32());
8767      return true;  // absence of property is signaled by empty handle.
8768    }
8769  } else if (!interceptor->getter()->IsUndefined()) {
8770    v8::IndexedPropertyGetter getter =
8771        v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
8772    LOG(isolate,
8773        ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
8774    v8::Handle<v8::Value> result;
8775    {
8776      // Leaving JavaScript.
8777      VMState state(isolate, EXTERNAL);
8778      result = getter(index, info);
8779    }
8780    if (!result.IsEmpty()) return true;
8781  }
8782
8783  if (holder_handle->GetElementsAccessor()->HasElement(
8784          *receiver_handle, *holder_handle, index)) {
8785    return true;
8786  }
8787
8788  if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
8789  Object* pt = holder_handle->GetPrototype();
8790  if (pt->IsJSProxy()) {
8791    // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8792    return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8793        receiver, index) != ABSENT;
8794  }
8795  if (pt->IsNull()) return false;
8796  return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
8797}
8798
8799
8800JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
8801  // Check access rights if needed.
8802  if (IsAccessCheckNeeded()) {
8803    Heap* heap = GetHeap();
8804    if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8805      heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8806      return UNDEFINED_ELEMENT;
8807    }
8808  }
8809
8810  if (IsJSGlobalProxy()) {
8811    Object* proto = GetPrototype();
8812    if (proto->IsNull()) return UNDEFINED_ELEMENT;
8813    ASSERT(proto->IsJSGlobalObject());
8814    return JSObject::cast(proto)->HasLocalElement(index);
8815  }
8816
8817  // Check for lookup interceptor
8818  if (HasIndexedInterceptor()) {
8819    return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8820                                                  : UNDEFINED_ELEMENT;
8821  }
8822
8823  // Handle [] on String objects.
8824  if (this->IsStringObjectWithCharacterAt(index)) {
8825    return STRING_CHARACTER_ELEMENT;
8826  }
8827
8828  switch (GetElementsKind()) {
8829    case FAST_SMI_ONLY_ELEMENTS:
8830    case FAST_ELEMENTS: {
8831      uint32_t length = IsJSArray() ?
8832          static_cast<uint32_t>
8833              (Smi::cast(JSArray::cast(this)->length())->value()) :
8834          static_cast<uint32_t>(FixedArray::cast(elements())->length());
8835      if ((index < length) &&
8836          !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8837        return FAST_ELEMENT;
8838      }
8839      break;
8840    }
8841    case FAST_DOUBLE_ELEMENTS: {
8842      uint32_t length = IsJSArray() ?
8843          static_cast<uint32_t>
8844              (Smi::cast(JSArray::cast(this)->length())->value()) :
8845          static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8846      if ((index < length) &&
8847          !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8848        return FAST_ELEMENT;
8849      }
8850      break;
8851    }
8852    case EXTERNAL_PIXEL_ELEMENTS: {
8853      ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
8854      if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8855      break;
8856    }
8857    case EXTERNAL_BYTE_ELEMENTS:
8858    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8859    case EXTERNAL_SHORT_ELEMENTS:
8860    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8861    case EXTERNAL_INT_ELEMENTS:
8862    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8863    case EXTERNAL_FLOAT_ELEMENTS:
8864    case EXTERNAL_DOUBLE_ELEMENTS: {
8865      ExternalArray* array = ExternalArray::cast(elements());
8866      if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8867      break;
8868    }
8869    case DICTIONARY_ELEMENTS: {
8870      if (element_dictionary()->FindEntry(index) !=
8871          SeededNumberDictionary::kNotFound) {
8872        return DICTIONARY_ELEMENT;
8873      }
8874      break;
8875    }
8876    case NON_STRICT_ARGUMENTS_ELEMENTS: {
8877      // Aliased parameters and non-aliased elements in a fast backing store
8878      // behave as FAST_ELEMENT.  Non-aliased elements in a dictionary
8879      // backing store behave as DICTIONARY_ELEMENT.
8880      FixedArray* parameter_map = FixedArray::cast(elements());
8881      uint32_t length = parameter_map->length();
8882      Object* probe =
8883          index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8884      if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8885      // If not aliased, check the arguments.
8886      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8887      if (arguments->IsDictionary()) {
8888        SeededNumberDictionary* dictionary =
8889            SeededNumberDictionary::cast(arguments);
8890        if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
8891          return DICTIONARY_ELEMENT;
8892        }
8893      } else {
8894        length = arguments->length();
8895        probe = (index < length) ? arguments->get(index) : NULL;
8896        if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8897      }
8898      break;
8899    }
8900  }
8901
8902  return UNDEFINED_ELEMENT;
8903}
8904
8905
8906bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
8907  // Check access rights if needed.
8908  if (IsAccessCheckNeeded()) {
8909    Heap* heap = GetHeap();
8910    if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8911      heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8912      return false;
8913    }
8914  }
8915
8916  // Check for lookup interceptor
8917  if (HasIndexedInterceptor()) {
8918    return HasElementWithInterceptor(receiver, index);
8919  }
8920
8921  ElementsAccessor* accessor = GetElementsAccessor();
8922  if (accessor->HasElement(receiver, this, index)) {
8923    return true;
8924  }
8925
8926  // Handle [] on String objects.
8927  if (this->IsStringObjectWithCharacterAt(index)) return true;
8928
8929  Object* pt = GetPrototype();
8930  if (pt->IsNull()) return false;
8931  if (pt->IsJSProxy()) {
8932    // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8933    return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8934        receiver, index) != ABSENT;
8935  }
8936  return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8937}
8938
8939
8940MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
8941                                                 Object* value,
8942                                                 PropertyAttributes attributes,
8943                                                 StrictModeFlag strict_mode,
8944                                                 bool check_prototype,
8945                                                 SetPropertyMode set_mode) {
8946  Isolate* isolate = GetIsolate();
8947  // Make sure that the top context does not change when doing
8948  // callbacks or interceptor calls.
8949  AssertNoContextChange ncc;
8950  HandleScope scope(isolate);
8951  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8952  Handle<JSObject> this_handle(this);
8953  Handle<Object> value_handle(value, isolate);
8954  if (!interceptor->setter()->IsUndefined()) {
8955    v8::IndexedPropertySetter setter =
8956        v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
8957    LOG(isolate,
8958        ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8959    CustomArguments args(isolate, interceptor->data(), this, this);
8960    v8::AccessorInfo info(args.end());
8961    v8::Handle<v8::Value> result;
8962    {
8963      // Leaving JavaScript.
8964      VMState state(isolate, EXTERNAL);
8965      result = setter(index, v8::Utils::ToLocal(value_handle), info);
8966    }
8967    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8968    if (!result.IsEmpty()) return *value_handle;
8969  }
8970  MaybeObject* raw_result =
8971      this_handle->SetElementWithoutInterceptor(index,
8972                                                *value_handle,
8973                                                attributes,
8974                                                strict_mode,
8975                                                check_prototype,
8976                                                set_mode);
8977  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8978  return raw_result;
8979}
8980
8981
8982MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8983                                              Object* structure,
8984                                              uint32_t index,
8985                                              Object* holder) {
8986  Isolate* isolate = GetIsolate();
8987  ASSERT(!structure->IsForeign());
8988
8989  // api style callbacks.
8990  if (structure->IsAccessorInfo()) {
8991    Handle<AccessorInfo> data(AccessorInfo::cast(structure));
8992    Object* fun_obj = data->getter();
8993    v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
8994    HandleScope scope(isolate);
8995    Handle<JSObject> self(JSObject::cast(receiver));
8996    Handle<JSObject> holder_handle(JSObject::cast(holder));
8997    Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8998    Handle<String> key = isolate->factory()->NumberToString(number);
8999    LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
9000    CustomArguments args(isolate, data->data(), *self, *holder_handle);
9001    v8::AccessorInfo info(args.end());
9002    v8::Handle<v8::Value> result;
9003    {
9004      // Leaving JavaScript.
9005      VMState state(isolate, EXTERNAL);
9006      result = call_fun(v8::Utils::ToLocal(key), info);
9007    }
9008    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9009    if (result.IsEmpty()) return isolate->heap()->undefined_value();
9010    return *v8::Utils::OpenHandle(*result);
9011  }
9012
9013  // __defineGetter__ callback
9014  if (structure->IsAccessorPair()) {
9015    Object* getter = AccessorPair::cast(structure)->getter();
9016    if (getter->IsSpecFunction()) {
9017      // TODO(rossberg): nicer would be to cast to some JSCallable here...
9018      return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
9019    }
9020    // Getter is not a function.
9021    return isolate->heap()->undefined_value();
9022  }
9023
9024  UNREACHABLE();
9025  return NULL;
9026}
9027
9028
9029MaybeObject* JSObject::SetElementWithCallback(Object* structure,
9030                                              uint32_t index,
9031                                              Object* value,
9032                                              JSObject* holder,
9033                                              StrictModeFlag strict_mode) {
9034  Isolate* isolate = GetIsolate();
9035  HandleScope scope(isolate);
9036
9037  // We should never get here to initialize a const with the hole
9038  // value since a const declaration would conflict with the setter.
9039  ASSERT(!value->IsTheHole());
9040  Handle<Object> value_handle(value, isolate);
9041
9042  // To accommodate both the old and the new api we switch on the
9043  // data structure used to store the callbacks.  Eventually foreign
9044  // callbacks should be phased out.
9045  ASSERT(!structure->IsForeign());
9046
9047  if (structure->IsAccessorInfo()) {
9048    // api style callbacks
9049    Handle<JSObject> self(this);
9050    Handle<JSObject> holder_handle(JSObject::cast(holder));
9051    Handle<AccessorInfo> data(AccessorInfo::cast(structure));
9052    Object* call_obj = data->setter();
9053    v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9054    if (call_fun == NULL) return value;
9055    Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9056    Handle<String> key(isolate->factory()->NumberToString(number));
9057    LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9058    CustomArguments args(isolate, data->data(), *self, *holder_handle);
9059    v8::AccessorInfo info(args.end());
9060    {
9061      // Leaving JavaScript.
9062      VMState state(isolate, EXTERNAL);
9063      call_fun(v8::Utils::ToLocal(key),
9064               v8::Utils::ToLocal(value_handle),
9065               info);
9066    }
9067    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9068    return *value_handle;
9069  }
9070
9071  if (structure->IsAccessorPair()) {
9072    Handle<Object> setter(AccessorPair::cast(structure)->setter());
9073    if (setter->IsSpecFunction()) {
9074      // TODO(rossberg): nicer would be to cast to some JSCallable here...
9075      return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
9076    } else {
9077      if (strict_mode == kNonStrictMode) {
9078        return value;
9079      }
9080      Handle<Object> holder_handle(holder, isolate);
9081      Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
9082      Handle<Object> args[2] = { key, holder_handle };
9083      return isolate->Throw(
9084          *isolate->factory()->NewTypeError("no_setter_in_callback",
9085                                            HandleVector(args, 2)));
9086    }
9087  }
9088
9089  UNREACHABLE();
9090  return NULL;
9091}
9092
9093
9094bool JSObject::HasFastArgumentsElements() {
9095  Heap* heap = GetHeap();
9096  if (!elements()->IsFixedArray()) return false;
9097  FixedArray* elements = FixedArray::cast(this->elements());
9098  if (elements->map() != heap->non_strict_arguments_elements_map()) {
9099    return false;
9100  }
9101  FixedArray* arguments = FixedArray::cast(elements->get(1));
9102  return !arguments->IsDictionary();
9103}
9104
9105
9106bool JSObject::HasDictionaryArgumentsElements() {
9107  Heap* heap = GetHeap();
9108  if (!elements()->IsFixedArray()) return false;
9109  FixedArray* elements = FixedArray::cast(this->elements());
9110  if (elements->map() != heap->non_strict_arguments_elements_map()) {
9111    return false;
9112  }
9113  FixedArray* arguments = FixedArray::cast(elements->get(1));
9114  return arguments->IsDictionary();
9115}
9116
9117
9118// Adding n elements in fast case is O(n*n).
9119// Note: revisit design to have dual undefined values to capture absent
9120// elements.
9121MaybeObject* JSObject::SetFastElement(uint32_t index,
9122                                      Object* value,
9123                                      StrictModeFlag strict_mode,
9124                                      bool check_prototype) {
9125  ASSERT(HasFastTypeElements() ||
9126         HasFastArgumentsElements());
9127
9128  FixedArray* backing_store = FixedArray::cast(elements());
9129  if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9130    backing_store = FixedArray::cast(backing_store->get(1));
9131  } else {
9132    MaybeObject* maybe = EnsureWritableFastElements();
9133    if (!maybe->To(&backing_store)) return maybe;
9134  }
9135  uint32_t capacity = static_cast<uint32_t>(backing_store->length());
9136
9137  if (check_prototype &&
9138      (index >= capacity || backing_store->get(index)->IsTheHole())) {
9139    bool found;
9140    MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9141                                                                   value,
9142                                                                   &found,
9143                                                                   strict_mode);
9144    if (found) return result;
9145  }
9146
9147  uint32_t new_capacity = capacity;
9148  // Check if the length property of this object needs to be updated.
9149  uint32_t array_length = 0;
9150  bool must_update_array_length = false;
9151  if (IsJSArray()) {
9152    CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9153    if (index >= array_length) {
9154      must_update_array_length = true;
9155      array_length = index + 1;
9156    }
9157  }
9158  // Check if the capacity of the backing store needs to be increased, or if
9159  // a transition to slow elements is necessary.
9160  if (index >= capacity) {
9161    bool convert_to_slow = true;
9162    if ((index - capacity) < kMaxGap) {
9163      new_capacity = NewElementsCapacity(index + 1);
9164      ASSERT(new_capacity > index);
9165      if (!ShouldConvertToSlowElements(new_capacity)) {
9166        convert_to_slow = false;
9167      }
9168    }
9169    if (convert_to_slow) {
9170      MaybeObject* result = NormalizeElements();
9171      if (result->IsFailure()) return result;
9172      return SetDictionaryElement(index, value, NONE, strict_mode,
9173                                  check_prototype);
9174    }
9175  }
9176  // Convert to fast double elements if appropriate.
9177  if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9178    MaybeObject* maybe =
9179        SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9180    if (maybe->IsFailure()) return maybe;
9181    FixedDoubleArray::cast(elements())->set(index, value->Number());
9182    return value;
9183  }
9184  // Change elements kind from SMI_ONLY to generic FAST if necessary.
9185  if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9186    Map* new_map;
9187    { MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9188                                                            FAST_ELEMENTS);
9189      if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9190    }
9191    set_map(new_map);
9192    if (FLAG_trace_elements_transitions) {
9193      PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9194                              FAST_ELEMENTS, elements());
9195    }
9196  }
9197  // Increase backing store capacity if that's been decided previously.
9198  if (new_capacity != capacity) {
9199    FixedArray* new_elements;
9200    SetFastElementsCapacityMode set_capacity_mode =
9201        value->IsSmi() && HasFastSmiOnlyElements()
9202            ? kAllowSmiOnlyElements
9203            : kDontAllowSmiOnlyElements;
9204    { MaybeObject* maybe =
9205          SetFastElementsCapacityAndLength(new_capacity,
9206                                           array_length,
9207                                           set_capacity_mode);
9208      if (!maybe->To(&new_elements)) return maybe;
9209    }
9210    new_elements->set(index, value);
9211    return value;
9212  }
9213  // Finally, set the new element and length.
9214  ASSERT(elements()->IsFixedArray());
9215  backing_store->set(index, value);
9216  if (must_update_array_length) {
9217    JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9218  }
9219  return value;
9220}
9221
9222
9223MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9224                                            Object* value,
9225                                            PropertyAttributes attributes,
9226                                            StrictModeFlag strict_mode,
9227                                            bool check_prototype,
9228                                            SetPropertyMode set_mode) {
9229  ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9230  Isolate* isolate = GetIsolate();
9231  Heap* heap = isolate->heap();
9232
9233  // Insert element in the dictionary.
9234  FixedArray* elements = FixedArray::cast(this->elements());
9235  bool is_arguments =
9236      (elements->map() == heap->non_strict_arguments_elements_map());
9237  SeededNumberDictionary* dictionary = NULL;
9238  if (is_arguments) {
9239    dictionary = SeededNumberDictionary::cast(elements->get(1));
9240  } else {
9241    dictionary = SeededNumberDictionary::cast(elements);
9242  }
9243
9244  int entry = dictionary->FindEntry(index);
9245  if (entry != SeededNumberDictionary::kNotFound) {
9246    Object* element = dictionary->ValueAt(entry);
9247    PropertyDetails details = dictionary->DetailsAt(entry);
9248    if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
9249      return SetElementWithCallback(element, index, value, this, strict_mode);
9250    } else {
9251      dictionary->UpdateMaxNumberKey(index);
9252      // If a value has not been initialized we allow writing to it even if it
9253      // is read-only (a declared const that has not been initialized).  If a
9254      // value is being defined we skip attribute checks completely.
9255      if (set_mode == DEFINE_PROPERTY) {
9256        details = PropertyDetails(attributes, NORMAL, details.index());
9257        dictionary->DetailsAtPut(entry, details);
9258      } else if (details.IsReadOnly() && !element->IsTheHole()) {
9259        if (strict_mode == kNonStrictMode) {
9260          return isolate->heap()->undefined_value();
9261        } else {
9262          Handle<Object> holder(this);
9263          Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9264          Handle<Object> args[2] = { number, holder };
9265          Handle<Object> error =
9266              isolate->factory()->NewTypeError("strict_read_only_property",
9267                                               HandleVector(args, 2));
9268          return isolate->Throw(*error);
9269        }
9270      }
9271      // Elements of the arguments object in slow mode might be slow aliases.
9272      if (is_arguments && element->IsAliasedArgumentsEntry()) {
9273        AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
9274        Context* context = Context::cast(elements->get(0));
9275        int context_index = entry->aliased_context_slot();
9276        ASSERT(!context->get(context_index)->IsTheHole());
9277        context->set(context_index, value);
9278        // For elements that are still writable we keep slow aliasing.
9279        if (!details.IsReadOnly()) value = element;
9280      }
9281      dictionary->ValueAtPut(entry, value);
9282    }
9283  } else {
9284    // Index not already used. Look for an accessor in the prototype chain.
9285    if (check_prototype) {
9286      bool found;
9287      MaybeObject* result =
9288          SetElementWithCallbackSetterInPrototypes(
9289              index, value, &found, strict_mode);
9290      if (found) return result;
9291    }
9292    // When we set the is_extensible flag to false we always force the
9293    // element into dictionary mode (and force them to stay there).
9294    if (!map()->is_extensible()) {
9295      if (strict_mode == kNonStrictMode) {
9296        return isolate->heap()->undefined_value();
9297      } else {
9298        Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9299        Handle<String> name = isolate->factory()->NumberToString(number);
9300        Handle<Object> args[1] = { name };
9301        Handle<Object> error =
9302            isolate->factory()->NewTypeError("object_not_extensible",
9303                                             HandleVector(args, 1));
9304        return isolate->Throw(*error);
9305      }
9306    }
9307    FixedArrayBase* new_dictionary;
9308    PropertyDetails details = PropertyDetails(attributes, NORMAL);
9309    MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details);
9310    if (!maybe->To(&new_dictionary)) return maybe;
9311    if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
9312      if (is_arguments) {
9313        elements->set(1, new_dictionary);
9314      } else {
9315        set_elements(new_dictionary);
9316      }
9317      dictionary = SeededNumberDictionary::cast(new_dictionary);
9318    }
9319  }
9320
9321  // Update the array length if this JSObject is an array.
9322  if (IsJSArray()) {
9323    MaybeObject* result =
9324        JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9325    if (result->IsFailure()) return result;
9326  }
9327
9328  // Attempt to put this object back in fast case.
9329  if (ShouldConvertToFastElements()) {
9330    uint32_t new_length = 0;
9331    if (IsJSArray()) {
9332      CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9333    } else {
9334      new_length = dictionary->max_number_key() + 1;
9335    }
9336    SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9337        ? kAllowSmiOnlyElements
9338        : kDontAllowSmiOnlyElements;
9339    bool has_smi_only_elements = false;
9340    bool should_convert_to_fast_double_elements =
9341        ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9342    if (has_smi_only_elements) {
9343      set_capacity_mode = kForceSmiOnlyElements;
9344    }
9345    MaybeObject* result = should_convert_to_fast_double_elements
9346        ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
9347        : SetFastElementsCapacityAndLength(new_length,
9348                                           new_length,
9349                                           set_capacity_mode);
9350    if (result->IsFailure()) return result;
9351#ifdef DEBUG
9352    if (FLAG_trace_normalization) {
9353      PrintF("Object elements are fast case again:\n");
9354      Print();
9355    }
9356#endif
9357  }
9358  return value;
9359}
9360
9361
9362MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9363    uint32_t index,
9364    Object* value,
9365    StrictModeFlag strict_mode,
9366    bool check_prototype) {
9367  ASSERT(HasFastDoubleElements());
9368
9369  FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
9370  uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
9371
9372  // If storing to an element that isn't in the array, pass the store request
9373  // up the prototype chain before storing in the receiver's elements.
9374  if (check_prototype &&
9375      (index >= elms_length ||
9376       FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
9377    bool found;
9378    MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9379                                                                   value,
9380                                                                   &found,
9381                                                                   strict_mode);
9382    if (found) return result;
9383  }
9384
9385  // If the value object is not a heap number, switch to fast elements and try
9386  // again.
9387  bool value_is_smi = value->IsSmi();
9388  if (!value->IsNumber()) {
9389    Object* obj;
9390    uint32_t length = elms_length;
9391    if (IsJSArray()) {
9392      CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9393    }
9394    MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9395        elms_length,
9396        length,
9397        kDontAllowSmiOnlyElements);
9398    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9399    return SetFastElement(index,
9400                          value,
9401                          strict_mode,
9402                          check_prototype);
9403  }
9404
9405  double double_value = value_is_smi
9406      ? static_cast<double>(Smi::cast(value)->value())
9407      : HeapNumber::cast(value)->value();
9408
9409  // Check whether there is extra space in the fixed array.
9410  if (index < elms_length) {
9411    FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9412    elms->set(index, double_value);
9413    if (IsJSArray()) {
9414      // Update the length of the array if needed.
9415      uint32_t array_length = 0;
9416      CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9417      if (index >= array_length) {
9418        JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
9419      }
9420    }
9421    return value;
9422  }
9423
9424  // Allow gap in fast case.
9425  if ((index - elms_length) < kMaxGap) {
9426    // Try allocating extra space.
9427    int new_capacity = NewElementsCapacity(index+1);
9428    if (!ShouldConvertToSlowElements(new_capacity)) {
9429      ASSERT(static_cast<uint32_t>(new_capacity) > index);
9430      Object* obj;
9431      { MaybeObject* maybe_obj =
9432            SetFastDoubleElementsCapacityAndLength(new_capacity,
9433                                                   index + 1);
9434        if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9435      }
9436      FixedDoubleArray::cast(elements())->set(index, double_value);
9437      return value;
9438    }
9439  }
9440
9441  // Otherwise default to slow case.
9442  ASSERT(HasFastDoubleElements());
9443  ASSERT(map()->has_fast_double_elements());
9444  ASSERT(elements()->IsFixedDoubleArray());
9445  Object* obj;
9446  { MaybeObject* maybe_obj = NormalizeElements();
9447    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9448  }
9449  ASSERT(HasDictionaryElements());
9450  return SetElement(index, value, NONE, strict_mode, check_prototype);
9451}
9452
9453
9454MaybeObject* JSReceiver::SetElement(uint32_t index,
9455                                    Object* value,
9456                                    PropertyAttributes attributes,
9457                                    StrictModeFlag strict_mode,
9458                                    bool check_proto) {
9459  if (IsJSProxy()) {
9460    return JSProxy::cast(this)->SetElementWithHandler(
9461        index, value, strict_mode);
9462  } else {
9463    return JSObject::cast(this)->SetElement(
9464        index, value, attributes, strict_mode, check_proto);
9465  }
9466}
9467
9468
9469Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9470                                       uint32_t index,
9471                                       Handle<Object> value,
9472                                       StrictModeFlag strict_mode) {
9473  ASSERT(!object->HasExternalArrayElements());
9474  CALL_HEAP_FUNCTION(
9475      object->GetIsolate(),
9476      object->SetElement(index, *value, NONE, strict_mode, false),
9477      Object);
9478}
9479
9480
9481Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9482                                    uint32_t index,
9483                                    Handle<Object> value,
9484                                    PropertyAttributes attr,
9485                                    StrictModeFlag strict_mode,
9486                                    SetPropertyMode set_mode) {
9487  if (object->HasExternalArrayElements()) {
9488    if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9489      bool has_exception;
9490      Handle<Object> number = Execution::ToNumber(value, &has_exception);
9491      if (has_exception) return Handle<Object>();
9492      value = number;
9493    }
9494  }
9495  CALL_HEAP_FUNCTION(
9496      object->GetIsolate(),
9497      object->SetElement(index, *value, attr, strict_mode, true, set_mode),
9498      Object);
9499}
9500
9501
9502MaybeObject* JSObject::SetElement(uint32_t index,
9503                                  Object* value,
9504                                  PropertyAttributes attributes,
9505                                  StrictModeFlag strict_mode,
9506                                  bool check_prototype,
9507                                  SetPropertyMode set_mode) {
9508  // Check access rights if needed.
9509  if (IsAccessCheckNeeded()) {
9510    Heap* heap = GetHeap();
9511    if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
9512      HandleScope scope(heap->isolate());
9513      Handle<Object> value_handle(value);
9514      heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9515      return *value_handle;
9516    }
9517  }
9518
9519  if (IsJSGlobalProxy()) {
9520    Object* proto = GetPrototype();
9521    if (proto->IsNull()) return value;
9522    ASSERT(proto->IsJSGlobalObject());
9523    return JSObject::cast(proto)->SetElement(index,
9524                                             value,
9525                                             attributes,
9526                                             strict_mode,
9527                                             check_prototype,
9528                                             set_mode);
9529  }
9530
9531  // Don't allow element properties to be redefined for external arrays.
9532  if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
9533    Isolate* isolate = GetHeap()->isolate();
9534    Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9535    Handle<Object> args[] = { Handle<Object>(this), number };
9536    Handle<Object> error = isolate->factory()->NewTypeError(
9537        "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
9538    return isolate->Throw(*error);
9539  }
9540
9541  // Normalize the elements to enable attributes on the property.
9542  if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
9543    SeededNumberDictionary* dictionary;
9544    MaybeObject* maybe_object = NormalizeElements();
9545    if (!maybe_object->To(&dictionary)) return maybe_object;
9546    // Make sure that we never go back to fast case.
9547    dictionary->set_requires_slow_elements();
9548  }
9549
9550  // Check for lookup interceptor
9551  if (HasIndexedInterceptor()) {
9552    return SetElementWithInterceptor(index,
9553                                     value,
9554                                     attributes,
9555                                     strict_mode,
9556                                     check_prototype,
9557                                     set_mode);
9558  }
9559
9560  return SetElementWithoutInterceptor(index,
9561                                      value,
9562                                      attributes,
9563                                      strict_mode,
9564                                      check_prototype,
9565                                      set_mode);
9566}
9567
9568
9569MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
9570                                                    Object* value,
9571                                                    PropertyAttributes attr,
9572                                                    StrictModeFlag strict_mode,
9573                                                    bool check_prototype,
9574                                                    SetPropertyMode set_mode) {
9575  ASSERT(HasDictionaryElements() ||
9576         HasDictionaryArgumentsElements() ||
9577         (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
9578  Isolate* isolate = GetIsolate();
9579  switch (GetElementsKind()) {
9580    case FAST_SMI_ONLY_ELEMENTS:
9581    case FAST_ELEMENTS:
9582      return SetFastElement(index, value, strict_mode, check_prototype);
9583    case FAST_DOUBLE_ELEMENTS:
9584      return SetFastDoubleElement(index, value, strict_mode, check_prototype);
9585    case EXTERNAL_PIXEL_ELEMENTS: {
9586      ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
9587      return pixels->SetValue(index, value);
9588    }
9589    case EXTERNAL_BYTE_ELEMENTS: {
9590      ExternalByteArray* array = ExternalByteArray::cast(elements());
9591      return array->SetValue(index, value);
9592    }
9593    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9594      ExternalUnsignedByteArray* array =
9595          ExternalUnsignedByteArray::cast(elements());
9596      return array->SetValue(index, value);
9597    }
9598    case EXTERNAL_SHORT_ELEMENTS: {
9599      ExternalShortArray* array = ExternalShortArray::cast(elements());
9600      return array->SetValue(index, value);
9601    }
9602    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9603      ExternalUnsignedShortArray* array =
9604          ExternalUnsignedShortArray::cast(elements());
9605      return array->SetValue(index, value);
9606    }
9607    case EXTERNAL_INT_ELEMENTS: {
9608      ExternalIntArray* array = ExternalIntArray::cast(elements());
9609      return array->SetValue(index, value);
9610    }
9611    case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9612      ExternalUnsignedIntArray* array =
9613          ExternalUnsignedIntArray::cast(elements());
9614      return array->SetValue(index, value);
9615    }
9616    case EXTERNAL_FLOAT_ELEMENTS: {
9617      ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9618      return array->SetValue(index, value);
9619    }
9620    case EXTERNAL_DOUBLE_ELEMENTS: {
9621      ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9622      return array->SetValue(index, value);
9623    }
9624    case DICTIONARY_ELEMENTS:
9625      return SetDictionaryElement(index, value, attr, strict_mode,
9626                                  check_prototype, set_mode);
9627    case NON_STRICT_ARGUMENTS_ELEMENTS: {
9628      FixedArray* parameter_map = FixedArray::cast(elements());
9629      uint32_t length = parameter_map->length();
9630      Object* probe =
9631          (index < length - 2) ? parameter_map->get(index + 2) : NULL;
9632      if (probe != NULL && !probe->IsTheHole()) {
9633        Context* context = Context::cast(parameter_map->get(0));
9634        int context_index = Smi::cast(probe)->value();
9635        ASSERT(!context->get(context_index)->IsTheHole());
9636        context->set(context_index, value);
9637        // Redefining attributes of an aliased element destroys fast aliasing.
9638        if (set_mode == SET_PROPERTY || attr == NONE) return value;
9639        parameter_map->set_the_hole(index + 2);
9640        // For elements that are still writable we re-establish slow aliasing.
9641        if ((attr & READ_ONLY) == 0) {
9642          MaybeObject* maybe_entry =
9643              isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
9644          if (!maybe_entry->ToObject(&value)) return maybe_entry;
9645        }
9646      }
9647      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9648      if (arguments->IsDictionary()) {
9649        return SetDictionaryElement(index, value, attr, strict_mode,
9650                                    check_prototype, set_mode);
9651      } else {
9652        return SetFastElement(index, value, strict_mode, check_prototype);
9653      }
9654    }
9655  }
9656  // All possible cases have been handled above. Add a return to avoid the
9657  // complaints from the compiler.
9658  UNREACHABLE();
9659  return isolate->heap()->null_value();
9660}
9661
9662
9663Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9664                                                ElementsKind to_kind) {
9665  CALL_HEAP_FUNCTION(object->GetIsolate(),
9666                     object->TransitionElementsKind(to_kind),
9667                     Object);
9668}
9669
9670
9671MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
9672  ElementsKind from_kind = map()->elements_kind();
9673
9674  Isolate* isolate = GetIsolate();
9675  if ((from_kind == FAST_SMI_ONLY_ELEMENTS ||
9676      elements() == isolate->heap()->empty_fixed_array()) &&
9677      to_kind == FAST_ELEMENTS) {
9678    ASSERT(from_kind != FAST_ELEMENTS);
9679    MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9680    Map* new_map;
9681    if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9682    set_map(new_map);
9683    if (FLAG_trace_elements_transitions) {
9684      FixedArrayBase* elms = FixedArrayBase::cast(elements());
9685      PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9686    }
9687    return this;
9688  }
9689
9690  FixedArrayBase* elms = FixedArrayBase::cast(elements());
9691  uint32_t capacity = static_cast<uint32_t>(elms->length());
9692  uint32_t length = capacity;
9693
9694  if (IsJSArray()) {
9695    Object* raw_length = JSArray::cast(this)->length();
9696    if (raw_length->IsUndefined()) {
9697      // If length is undefined, then JSArray is being initialized and has no
9698      // elements, assume a length of zero.
9699      length = 0;
9700    } else {
9701      CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9702    }
9703  }
9704
9705  if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9706      to_kind == FAST_DOUBLE_ELEMENTS) {
9707    MaybeObject* maybe_result =
9708        SetFastDoubleElementsCapacityAndLength(capacity, length);
9709    if (maybe_result->IsFailure()) return maybe_result;
9710    return this;
9711  }
9712
9713  if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
9714    MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9715        capacity, length, kDontAllowSmiOnlyElements);
9716    if (maybe_result->IsFailure()) return maybe_result;
9717    return this;
9718  }
9719
9720  // This method should never be called for any other case than the ones
9721  // handled above.
9722  UNREACHABLE();
9723  return GetIsolate()->heap()->null_value();
9724}
9725
9726
9727// static
9728bool Map::IsValidElementsTransition(ElementsKind from_kind,
9729                                    ElementsKind to_kind) {
9730  return
9731      (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9732          (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9733      (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9734}
9735
9736
9737MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9738                                                   Object* value) {
9739  uint32_t old_len = 0;
9740  CHECK(length()->ToArrayIndex(&old_len));
9741  // Check to see if we need to update the length. For now, we make
9742  // sure that the length stays within 32-bits (unsigned).
9743  if (index >= old_len && index != 0xffffffff) {
9744    Object* len;
9745    { MaybeObject* maybe_len =
9746          GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
9747      if (!maybe_len->ToObject(&len)) return maybe_len;
9748    }
9749    set_length(len);
9750  }
9751  return value;
9752}
9753
9754
9755MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
9756                                                 uint32_t index) {
9757  Isolate* isolate = GetIsolate();
9758  // Make sure that the top context does not change when doing
9759  // callbacks or interceptor calls.
9760  AssertNoContextChange ncc;
9761  HandleScope scope(isolate);
9762  Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9763  Handle<Object> this_handle(receiver, isolate);
9764  Handle<JSObject> holder_handle(this, isolate);
9765  if (!interceptor->getter()->IsUndefined()) {
9766    v8::IndexedPropertyGetter getter =
9767        v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
9768    LOG(isolate,
9769        ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9770    CustomArguments args(isolate, interceptor->data(), receiver, this);
9771    v8::AccessorInfo info(args.end());
9772    v8::Handle<v8::Value> result;
9773    {
9774      // Leaving JavaScript.
9775      VMState state(isolate, EXTERNAL);
9776      result = getter(index, info);
9777    }
9778    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9779    if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9780  }
9781
9782  Heap* heap = holder_handle->GetHeap();
9783  ElementsAccessor* handler = holder_handle->GetElementsAccessor();
9784  MaybeObject* raw_result = handler->Get(*this_handle,
9785                                         *holder_handle,
9786                                         index);
9787  if (raw_result != heap->the_hole_value()) return raw_result;
9788
9789  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9790
9791  Object* pt = holder_handle->GetPrototype();
9792  if (pt == heap->null_value()) return heap->undefined_value();
9793  return pt->GetElementWithReceiver(*this_handle, index);
9794}
9795
9796
9797bool JSObject::HasDenseElements() {
9798  int capacity = 0;
9799  int used = 0;
9800  GetElementsCapacityAndUsage(&capacity, &used);
9801  return (capacity == 0) || (used > (capacity / 2));
9802}
9803
9804
9805void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9806  *capacity = 0;
9807  *used = 0;
9808
9809  FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9810  FixedArray* backing_store = NULL;
9811  switch (GetElementsKind()) {
9812    case NON_STRICT_ARGUMENTS_ELEMENTS:
9813      backing_store_base =
9814          FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9815      backing_store = FixedArray::cast(backing_store_base);
9816      if (backing_store->IsDictionary()) {
9817        SeededNumberDictionary* dictionary =
9818            SeededNumberDictionary::cast(backing_store);
9819        *capacity = dictionary->Capacity();
9820        *used = dictionary->NumberOfElements();
9821        break;
9822      }
9823      // Fall through.
9824    case FAST_SMI_ONLY_ELEMENTS:
9825    case FAST_ELEMENTS:
9826      backing_store = FixedArray::cast(backing_store_base);
9827      *capacity = backing_store->length();
9828      for (int i = 0; i < *capacity; ++i) {
9829        if (!backing_store->get(i)->IsTheHole()) ++(*used);
9830      }
9831      break;
9832    case DICTIONARY_ELEMENTS: {
9833      SeededNumberDictionary* dictionary =
9834          SeededNumberDictionary::cast(FixedArray::cast(elements()));
9835      *capacity = dictionary->Capacity();
9836      *used = dictionary->NumberOfElements();
9837      break;
9838    }
9839    case FAST_DOUBLE_ELEMENTS: {
9840      FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9841      *capacity = elms->length();
9842      for (int i = 0; i < *capacity; i++) {
9843        if (!elms->is_the_hole(i)) ++(*used);
9844      }
9845      break;
9846    }
9847    case EXTERNAL_BYTE_ELEMENTS:
9848    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9849    case EXTERNAL_SHORT_ELEMENTS:
9850    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9851    case EXTERNAL_INT_ELEMENTS:
9852    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9853    case EXTERNAL_FLOAT_ELEMENTS:
9854    case EXTERNAL_DOUBLE_ELEMENTS:
9855    case EXTERNAL_PIXEL_ELEMENTS:
9856      // External arrays are considered 100% used.
9857      ExternalArray* external_array = ExternalArray::cast(elements());
9858      *capacity = external_array->length();
9859      *used = external_array->length();
9860      break;
9861  }
9862}
9863
9864
9865bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
9866  STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
9867                kMaxUncheckedFastElementsLength);
9868  if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
9869      (new_capacity <= kMaxUncheckedFastElementsLength &&
9870       GetHeap()->InNewSpace(this))) {
9871    return false;
9872  }
9873  // If the fast-case backing storage takes up roughly three times as
9874  // much space (in machine words) as a dictionary backing storage
9875  // would, the object should have slow elements.
9876  int old_capacity = 0;
9877  int used_elements = 0;
9878  GetElementsCapacityAndUsage(&old_capacity, &used_elements);
9879  int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
9880      SeededNumberDictionary::kEntrySize;
9881  return 3 * dictionary_size <= new_capacity;
9882}
9883
9884
9885bool JSObject::ShouldConvertToFastElements() {
9886  ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9887  // If the elements are sparse, we should not go back to fast case.
9888  if (!HasDenseElements()) return false;
9889  // An object requiring access checks is never allowed to have fast
9890  // elements.  If it had fast elements we would skip security checks.
9891  if (IsAccessCheckNeeded()) return false;
9892
9893  FixedArray* elements = FixedArray::cast(this->elements());
9894  SeededNumberDictionary* dictionary = NULL;
9895  if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
9896    dictionary = SeededNumberDictionary::cast(elements->get(1));
9897  } else {
9898    dictionary = SeededNumberDictionary::cast(elements);
9899  }
9900  // If an element has been added at a very high index in the elements
9901  // dictionary, we cannot go back to fast case.
9902  if (dictionary->requires_slow_elements()) return false;
9903  // If the dictionary backing storage takes up roughly half as much
9904  // space (in machine words) as a fast-case backing storage would,
9905  // the object should have fast elements.
9906  uint32_t array_size = 0;
9907  if (IsJSArray()) {
9908    CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
9909  } else {
9910    array_size = dictionary->max_number_key();
9911  }
9912  uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
9913      SeededNumberDictionary::kEntrySize;
9914  return 2 * dictionary_size >= array_size;
9915}
9916
9917
9918bool JSObject::ShouldConvertToFastDoubleElements(
9919    bool* has_smi_only_elements) {
9920  *has_smi_only_elements = false;
9921  if (FLAG_unbox_double_arrays) {
9922    ASSERT(HasDictionaryElements());
9923    SeededNumberDictionary* dictionary =
9924        SeededNumberDictionary::cast(elements());
9925    bool found_double = false;
9926    for (int i = 0; i < dictionary->Capacity(); i++) {
9927      Object* key = dictionary->KeyAt(i);
9928      if (key->IsNumber()) {
9929        Object* value = dictionary->ValueAt(i);
9930        if (!value->IsNumber()) return false;
9931        if (!value->IsSmi()) {
9932          found_double = true;
9933        }
9934      }
9935    }
9936    *has_smi_only_elements = !found_double;
9937    return found_double;
9938  } else {
9939    return false;
9940  }
9941}
9942
9943
9944// Certain compilers request function template instantiation when they
9945// see the definition of the other template functions in the
9946// class. This requires us to have the template functions put
9947// together, so even though this function belongs in objects-debug.cc,
9948// we keep it here instead to satisfy certain compilers.
9949#ifdef OBJECT_PRINT
9950template<typename Shape, typename Key>
9951void Dictionary<Shape, Key>::Print(FILE* out) {
9952  int capacity = HashTable<Shape, Key>::Capacity();
9953  for (int i = 0; i < capacity; i++) {
9954    Object* k = HashTable<Shape, Key>::KeyAt(i);
9955    if (HashTable<Shape, Key>::IsKey(k)) {
9956      PrintF(out, " ");
9957      if (k->IsString()) {
9958        String::cast(k)->StringPrint(out);
9959      } else {
9960        k->ShortPrint(out);
9961      }
9962      PrintF(out, ": ");
9963      ValueAt(i)->ShortPrint(out);
9964      PrintF(out, "\n");
9965    }
9966  }
9967}
9968#endif
9969
9970
9971template<typename Shape, typename Key>
9972void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
9973  int pos = 0;
9974  int capacity = HashTable<Shape, Key>::Capacity();
9975  AssertNoAllocation no_gc;
9976  WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
9977  for (int i = 0; i < capacity; i++) {
9978    Object* k =  Dictionary<Shape, Key>::KeyAt(i);
9979    if (Dictionary<Shape, Key>::IsKey(k)) {
9980      elements->set(pos++, ValueAt(i), mode);
9981    }
9982  }
9983  ASSERT(pos == elements->length());
9984}
9985
9986
9987InterceptorInfo* JSObject::GetNamedInterceptor() {
9988  ASSERT(map()->has_named_interceptor());
9989  JSFunction* constructor = JSFunction::cast(map()->constructor());
9990  ASSERT(constructor->shared()->IsApiFunction());
9991  Object* result =
9992      constructor->shared()->get_api_func_data()->named_property_handler();
9993  return InterceptorInfo::cast(result);
9994}
9995
9996
9997InterceptorInfo* JSObject::GetIndexedInterceptor() {
9998  ASSERT(map()->has_indexed_interceptor());
9999  JSFunction* constructor = JSFunction::cast(map()->constructor());
10000  ASSERT(constructor->shared()->IsApiFunction());
10001  Object* result =
10002      constructor->shared()->get_api_func_data()->indexed_property_handler();
10003  return InterceptorInfo::cast(result);
10004}
10005
10006
10007MaybeObject* JSObject::GetPropertyPostInterceptor(
10008    JSReceiver* receiver,
10009    String* name,
10010    PropertyAttributes* attributes) {
10011  // Check local property in holder, ignore interceptor.
10012  LookupResult result(GetIsolate());
10013  LocalLookupRealNamedProperty(name, &result);
10014  if (result.IsProperty()) {
10015    return GetProperty(receiver, &result, name, attributes);
10016  }
10017  // Continue searching via the prototype chain.
10018  Object* pt = GetPrototype();
10019  *attributes = ABSENT;
10020  if (pt->IsNull()) return GetHeap()->undefined_value();
10021  return pt->GetPropertyWithReceiver(receiver, name, attributes);
10022}
10023
10024
10025MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
10026    JSReceiver* receiver,
10027    String* name,
10028    PropertyAttributes* attributes) {
10029  // Check local property in holder, ignore interceptor.
10030  LookupResult result(GetIsolate());
10031  LocalLookupRealNamedProperty(name, &result);
10032  if (result.IsProperty()) {
10033    return GetProperty(receiver, &result, name, attributes);
10034  }
10035  return GetHeap()->undefined_value();
10036}
10037
10038
10039MaybeObject* JSObject::GetPropertyWithInterceptor(
10040    JSReceiver* receiver,
10041    String* name,
10042    PropertyAttributes* attributes) {
10043  Isolate* isolate = GetIsolate();
10044  InterceptorInfo* interceptor = GetNamedInterceptor();
10045  HandleScope scope(isolate);
10046  Handle<JSReceiver> receiver_handle(receiver);
10047  Handle<JSObject> holder_handle(this);
10048  Handle<String> name_handle(name);
10049
10050  if (!interceptor->getter()->IsUndefined()) {
10051    v8::NamedPropertyGetter getter =
10052        v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
10053    LOG(isolate,
10054        ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10055    CustomArguments args(isolate, interceptor->data(), receiver, this);
10056    v8::AccessorInfo info(args.end());
10057    v8::Handle<v8::Value> result;
10058    {
10059      // Leaving JavaScript.
10060      VMState state(isolate, EXTERNAL);
10061      result = getter(v8::Utils::ToLocal(name_handle), info);
10062    }
10063    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
10064    if (!result.IsEmpty()) {
10065      *attributes = NONE;
10066      return *v8::Utils::OpenHandle(*result);
10067    }
10068  }
10069
10070  MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
10071      *receiver_handle,
10072      *name_handle,
10073      attributes);
10074  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
10075  return result;
10076}
10077
10078
10079bool JSObject::HasRealNamedProperty(String* key) {
10080  // Check access rights if needed.
10081  Isolate* isolate = GetIsolate();
10082  if (IsAccessCheckNeeded()) {
10083    if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10084      isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10085      return false;
10086    }
10087  }
10088
10089  LookupResult result(isolate);
10090  LocalLookupRealNamedProperty(key, &result);
10091  return result.IsProperty() && (result.type() != INTERCEPTOR);
10092}
10093
10094
10095bool JSObject::HasRealElementProperty(uint32_t index) {
10096  // Check access rights if needed.
10097  if (IsAccessCheckNeeded()) {
10098    Heap* heap = GetHeap();
10099    if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10100      heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10101      return false;
10102    }
10103  }
10104
10105  // Handle [] on String objects.
10106  if (this->IsStringObjectWithCharacterAt(index)) return true;
10107
10108  switch (GetElementsKind()) {
10109    case FAST_SMI_ONLY_ELEMENTS:
10110    case FAST_ELEMENTS: {
10111      uint32_t length = IsJSArray() ?
10112          static_cast<uint32_t>(
10113              Smi::cast(JSArray::cast(this)->length())->value()) :
10114          static_cast<uint32_t>(FixedArray::cast(elements())->length());
10115      return (index < length) &&
10116          !FixedArray::cast(elements())->get(index)->IsTheHole();
10117    }
10118    case FAST_DOUBLE_ELEMENTS: {
10119      uint32_t length = IsJSArray() ?
10120          static_cast<uint32_t>(
10121              Smi::cast(JSArray::cast(this)->length())->value()) :
10122          static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
10123      return (index < length) &&
10124          !FixedDoubleArray::cast(elements())->is_the_hole(index);
10125      break;
10126    }
10127    case EXTERNAL_PIXEL_ELEMENTS: {
10128      ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
10129      return index < static_cast<uint32_t>(pixels->length());
10130    }
10131    case EXTERNAL_BYTE_ELEMENTS:
10132    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10133    case EXTERNAL_SHORT_ELEMENTS:
10134    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10135    case EXTERNAL_INT_ELEMENTS:
10136    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10137    case EXTERNAL_FLOAT_ELEMENTS:
10138    case EXTERNAL_DOUBLE_ELEMENTS: {
10139      ExternalArray* array = ExternalArray::cast(elements());
10140      return index < static_cast<uint32_t>(array->length());
10141    }
10142    case DICTIONARY_ELEMENTS: {
10143      return element_dictionary()->FindEntry(index)
10144          != SeededNumberDictionary::kNotFound;
10145    }
10146    case NON_STRICT_ARGUMENTS_ELEMENTS:
10147      UNIMPLEMENTED();
10148      break;
10149  }
10150  // All possibilities have been handled above already.
10151  UNREACHABLE();
10152  return GetHeap()->null_value();
10153}
10154
10155
10156bool JSObject::HasRealNamedCallbackProperty(String* key) {
10157  // Check access rights if needed.
10158  Isolate* isolate = GetIsolate();
10159  if (IsAccessCheckNeeded()) {
10160    if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10161      isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10162      return false;
10163    }
10164  }
10165
10166  LookupResult result(isolate);
10167  LocalLookupRealNamedProperty(key, &result);
10168  return result.IsFound() && (result.type() == CALLBACKS);
10169}
10170
10171
10172int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
10173  return HasFastProperties() ?
10174      map()->NumberOfDescribedProperties(filter) :
10175      property_dictionary()->NumberOfElementsFilterAttributes(filter);
10176}
10177
10178
10179void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
10180  Object* temp = get(i);
10181  set(i, get(j));
10182  set(j, temp);
10183  if (this != numbers) {
10184    temp = numbers->get(i);
10185    numbers->set(i, Smi::cast(numbers->get(j)));
10186    numbers->set(j, Smi::cast(temp));
10187  }
10188}
10189
10190
10191static void InsertionSortPairs(FixedArray* content,
10192                               FixedArray* numbers,
10193                               int len) {
10194  for (int i = 1; i < len; i++) {
10195    int j = i;
10196    while (j > 0 &&
10197           (NumberToUint32(numbers->get(j - 1)) >
10198            NumberToUint32(numbers->get(j)))) {
10199      content->SwapPairs(numbers, j - 1, j);
10200      j--;
10201    }
10202  }
10203}
10204
10205
10206void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
10207  // In-place heap sort.
10208  ASSERT(content->length() == numbers->length());
10209
10210  // Bottom-up max-heap construction.
10211  for (int i = 1; i < len; ++i) {
10212    int child_index = i;
10213    while (child_index > 0) {
10214      int parent_index = ((child_index + 1) >> 1) - 1;
10215      uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10216      uint32_t child_value = NumberToUint32(numbers->get(child_index));
10217      if (parent_value < child_value) {
10218        content->SwapPairs(numbers, parent_index, child_index);
10219      } else {
10220        break;
10221      }
10222      child_index = parent_index;
10223    }
10224  }
10225
10226  // Extract elements and create sorted array.
10227  for (int i = len - 1; i > 0; --i) {
10228    // Put max element at the back of the array.
10229    content->SwapPairs(numbers, 0, i);
10230    // Sift down the new top element.
10231    int parent_index = 0;
10232    while (true) {
10233      int child_index = ((parent_index + 1) << 1) - 1;
10234      if (child_index >= i) break;
10235      uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10236      uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10237      uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10238      if (child_index + 1 >= i || child1_value > child2_value) {
10239        if (parent_value > child1_value) break;
10240        content->SwapPairs(numbers, parent_index, child_index);
10241        parent_index = child_index;
10242      } else {
10243        if (parent_value > child2_value) break;
10244        content->SwapPairs(numbers, parent_index, child_index + 1);
10245        parent_index = child_index + 1;
10246      }
10247    }
10248  }
10249}
10250
10251
10252// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
10253void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10254  ASSERT(this->length() == numbers->length());
10255  // For small arrays, simply use insertion sort.
10256  if (len <= 10) {
10257    InsertionSortPairs(this, numbers, len);
10258    return;
10259  }
10260  // Check the range of indices.
10261  uint32_t min_index = NumberToUint32(numbers->get(0));
10262  uint32_t max_index = min_index;
10263  uint32_t i;
10264  for (i = 1; i < len; i++) {
10265    if (NumberToUint32(numbers->get(i)) < min_index) {
10266      min_index = NumberToUint32(numbers->get(i));
10267    } else if (NumberToUint32(numbers->get(i)) > max_index) {
10268      max_index = NumberToUint32(numbers->get(i));
10269    }
10270  }
10271  if (max_index - min_index + 1 == len) {
10272    // Indices form a contiguous range, unless there are duplicates.
10273    // Do an in-place linear time sort assuming distinct numbers, but
10274    // avoid hanging in case they are not.
10275    for (i = 0; i < len; i++) {
10276      uint32_t p;
10277      uint32_t j = 0;
10278      // While the current element at i is not at its correct position p,
10279      // swap the elements at these two positions.
10280      while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
10281             j++ < len) {
10282        SwapPairs(numbers, i, p);
10283      }
10284    }
10285  } else {
10286    HeapSortPairs(this, numbers, len);
10287    return;
10288  }
10289}
10290
10291
10292// Fill in the names of local properties into the supplied storage. The main
10293// purpose of this function is to provide reflection information for the object
10294// mirrors.
10295void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
10296  ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
10297  if (HasFastProperties()) {
10298    DescriptorArray* descs = map()->instance_descriptors();
10299    for (int i = 0; i < descs->number_of_descriptors(); i++) {
10300      if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
10301    }
10302    ASSERT(storage->length() >= index);
10303  } else {
10304    property_dictionary()->CopyKeysTo(storage,
10305                                      index,
10306                                      StringDictionary::UNSORTED);
10307  }
10308}
10309
10310
10311int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10312  return GetLocalElementKeys(NULL, filter);
10313}
10314
10315
10316int JSObject::NumberOfEnumElements() {
10317  // Fast case for objects with no elements.
10318  if (!IsJSValue() && HasFastElements()) {
10319    uint32_t length = IsJSArray() ?
10320        static_cast<uint32_t>(
10321            Smi::cast(JSArray::cast(this)->length())->value()) :
10322        static_cast<uint32_t>(FixedArray::cast(elements())->length());
10323    if (length == 0) return 0;
10324  }
10325  // Compute the number of enumerable elements.
10326  return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10327}
10328
10329
10330int JSObject::GetLocalElementKeys(FixedArray* storage,
10331                                  PropertyAttributes filter) {
10332  int counter = 0;
10333  switch (GetElementsKind()) {
10334    case FAST_SMI_ONLY_ELEMENTS:
10335    case FAST_ELEMENTS: {
10336      int length = IsJSArray() ?
10337          Smi::cast(JSArray::cast(this)->length())->value() :
10338          FixedArray::cast(elements())->length();
10339      for (int i = 0; i < length; i++) {
10340        if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10341          if (storage != NULL) {
10342            storage->set(counter, Smi::FromInt(i));
10343          }
10344          counter++;
10345        }
10346      }
10347      ASSERT(!storage || storage->length() >= counter);
10348      break;
10349    }
10350    case FAST_DOUBLE_ELEMENTS: {
10351      int length = IsJSArray() ?
10352          Smi::cast(JSArray::cast(this)->length())->value() :
10353          FixedDoubleArray::cast(elements())->length();
10354      for (int i = 0; i < length; i++) {
10355        if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10356          if (storage != NULL) {
10357            storage->set(counter, Smi::FromInt(i));
10358          }
10359          counter++;
10360        }
10361      }
10362      ASSERT(!storage || storage->length() >= counter);
10363      break;
10364    }
10365    case EXTERNAL_PIXEL_ELEMENTS: {
10366      int length = ExternalPixelArray::cast(elements())->length();
10367      while (counter < length) {
10368        if (storage != NULL) {
10369          storage->set(counter, Smi::FromInt(counter));
10370        }
10371        counter++;
10372      }
10373      ASSERT(!storage || storage->length() >= counter);
10374      break;
10375    }
10376    case EXTERNAL_BYTE_ELEMENTS:
10377    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10378    case EXTERNAL_SHORT_ELEMENTS:
10379    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10380    case EXTERNAL_INT_ELEMENTS:
10381    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10382    case EXTERNAL_FLOAT_ELEMENTS:
10383    case EXTERNAL_DOUBLE_ELEMENTS: {
10384      int length = ExternalArray::cast(elements())->length();
10385      while (counter < length) {
10386        if (storage != NULL) {
10387          storage->set(counter, Smi::FromInt(counter));
10388        }
10389        counter++;
10390      }
10391      ASSERT(!storage || storage->length() >= counter);
10392      break;
10393    }
10394    case DICTIONARY_ELEMENTS: {
10395      if (storage != NULL) {
10396        element_dictionary()->CopyKeysTo(storage,
10397                                         filter,
10398                                         SeededNumberDictionary::SORTED);
10399      }
10400      counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
10401      break;
10402    }
10403    case NON_STRICT_ARGUMENTS_ELEMENTS: {
10404      FixedArray* parameter_map = FixedArray::cast(elements());
10405      int mapped_length = parameter_map->length() - 2;
10406      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10407      if (arguments->IsDictionary()) {
10408        // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10409        // will insert in storage starting at index 0.
10410        SeededNumberDictionary* dictionary =
10411            SeededNumberDictionary::cast(arguments);
10412        if (storage != NULL) {
10413          dictionary->CopyKeysTo(
10414              storage, filter, SeededNumberDictionary::UNSORTED);
10415        }
10416        counter += dictionary->NumberOfElementsFilterAttributes(filter);
10417        for (int i = 0; i < mapped_length; ++i) {
10418          if (!parameter_map->get(i + 2)->IsTheHole()) {
10419            if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10420            ++counter;
10421          }
10422        }
10423        if (storage != NULL) storage->SortPairs(storage, counter);
10424
10425      } else {
10426        int backing_length = arguments->length();
10427        int i = 0;
10428        for (; i < mapped_length; ++i) {
10429          if (!parameter_map->get(i + 2)->IsTheHole()) {
10430            if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10431            ++counter;
10432          } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10433            if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10434            ++counter;
10435          }
10436        }
10437        for (; i < backing_length; ++i) {
10438          if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10439          ++counter;
10440        }
10441      }
10442      break;
10443    }
10444  }
10445
10446  if (this->IsJSValue()) {
10447    Object* val = JSValue::cast(this)->value();
10448    if (val->IsString()) {
10449      String* str = String::cast(val);
10450      if (storage) {
10451        for (int i = 0; i < str->length(); i++) {
10452          storage->set(counter + i, Smi::FromInt(i));
10453        }
10454      }
10455      counter += str->length();
10456    }
10457  }
10458  ASSERT(!storage || storage->length() == counter);
10459  return counter;
10460}
10461
10462
10463int JSObject::GetEnumElementKeys(FixedArray* storage) {
10464  return GetLocalElementKeys(storage,
10465                             static_cast<PropertyAttributes>(DONT_ENUM));
10466}
10467
10468
10469// StringKey simply carries a string object as key.
10470class StringKey : public HashTableKey {
10471 public:
10472  explicit StringKey(String* string) :
10473      string_(string),
10474      hash_(HashForObject(string)) { }
10475
10476  bool IsMatch(Object* string) {
10477    // We know that all entries in a hash table had their hash keys created.
10478    // Use that knowledge to have fast failure.
10479    if (hash_ != HashForObject(string)) {
10480      return false;
10481    }
10482    return string_->Equals(String::cast(string));
10483  }
10484
10485  uint32_t Hash() { return hash_; }
10486
10487  uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
10488
10489  Object* AsObject() { return string_; }
10490
10491  String* string_;
10492  uint32_t hash_;
10493};
10494
10495
10496// StringSharedKeys are used as keys in the eval cache.
10497class StringSharedKey : public HashTableKey {
10498 public:
10499  StringSharedKey(String* source,
10500                  SharedFunctionInfo* shared,
10501                  LanguageMode language_mode,
10502                  int scope_position)
10503      : source_(source),
10504        shared_(shared),
10505        language_mode_(language_mode),
10506        scope_position_(scope_position) { }
10507
10508  bool IsMatch(Object* other) {
10509    if (!other->IsFixedArray()) return false;
10510    FixedArray* other_array = FixedArray::cast(other);
10511    SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10512    if (shared != shared_) return false;
10513    int language_unchecked = Smi::cast(other_array->get(2))->value();
10514    ASSERT(language_unchecked == CLASSIC_MODE ||
10515           language_unchecked == STRICT_MODE ||
10516           language_unchecked == EXTENDED_MODE);
10517    LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10518    if (language_mode != language_mode_) return false;
10519    int scope_position = Smi::cast(other_array->get(3))->value();
10520    if (scope_position != scope_position_) return false;
10521    String* source = String::cast(other_array->get(1));
10522    return source->Equals(source_);
10523  }
10524
10525  static uint32_t StringSharedHashHelper(String* source,
10526                                         SharedFunctionInfo* shared,
10527                                         LanguageMode language_mode,
10528                                         int scope_position) {
10529    uint32_t hash = source->Hash();
10530    if (shared->HasSourceCode()) {
10531      // Instead of using the SharedFunctionInfo pointer in the hash
10532      // code computation, we use a combination of the hash of the
10533      // script source code and the start position of the calling scope.
10534      // We do this to ensure that the cache entries can survive garbage
10535      // collection.
10536      Script* script = Script::cast(shared->script());
10537      hash ^= String::cast(script->source())->Hash();
10538      if (language_mode == STRICT_MODE) hash ^= 0x8000;
10539      if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
10540      hash += scope_position;
10541    }
10542    return hash;
10543  }
10544
10545  uint32_t Hash() {
10546    return StringSharedHashHelper(
10547        source_, shared_, language_mode_, scope_position_);
10548  }
10549
10550  uint32_t HashForObject(Object* obj) {
10551    FixedArray* other_array = FixedArray::cast(obj);
10552    SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10553    String* source = String::cast(other_array->get(1));
10554    int language_unchecked = Smi::cast(other_array->get(2))->value();
10555    ASSERT(language_unchecked == CLASSIC_MODE ||
10556           language_unchecked == STRICT_MODE ||
10557           language_unchecked == EXTENDED_MODE);
10558    LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10559    int scope_position = Smi::cast(other_array->get(3))->value();
10560    return StringSharedHashHelper(
10561        source, shared, language_mode, scope_position);
10562  }
10563
10564  MUST_USE_RESULT MaybeObject* AsObject() {
10565    Object* obj;
10566    { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
10567      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10568    }
10569    FixedArray* other_array = FixedArray::cast(obj);
10570    other_array->set(0, shared_);
10571    other_array->set(1, source_);
10572    other_array->set(2, Smi::FromInt(language_mode_));
10573    other_array->set(3, Smi::FromInt(scope_position_));
10574    return other_array;
10575  }
10576
10577 private:
10578  String* source_;
10579  SharedFunctionInfo* shared_;
10580  LanguageMode language_mode_;
10581  int scope_position_;
10582};
10583
10584
10585// RegExpKey carries the source and flags of a regular expression as key.
10586class RegExpKey : public HashTableKey {
10587 public:
10588  RegExpKey(String* string, JSRegExp::Flags flags)
10589      : string_(string),
10590        flags_(Smi::FromInt(flags.value())) { }
10591
10592  // Rather than storing the key in the hash table, a pointer to the
10593  // stored value is stored where the key should be.  IsMatch then
10594  // compares the search key to the found object, rather than comparing
10595  // a key to a key.
10596  bool IsMatch(Object* obj) {
10597    FixedArray* val = FixedArray::cast(obj);
10598    return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10599        && (flags_ == val->get(JSRegExp::kFlagsIndex));
10600  }
10601
10602  uint32_t Hash() { return RegExpHash(string_, flags_); }
10603
10604  Object* AsObject() {
10605    // Plain hash maps, which is where regexp keys are used, don't
10606    // use this function.
10607    UNREACHABLE();
10608    return NULL;
10609  }
10610
10611  uint32_t HashForObject(Object* obj) {
10612    FixedArray* val = FixedArray::cast(obj);
10613    return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10614                      Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10615  }
10616
10617  static uint32_t RegExpHash(String* string, Smi* flags) {
10618    return string->Hash() + flags->value();
10619  }
10620
10621  String* string_;
10622  Smi* flags_;
10623};
10624
10625// Utf8SymbolKey carries a vector of chars as key.
10626class Utf8SymbolKey : public HashTableKey {
10627 public:
10628  explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10629      : string_(string), hash_field_(0), seed_(seed) { }
10630
10631  bool IsMatch(Object* string) {
10632    return String::cast(string)->IsEqualTo(string_);
10633  }
10634
10635  uint32_t Hash() {
10636    if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
10637    unibrow::Utf8InputBuffer<> buffer(string_.start(),
10638                                      static_cast<unsigned>(string_.length()));
10639    chars_ = buffer.Utf16Length();
10640    hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
10641    uint32_t result = hash_field_ >> String::kHashShift;
10642    ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
10643    return result;
10644  }
10645
10646  uint32_t HashForObject(Object* other) {
10647    return String::cast(other)->Hash();
10648  }
10649
10650  MaybeObject* AsObject() {
10651    if (hash_field_ == 0) Hash();
10652    return Isolate::Current()->heap()->AllocateSymbol(
10653        string_, chars_, hash_field_);
10654  }
10655
10656  Vector<const char> string_;
10657  uint32_t hash_field_;
10658  int chars_;  // Caches the number of characters when computing the hash code.
10659  uint32_t seed_;
10660};
10661
10662
10663template <typename Char>
10664class SequentialSymbolKey : public HashTableKey {
10665 public:
10666  explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10667      : string_(string), hash_field_(0), seed_(seed) { }
10668
10669  uint32_t Hash() {
10670    StringHasher hasher(string_.length(), seed_);
10671
10672    // Very long strings have a trivial hash that doesn't inspect the
10673    // string contents.
10674    if (hasher.has_trivial_hash()) {
10675      hash_field_ = hasher.GetHashField();
10676    } else {
10677      int i = 0;
10678      // Do the iterative array index computation as long as there is a
10679      // chance this is an array index.
10680      while (i < string_.length() && hasher.is_array_index()) {
10681        hasher.AddCharacter(static_cast<uc32>(string_[i]));
10682        i++;
10683      }
10684
10685      // Process the remaining characters without updating the array
10686      // index.
10687      while (i < string_.length()) {
10688        hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10689        i++;
10690      }
10691      hash_field_ = hasher.GetHashField();
10692    }
10693
10694    uint32_t result = hash_field_ >> String::kHashShift;
10695    ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
10696    return result;
10697  }
10698
10699
10700  uint32_t HashForObject(Object* other) {
10701    return String::cast(other)->Hash();
10702  }
10703
10704  Vector<const Char> string_;
10705  uint32_t hash_field_;
10706  uint32_t seed_;
10707};
10708
10709
10710
10711class AsciiSymbolKey : public SequentialSymbolKey<char> {
10712 public:
10713  AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10714      : SequentialSymbolKey<char>(str, seed) { }
10715
10716  bool IsMatch(Object* string) {
10717    return String::cast(string)->IsAsciiEqualTo(string_);
10718  }
10719
10720  MaybeObject* AsObject() {
10721    if (hash_field_ == 0) Hash();
10722    return HEAP->AllocateAsciiSymbol(string_, hash_field_);
10723  }
10724};
10725
10726
10727class SubStringAsciiSymbolKey : public HashTableKey {
10728 public:
10729  explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10730                                   int from,
10731                                   int length,
10732                                   uint32_t seed)
10733      : string_(string), from_(from), length_(length), seed_(seed) { }
10734
10735  uint32_t Hash() {
10736    ASSERT(length_ >= 0);
10737    ASSERT(from_ + length_ <= string_->length());
10738    StringHasher hasher(length_, string_->GetHeap()->HashSeed());
10739
10740    // Very long strings have a trivial hash that doesn't inspect the
10741    // string contents.
10742    if (hasher.has_trivial_hash()) {
10743      hash_field_ = hasher.GetHashField();
10744    } else {
10745      int i = 0;
10746      // Do the iterative array index computation as long as there is a
10747      // chance this is an array index.
10748      while (i < length_ && hasher.is_array_index()) {
10749        hasher.AddCharacter(static_cast<uc32>(
10750            string_->SeqAsciiStringGet(i + from_)));
10751        i++;
10752      }
10753
10754      // Process the remaining characters without updating the array
10755      // index.
10756      while (i < length_) {
10757        hasher.AddCharacterNoIndex(static_cast<uc32>(
10758            string_->SeqAsciiStringGet(i + from_)));
10759        i++;
10760      }
10761      hash_field_ = hasher.GetHashField();
10762    }
10763
10764    uint32_t result = hash_field_ >> String::kHashShift;
10765    ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
10766    return result;
10767  }
10768
10769
10770  uint32_t HashForObject(Object* other) {
10771    return String::cast(other)->Hash();
10772  }
10773
10774  bool IsMatch(Object* string) {
10775    Vector<const char> chars(string_->GetChars() + from_, length_);
10776    return String::cast(string)->IsAsciiEqualTo(chars);
10777  }
10778
10779  MaybeObject* AsObject() {
10780    if (hash_field_ == 0) Hash();
10781    Vector<const char> chars(string_->GetChars() + from_, length_);
10782    return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10783  }
10784
10785 private:
10786  Handle<SeqAsciiString> string_;
10787  int from_;
10788  int length_;
10789  uint32_t hash_field_;
10790  uint32_t seed_;
10791};
10792
10793
10794class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10795 public:
10796  explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10797      : SequentialSymbolKey<uc16>(str, seed) { }
10798
10799  bool IsMatch(Object* string) {
10800    return String::cast(string)->IsTwoByteEqualTo(string_);
10801  }
10802
10803  MaybeObject* AsObject() {
10804    if (hash_field_ == 0) Hash();
10805    return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
10806  }
10807};
10808
10809
10810// SymbolKey carries a string/symbol object as key.
10811class SymbolKey : public HashTableKey {
10812 public:
10813  explicit SymbolKey(String* string)
10814      : string_(string) { }
10815
10816  bool IsMatch(Object* string) {
10817    return String::cast(string)->Equals(string_);
10818  }
10819
10820  uint32_t Hash() { return string_->Hash(); }
10821
10822  uint32_t HashForObject(Object* other) {
10823    return String::cast(other)->Hash();
10824  }
10825
10826  MaybeObject* AsObject() {
10827    // Attempt to flatten the string, so that symbols will most often
10828    // be flat strings.
10829    string_ = string_->TryFlattenGetString();
10830    Heap* heap = string_->GetHeap();
10831    // Transform string to symbol if possible.
10832    Map* map = heap->SymbolMapForString(string_);
10833    if (map != NULL) {
10834      string_->set_map_no_write_barrier(map);
10835      ASSERT(string_->IsSymbol());
10836      return string_;
10837    }
10838    // Otherwise allocate a new symbol.
10839    StringInputBuffer buffer(string_);
10840    return heap->AllocateInternalSymbol(&buffer,
10841                                        string_->length(),
10842                                        string_->hash_field());
10843  }
10844
10845  static uint32_t StringHash(Object* obj) {
10846    return String::cast(obj)->Hash();
10847  }
10848
10849  String* string_;
10850};
10851
10852
10853template<typename Shape, typename Key>
10854void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
10855  IteratePointers(v, 0, kElementsStartOffset);
10856}
10857
10858
10859template<typename Shape, typename Key>
10860void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
10861  IteratePointers(v,
10862                  kElementsStartOffset,
10863                  kHeaderSize + length() * kPointerSize);
10864}
10865
10866
10867template<typename Shape, typename Key>
10868MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10869                                             PretenureFlag pretenure) {
10870  int capacity = ComputeCapacity(at_least_space_for);
10871  if (capacity > HashTable::kMaxCapacity) {
10872    return Failure::OutOfMemoryException();
10873  }
10874
10875  Object* obj;
10876  { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10877        AllocateHashTable(EntryToIndex(capacity), pretenure);
10878    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10879  }
10880  HashTable::cast(obj)->SetNumberOfElements(0);
10881  HashTable::cast(obj)->SetNumberOfDeletedElements(0);
10882  HashTable::cast(obj)->SetCapacity(capacity);
10883  return obj;
10884}
10885
10886
10887// Find entry for key otherwise return kNotFound.
10888int StringDictionary::FindEntry(String* key) {
10889  if (!key->IsSymbol()) {
10890    return HashTable<StringDictionaryShape, String*>::FindEntry(key);
10891  }
10892
10893  // Optimized for symbol key. Knowledge of the key type allows:
10894  // 1. Move the check if the key is a symbol out of the loop.
10895  // 2. Avoid comparing hash codes in symbol to symbol comparison.
10896  // 3. Detect a case when a dictionary key is not a symbol but the key is.
10897  //    In case of positive result the dictionary key may be replaced by
10898  //    the symbol with minimal performance penalty. It gives a chance to
10899  //    perform further lookups in code stubs (and significant performance boost
10900  //    a certain style of code).
10901
10902  // EnsureCapacity will guarantee the hash table is never full.
10903  uint32_t capacity = Capacity();
10904  uint32_t entry = FirstProbe(key->Hash(), capacity);
10905  uint32_t count = 1;
10906
10907  while (true) {
10908    int index = EntryToIndex(entry);
10909    Object* element = get(index);
10910    if (element->IsUndefined()) break;  // Empty entry.
10911    if (key == element) return entry;
10912    if (!element->IsSymbol() &&
10913        !element->IsTheHole() &&
10914        String::cast(element)->Equals(key)) {
10915      // Replace a non-symbol key by the equivalent symbol for faster further
10916      // lookups.
10917      set(index, key);
10918      return entry;
10919    }
10920    ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
10921    entry = NextProbe(entry, count++, capacity);
10922  }
10923  return kNotFound;
10924}
10925
10926
10927bool StringDictionary::ContainsTransition(int entry) {
10928  switch (DetailsAt(entry).type()) {
10929    case MAP_TRANSITION:
10930    case CONSTANT_TRANSITION:
10931    case ELEMENTS_TRANSITION:
10932      return true;
10933    case CALLBACKS: {
10934      Object* value = ValueAt(entry);
10935      if (!value->IsAccessorPair()) return false;
10936      AccessorPair* accessors = AccessorPair::cast(value);
10937      return accessors->getter()->IsMap() || accessors->setter()->IsMap();
10938    }
10939    case NORMAL:
10940    case FIELD:
10941    case CONSTANT_FUNCTION:
10942    case HANDLER:
10943    case INTERCEPTOR:
10944    case NULL_DESCRIPTOR:
10945      return false;
10946  }
10947  UNREACHABLE();  // Keep the compiler happy.
10948  return false;
10949}
10950
10951
10952template<typename Shape, typename Key>
10953MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
10954  ASSERT(NumberOfElements() < new_table->Capacity());
10955
10956  AssertNoAllocation no_gc;
10957  WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
10958
10959  // Copy prefix to new array.
10960  for (int i = kPrefixStartIndex;
10961       i < kPrefixStartIndex + Shape::kPrefixSize;
10962       i++) {
10963    new_table->set(i, get(i), mode);
10964  }
10965
10966  // Rehash the elements.
10967  int capacity = Capacity();
10968  for (int i = 0; i < capacity; i++) {
10969    uint32_t from_index = EntryToIndex(i);
10970    Object* k = get(from_index);
10971    if (IsKey(k)) {
10972      uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
10973      uint32_t insertion_index =
10974          EntryToIndex(new_table->FindInsertionEntry(hash));
10975      for (int j = 0; j < Shape::kEntrySize; j++) {
10976        new_table->set(insertion_index + j, get(from_index + j), mode);
10977      }
10978    }
10979  }
10980  new_table->SetNumberOfElements(NumberOfElements());
10981  new_table->SetNumberOfDeletedElements(0);
10982  return new_table;
10983}
10984
10985
10986template<typename Shape, typename Key>
10987MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
10988  int capacity = Capacity();
10989  int nof = NumberOfElements() + n;
10990  int nod = NumberOfDeletedElements();
10991  // Return if:
10992  //   50% is still free after adding n elements and
10993  //   at most 50% of the free elements are deleted elements.
10994  if (nod <= (capacity - nof) >> 1) {
10995    int needed_free = nof >> 1;
10996    if (nof + needed_free <= capacity) return this;
10997  }
10998
10999  const int kMinCapacityForPretenure = 256;
11000  bool pretenure =
11001      (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
11002  Object* obj;
11003  { MaybeObject* maybe_obj =
11004        Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
11005    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11006  }
11007
11008  return Rehash(HashTable::cast(obj), key);
11009}
11010
11011
11012template<typename Shape, typename Key>
11013MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
11014  int capacity = Capacity();
11015  int nof = NumberOfElements();
11016
11017  // Shrink to fit the number of elements if only a quarter of the
11018  // capacity is filled with elements.
11019  if (nof > (capacity >> 2)) return this;
11020  // Allocate a new dictionary with room for at least the current
11021  // number of elements. The allocation method will make sure that
11022  // there is extra room in the dictionary for additions. Don't go
11023  // lower than room for 16 elements.
11024  int at_least_room_for = nof;
11025  if (at_least_room_for < 16) return this;
11026
11027  const int kMinCapacityForPretenure = 256;
11028  bool pretenure =
11029      (at_least_room_for > kMinCapacityForPretenure) &&
11030      !GetHeap()->InNewSpace(this);
11031  Object* obj;
11032  { MaybeObject* maybe_obj =
11033        Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
11034    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11035  }
11036
11037  return Rehash(HashTable::cast(obj), key);
11038}
11039
11040
11041template<typename Shape, typename Key>
11042uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
11043  uint32_t capacity = Capacity();
11044  uint32_t entry = FirstProbe(hash, capacity);
11045  uint32_t count = 1;
11046  // EnsureCapacity will guarantee the hash table is never full.
11047  while (true) {
11048    Object* element = KeyAt(entry);
11049    if (element->IsUndefined() || element->IsTheHole()) break;
11050    entry = NextProbe(entry, count++, capacity);
11051  }
11052  return entry;
11053}
11054
11055// Force instantiation of template instances class.
11056// Please note this list is compiler dependent.
11057
11058template class HashTable<SymbolTableShape, HashTableKey*>;
11059
11060template class HashTable<CompilationCacheShape, HashTableKey*>;
11061
11062template class HashTable<MapCacheShape, HashTableKey*>;
11063
11064template class HashTable<ObjectHashTableShape<1>, Object*>;
11065
11066template class HashTable<ObjectHashTableShape<2>, Object*>;
11067
11068template class Dictionary<StringDictionaryShape, String*>;
11069
11070template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
11071
11072template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11073
11074template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11075    Allocate(int at_least_space_for);
11076
11077template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11078    Allocate(int at_least_space_for);
11079
11080template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
11081    int);
11082
11083template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
11084    uint32_t, Object*);
11085
11086template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11087    AtPut(uint32_t, Object*);
11088
11089template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11090    SlowReverseLookup(Object* value);
11091
11092template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11093    SlowReverseLookup(Object* value);
11094
11095template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11096    Object*);
11097
11098template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
11099    FixedArray*,
11100    PropertyAttributes,
11101    Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
11102
11103template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11104    int, JSObject::DeleteMode);
11105
11106template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11107    DeleteProperty(int, JSObject::DeleteMode);
11108
11109template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11110    String*);
11111
11112template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
11113    uint32_t);
11114
11115template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
11116    FixedArray*,
11117    int,
11118    Dictionary<StringDictionaryShape, String*>::SortMode);
11119
11120template int
11121Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11122    PropertyAttributes);
11123
11124template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
11125    String*, Object*, PropertyDetails);
11126
11127template MaybeObject*
11128Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11129
11130template int
11131Dictionary<SeededNumberDictionaryShape, uint32_t>::
11132    NumberOfElementsFilterAttributes(PropertyAttributes);
11133
11134template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
11135    uint32_t, Object*, PropertyDetails);
11136
11137template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11138    uint32_t, Object*, PropertyDetails);
11139
11140template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11141    EnsureCapacity(int, uint32_t);
11142
11143template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11144    EnsureCapacity(int, uint32_t);
11145
11146template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11147    EnsureCapacity(int, String*);
11148
11149template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11150    AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11151
11152template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11153    AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11154
11155template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
11156    String*, Object*, PropertyDetails, uint32_t);
11157
11158template
11159int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
11160
11161template
11162int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
11163
11164template
11165int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
11166
11167
11168// Collates undefined and unexisting elements below limit from position
11169// zero of the elements. The object stays in Dictionary mode.
11170MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
11171  ASSERT(HasDictionaryElements());
11172  // Must stay in dictionary mode, either because of requires_slow_elements,
11173  // or because we are not going to sort (and therefore compact) all of the
11174  // elements.
11175  SeededNumberDictionary* dict = element_dictionary();
11176  HeapNumber* result_double = NULL;
11177  if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11178    // Allocate space for result before we start mutating the object.
11179    Object* new_double;
11180    { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
11181      if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11182    }
11183    result_double = HeapNumber::cast(new_double);
11184  }
11185
11186  Object* obj;
11187  { MaybeObject* maybe_obj =
11188        SeededNumberDictionary::Allocate(dict->NumberOfElements());
11189    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11190  }
11191  SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
11192
11193  AssertNoAllocation no_alloc;
11194
11195  uint32_t pos = 0;
11196  uint32_t undefs = 0;
11197  int capacity = dict->Capacity();
11198  for (int i = 0; i < capacity; i++) {
11199    Object* k = dict->KeyAt(i);
11200    if (dict->IsKey(k)) {
11201      ASSERT(k->IsNumber());
11202      ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11203      ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11204      ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11205      Object* value = dict->ValueAt(i);
11206      PropertyDetails details = dict->DetailsAt(i);
11207      if (details.type() == CALLBACKS) {
11208        // Bail out and do the sorting of undefineds and array holes in JS.
11209        return Smi::FromInt(-1);
11210      }
11211      uint32_t key = NumberToUint32(k);
11212      // In the following we assert that adding the entry to the new dictionary
11213      // does not cause GC.  This is the case because we made sure to allocate
11214      // the dictionary big enough above, so it need not grow.
11215      if (key < limit) {
11216        if (value->IsUndefined()) {
11217          undefs++;
11218        } else {
11219          if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11220            // Adding an entry with the key beyond smi-range requires
11221            // allocation. Bailout.
11222            return Smi::FromInt(-1);
11223          }
11224          new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
11225          pos++;
11226        }
11227      } else {
11228        if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11229          // Adding an entry with the key beyond smi-range requires
11230          // allocation. Bailout.
11231          return Smi::FromInt(-1);
11232        }
11233        new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
11234      }
11235    }
11236  }
11237
11238  uint32_t result = pos;
11239  PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
11240  Heap* heap = GetHeap();
11241  while (undefs > 0) {
11242    if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11243      // Adding an entry with the key beyond smi-range requires
11244      // allocation. Bailout.
11245      return Smi::FromInt(-1);
11246    }
11247    new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
11248        ToObjectUnchecked();
11249    pos++;
11250    undefs--;
11251  }
11252
11253  set_elements(new_dict);
11254
11255  if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11256    return Smi::FromInt(static_cast<int>(result));
11257  }
11258
11259  ASSERT_NE(NULL, result_double);
11260  result_double->set_value(static_cast<double>(result));
11261  return result_double;
11262}
11263
11264
11265// Collects all defined (non-hole) and non-undefined (array) elements at
11266// the start of the elements array.
11267// If the object is in dictionary mode, it is converted to fast elements
11268// mode.
11269MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
11270  Heap* heap = GetHeap();
11271
11272  if (HasDictionaryElements()) {
11273    // Convert to fast elements containing only the existing properties.
11274    // Ordering is irrelevant, since we are going to sort anyway.
11275    SeededNumberDictionary* dict = element_dictionary();
11276    if (IsJSArray() || dict->requires_slow_elements() ||
11277        dict->max_number_key() >= limit) {
11278      return PrepareSlowElementsForSort(limit);
11279    }
11280    // Convert to fast elements.
11281
11282    Object* obj;
11283    { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11284                                                        FAST_ELEMENTS);
11285      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11286    }
11287    Map* new_map = Map::cast(obj);
11288
11289    PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
11290    Object* new_array;
11291    { MaybeObject* maybe_new_array =
11292          heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
11293      if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11294    }
11295    FixedArray* fast_elements = FixedArray::cast(new_array);
11296    dict->CopyValuesTo(fast_elements);
11297
11298    set_map(new_map);
11299    set_elements(fast_elements);
11300  } else if (HasExternalArrayElements()) {
11301    // External arrays cannot have holes or undefined elements.
11302    return Smi::FromInt(ExternalArray::cast(elements())->length());
11303  } else if (!HasFastDoubleElements()) {
11304    Object* obj;
11305    { MaybeObject* maybe_obj = EnsureWritableFastElements();
11306      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11307    }
11308  }
11309  ASSERT(HasFastTypeElements() || HasFastDoubleElements());
11310
11311  // Collect holes at the end, undefined before that and the rest at the
11312  // start, and return the number of non-hole, non-undefined values.
11313
11314  FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11315  uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
11316  if (limit > elements_length) {
11317    limit = elements_length ;
11318  }
11319  if (limit == 0) {
11320    return Smi::FromInt(0);
11321  }
11322
11323  HeapNumber* result_double = NULL;
11324  if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11325    // Pessimistically allocate space for return value before
11326    // we start mutating the array.
11327    Object* new_double;
11328    { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
11329      if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11330    }
11331    result_double = HeapNumber::cast(new_double);
11332  }
11333
11334  uint32_t result = 0;
11335  if (elements_base->map() == heap->fixed_double_array_map()) {
11336    FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11337    // Split elements into defined and the_hole, in that order.
11338    unsigned int holes = limit;
11339    // Assume most arrays contain no holes and undefined values, so minimize the
11340    // number of stores of non-undefined, non-the-hole values.
11341    for (unsigned int i = 0; i < holes; i++) {
11342      if (elements->is_the_hole(i)) {
11343        holes--;
11344      } else {
11345        continue;
11346      }
11347      // Position i needs to be filled.
11348      while (holes > i) {
11349        if (elements->is_the_hole(holes)) {
11350          holes--;
11351        } else {
11352          elements->set(i, elements->get_scalar(holes));
11353          break;
11354        }
11355      }
11356    }
11357    result = holes;
11358    while (holes < limit) {
11359      elements->set_the_hole(holes);
11360      holes++;
11361    }
11362  } else {
11363    FixedArray* elements = FixedArray::cast(elements_base);
11364    AssertNoAllocation no_alloc;
11365
11366    // Split elements into defined, undefined and the_hole, in that order.  Only
11367    // count locations for undefined and the hole, and fill them afterwards.
11368    WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11369    unsigned int undefs = limit;
11370    unsigned int holes = limit;
11371    // Assume most arrays contain no holes and undefined values, so minimize the
11372    // number of stores of non-undefined, non-the-hole values.
11373    for (unsigned int i = 0; i < undefs; i++) {
11374      Object* current = elements->get(i);
11375      if (current->IsTheHole()) {
11376        holes--;
11377        undefs--;
11378      } else if (current->IsUndefined()) {
11379        undefs--;
11380      } else {
11381        continue;
11382      }
11383      // Position i needs to be filled.
11384      while (undefs > i) {
11385        current = elements->get(undefs);
11386        if (current->IsTheHole()) {
11387          holes--;
11388          undefs--;
11389        } else if (current->IsUndefined()) {
11390          undefs--;
11391        } else {
11392          elements->set(i, current, write_barrier);
11393          break;
11394        }
11395      }
11396    }
11397    result = undefs;
11398    while (undefs < holes) {
11399      elements->set_undefined(undefs);
11400      undefs++;
11401    }
11402    while (holes < limit) {
11403      elements->set_the_hole(holes);
11404      holes++;
11405    }
11406  }
11407
11408  if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11409    return Smi::FromInt(static_cast<int>(result));
11410  }
11411  ASSERT_NE(NULL, result_double);
11412  result_double->set_value(static_cast<double>(result));
11413  return result_double;
11414}
11415
11416
11417Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
11418  uint8_t clamped_value = 0;
11419  if (index < static_cast<uint32_t>(length())) {
11420    if (value->IsSmi()) {
11421      int int_value = Smi::cast(value)->value();
11422      if (int_value < 0) {
11423        clamped_value = 0;
11424      } else if (int_value > 255) {
11425        clamped_value = 255;
11426      } else {
11427        clamped_value = static_cast<uint8_t>(int_value);
11428      }
11429    } else if (value->IsHeapNumber()) {
11430      double double_value = HeapNumber::cast(value)->value();
11431      if (!(double_value > 0)) {
11432        // NaN and less than zero clamp to zero.
11433        clamped_value = 0;
11434      } else if (double_value > 255) {
11435        // Greater than 255 clamp to 255.
11436        clamped_value = 255;
11437      } else {
11438        // Other doubles are rounded to the nearest integer.
11439        clamped_value = static_cast<uint8_t>(double_value + 0.5);
11440      }
11441    } else {
11442      // Clamp undefined to zero (default). All other types have been
11443      // converted to a number type further up in the call chain.
11444      ASSERT(value->IsUndefined());
11445    }
11446    set(index, clamped_value);
11447  }
11448  return Smi::FromInt(clamped_value);
11449}
11450
11451
11452template<typename ExternalArrayClass, typename ValueType>
11453static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11454                                           ExternalArrayClass* receiver,
11455                                           uint32_t index,
11456                                           Object* value) {
11457  ValueType cast_value = 0;
11458  if (index < static_cast<uint32_t>(receiver->length())) {
11459    if (value->IsSmi()) {
11460      int int_value = Smi::cast(value)->value();
11461      cast_value = static_cast<ValueType>(int_value);
11462    } else if (value->IsHeapNumber()) {
11463      double double_value = HeapNumber::cast(value)->value();
11464      cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11465    } else {
11466      // Clamp undefined to zero (default). All other types have been
11467      // converted to a number type further up in the call chain.
11468      ASSERT(value->IsUndefined());
11469    }
11470    receiver->set(index, cast_value);
11471  }
11472  return heap->NumberFromInt32(cast_value);
11473}
11474
11475
11476MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
11477  return ExternalArrayIntSetter<ExternalByteArray, int8_t>
11478      (GetHeap(), this, index, value);
11479}
11480
11481
11482MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11483                                                 Object* value) {
11484  return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
11485      (GetHeap(), this, index, value);
11486}
11487
11488
11489MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11490                                          Object* value) {
11491  return ExternalArrayIntSetter<ExternalShortArray, int16_t>
11492      (GetHeap(), this, index, value);
11493}
11494
11495
11496MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11497                                                  Object* value) {
11498  return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
11499      (GetHeap(), this, index, value);
11500}
11501
11502
11503MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
11504  return ExternalArrayIntSetter<ExternalIntArray, int32_t>
11505      (GetHeap(), this, index, value);
11506}
11507
11508
11509MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
11510  uint32_t cast_value = 0;
11511  Heap* heap = GetHeap();
11512  if (index < static_cast<uint32_t>(length())) {
11513    if (value->IsSmi()) {
11514      int int_value = Smi::cast(value)->value();
11515      cast_value = static_cast<uint32_t>(int_value);
11516    } else if (value->IsHeapNumber()) {
11517      double double_value = HeapNumber::cast(value)->value();
11518      cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11519    } else {
11520      // Clamp undefined to zero (default). All other types have been
11521      // converted to a number type further up in the call chain.
11522      ASSERT(value->IsUndefined());
11523    }
11524    set(index, cast_value);
11525  }
11526  return heap->NumberFromUint32(cast_value);
11527}
11528
11529
11530MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
11531  float cast_value = static_cast<float>(OS::nan_value());
11532  Heap* heap = GetHeap();
11533  if (index < static_cast<uint32_t>(length())) {
11534    if (value->IsSmi()) {
11535      int int_value = Smi::cast(value)->value();
11536      cast_value = static_cast<float>(int_value);
11537    } else if (value->IsHeapNumber()) {
11538      double double_value = HeapNumber::cast(value)->value();
11539      cast_value = static_cast<float>(double_value);
11540    } else {
11541      // Clamp undefined to NaN (default). All other types have been
11542      // converted to a number type further up in the call chain.
11543      ASSERT(value->IsUndefined());
11544    }
11545    set(index, cast_value);
11546  }
11547  return heap->AllocateHeapNumber(cast_value);
11548}
11549
11550
11551MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
11552  double double_value = OS::nan_value();
11553  Heap* heap = GetHeap();
11554  if (index < static_cast<uint32_t>(length())) {
11555    if (value->IsSmi()) {
11556      int int_value = Smi::cast(value)->value();
11557      double_value = static_cast<double>(int_value);
11558    } else if (value->IsHeapNumber()) {
11559      double_value = HeapNumber::cast(value)->value();
11560    } else {
11561      // Clamp undefined to NaN (default). All other types have been
11562      // converted to a number type further up in the call chain.
11563      ASSERT(value->IsUndefined());
11564    }
11565    set(index, double_value);
11566  }
11567  return heap->AllocateHeapNumber(double_value);
11568}
11569
11570
11571JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
11572  ASSERT(!HasFastProperties());
11573  Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
11574  return JSGlobalPropertyCell::cast(value);
11575}
11576
11577
11578Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11579    Handle<GlobalObject> global,
11580    Handle<String> name) {
11581  Isolate* isolate = global->GetIsolate();
11582  CALL_HEAP_FUNCTION(isolate,
11583                     global->EnsurePropertyCell(*name),
11584                     JSGlobalPropertyCell);
11585}
11586
11587
11588MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
11589  ASSERT(!HasFastProperties());
11590  int entry = property_dictionary()->FindEntry(name);
11591  if (entry == StringDictionary::kNotFound) {
11592    Heap* heap = GetHeap();
11593    Object* cell;
11594    { MaybeObject* maybe_cell =
11595          heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
11596      if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11597    }
11598    PropertyDetails details(NONE, NORMAL);
11599    details = details.AsDeleted();
11600    Object* dictionary;
11601    { MaybeObject* maybe_dictionary =
11602          property_dictionary()->Add(name, cell, details);
11603      if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11604    }
11605    set_properties(StringDictionary::cast(dictionary));
11606    return cell;
11607  } else {
11608    Object* value = property_dictionary()->ValueAt(entry);
11609    ASSERT(value->IsJSGlobalPropertyCell());
11610    return value;
11611  }
11612}
11613
11614
11615MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
11616  SymbolKey key(string);
11617  return LookupKey(&key, s);
11618}
11619
11620
11621// This class is used for looking up two character strings in the symbol table.
11622// If we don't have a hit we don't want to waste much time so we unroll the
11623// string hash calculation loop here for speed.  Doesn't work if the two
11624// characters form a decimal integer, since such strings have a different hash
11625// algorithm.
11626class TwoCharHashTableKey : public HashTableKey {
11627 public:
11628  TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
11629    : c1_(c1), c2_(c2) {
11630    // Char 1.
11631    uint32_t hash = seed;
11632    hash += c1;
11633    hash += hash << 10;
11634    hash ^= hash >> 6;
11635    // Char 2.
11636    hash += c2;
11637    hash += hash << 10;
11638    hash ^= hash >> 6;
11639    // GetHash.
11640    hash += hash << 3;
11641    hash ^= hash >> 11;
11642    hash += hash << 15;
11643    if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
11644#ifdef DEBUG
11645    StringHasher hasher(2, seed);
11646    hasher.AddCharacter(c1);
11647    hasher.AddCharacter(c2);
11648    // If this assert fails then we failed to reproduce the two-character
11649    // version of the string hashing algorithm above.  One reason could be
11650    // that we were passed two digits as characters, since the hash
11651    // algorithm is different in that case.
11652    ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11653#endif
11654    hash_ = hash;
11655  }
11656
11657  bool IsMatch(Object* o) {
11658    if (!o->IsString()) return false;
11659    String* other = String::cast(o);
11660    if (other->length() != 2) return false;
11661    if (other->Get(0) != c1_) return false;
11662    return other->Get(1) == c2_;
11663  }
11664
11665  uint32_t Hash() { return hash_; }
11666  uint32_t HashForObject(Object* key) {
11667    if (!key->IsString()) return 0;
11668    return String::cast(key)->Hash();
11669  }
11670
11671  Object* AsObject() {
11672    // The TwoCharHashTableKey is only used for looking in the symbol
11673    // table, not for adding to it.
11674    UNREACHABLE();
11675    return NULL;
11676  }
11677
11678 private:
11679  uint32_t c1_;
11680  uint32_t c2_;
11681  uint32_t hash_;
11682};
11683
11684
11685bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11686  SymbolKey key(string);
11687  int entry = FindEntry(&key);
11688  if (entry == kNotFound) {
11689    return false;
11690  } else {
11691    String* result = String::cast(KeyAt(entry));
11692    ASSERT(StringShape(result).IsSymbol());
11693    *symbol = result;
11694    return true;
11695  }
11696}
11697
11698
11699bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11700                                               uint32_t c2,
11701                                               String** symbol) {
11702  TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
11703  int entry = FindEntry(&key);
11704  if (entry == kNotFound) {
11705    return false;
11706  } else {
11707    String* result = String::cast(KeyAt(entry));
11708    ASSERT(StringShape(result).IsSymbol());
11709    *symbol = result;
11710    return true;
11711  }
11712}
11713
11714
11715MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11716                                       Object** s) {
11717  Utf8SymbolKey key(str, GetHeap()->HashSeed());
11718  return LookupKey(&key, s);
11719}
11720
11721
11722MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11723                                            Object** s) {
11724  AsciiSymbolKey key(str, GetHeap()->HashSeed());
11725  return LookupKey(&key, s);
11726}
11727
11728
11729MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11730                                                     int from,
11731                                                     int length,
11732                                                     Object** s) {
11733  SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
11734  return LookupKey(&key, s);
11735}
11736
11737
11738MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11739                                              Object** s) {
11740  TwoByteSymbolKey key(str, GetHeap()->HashSeed());
11741  return LookupKey(&key, s);
11742}
11743
11744MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
11745  int entry = FindEntry(key);
11746
11747  // Symbol already in table.
11748  if (entry != kNotFound) {
11749    *s = KeyAt(entry);
11750    return this;
11751  }
11752
11753  // Adding new symbol. Grow table if needed.
11754  Object* obj;
11755  { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11756    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11757  }
11758
11759  // Create symbol object.
11760  Object* symbol;
11761  { MaybeObject* maybe_symbol = key->AsObject();
11762    if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11763  }
11764
11765  // If the symbol table grew as part of EnsureCapacity, obj is not
11766  // the current symbol table and therefore we cannot use
11767  // SymbolTable::cast here.
11768  SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11769
11770  // Add the new symbol and return it along with the symbol table.
11771  entry = table->FindInsertionEntry(key->Hash());
11772  table->set(EntryToIndex(entry), symbol);
11773  table->ElementAdded();
11774  *s = symbol;
11775  return table;
11776}
11777
11778
11779Object* CompilationCacheTable::Lookup(String* src) {
11780  StringKey key(src);
11781  int entry = FindEntry(&key);
11782  if (entry == kNotFound) return GetHeap()->undefined_value();
11783  return get(EntryToIndex(entry) + 1);
11784}
11785
11786
11787Object* CompilationCacheTable::LookupEval(String* src,
11788                                          Context* context,
11789                                          LanguageMode language_mode,
11790                                          int scope_position) {
11791  StringSharedKey key(src,
11792                      context->closure()->shared(),
11793                      language_mode,
11794                      scope_position);
11795  int entry = FindEntry(&key);
11796  if (entry == kNotFound) return GetHeap()->undefined_value();
11797  return get(EntryToIndex(entry) + 1);
11798}
11799
11800
11801Object* CompilationCacheTable::LookupRegExp(String* src,
11802                                            JSRegExp::Flags flags) {
11803  RegExpKey key(src, flags);
11804  int entry = FindEntry(&key);
11805  if (entry == kNotFound) return GetHeap()->undefined_value();
11806  return get(EntryToIndex(entry) + 1);
11807}
11808
11809
11810MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
11811  StringKey key(src);
11812  Object* obj;
11813  { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11814    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11815  }
11816
11817  CompilationCacheTable* cache =
11818      reinterpret_cast<CompilationCacheTable*>(obj);
11819  int entry = cache->FindInsertionEntry(key.Hash());
11820  cache->set(EntryToIndex(entry), src);
11821  cache->set(EntryToIndex(entry) + 1, value);
11822  cache->ElementAdded();
11823  return cache;
11824}
11825
11826
11827MaybeObject* CompilationCacheTable::PutEval(String* src,
11828                                            Context* context,
11829                                            SharedFunctionInfo* value,
11830                                            int scope_position) {
11831  StringSharedKey key(src,
11832                      context->closure()->shared(),
11833                      value->language_mode(),
11834                      scope_position);
11835  Object* obj;
11836  { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11837    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11838  }
11839
11840  CompilationCacheTable* cache =
11841      reinterpret_cast<CompilationCacheTable*>(obj);
11842  int entry = cache->FindInsertionEntry(key.Hash());
11843
11844  Object* k;
11845  { MaybeObject* maybe_k = key.AsObject();
11846    if (!maybe_k->ToObject(&k)) return maybe_k;
11847  }
11848
11849  cache->set(EntryToIndex(entry), k);
11850  cache->set(EntryToIndex(entry) + 1, value);
11851  cache->ElementAdded();
11852  return cache;
11853}
11854
11855
11856MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11857                                              JSRegExp::Flags flags,
11858                                              FixedArray* value) {
11859  RegExpKey key(src, flags);
11860  Object* obj;
11861  { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11862    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11863  }
11864
11865  CompilationCacheTable* cache =
11866      reinterpret_cast<CompilationCacheTable*>(obj);
11867  int entry = cache->FindInsertionEntry(key.Hash());
11868  // We store the value in the key slot, and compare the search key
11869  // to the stored value with a custon IsMatch function during lookups.
11870  cache->set(EntryToIndex(entry), value);
11871  cache->set(EntryToIndex(entry) + 1, value);
11872  cache->ElementAdded();
11873  return cache;
11874}
11875
11876
11877void CompilationCacheTable::Remove(Object* value) {
11878  Object* the_hole_value = GetHeap()->the_hole_value();
11879  for (int entry = 0, size = Capacity(); entry < size; entry++) {
11880    int entry_index = EntryToIndex(entry);
11881    int value_index = entry_index + 1;
11882    if (get(value_index) == value) {
11883      NoWriteBarrierSet(this, entry_index, the_hole_value);
11884      NoWriteBarrierSet(this, value_index, the_hole_value);
11885      ElementRemoved();
11886    }
11887  }
11888  return;
11889}
11890
11891
11892// SymbolsKey used for HashTable where key is array of symbols.
11893class SymbolsKey : public HashTableKey {
11894 public:
11895  explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
11896
11897  bool IsMatch(Object* symbols) {
11898    FixedArray* o = FixedArray::cast(symbols);
11899    int len = symbols_->length();
11900    if (o->length() != len) return false;
11901    for (int i = 0; i < len; i++) {
11902      if (o->get(i) != symbols_->get(i)) return false;
11903    }
11904    return true;
11905  }
11906
11907  uint32_t Hash() { return HashForObject(symbols_); }
11908
11909  uint32_t HashForObject(Object* obj) {
11910    FixedArray* symbols = FixedArray::cast(obj);
11911    int len = symbols->length();
11912    uint32_t hash = 0;
11913    for (int i = 0; i < len; i++) {
11914      hash ^= String::cast(symbols->get(i))->Hash();
11915    }
11916    return hash;
11917  }
11918
11919  Object* AsObject() { return symbols_; }
11920
11921 private:
11922  FixedArray* symbols_;
11923};
11924
11925
11926Object* MapCache::Lookup(FixedArray* array) {
11927  SymbolsKey key(array);
11928  int entry = FindEntry(&key);
11929  if (entry == kNotFound) return GetHeap()->undefined_value();
11930  return get(EntryToIndex(entry) + 1);
11931}
11932
11933
11934MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
11935  SymbolsKey key(array);
11936  Object* obj;
11937  { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11938    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11939  }
11940
11941  MapCache* cache = reinterpret_cast<MapCache*>(obj);
11942  int entry = cache->FindInsertionEntry(key.Hash());
11943  cache->set(EntryToIndex(entry), array);
11944  cache->set(EntryToIndex(entry) + 1, value);
11945  cache->ElementAdded();
11946  return cache;
11947}
11948
11949
11950template<typename Shape, typename Key>
11951MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
11952  Object* obj;
11953  { MaybeObject* maybe_obj =
11954        HashTable<Shape, Key>::Allocate(at_least_space_for);
11955    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11956  }
11957  // Initialize the next enumeration index.
11958  Dictionary<Shape, Key>::cast(obj)->
11959      SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
11960  return obj;
11961}
11962
11963
11964template<typename Shape, typename Key>
11965MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
11966  Heap* heap = Dictionary<Shape, Key>::GetHeap();
11967  int length = HashTable<Shape, Key>::NumberOfElements();
11968
11969  // Allocate and initialize iteration order array.
11970  Object* obj;
11971  { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
11972    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11973  }
11974  FixedArray* iteration_order = FixedArray::cast(obj);
11975  for (int i = 0; i < length; i++) {
11976    iteration_order->set(i, Smi::FromInt(i));
11977  }
11978
11979  // Allocate array with enumeration order.
11980  { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
11981    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11982  }
11983  FixedArray* enumeration_order = FixedArray::cast(obj);
11984
11985  // Fill the enumeration order array with property details.
11986  int capacity = HashTable<Shape, Key>::Capacity();
11987  int pos = 0;
11988  for (int i = 0; i < capacity; i++) {
11989    if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
11990      enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
11991    }
11992  }
11993
11994  // Sort the arrays wrt. enumeration order.
11995  iteration_order->SortPairs(enumeration_order, enumeration_order->length());
11996
11997  // Overwrite the enumeration_order with the enumeration indices.
11998  for (int i = 0; i < length; i++) {
11999    int index = Smi::cast(iteration_order->get(i))->value();
12000    int enum_index = PropertyDetails::kInitialIndex + i;
12001    enumeration_order->set(index, Smi::FromInt(enum_index));
12002  }
12003
12004  // Update the dictionary with new indices.
12005  capacity = HashTable<Shape, Key>::Capacity();
12006  pos = 0;
12007  for (int i = 0; i < capacity; i++) {
12008    if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
12009      int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
12010      PropertyDetails details = DetailsAt(i);
12011      PropertyDetails new_details =
12012          PropertyDetails(details.attributes(), details.type(), enum_index);
12013      DetailsAtPut(i, new_details);
12014    }
12015  }
12016
12017  // Set the next enumeration index.
12018  SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
12019  return this;
12020}
12021
12022template<typename Shape, typename Key>
12023MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
12024  // Check whether there are enough enumeration indices to add n elements.
12025  if (Shape::kIsEnumerable &&
12026      !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
12027    // If not, we generate new indices for the properties.
12028    Object* result;
12029    { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12030      if (!maybe_result->ToObject(&result)) return maybe_result;
12031    }
12032  }
12033  return HashTable<Shape, Key>::EnsureCapacity(n, key);
12034}
12035
12036
12037template<typename Shape, typename Key>
12038Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
12039                                               JSReceiver::DeleteMode mode) {
12040  Heap* heap = Dictionary<Shape, Key>::GetHeap();
12041  PropertyDetails details = DetailsAt(entry);
12042  // Ignore attributes if forcing a deletion.
12043  if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
12044    return heap->false_value();
12045  }
12046  SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
12047  HashTable<Shape, Key>::ElementRemoved();
12048  return heap->true_value();
12049}
12050
12051
12052template<typename Shape, typename Key>
12053MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12054  return HashTable<Shape, Key>::Shrink(key);
12055}
12056
12057
12058template<typename Shape, typename Key>
12059MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
12060  int entry = this->FindEntry(key);
12061
12062  // If the entry is present set the value;
12063  if (entry != Dictionary<Shape, Key>::kNotFound) {
12064    ValueAtPut(entry, value);
12065    return this;
12066  }
12067
12068  // Check whether the dictionary should be extended.
12069  Object* obj;
12070  { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12071    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12072  }
12073
12074  Object* k;
12075  { MaybeObject* maybe_k = Shape::AsObject(key);
12076    if (!maybe_k->ToObject(&k)) return maybe_k;
12077  }
12078  PropertyDetails details = PropertyDetails(NONE, NORMAL);
12079
12080  return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12081      Dictionary<Shape, Key>::Hash(key));
12082}
12083
12084
12085template<typename Shape, typename Key>
12086MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12087                                         Object* value,
12088                                         PropertyDetails details) {
12089  // Valdate key is absent.
12090  SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
12091  // Check whether the dictionary should be extended.
12092  Object* obj;
12093  { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12094    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12095  }
12096
12097  return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12098      Dictionary<Shape, Key>::Hash(key));
12099}
12100
12101
12102// Add a key, value pair to the dictionary.
12103template<typename Shape, typename Key>
12104MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12105                                              Object* value,
12106                                              PropertyDetails details,
12107                                              uint32_t hash) {
12108  // Compute the key object.
12109  Object* k;
12110  { MaybeObject* maybe_k = Shape::AsObject(key);
12111    if (!maybe_k->ToObject(&k)) return maybe_k;
12112  }
12113
12114  uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
12115  // Insert element at empty or deleted entry
12116  if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
12117    // Assign an enumeration index to the property and update
12118    // SetNextEnumerationIndex.
12119    int index = NextEnumerationIndex();
12120    details = PropertyDetails(details.attributes(), details.type(), index);
12121    SetNextEnumerationIndex(index + 1);
12122  }
12123  SetEntry(entry, k, value, details);
12124  ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12125          || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12126  HashTable<Shape, Key>::ElementAdded();
12127  return this;
12128}
12129
12130
12131void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
12132  // If the dictionary requires slow elements an element has already
12133  // been added at a high index.
12134  if (requires_slow_elements()) return;
12135  // Check if this index is high enough that we should require slow
12136  // elements.
12137  if (key > kRequiresSlowElementsLimit) {
12138    set_requires_slow_elements();
12139    return;
12140  }
12141  // Update max key value.
12142  Object* max_index_object = get(kMaxNumberKeyIndex);
12143  if (!max_index_object->IsSmi() || max_number_key() < key) {
12144    FixedArray::set(kMaxNumberKeyIndex,
12145                    Smi::FromInt(key << kRequiresSlowElementsTagSize));
12146  }
12147}
12148
12149
12150MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12151                                                    Object* value,
12152                                                    PropertyDetails details) {
12153  UpdateMaxNumberKey(key);
12154  SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12155  return Add(key, value, details);
12156}
12157
12158
12159MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12160                                                      Object* value) {
12161  SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12162  return Add(key, value, PropertyDetails(NONE, NORMAL));
12163}
12164
12165
12166MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
12167  UpdateMaxNumberKey(key);
12168  return AtPut(key, value);
12169}
12170
12171
12172MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12173                                                   Object* value) {
12174  return AtPut(key, value);
12175}
12176
12177
12178Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12179    Handle<SeededNumberDictionary> dictionary,
12180    uint32_t index,
12181    Handle<Object> value,
12182    PropertyDetails details) {
12183  CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12184                     dictionary->Set(index, *value, details),
12185                     SeededNumberDictionary);
12186}
12187
12188
12189Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12190    Handle<UnseededNumberDictionary> dictionary,
12191    uint32_t index,
12192    Handle<Object> value) {
12193  CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12194                     dictionary->Set(index, *value),
12195                     UnseededNumberDictionary);
12196}
12197
12198
12199MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12200                                         Object* value,
12201                                         PropertyDetails details) {
12202  int entry = FindEntry(key);
12203  if (entry == kNotFound) return AddNumberEntry(key, value, details);
12204  // Preserve enumeration index.
12205  details = PropertyDetails(details.attributes(),
12206                            details.type(),
12207                            DetailsAt(entry).index());
12208  MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
12209  Object* object_key;
12210  if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12211  SetEntry(entry, object_key, value, details);
12212  return this;
12213}
12214
12215
12216MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12217                                           Object* value) {
12218  int entry = FindEntry(key);
12219  if (entry == kNotFound) return AddNumberEntry(key, value);
12220  MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12221  Object* object_key;
12222  if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12223  SetEntry(entry, object_key, value);
12224  return this;
12225}
12226
12227
12228
12229template<typename Shape, typename Key>
12230int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12231    PropertyAttributes filter) {
12232  int capacity = HashTable<Shape, Key>::Capacity();
12233  int result = 0;
12234  for (int i = 0; i < capacity; i++) {
12235    Object* k = HashTable<Shape, Key>::KeyAt(i);
12236    if (HashTable<Shape, Key>::IsKey(k)) {
12237      PropertyDetails details = DetailsAt(i);
12238      if (details.IsDeleted()) continue;
12239      PropertyAttributes attr = details.attributes();
12240      if ((attr & filter) == 0) result++;
12241    }
12242  }
12243  return result;
12244}
12245
12246
12247template<typename Shape, typename Key>
12248int Dictionary<Shape, Key>::NumberOfEnumElements() {
12249  return NumberOfElementsFilterAttributes(
12250      static_cast<PropertyAttributes>(DONT_ENUM));
12251}
12252
12253
12254template<typename Shape, typename Key>
12255void Dictionary<Shape, Key>::CopyKeysTo(
12256    FixedArray* storage,
12257    PropertyAttributes filter,
12258    typename Dictionary<Shape, Key>::SortMode sort_mode) {
12259  ASSERT(storage->length() >= NumberOfEnumElements());
12260  int capacity = HashTable<Shape, Key>::Capacity();
12261  int index = 0;
12262  for (int i = 0; i < capacity; i++) {
12263     Object* k = HashTable<Shape, Key>::KeyAt(i);
12264     if (HashTable<Shape, Key>::IsKey(k)) {
12265       PropertyDetails details = DetailsAt(i);
12266       if (details.IsDeleted()) continue;
12267       PropertyAttributes attr = details.attributes();
12268       if ((attr & filter) == 0) storage->set(index++, k);
12269     }
12270  }
12271  if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12272    storage->SortPairs(storage, index);
12273  }
12274  ASSERT(storage->length() >= index);
12275}
12276
12277
12278void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12279                                      FixedArray* sort_array) {
12280  ASSERT(storage->length() >= NumberOfEnumElements());
12281  int capacity = Capacity();
12282  int index = 0;
12283  for (int i = 0; i < capacity; i++) {
12284     Object* k = KeyAt(i);
12285     if (IsKey(k)) {
12286       PropertyDetails details = DetailsAt(i);
12287       if (details.IsDeleted() || details.IsDontEnum()) continue;
12288       storage->set(index, k);
12289       sort_array->set(index, Smi::FromInt(details.index()));
12290       index++;
12291     }
12292  }
12293  storage->SortPairs(sort_array, sort_array->length());
12294  ASSERT(storage->length() >= index);
12295}
12296
12297
12298template<typename Shape, typename Key>
12299void Dictionary<Shape, Key>::CopyKeysTo(
12300    FixedArray* storage,
12301    int index,
12302    typename Dictionary<Shape, Key>::SortMode sort_mode) {
12303  ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12304      static_cast<PropertyAttributes>(NONE)));
12305  int capacity = HashTable<Shape, Key>::Capacity();
12306  for (int i = 0; i < capacity; i++) {
12307    Object* k = HashTable<Shape, Key>::KeyAt(i);
12308    if (HashTable<Shape, Key>::IsKey(k)) {
12309      PropertyDetails details = DetailsAt(i);
12310      if (details.IsDeleted()) continue;
12311      storage->set(index++, k);
12312    }
12313  }
12314  if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12315    storage->SortPairs(storage, index);
12316  }
12317  ASSERT(storage->length() >= index);
12318}
12319
12320
12321// Backwards lookup (slow).
12322template<typename Shape, typename Key>
12323Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12324  int capacity = HashTable<Shape, Key>::Capacity();
12325  for (int i = 0; i < capacity; i++) {
12326    Object* k =  HashTable<Shape, Key>::KeyAt(i);
12327    if (Dictionary<Shape, Key>::IsKey(k)) {
12328      Object* e = ValueAt(i);
12329      if (e->IsJSGlobalPropertyCell()) {
12330        e = JSGlobalPropertyCell::cast(e)->value();
12331      }
12332      if (e == value) return k;
12333    }
12334  }
12335  Heap* heap = Dictionary<Shape, Key>::GetHeap();
12336  return heap->undefined_value();
12337}
12338
12339
12340MaybeObject* StringDictionary::TransformPropertiesToFastFor(
12341    JSObject* obj, int unused_property_fields) {
12342  // Make sure we preserve dictionary representation if there are too many
12343  // descriptors.
12344  if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12345
12346  // Figure out if it is necessary to generate new enumeration indices.
12347  int max_enumeration_index =
12348      NextEnumerationIndex() +
12349          (DescriptorArray::kMaxNumberOfDescriptors -
12350           NumberOfElements());
12351  if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
12352    Object* result;
12353    { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12354      if (!maybe_result->ToObject(&result)) return maybe_result;
12355    }
12356  }
12357
12358  int instance_descriptor_length = 0;
12359  int number_of_fields = 0;
12360
12361  Heap* heap = GetHeap();
12362
12363  // Compute the length of the instance descriptor.
12364  int capacity = Capacity();
12365  for (int i = 0; i < capacity; i++) {
12366    Object* k = KeyAt(i);
12367    if (IsKey(k)) {
12368      Object* value = ValueAt(i);
12369      PropertyType type = DetailsAt(i).type();
12370      ASSERT(type != FIELD);
12371      instance_descriptor_length++;
12372      if (type == NORMAL &&
12373          (!value->IsJSFunction() || heap->InNewSpace(value))) {
12374        number_of_fields += 1;
12375      }
12376    }
12377  }
12378
12379  // Allocate the instance descriptor.
12380  DescriptorArray* descriptors;
12381  { MaybeObject* maybe_descriptors =
12382        DescriptorArray::Allocate(instance_descriptor_length);
12383    if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12384      return maybe_descriptors;
12385    }
12386  }
12387
12388  DescriptorArray::WhitenessWitness witness(descriptors);
12389
12390  int inobject_props = obj->map()->inobject_properties();
12391  int number_of_allocated_fields =
12392      number_of_fields + unused_property_fields - inobject_props;
12393  if (number_of_allocated_fields < 0) {
12394    // There is enough inobject space for all fields (including unused).
12395    number_of_allocated_fields = 0;
12396    unused_property_fields = inobject_props - number_of_fields;
12397  }
12398
12399  // Allocate the fixed array for the fields.
12400  Object* fields;
12401  { MaybeObject* maybe_fields =
12402        heap->AllocateFixedArray(number_of_allocated_fields);
12403    if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12404  }
12405
12406  // Fill in the instance descriptor and the fields.
12407  int next_descriptor = 0;
12408  int current_offset = 0;
12409  for (int i = 0; i < capacity; i++) {
12410    Object* k = KeyAt(i);
12411    if (IsKey(k)) {
12412      Object* value = ValueAt(i);
12413      // Ensure the key is a symbol before writing into the instance descriptor.
12414      Object* key;
12415      { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
12416        if (!maybe_key->ToObject(&key)) return maybe_key;
12417      }
12418      PropertyDetails details = DetailsAt(i);
12419      PropertyType type = details.type();
12420
12421      if (value->IsJSFunction() && !heap->InNewSpace(value)) {
12422        ConstantFunctionDescriptor d(String::cast(key),
12423                                     JSFunction::cast(value),
12424                                     details.attributes(),
12425                                     details.index());
12426        descriptors->Set(next_descriptor++, &d, witness);
12427      } else if (type == NORMAL) {
12428        if (current_offset < inobject_props) {
12429          obj->InObjectPropertyAtPut(current_offset,
12430                                     value,
12431                                     UPDATE_WRITE_BARRIER);
12432        } else {
12433          int offset = current_offset - inobject_props;
12434          FixedArray::cast(fields)->set(offset, value);
12435        }
12436        FieldDescriptor d(String::cast(key),
12437                          current_offset++,
12438                          details.attributes(),
12439                          details.index());
12440        descriptors->Set(next_descriptor++, &d, witness);
12441      } else if (type == CALLBACKS) {
12442        if (value->IsAccessorPair()) {
12443          MaybeObject* maybe_copy =
12444              AccessorPair::cast(value)->CopyWithoutTransitions();
12445          if (!maybe_copy->To(&value)) return maybe_copy;
12446        }
12447        CallbacksDescriptor d(String::cast(key),
12448                              value,
12449                              details.attributes(),
12450                              details.index());
12451        descriptors->Set(next_descriptor++, &d, witness);
12452      } else {
12453        UNREACHABLE();
12454      }
12455    }
12456  }
12457  ASSERT(current_offset == number_of_fields);
12458
12459  descriptors->Sort(witness);
12460  // Allocate new map.
12461  Object* new_map;
12462  { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12463    if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12464  }
12465
12466  // Transform the object.
12467  obj->set_map(Map::cast(new_map));
12468  obj->map()->set_instance_descriptors(descriptors);
12469  obj->map()->set_unused_property_fields(unused_property_fields);
12470
12471  obj->set_properties(FixedArray::cast(fields));
12472  ASSERT(obj->IsJSObject());
12473
12474  descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
12475  // Check that it really works.
12476  ASSERT(obj->HasFastProperties());
12477
12478  return obj;
12479}
12480
12481
12482bool ObjectHashSet::Contains(Object* key) {
12483  ASSERT(IsKey(key));
12484
12485  // If the object does not have an identity hash, it was never used as a key.
12486  { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12487    if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12488  }
12489  return (FindEntry(key) != kNotFound);
12490}
12491
12492
12493MaybeObject* ObjectHashSet::Add(Object* key) {
12494  ASSERT(IsKey(key));
12495
12496  // Make sure the key object has an identity hash code.
12497  int hash;
12498  { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12499    if (maybe_hash->IsFailure()) return maybe_hash;
12500    hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12501  }
12502  int entry = FindEntry(key);
12503
12504  // Check whether key is already present.
12505  if (entry != kNotFound) return this;
12506
12507  // Check whether the hash set should be extended and add entry.
12508  Object* obj;
12509  { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12510    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12511  }
12512  ObjectHashSet* table = ObjectHashSet::cast(obj);
12513  entry = table->FindInsertionEntry(hash);
12514  table->set(EntryToIndex(entry), key);
12515  table->ElementAdded();
12516  return table;
12517}
12518
12519
12520MaybeObject* ObjectHashSet::Remove(Object* key) {
12521  ASSERT(IsKey(key));
12522
12523  // If the object does not have an identity hash, it was never used as a key.
12524  { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12525    if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12526  }
12527  int entry = FindEntry(key);
12528
12529  // Check whether key is actually present.
12530  if (entry == kNotFound) return this;
12531
12532  // Remove entry and try to shrink this hash set.
12533  set_the_hole(EntryToIndex(entry));
12534  ElementRemoved();
12535  return Shrink(key);
12536}
12537
12538
12539Object* ObjectHashTable::Lookup(Object* key) {
12540  ASSERT(IsKey(key));
12541
12542  // If the object does not have an identity hash, it was never used as a key.
12543  { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12544    if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12545      return GetHeap()->undefined_value();
12546    }
12547  }
12548  int entry = FindEntry(key);
12549  if (entry == kNotFound) return GetHeap()->undefined_value();
12550  return get(EntryToIndex(entry) + 1);
12551}
12552
12553
12554MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
12555  ASSERT(IsKey(key));
12556
12557  // Make sure the key object has an identity hash code.
12558  int hash;
12559  { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12560    if (maybe_hash->IsFailure()) return maybe_hash;
12561    hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12562  }
12563  int entry = FindEntry(key);
12564
12565  // Check whether to perform removal operation.
12566  if (value->IsUndefined()) {
12567    if (entry == kNotFound) return this;
12568    RemoveEntry(entry);
12569    return Shrink(key);
12570  }
12571
12572  // Key is already in table, just overwrite value.
12573  if (entry != kNotFound) {
12574    set(EntryToIndex(entry) + 1, value);
12575    return this;
12576  }
12577
12578  // Check whether the hash table should be extended.
12579  Object* obj;
12580  { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12581    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12582  }
12583  ObjectHashTable* table = ObjectHashTable::cast(obj);
12584  table->AddEntry(table->FindInsertionEntry(hash), key, value);
12585  return table;
12586}
12587
12588
12589void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
12590  set(EntryToIndex(entry), key);
12591  set(EntryToIndex(entry) + 1, value);
12592  ElementAdded();
12593}
12594
12595
12596void ObjectHashTable::RemoveEntry(int entry) {
12597  set_the_hole(EntryToIndex(entry));
12598  set_the_hole(EntryToIndex(entry) + 1);
12599  ElementRemoved();
12600}
12601
12602
12603#ifdef ENABLE_DEBUGGER_SUPPORT
12604// Check if there is a break point at this code position.
12605bool DebugInfo::HasBreakPoint(int code_position) {
12606  // Get the break point info object for this code position.
12607  Object* break_point_info = GetBreakPointInfo(code_position);
12608
12609  // If there is no break point info object or no break points in the break
12610  // point info object there is no break point at this code position.
12611  if (break_point_info->IsUndefined()) return false;
12612  return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12613}
12614
12615
12616// Get the break point info object for this code position.
12617Object* DebugInfo::GetBreakPointInfo(int code_position) {
12618  // Find the index of the break point info object for this code position.
12619  int index = GetBreakPointInfoIndex(code_position);
12620
12621  // Return the break point info object if any.
12622  if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
12623  return BreakPointInfo::cast(break_points()->get(index));
12624}
12625
12626
12627// Clear a break point at the specified code position.
12628void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12629                                int code_position,
12630                                Handle<Object> break_point_object) {
12631  Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12632  if (break_point_info->IsUndefined()) return;
12633  BreakPointInfo::ClearBreakPoint(
12634      Handle<BreakPointInfo>::cast(break_point_info),
12635      break_point_object);
12636}
12637
12638
12639void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12640                              int code_position,
12641                              int source_position,
12642                              int statement_position,
12643                              Handle<Object> break_point_object) {
12644  Isolate* isolate = Isolate::Current();
12645  Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12646  if (!break_point_info->IsUndefined()) {
12647    BreakPointInfo::SetBreakPoint(
12648        Handle<BreakPointInfo>::cast(break_point_info),
12649        break_point_object);
12650    return;
12651  }
12652
12653  // Adding a new break point for a code position which did not have any
12654  // break points before. Try to find a free slot.
12655  int index = kNoBreakPointInfo;
12656  for (int i = 0; i < debug_info->break_points()->length(); i++) {
12657    if (debug_info->break_points()->get(i)->IsUndefined()) {
12658      index = i;
12659      break;
12660    }
12661  }
12662  if (index == kNoBreakPointInfo) {
12663    // No free slot - extend break point info array.
12664    Handle<FixedArray> old_break_points =
12665        Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
12666    Handle<FixedArray> new_break_points =
12667        isolate->factory()->NewFixedArray(
12668            old_break_points->length() +
12669            Debug::kEstimatedNofBreakPointsInFunction);
12670
12671    debug_info->set_break_points(*new_break_points);
12672    for (int i = 0; i < old_break_points->length(); i++) {
12673      new_break_points->set(i, old_break_points->get(i));
12674    }
12675    index = old_break_points->length();
12676  }
12677  ASSERT(index != kNoBreakPointInfo);
12678
12679  // Allocate new BreakPointInfo object and set the break point.
12680  Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12681      isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
12682  new_break_point_info->set_code_position(Smi::FromInt(code_position));
12683  new_break_point_info->set_source_position(Smi::FromInt(source_position));
12684  new_break_point_info->
12685      set_statement_position(Smi::FromInt(statement_position));
12686  new_break_point_info->set_break_point_objects(
12687      isolate->heap()->undefined_value());
12688  BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12689  debug_info->break_points()->set(index, *new_break_point_info);
12690}
12691
12692
12693// Get the break point objects for a code position.
12694Object* DebugInfo::GetBreakPointObjects(int code_position) {
12695  Object* break_point_info = GetBreakPointInfo(code_position);
12696  if (break_point_info->IsUndefined()) {
12697    return GetHeap()->undefined_value();
12698  }
12699  return BreakPointInfo::cast(break_point_info)->break_point_objects();
12700}
12701
12702
12703// Get the total number of break points.
12704int DebugInfo::GetBreakPointCount() {
12705  if (break_points()->IsUndefined()) return 0;
12706  int count = 0;
12707  for (int i = 0; i < break_points()->length(); i++) {
12708    if (!break_points()->get(i)->IsUndefined()) {
12709      BreakPointInfo* break_point_info =
12710          BreakPointInfo::cast(break_points()->get(i));
12711      count += break_point_info->GetBreakPointCount();
12712    }
12713  }
12714  return count;
12715}
12716
12717
12718Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12719                                      Handle<Object> break_point_object) {
12720  Heap* heap = debug_info->GetHeap();
12721  if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
12722  for (int i = 0; i < debug_info->break_points()->length(); i++) {
12723    if (!debug_info->break_points()->get(i)->IsUndefined()) {
12724      Handle<BreakPointInfo> break_point_info =
12725          Handle<BreakPointInfo>(BreakPointInfo::cast(
12726              debug_info->break_points()->get(i)));
12727      if (BreakPointInfo::HasBreakPointObject(break_point_info,
12728                                              break_point_object)) {
12729        return *break_point_info;
12730      }
12731    }
12732  }
12733  return heap->undefined_value();
12734}
12735
12736
12737// Find the index of the break point info object for the specified code
12738// position.
12739int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12740  if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12741  for (int i = 0; i < break_points()->length(); i++) {
12742    if (!break_points()->get(i)->IsUndefined()) {
12743      BreakPointInfo* break_point_info =
12744          BreakPointInfo::cast(break_points()->get(i));
12745      if (break_point_info->code_position()->value() == code_position) {
12746        return i;
12747      }
12748    }
12749  }
12750  return kNoBreakPointInfo;
12751}
12752
12753
12754// Remove the specified break point object.
12755void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12756                                     Handle<Object> break_point_object) {
12757  Isolate* isolate = Isolate::Current();
12758  // If there are no break points just ignore.
12759  if (break_point_info->break_point_objects()->IsUndefined()) return;
12760  // If there is a single break point clear it if it is the same.
12761  if (!break_point_info->break_point_objects()->IsFixedArray()) {
12762    if (break_point_info->break_point_objects() == *break_point_object) {
12763      break_point_info->set_break_point_objects(
12764          isolate->heap()->undefined_value());
12765    }
12766    return;
12767  }
12768  // If there are multiple break points shrink the array
12769  ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12770  Handle<FixedArray> old_array =
12771      Handle<FixedArray>(
12772          FixedArray::cast(break_point_info->break_point_objects()));
12773  Handle<FixedArray> new_array =
12774      isolate->factory()->NewFixedArray(old_array->length() - 1);
12775  int found_count = 0;
12776  for (int i = 0; i < old_array->length(); i++) {
12777    if (old_array->get(i) == *break_point_object) {
12778      ASSERT(found_count == 0);
12779      found_count++;
12780    } else {
12781      new_array->set(i - found_count, old_array->get(i));
12782    }
12783  }
12784  // If the break point was found in the list change it.
12785  if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12786}
12787
12788
12789// Add the specified break point object.
12790void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12791                                   Handle<Object> break_point_object) {
12792  // If there was no break point objects before just set it.
12793  if (break_point_info->break_point_objects()->IsUndefined()) {
12794    break_point_info->set_break_point_objects(*break_point_object);
12795    return;
12796  }
12797  // If the break point object is the same as before just ignore.
12798  if (break_point_info->break_point_objects() == *break_point_object) return;
12799  // If there was one break point object before replace with array.
12800  if (!break_point_info->break_point_objects()->IsFixedArray()) {
12801    Handle<FixedArray> array = FACTORY->NewFixedArray(2);
12802    array->set(0, break_point_info->break_point_objects());
12803    array->set(1, *break_point_object);
12804    break_point_info->set_break_point_objects(*array);
12805    return;
12806  }
12807  // If there was more than one break point before extend array.
12808  Handle<FixedArray> old_array =
12809      Handle<FixedArray>(
12810          FixedArray::cast(break_point_info->break_point_objects()));
12811  Handle<FixedArray> new_array =
12812      FACTORY->NewFixedArray(old_array->length() + 1);
12813  for (int i = 0; i < old_array->length(); i++) {
12814    // If the break point was there before just ignore.
12815    if (old_array->get(i) == *break_point_object) return;
12816    new_array->set(i, old_array->get(i));
12817  }
12818  // Add the new break point.
12819  new_array->set(old_array->length(), *break_point_object);
12820  break_point_info->set_break_point_objects(*new_array);
12821}
12822
12823
12824bool BreakPointInfo::HasBreakPointObject(
12825    Handle<BreakPointInfo> break_point_info,
12826    Handle<Object> break_point_object) {
12827  // No break point.
12828  if (break_point_info->break_point_objects()->IsUndefined()) return false;
12829  // Single break point.
12830  if (!break_point_info->break_point_objects()->IsFixedArray()) {
12831    return break_point_info->break_point_objects() == *break_point_object;
12832  }
12833  // Multiple break points.
12834  FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12835  for (int i = 0; i < array->length(); i++) {
12836    if (array->get(i) == *break_point_object) {
12837      return true;
12838    }
12839  }
12840  return false;
12841}
12842
12843
12844// Get the number of break points.
12845int BreakPointInfo::GetBreakPointCount() {
12846  // No break point.
12847  if (break_point_objects()->IsUndefined()) return 0;
12848  // Single break point.
12849  if (!break_point_objects()->IsFixedArray()) return 1;
12850  // Multiple break points.
12851  return FixedArray::cast(break_point_objects())->length();
12852}
12853#endif  // ENABLE_DEBUGGER_SUPPORT
12854
12855
12856MaybeObject* JSDate::GetField(Object* object, Smi* index) {
12857  return JSDate::cast(object)->DoGetField(
12858      static_cast<FieldIndex>(index->value()));
12859}
12860
12861
12862Object* JSDate::DoGetField(FieldIndex index) {
12863  ASSERT(index != kDateValue);
12864
12865  DateCache* date_cache = GetIsolate()->date_cache();
12866
12867  if (index < kFirstUncachedField) {
12868    Object* stamp = cache_stamp();
12869    if (stamp != date_cache->stamp() && stamp->IsSmi()) {
12870      // Since the stamp is not NaN, the value is also not NaN.
12871      int64_t local_time_ms =
12872          date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
12873      SetLocalFields(local_time_ms, date_cache);
12874    }
12875    switch (index) {
12876      case kYear: return year();
12877      case kMonth: return month();
12878      case kDay: return day();
12879      case kWeekday: return weekday();
12880      case kHour: return hour();
12881      case kMinute: return min();
12882      case kSecond: return sec();
12883      default: UNREACHABLE();
12884    }
12885  }
12886
12887  if (index >= kFirstUTCField) {
12888    return GetUTCField(index, value()->Number(), date_cache);
12889  }
12890
12891  double time = value()->Number();
12892  if (isnan(time)) return GetIsolate()->heap()->nan_value();
12893
12894  int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
12895  int days = DateCache::DaysFromTime(local_time_ms);
12896
12897  if (index == kDays) return Smi::FromInt(days);
12898
12899  int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12900  if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
12901  ASSERT(index == kTimeInDay);
12902  return Smi::FromInt(time_in_day_ms);
12903}
12904
12905
12906Object* JSDate::GetUTCField(FieldIndex index,
12907                            double value,
12908                            DateCache* date_cache) {
12909  ASSERT(index >= kFirstUTCField);
12910
12911  if (isnan(value)) return GetIsolate()->heap()->nan_value();
12912
12913  int64_t time_ms = static_cast<int64_t>(value);
12914
12915  if (index == kTimezoneOffset) {
12916    return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
12917  }
12918
12919  int days = DateCache::DaysFromTime(time_ms);
12920
12921  if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
12922
12923  if (index <= kDayUTC) {
12924    int year, month, day;
12925    date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12926    if (index == kYearUTC) return Smi::FromInt(year);
12927    if (index == kMonthUTC) return Smi::FromInt(month);
12928    ASSERT(index == kDayUTC);
12929    return Smi::FromInt(day);
12930  }
12931
12932  int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
12933  switch (index) {
12934    case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
12935    case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
12936    case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
12937    case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
12938    case kDaysUTC: return Smi::FromInt(days);
12939    case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
12940    default: UNREACHABLE();
12941  }
12942
12943  UNREACHABLE();
12944  return NULL;
12945}
12946
12947
12948void JSDate::SetValue(Object* value, bool is_value_nan) {
12949  set_value(value);
12950  if (is_value_nan) {
12951    HeapNumber* nan = GetIsolate()->heap()->nan_value();
12952    set_cache_stamp(nan, SKIP_WRITE_BARRIER);
12953    set_year(nan, SKIP_WRITE_BARRIER);
12954    set_month(nan, SKIP_WRITE_BARRIER);
12955    set_day(nan, SKIP_WRITE_BARRIER);
12956    set_hour(nan, SKIP_WRITE_BARRIER);
12957    set_min(nan, SKIP_WRITE_BARRIER);
12958    set_sec(nan, SKIP_WRITE_BARRIER);
12959    set_weekday(nan, SKIP_WRITE_BARRIER);
12960  } else {
12961    set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
12962  }
12963}
12964
12965
12966void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
12967  int days = DateCache::DaysFromTime(local_time_ms);
12968  int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12969  int year, month, day;
12970  date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12971  int weekday = date_cache->Weekday(days);
12972  int hour = time_in_day_ms / (60 * 60 * 1000);
12973  int min = (time_in_day_ms / (60 * 1000)) % 60;
12974  int sec = (time_in_day_ms / 1000) % 60;
12975  set_cache_stamp(date_cache->stamp());
12976  set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
12977  set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
12978  set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
12979  set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
12980  set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
12981  set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
12982  set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
12983}
12984
12985} }  // namespace v8::internal
12986