1// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/v8.h"
6
7#include "src/accessors.h"
8#include "src/allocation-site-scopes.h"
9#include "src/api.h"
10#include "src/arguments.h"
11#include "src/bootstrapper.h"
12#include "src/codegen.h"
13#include "src/code-stubs.h"
14#include "src/cpu-profiler.h"
15#include "src/debug.h"
16#include "src/deoptimizer.h"
17#include "src/date.h"
18#include "src/elements.h"
19#include "src/execution.h"
20#include "src/field-index.h"
21#include "src/field-index-inl.h"
22#include "src/full-codegen.h"
23#include "src/hydrogen.h"
24#include "src/isolate-inl.h"
25#include "src/log.h"
26#include "src/lookup.h"
27#include "src/objects-inl.h"
28#include "src/objects-visiting-inl.h"
29#include "src/macro-assembler.h"
30#include "src/mark-compact.h"
31#include "src/safepoint-table.h"
32#include "src/string-search.h"
33#include "src/string-stream.h"
34#include "src/utils.h"
35
36#ifdef ENABLE_DISASSEMBLER
37#include "src/disasm.h"
38#include "src/disassembler.h"
39#endif
40
41namespace v8 {
42namespace internal {
43
44Handle<HeapType> Object::OptimalType(Isolate* isolate,
45                                     Representation representation) {
46  if (representation.IsNone()) return HeapType::None(isolate);
47  if (FLAG_track_field_types) {
48    if (representation.IsHeapObject() && IsHeapObject()) {
49      // We can track only JavaScript objects with stable maps.
50      Handle<Map> map(HeapObject::cast(this)->map(), isolate);
51      if (map->is_stable() &&
52          map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
53          map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
54        return HeapType::Class(map, isolate);
55      }
56    }
57  }
58  return HeapType::Any(isolate);
59}
60
61
62MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
63                                         Handle<Object> object,
64                                         Handle<Context> native_context) {
65  if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
66  Handle<JSFunction> constructor;
67  if (object->IsNumber()) {
68    constructor = handle(native_context->number_function(), isolate);
69  } else if (object->IsBoolean()) {
70    constructor = handle(native_context->boolean_function(), isolate);
71  } else if (object->IsString()) {
72    constructor = handle(native_context->string_function(), isolate);
73  } else if (object->IsSymbol()) {
74    constructor = handle(native_context->symbol_function(), isolate);
75  } else {
76    return MaybeHandle<JSReceiver>();
77  }
78  Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
79  Handle<JSValue>::cast(result)->set_value(*object);
80  return result;
81}
82
83
84bool Object::BooleanValue() {
85  if (IsBoolean()) return IsTrue();
86  if (IsSmi()) return Smi::cast(this)->value() != 0;
87  if (IsUndefined() || IsNull()) return false;
88  if (IsUndetectableObject()) return false;   // Undetectable object is false.
89  if (IsString()) return String::cast(this)->length() != 0;
90  if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
91  return true;
92}
93
94
95bool Object::IsCallable() {
96  Object* fun = this;
97  while (fun->IsJSFunctionProxy()) {
98    fun = JSFunctionProxy::cast(fun)->call_trap();
99  }
100  return fun->IsJSFunction() ||
101         (fun->IsHeapObject() &&
102          HeapObject::cast(fun)->map()->has_instance_call_handler());
103}
104
105
106void Object::Lookup(Handle<Name> name, LookupResult* result) {
107  DisallowHeapAllocation no_gc;
108  Object* holder = NULL;
109  if (IsJSReceiver()) {
110    holder = this;
111  } else {
112    Context* native_context = result->isolate()->context()->native_context();
113    if (IsNumber()) {
114      holder = native_context->number_function()->instance_prototype();
115    } else if (IsString()) {
116      holder = native_context->string_function()->instance_prototype();
117    } else if (IsSymbol()) {
118      holder = native_context->symbol_function()->instance_prototype();
119    } else if (IsBoolean()) {
120      holder = native_context->boolean_function()->instance_prototype();
121    } else {
122      result->isolate()->PushStackTraceAndDie(
123          0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
124    }
125  }
126  ASSERT(holder != NULL);  // Cannot handle null or undefined.
127  JSReceiver::cast(holder)->Lookup(name, result);
128}
129
130
131MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
132  for (; it->IsFound(); it->Next()) {
133    switch (it->state()) {
134      case LookupIterator::NOT_FOUND:
135        UNREACHABLE();
136      case LookupIterator::JSPROXY:
137        return JSProxy::GetPropertyWithHandler(
138            it->GetJSProxy(), it->GetReceiver(), it->name());
139      case LookupIterator::INTERCEPTOR: {
140        MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithInterceptor(
141            it->GetHolder(), it->GetReceiver(), it->name());
142        if (!maybe_result.is_null()) return maybe_result;
143        if (it->isolate()->has_pending_exception()) return maybe_result;
144        break;
145      }
146      case LookupIterator::ACCESS_CHECK:
147        if (it->HasAccess(v8::ACCESS_GET)) break;
148        return JSObject::GetPropertyWithFailedAccessCheck(it);
149      case LookupIterator::PROPERTY:
150        if (it->HasProperty()) {
151          switch (it->property_kind()) {
152            case LookupIterator::ACCESSOR:
153              return GetPropertyWithAccessor(
154                  it->GetReceiver(), it->name(),
155                  it->GetHolder(), it->GetAccessors());
156            case LookupIterator::DATA:
157              return it->GetDataValue();
158          }
159        }
160        break;
161    }
162  }
163  return it->factory()->undefined_value();
164}
165
166
167bool Object::ToInt32(int32_t* value) {
168  if (IsSmi()) {
169    *value = Smi::cast(this)->value();
170    return true;
171  }
172  if (IsHeapNumber()) {
173    double num = HeapNumber::cast(this)->value();
174    if (FastI2D(FastD2I(num)) == num) {
175      *value = FastD2I(num);
176      return true;
177    }
178  }
179  return false;
180}
181
182
183bool Object::ToUint32(uint32_t* value) {
184  if (IsSmi()) {
185    int num = Smi::cast(this)->value();
186    if (num >= 0) {
187      *value = static_cast<uint32_t>(num);
188      return true;
189    }
190  }
191  if (IsHeapNumber()) {
192    double num = HeapNumber::cast(this)->value();
193    if (num >= 0 && FastUI2D(FastD2UI(num)) == num) {
194      *value = FastD2UI(num);
195      return true;
196    }
197  }
198  return false;
199}
200
201
202bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
203  if (!object->IsHeapObject()) return false;
204  return IsTemplateFor(HeapObject::cast(object)->map());
205}
206
207
208bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
209  // There is a constraint on the object; check.
210  if (!map->IsJSObjectMap()) return false;
211  // Fetch the constructor function of the object.
212  Object* cons_obj = map->constructor();
213  if (!cons_obj->IsJSFunction()) return false;
214  JSFunction* fun = JSFunction::cast(cons_obj);
215  // Iterate through the chain of inheriting function templates to
216  // see if the required one occurs.
217  for (Object* type = fun->shared()->function_data();
218       type->IsFunctionTemplateInfo();
219       type = FunctionTemplateInfo::cast(type)->parent_template()) {
220    if (type == this) return true;
221  }
222  // Didn't find the required type in the inheritance chain.
223  return false;
224}
225
226
227template<typename To>
228static inline To* CheckedCast(void *from) {
229  uintptr_t temp = reinterpret_cast<uintptr_t>(from);
230  ASSERT(temp % sizeof(To) == 0);
231  return reinterpret_cast<To*>(temp);
232}
233
234
235static Handle<Object> PerformCompare(const BitmaskCompareDescriptor& descriptor,
236                                     char* ptr,
237                                     Isolate* isolate) {
238  uint32_t bitmask = descriptor.bitmask;
239  uint32_t compare_value = descriptor.compare_value;
240  uint32_t value;
241  switch (descriptor.size) {
242    case 1:
243      value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
244      compare_value &= 0xff;
245      bitmask &= 0xff;
246      break;
247    case 2:
248      value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
249      compare_value &= 0xffff;
250      bitmask &= 0xffff;
251      break;
252    case 4:
253      value = *CheckedCast<uint32_t>(ptr);
254      break;
255    default:
256      UNREACHABLE();
257      return isolate->factory()->undefined_value();
258  }
259  return isolate->factory()->ToBoolean(
260      (bitmask & value) == (bitmask & compare_value));
261}
262
263
264static Handle<Object> PerformCompare(const PointerCompareDescriptor& descriptor,
265                                     char* ptr,
266                                     Isolate* isolate) {
267  uintptr_t compare_value =
268      reinterpret_cast<uintptr_t>(descriptor.compare_value);
269  uintptr_t value = *CheckedCast<uintptr_t>(ptr);
270  return isolate->factory()->ToBoolean(compare_value == value);
271}
272
273
274static Handle<Object> GetPrimitiveValue(
275    const PrimitiveValueDescriptor& descriptor,
276    char* ptr,
277    Isolate* isolate) {
278  int32_t int32_value = 0;
279  switch (descriptor.data_type) {
280    case kDescriptorInt8Type:
281      int32_value = *CheckedCast<int8_t>(ptr);
282      break;
283    case kDescriptorUint8Type:
284      int32_value = *CheckedCast<uint8_t>(ptr);
285      break;
286    case kDescriptorInt16Type:
287      int32_value = *CheckedCast<int16_t>(ptr);
288      break;
289    case kDescriptorUint16Type:
290      int32_value = *CheckedCast<uint16_t>(ptr);
291      break;
292    case kDescriptorInt32Type:
293      int32_value = *CheckedCast<int32_t>(ptr);
294      break;
295    case kDescriptorUint32Type: {
296      uint32_t value = *CheckedCast<uint32_t>(ptr);
297      AllowHeapAllocation allow_gc;
298      return isolate->factory()->NewNumberFromUint(value);
299    }
300    case kDescriptorBoolType: {
301      uint8_t byte = *CheckedCast<uint8_t>(ptr);
302      return isolate->factory()->ToBoolean(
303          byte & (0x1 << descriptor.bool_offset));
304    }
305    case kDescriptorFloatType: {
306      float value = *CheckedCast<float>(ptr);
307      AllowHeapAllocation allow_gc;
308      return isolate->factory()->NewNumber(value);
309    }
310    case kDescriptorDoubleType: {
311      double value = *CheckedCast<double>(ptr);
312      AllowHeapAllocation allow_gc;
313      return isolate->factory()->NewNumber(value);
314    }
315  }
316  AllowHeapAllocation allow_gc;
317  return isolate->factory()->NewNumberFromInt(int32_value);
318}
319
320
321static Handle<Object> GetDeclaredAccessorProperty(
322    Handle<Object> receiver,
323    Handle<DeclaredAccessorInfo> info,
324    Isolate* isolate) {
325  DisallowHeapAllocation no_gc;
326  char* current = reinterpret_cast<char*>(*receiver);
327  DeclaredAccessorDescriptorIterator iterator(info->descriptor());
328  while (true) {
329    const DeclaredAccessorDescriptorData* data = iterator.Next();
330    switch (data->type) {
331      case kDescriptorReturnObject: {
332        ASSERT(iterator.Complete());
333        current = *CheckedCast<char*>(current);
334        return handle(*CheckedCast<Object*>(current), isolate);
335      }
336      case kDescriptorPointerDereference:
337        ASSERT(!iterator.Complete());
338        current = *reinterpret_cast<char**>(current);
339        break;
340      case kDescriptorPointerShift:
341        ASSERT(!iterator.Complete());
342        current += data->pointer_shift_descriptor.byte_offset;
343        break;
344      case kDescriptorObjectDereference: {
345        ASSERT(!iterator.Complete());
346        Object* object = CheckedCast<Object>(current);
347        int field = data->object_dereference_descriptor.internal_field;
348        Object* smi = JSObject::cast(object)->GetInternalField(field);
349        ASSERT(smi->IsSmi());
350        current = reinterpret_cast<char*>(smi);
351        break;
352      }
353      case kDescriptorBitmaskCompare:
354        ASSERT(iterator.Complete());
355        return PerformCompare(data->bitmask_compare_descriptor,
356                              current,
357                              isolate);
358      case kDescriptorPointerCompare:
359        ASSERT(iterator.Complete());
360        return PerformCompare(data->pointer_compare_descriptor,
361                              current,
362                              isolate);
363      case kDescriptorPrimitiveValue:
364        ASSERT(iterator.Complete());
365        return GetPrimitiveValue(data->primitive_value_descriptor,
366                                 current,
367                                 isolate);
368    }
369  }
370  UNREACHABLE();
371  return isolate->factory()->undefined_value();
372}
373
374
375Handle<FixedArray> JSObject::EnsureWritableFastElements(
376    Handle<JSObject> object) {
377  ASSERT(object->HasFastSmiOrObjectElements());
378  Isolate* isolate = object->GetIsolate();
379  Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
380  if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
381  Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
382      elems, isolate->factory()->fixed_array_map());
383  object->set_elements(*writable_elems);
384  isolate->counters()->cow_arrays_converted()->Increment();
385  return writable_elems;
386}
387
388
389MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy,
390                                                    Handle<Object> receiver,
391                                                    Handle<Name> name) {
392  Isolate* isolate = proxy->GetIsolate();
393
394  // TODO(rossberg): adjust once there is a story for symbols vs proxies.
395  if (name->IsSymbol()) return isolate->factory()->undefined_value();
396
397  Handle<Object> args[] = { receiver, name };
398  return CallTrap(
399      proxy, "get",  isolate->derived_get_trap(), ARRAY_SIZE(args), args);
400}
401
402
403MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
404                                                    Handle<Name> name,
405                                                    Handle<JSObject> holder,
406                                                    Handle<Object> structure) {
407  Isolate* isolate = name->GetIsolate();
408  ASSERT(!structure->IsForeign());
409  // api style callbacks.
410  if (structure->IsAccessorInfo()) {
411    Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
412    if (!accessor_info->IsCompatibleReceiver(*receiver)) {
413      Handle<Object> args[2] = { name, receiver };
414      Handle<Object> error =
415          isolate->factory()->NewTypeError("incompatible_method_receiver",
416                                           HandleVector(args,
417                                                        ARRAY_SIZE(args)));
418      return isolate->Throw<Object>(error);
419    }
420    // TODO(rossberg): Handling symbols in the API requires changing the API,
421    // so we do not support it for now.
422    if (name->IsSymbol()) return isolate->factory()->undefined_value();
423    if (structure->IsDeclaredAccessorInfo()) {
424      return GetDeclaredAccessorProperty(
425          receiver,
426          Handle<DeclaredAccessorInfo>::cast(structure),
427          isolate);
428    }
429
430    Handle<ExecutableAccessorInfo> data =
431        Handle<ExecutableAccessorInfo>::cast(structure);
432    v8::AccessorGetterCallback call_fun =
433        v8::ToCData<v8::AccessorGetterCallback>(data->getter());
434    if (call_fun == NULL) return isolate->factory()->undefined_value();
435
436    Handle<String> key = Handle<String>::cast(name);
437    LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
438    PropertyCallbackArguments args(isolate, data->data(), *receiver, *holder);
439    v8::Handle<v8::Value> result =
440        args.Call(call_fun, v8::Utils::ToLocal(key));
441    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
442    if (result.IsEmpty()) {
443      return isolate->factory()->undefined_value();
444    }
445    Handle<Object> return_value = v8::Utils::OpenHandle(*result);
446    return_value->VerifyApiCallResultType();
447    // Rebox handle before return.
448    return handle(*return_value, isolate);
449  }
450
451  // __defineGetter__ callback
452  Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
453                        isolate);
454  if (getter->IsSpecFunction()) {
455    // TODO(rossberg): nicer would be to cast to some JSCallable here...
456    return Object::GetPropertyWithDefinedGetter(
457        receiver, Handle<JSReceiver>::cast(getter));
458  }
459  // Getter is not a function.
460  return isolate->factory()->undefined_value();
461}
462
463
464MaybeHandle<Object> Object::SetPropertyWithCallback(Handle<Object> receiver,
465                                                    Handle<Name> name,
466                                                    Handle<Object> value,
467                                                    Handle<JSObject> holder,
468                                                    Handle<Object> structure,
469                                                    StrictMode strict_mode) {
470  Isolate* isolate = name->GetIsolate();
471
472  // We should never get here to initialize a const with the hole
473  // value since a const declaration would conflict with the setter.
474  ASSERT(!value->IsTheHole());
475  ASSERT(!structure->IsForeign());
476  if (structure->IsExecutableAccessorInfo()) {
477    // api style callbacks
478    ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure);
479    if (!data->IsCompatibleReceiver(*receiver)) {
480      Handle<Object> args[2] = { name, receiver };
481      Handle<Object> error =
482          isolate->factory()->NewTypeError("incompatible_method_receiver",
483                                           HandleVector(args,
484                                                        ARRAY_SIZE(args)));
485      return isolate->Throw<Object>(error);
486    }
487    // TODO(rossberg): Support symbols in the API.
488    if (name->IsSymbol()) return value;
489    Object* call_obj = data->setter();
490    v8::AccessorSetterCallback call_fun =
491        v8::ToCData<v8::AccessorSetterCallback>(call_obj);
492    if (call_fun == NULL) return value;
493    Handle<String> key = Handle<String>::cast(name);
494    LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
495    PropertyCallbackArguments args(isolate, data->data(), *receiver, *holder);
496    args.Call(call_fun,
497              v8::Utils::ToLocal(key),
498              v8::Utils::ToLocal(value));
499    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
500    return value;
501  }
502
503  if (structure->IsAccessorPair()) {
504    Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
505    if (setter->IsSpecFunction()) {
506      // TODO(rossberg): nicer would be to cast to some JSCallable here...
507      return SetPropertyWithDefinedSetter(
508          receiver, Handle<JSReceiver>::cast(setter), value);
509    } else {
510      if (strict_mode == SLOPPY) return value;
511      Handle<Object> args[2] = { name, holder };
512      Handle<Object> error =
513          isolate->factory()->NewTypeError("no_setter_in_callback",
514                                           HandleVector(args, 2));
515      return isolate->Throw<Object>(error);
516    }
517  }
518
519  // TODO(dcarney): Handle correctly.
520  if (structure->IsDeclaredAccessorInfo()) {
521    return value;
522  }
523
524  UNREACHABLE();
525  return MaybeHandle<Object>();
526}
527
528
529MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
530    Handle<Object> receiver,
531    Handle<JSReceiver> getter) {
532  Isolate* isolate = getter->GetIsolate();
533  Debug* debug = isolate->debug();
534  // Handle stepping into a getter if step into is active.
535  // TODO(rossberg): should this apply to getters that are function proxies?
536  if (debug->StepInActive() && getter->IsJSFunction()) {
537    debug->HandleStepIn(
538        Handle<JSFunction>::cast(getter), Handle<Object>::null(), 0, false);
539  }
540
541  return Execution::Call(isolate, getter, receiver, 0, NULL, true);
542}
543
544
545MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
546    Handle<Object> receiver,
547    Handle<JSReceiver> setter,
548    Handle<Object> value) {
549  Isolate* isolate = setter->GetIsolate();
550
551  Debug* debug = isolate->debug();
552  // Handle stepping into a setter if step into is active.
553  // TODO(rossberg): should this apply to getters that are function proxies?
554  if (debug->StepInActive() && setter->IsJSFunction()) {
555    debug->HandleStepIn(
556        Handle<JSFunction>::cast(setter), Handle<Object>::null(), 0, false);
557  }
558
559  Handle<Object> argv[] = { value };
560  RETURN_ON_EXCEPTION(
561      isolate,
562      Execution::Call(isolate, setter, receiver, ARRAY_SIZE(argv), argv),
563      Object);
564  return value;
565}
566
567
568static bool FindAllCanReadHolder(LookupIterator* it) {
569  it->skip_interceptor();
570  it->skip_access_check();
571  for (; it->IsFound(); it->Next()) {
572    if (it->state() == LookupIterator::PROPERTY &&
573        it->HasProperty() &&
574        it->property_kind() == LookupIterator::ACCESSOR) {
575      Handle<Object> accessors = it->GetAccessors();
576      if (accessors->IsAccessorInfo()) {
577        if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
578      } else if (accessors->IsAccessorPair()) {
579        if (AccessorPair::cast(*accessors)->all_can_read()) return true;
580      }
581    }
582  }
583  return false;
584}
585
586
587MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
588    LookupIterator* it) {
589  Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder());
590  if (FindAllCanReadHolder(it)) {
591    return GetPropertyWithAccessor(
592        it->GetReceiver(), it->name(), it->GetHolder(), it->GetAccessors());
593  }
594  it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET);
595  RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
596  return it->factory()->undefined_value();
597}
598
599
600PropertyAttributes JSObject::GetPropertyAttributesWithFailedAccessCheck(
601    LookupIterator* it) {
602  Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder());
603  if (FindAllCanReadHolder(it)) return it->property_details().attributes();
604  it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS);
605  // TODO(yangguo): Issue 3269, check for scheduled exception missing?
606  return ABSENT;
607}
608
609
610static bool FindAllCanWriteHolder(LookupResult* result,
611                                  Handle<Name> name,
612                                  bool check_prototype) {
613  if (result->IsInterceptor()) {
614    result->holder()->LookupOwnRealNamedProperty(name, result);
615  }
616
617  while (result->IsProperty()) {
618    if (result->type() == CALLBACKS) {
619      Object* callback_obj = result->GetCallbackObject();
620      if (callback_obj->IsAccessorInfo()) {
621        if (AccessorInfo::cast(callback_obj)->all_can_write()) return true;
622      } else if (callback_obj->IsAccessorPair()) {
623        if (AccessorPair::cast(callback_obj)->all_can_write()) return true;
624      }
625    }
626    if (!check_prototype) break;
627    result->holder()->LookupRealNamedPropertyInPrototypes(name, result);
628  }
629  return false;
630}
631
632
633MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
634    Handle<JSObject> object,
635    LookupResult* result,
636    Handle<Name> name,
637    Handle<Object> value,
638    bool check_prototype,
639    StrictMode strict_mode) {
640  if (check_prototype && !result->IsProperty()) {
641    object->LookupRealNamedPropertyInPrototypes(name, result);
642  }
643
644  if (FindAllCanWriteHolder(result, name, check_prototype)) {
645    Handle<JSObject> holder(result->holder());
646    Handle<Object> callbacks(result->GetCallbackObject(), result->isolate());
647    return SetPropertyWithCallback(
648        object, name, value, holder, callbacks, strict_mode);
649  }
650
651  Isolate* isolate = object->GetIsolate();
652  isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
653  RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
654  return value;
655}
656
657
658Object* JSObject::GetNormalizedProperty(const LookupResult* result) {
659  ASSERT(!HasFastProperties());
660  Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
661  if (IsGlobalObject()) {
662    value = PropertyCell::cast(value)->value();
663  }
664  ASSERT(!value->IsPropertyCell() && !value->IsCell());
665  return value;
666}
667
668
669Handle<Object> JSObject::GetNormalizedProperty(Handle<JSObject> object,
670                                               const LookupResult* result) {
671  ASSERT(!object->HasFastProperties());
672  Isolate* isolate = object->GetIsolate();
673  Handle<Object> value(object->property_dictionary()->ValueAt(
674      result->GetDictionaryEntry()), isolate);
675  if (object->IsGlobalObject()) {
676    value = Handle<Object>(Handle<PropertyCell>::cast(value)->value(), isolate);
677  }
678  ASSERT(!value->IsPropertyCell() && !value->IsCell());
679  return value;
680}
681
682
683void JSObject::SetNormalizedProperty(Handle<JSObject> object,
684                                     const LookupResult* result,
685                                     Handle<Object> value) {
686  ASSERT(!object->HasFastProperties());
687  NameDictionary* property_dictionary = object->property_dictionary();
688  if (object->IsGlobalObject()) {
689    Handle<PropertyCell> cell(PropertyCell::cast(
690        property_dictionary->ValueAt(result->GetDictionaryEntry())));
691    PropertyCell::SetValueInferType(cell, value);
692  } else {
693    property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value);
694  }
695}
696
697
698void JSObject::SetNormalizedProperty(Handle<JSObject> object,
699                                     Handle<Name> name,
700                                     Handle<Object> value,
701                                     PropertyDetails details) {
702  ASSERT(!object->HasFastProperties());
703  Handle<NameDictionary> property_dictionary(object->property_dictionary());
704
705  if (!name->IsUniqueName()) {
706    name = object->GetIsolate()->factory()->InternalizeString(
707        Handle<String>::cast(name));
708  }
709
710  int entry = property_dictionary->FindEntry(name);
711  if (entry == NameDictionary::kNotFound) {
712    Handle<Object> store_value = value;
713    if (object->IsGlobalObject()) {
714      store_value = object->GetIsolate()->factory()->NewPropertyCell(value);
715    }
716
717    property_dictionary = NameDictionary::Add(
718        property_dictionary, name, store_value, details);
719    object->set_properties(*property_dictionary);
720    return;
721  }
722
723  PropertyDetails original_details = property_dictionary->DetailsAt(entry);
724  int enumeration_index;
725  // Preserve the enumeration index unless the property was deleted.
726  if (original_details.IsDeleted()) {
727    enumeration_index = property_dictionary->NextEnumerationIndex();
728    property_dictionary->SetNextEnumerationIndex(enumeration_index + 1);
729  } else {
730    enumeration_index = original_details.dictionary_index();
731    ASSERT(enumeration_index > 0);
732  }
733
734  details = PropertyDetails(
735      details.attributes(), details.type(), enumeration_index);
736
737  if (object->IsGlobalObject()) {
738    Handle<PropertyCell> cell(
739        PropertyCell::cast(property_dictionary->ValueAt(entry)));
740    PropertyCell::SetValueInferType(cell, value);
741    // Please note we have to update the property details.
742    property_dictionary->DetailsAtPut(entry, details);
743  } else {
744    property_dictionary->SetEntry(entry, name, value, details);
745  }
746}
747
748
749Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
750                                                  Handle<Name> name,
751                                                  DeleteMode mode) {
752  ASSERT(!object->HasFastProperties());
753  Isolate* isolate = object->GetIsolate();
754  Handle<NameDictionary> dictionary(object->property_dictionary());
755  int entry = dictionary->FindEntry(name);
756  if (entry != NameDictionary::kNotFound) {
757    // If we have a global object set the cell to the hole.
758    if (object->IsGlobalObject()) {
759      PropertyDetails details = dictionary->DetailsAt(entry);
760      if (details.IsDontDelete()) {
761        if (mode != FORCE_DELETION) return isolate->factory()->false_value();
762        // When forced to delete global properties, we have to make a
763        // map change to invalidate any ICs that think they can load
764        // from the DontDelete cell without checking if it contains
765        // the hole value.
766        Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
767        ASSERT(new_map->is_dictionary_map());
768        object->set_map(*new_map);
769      }
770      Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
771      Handle<Object> value = isolate->factory()->the_hole_value();
772      PropertyCell::SetValueInferType(cell, value);
773      dictionary->DetailsAtPut(entry, details.AsDeleted());
774    } else {
775      Handle<Object> deleted(
776          NameDictionary::DeleteProperty(dictionary, entry, mode));
777      if (*deleted == isolate->heap()->true_value()) {
778        Handle<NameDictionary> new_properties =
779            NameDictionary::Shrink(dictionary, name);
780        object->set_properties(*new_properties);
781      }
782      return deleted;
783    }
784  }
785  return isolate->factory()->true_value();
786}
787
788
789bool JSObject::IsDirty() {
790  Object* cons_obj = map()->constructor();
791  if (!cons_obj->IsJSFunction())
792    return true;
793  JSFunction* fun = JSFunction::cast(cons_obj);
794  if (!fun->shared()->IsApiFunction())
795    return true;
796  // If the object is fully fast case and has the same map it was
797  // created with then no changes can have been made to it.
798  return map() != fun->initial_map()
799      || !HasFastObjectElements()
800      || !HasFastProperties();
801}
802
803
804MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
805                                                   Handle<Object> object,
806                                                   Handle<Object> receiver,
807                                                   uint32_t index) {
808  Handle<Object> holder;
809
810  // Iterate up the prototype chain until an element is found or the null
811  // prototype is encountered.
812  for (holder = object;
813       !holder->IsNull();
814       holder = Handle<Object>(holder->GetPrototype(isolate), isolate)) {
815    if (!holder->IsJSObject()) {
816      Context* native_context = isolate->context()->native_context();
817      if (holder->IsNumber()) {
818        holder = Handle<Object>(
819            native_context->number_function()->instance_prototype(), isolate);
820      } else if (holder->IsString()) {
821        holder = Handle<Object>(
822            native_context->string_function()->instance_prototype(), isolate);
823      } else if (holder->IsSymbol()) {
824        holder = Handle<Object>(
825            native_context->symbol_function()->instance_prototype(), isolate);
826      } else if (holder->IsBoolean()) {
827        holder = Handle<Object>(
828            native_context->boolean_function()->instance_prototype(), isolate);
829      } else if (holder->IsJSProxy()) {
830        return JSProxy::GetElementWithHandler(
831            Handle<JSProxy>::cast(holder), receiver, index);
832      } else {
833        // Undefined and null have no indexed properties.
834        ASSERT(holder->IsUndefined() || holder->IsNull());
835        return isolate->factory()->undefined_value();
836      }
837    }
838
839    // Inline the case for JSObjects. Doing so significantly improves the
840    // performance of fetching elements where checking the prototype chain is
841    // necessary.
842    Handle<JSObject> js_object = Handle<JSObject>::cast(holder);
843
844    // Check access rights if needed.
845    if (js_object->IsAccessCheckNeeded()) {
846      if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
847        isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
848        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
849        return isolate->factory()->undefined_value();
850      }
851    }
852
853    if (js_object->HasIndexedInterceptor()) {
854      return JSObject::GetElementWithInterceptor(js_object, receiver, index);
855    }
856
857    if (js_object->elements() != isolate->heap()->empty_fixed_array()) {
858      Handle<Object> result;
859      ASSIGN_RETURN_ON_EXCEPTION(
860          isolate, result,
861          js_object->GetElementsAccessor()->Get(receiver, js_object, index),
862          Object);
863      if (!result->IsTheHole()) return result;
864    }
865  }
866
867  return isolate->factory()->undefined_value();
868}
869
870
871Object* Object::GetPrototype(Isolate* isolate) {
872  DisallowHeapAllocation no_alloc;
873  if (IsSmi()) {
874    Context* context = isolate->context()->native_context();
875    return context->number_function()->instance_prototype();
876  }
877
878  HeapObject* heap_object = HeapObject::cast(this);
879
880  // The object is either a number, a string, a boolean,
881  // a real JS object, or a Harmony proxy.
882  if (heap_object->IsJSReceiver()) {
883    return heap_object->map()->prototype();
884  }
885  Context* context = isolate->context()->native_context();
886
887  if (heap_object->IsHeapNumber()) {
888    return context->number_function()->instance_prototype();
889  }
890  if (heap_object->IsString()) {
891    return context->string_function()->instance_prototype();
892  }
893  if (heap_object->IsSymbol()) {
894    return context->symbol_function()->instance_prototype();
895  }
896  if (heap_object->IsBoolean()) {
897    return context->boolean_function()->instance_prototype();
898  } else {
899    return isolate->heap()->null_value();
900  }
901}
902
903
904Handle<Object> Object::GetPrototype(Isolate* isolate,
905                                    Handle<Object> object) {
906  return handle(object->GetPrototype(isolate), isolate);
907}
908
909
910Object* Object::GetHash() {
911  // The object is either a number, a name, an odd-ball,
912  // a real JS object, or a Harmony proxy.
913  if (IsNumber()) {
914    uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
915    return Smi::FromInt(hash & Smi::kMaxValue);
916  }
917  if (IsName()) {
918    uint32_t hash = Name::cast(this)->Hash();
919    return Smi::FromInt(hash);
920  }
921  if (IsOddball()) {
922    uint32_t hash = Oddball::cast(this)->to_string()->Hash();
923    return Smi::FromInt(hash);
924  }
925
926  ASSERT(IsJSReceiver());
927  return JSReceiver::cast(this)->GetIdentityHash();
928}
929
930
931Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
932  Handle<Object> hash(object->GetHash(), isolate);
933  if (hash->IsSmi()) return Handle<Smi>::cast(hash);
934
935  ASSERT(object->IsJSReceiver());
936  return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
937}
938
939
940bool Object::SameValue(Object* other) {
941  if (other == this) return true;
942
943  // The object is either a number, a name, an odd-ball,
944  // a real JS object, or a Harmony proxy.
945  if (IsNumber() && other->IsNumber()) {
946    double this_value = Number();
947    double other_value = other->Number();
948    bool equal = this_value == other_value;
949    // SameValue(NaN, NaN) is true.
950    if (!equal) return std::isnan(this_value) && std::isnan(other_value);
951    // SameValue(0.0, -0.0) is false.
952    return (this_value != 0) || ((1 / this_value) == (1 / other_value));
953  }
954  if (IsString() && other->IsString()) {
955    return String::cast(this)->Equals(String::cast(other));
956  }
957  return false;
958}
959
960
961bool Object::SameValueZero(Object* other) {
962  if (other == this) return true;
963
964  // The object is either a number, a name, an odd-ball,
965  // a real JS object, or a Harmony proxy.
966  if (IsNumber() && other->IsNumber()) {
967    double this_value = Number();
968    double other_value = other->Number();
969    // +0 == -0 is true
970    return this_value == other_value
971        || (std::isnan(this_value) && std::isnan(other_value));
972  }
973  if (IsString() && other->IsString()) {
974    return String::cast(this)->Equals(String::cast(other));
975  }
976  return false;
977}
978
979
980void Object::ShortPrint(FILE* out) {
981  HeapStringAllocator allocator;
982  StringStream accumulator(&allocator);
983  ShortPrint(&accumulator);
984  accumulator.OutputToFile(out);
985}
986
987
988void Object::ShortPrint(StringStream* accumulator) {
989  if (IsSmi()) {
990    Smi::cast(this)->SmiPrint(accumulator);
991  } else {
992    HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
993  }
994}
995
996
997void Smi::SmiPrint(FILE* out) {
998  PrintF(out, "%d", value());
999}
1000
1001
1002void Smi::SmiPrint(StringStream* accumulator) {
1003  accumulator->Add("%d", value());
1004}
1005
1006
1007// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1008// English?  Returns false for non-ASCII or words that don't start with
1009// a capital letter.  The a/an rule follows pronunciation in English.
1010// We don't use the BBC's overcorrect "an historic occasion" though if
1011// you speak a dialect you may well say "an 'istoric occasion".
1012static bool AnWord(String* str) {
1013  if (str->length() == 0) return false;  // A nothing.
1014  int c0 = str->Get(0);
1015  int c1 = str->length() > 1 ? str->Get(1) : 0;
1016  if (c0 == 'U') {
1017    if (c1 > 'Z') {
1018      return true;  // An Umpire, but a UTF8String, a U.
1019    }
1020  } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
1021    return true;    // An Ape, an ABCBook.
1022  } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1023           (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1024            c0 == 'S' || c0 == 'X')) {
1025    return true;    // An MP3File, an M.
1026  }
1027  return false;
1028}
1029
1030
1031Handle<String> String::SlowFlatten(Handle<ConsString> cons,
1032                                   PretenureFlag pretenure) {
1033  ASSERT(AllowHeapAllocation::IsAllowed());
1034  ASSERT(cons->second()->length() != 0);
1035  Isolate* isolate = cons->GetIsolate();
1036  int length = cons->length();
1037  PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
1038                                                            : TENURED;
1039  Handle<SeqString> result;
1040  if (cons->IsOneByteRepresentation()) {
1041    Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
1042        length, tenure).ToHandleChecked();
1043    DisallowHeapAllocation no_gc;
1044    WriteToFlat(*cons, flat->GetChars(), 0, length);
1045    result = flat;
1046  } else {
1047    Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
1048        length, tenure).ToHandleChecked();
1049    DisallowHeapAllocation no_gc;
1050    WriteToFlat(*cons, flat->GetChars(), 0, length);
1051    result = flat;
1052  }
1053  cons->set_first(*result);
1054  cons->set_second(isolate->heap()->empty_string());
1055  ASSERT(result->IsFlat());
1056  return result;
1057}
1058
1059
1060
1061bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
1062  // Externalizing twice leaks the external resource, so it's
1063  // prohibited by the API.
1064  ASSERT(!this->IsExternalString());
1065#ifdef ENABLE_SLOW_ASSERTS
1066  if (FLAG_enable_slow_asserts) {
1067    // Assert that the resource and the string are equivalent.
1068    ASSERT(static_cast<size_t>(this->length()) == resource->length());
1069    ScopedVector<uc16> smart_chars(this->length());
1070    String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1071    ASSERT(memcmp(smart_chars.start(),
1072                  resource->data(),
1073                  resource->length() * sizeof(smart_chars[0])) == 0);
1074  }
1075#endif  // DEBUG
1076  Heap* heap = GetHeap();
1077  int size = this->Size();  // Byte size of the original string.
1078  if (size < ExternalString::kShortSize) {
1079    return false;
1080  }
1081  bool is_ascii = this->IsOneByteRepresentation();
1082  bool is_internalized = this->IsInternalizedString();
1083
1084  // Morph the string to an external string by replacing the map and
1085  // reinitializing the fields.  This won't work if
1086  // - the space the existing string occupies is too small for a regular
1087  //   external string.
1088  // - the existing string is in old pointer space and the backing store of
1089  //   the external string is not aligned.  The GC cannot deal with a field
1090  //   containing a possibly unaligned address to outside of V8's heap.
1091  // In either case we resort to a short external string instead, omitting
1092  // the field caching the address of the backing store.  When we encounter
1093  // short external strings in generated code, we need to bailout to runtime.
1094  Map* new_map;
1095  if (size < ExternalString::kSize ||
1096      heap->old_pointer_space()->Contains(this)) {
1097    new_map = is_internalized
1098        ? (is_ascii
1099            ? heap->
1100                short_external_internalized_string_with_one_byte_data_map()
1101            : heap->short_external_internalized_string_map())
1102        : (is_ascii
1103            ? heap->short_external_string_with_one_byte_data_map()
1104            : heap->short_external_string_map());
1105  } else {
1106    new_map = is_internalized
1107        ? (is_ascii
1108            ? heap->external_internalized_string_with_one_byte_data_map()
1109            : heap->external_internalized_string_map())
1110        : (is_ascii
1111            ? heap->external_string_with_one_byte_data_map()
1112            : heap->external_string_map());
1113  }
1114
1115  // Byte size of the external String object.
1116  int new_size = this->SizeFromMap(new_map);
1117  heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1118
1119  // We are storing the new map using release store after creating a filler for
1120  // the left-over space to avoid races with the sweeper thread.
1121  this->synchronized_set_map(new_map);
1122
1123  ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1124  self->set_resource(resource);
1125  if (is_internalized) self->Hash();  // Force regeneration of the hash value.
1126
1127  heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
1128  return true;
1129}
1130
1131
1132bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
1133#ifdef ENABLE_SLOW_ASSERTS
1134  if (FLAG_enable_slow_asserts) {
1135    // Assert that the resource and the string are equivalent.
1136    ASSERT(static_cast<size_t>(this->length()) == resource->length());
1137    if (this->IsTwoByteRepresentation()) {
1138      ScopedVector<uint16_t> smart_chars(this->length());
1139      String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1140      ASSERT(String::IsOneByte(smart_chars.start(), this->length()));
1141    }
1142    ScopedVector<char> smart_chars(this->length());
1143    String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1144    ASSERT(memcmp(smart_chars.start(),
1145                  resource->data(),
1146                  resource->length() * sizeof(smart_chars[0])) == 0);
1147  }
1148#endif  // DEBUG
1149  Heap* heap = GetHeap();
1150  int size = this->Size();  // Byte size of the original string.
1151  if (size < ExternalString::kShortSize) {
1152    return false;
1153  }
1154  bool is_internalized = this->IsInternalizedString();
1155
1156  // Morph the string to an external string by replacing the map and
1157  // reinitializing the fields.  This won't work if
1158  // - the space the existing string occupies is too small for a regular
1159  //   external string.
1160  // - the existing string is in old pointer space and the backing store of
1161  //   the external string is not aligned.  The GC cannot deal with a field
1162  //   containing a possibly unaligned address to outside of V8's heap.
1163  // In either case we resort to a short external string instead, omitting
1164  // the field caching the address of the backing store.  When we encounter
1165  // short external strings in generated code, we need to bailout to runtime.
1166  Map* new_map;
1167  if (size < ExternalString::kSize ||
1168      heap->old_pointer_space()->Contains(this)) {
1169    new_map = is_internalized
1170        ? heap->short_external_ascii_internalized_string_map()
1171        : heap->short_external_ascii_string_map();
1172  } else {
1173    new_map = is_internalized
1174        ? heap->external_ascii_internalized_string_map()
1175        : heap->external_ascii_string_map();
1176  }
1177
1178  // Byte size of the external String object.
1179  int new_size = this->SizeFromMap(new_map);
1180  heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1181
1182  // We are storing the new map using release store after creating a filler for
1183  // the left-over space to avoid races with the sweeper thread.
1184  this->synchronized_set_map(new_map);
1185
1186  ExternalAsciiString* self = ExternalAsciiString::cast(this);
1187  self->set_resource(resource);
1188  if (is_internalized) self->Hash();  // Force regeneration of the hash value.
1189
1190  heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
1191  return true;
1192}
1193
1194
1195void String::StringShortPrint(StringStream* accumulator) {
1196  int len = length();
1197  if (len > kMaxShortPrintLength) {
1198    accumulator->Add("<Very long string[%u]>", len);
1199    return;
1200  }
1201
1202  if (!LooksValid()) {
1203    accumulator->Add("<Invalid String>");
1204    return;
1205  }
1206
1207  ConsStringIteratorOp op;
1208  StringCharacterStream stream(this, &op);
1209
1210  bool truncated = false;
1211  if (len > kMaxShortPrintLength) {
1212    len = kMaxShortPrintLength;
1213    truncated = true;
1214  }
1215  bool ascii = true;
1216  for (int i = 0; i < len; i++) {
1217    uint16_t c = stream.GetNext();
1218
1219    if (c < 32 || c >= 127) {
1220      ascii = false;
1221    }
1222  }
1223  stream.Reset(this);
1224  if (ascii) {
1225    accumulator->Add("<String[%u]: ", length());
1226    for (int i = 0; i < len; i++) {
1227      accumulator->Put(static_cast<char>(stream.GetNext()));
1228    }
1229    accumulator->Put('>');
1230  } else {
1231    // Backslash indicates that the string contains control
1232    // characters and that backslashes are therefore escaped.
1233    accumulator->Add("<String[%u]\\: ", length());
1234    for (int i = 0; i < len; i++) {
1235      uint16_t c = stream.GetNext();
1236      if (c == '\n') {
1237        accumulator->Add("\\n");
1238      } else if (c == '\r') {
1239        accumulator->Add("\\r");
1240      } else if (c == '\\') {
1241        accumulator->Add("\\\\");
1242      } else if (c < 32 || c > 126) {
1243        accumulator->Add("\\x%02x", c);
1244      } else {
1245        accumulator->Put(static_cast<char>(c));
1246      }
1247    }
1248    if (truncated) {
1249      accumulator->Put('.');
1250      accumulator->Put('.');
1251      accumulator->Put('.');
1252    }
1253    accumulator->Put('>');
1254  }
1255  return;
1256}
1257
1258
1259void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1260  switch (map()->instance_type()) {
1261    case JS_ARRAY_TYPE: {
1262      double length = JSArray::cast(this)->length()->IsUndefined()
1263          ? 0
1264          : JSArray::cast(this)->length()->Number();
1265      accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
1266      break;
1267    }
1268    case JS_WEAK_MAP_TYPE: {
1269      accumulator->Add("<JS WeakMap>");
1270      break;
1271    }
1272    case JS_WEAK_SET_TYPE: {
1273      accumulator->Add("<JS WeakSet>");
1274      break;
1275    }
1276    case JS_REGEXP_TYPE: {
1277      accumulator->Add("<JS RegExp>");
1278      break;
1279    }
1280    case JS_FUNCTION_TYPE: {
1281      JSFunction* function = JSFunction::cast(this);
1282      Object* fun_name = function->shared()->DebugName();
1283      bool printed = false;
1284      if (fun_name->IsString()) {
1285        String* str = String::cast(fun_name);
1286        if (str->length() > 0) {
1287          accumulator->Add("<JS Function ");
1288          accumulator->Put(str);
1289          printed = true;
1290        }
1291      }
1292      if (!printed) {
1293        accumulator->Add("<JS Function");
1294      }
1295      accumulator->Add(" (SharedFunctionInfo %p)",
1296                       reinterpret_cast<void*>(function->shared()));
1297      accumulator->Put('>');
1298      break;
1299    }
1300    case JS_GENERATOR_OBJECT_TYPE: {
1301      accumulator->Add("<JS Generator>");
1302      break;
1303    }
1304    case JS_MODULE_TYPE: {
1305      accumulator->Add("<JS Module>");
1306      break;
1307    }
1308    // All other JSObjects are rather similar to each other (JSObject,
1309    // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1310    default: {
1311      Map* map_of_this = map();
1312      Heap* heap = GetHeap();
1313      Object* constructor = map_of_this->constructor();
1314      bool printed = false;
1315      if (constructor->IsHeapObject() &&
1316          !heap->Contains(HeapObject::cast(constructor))) {
1317        accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1318      } else {
1319        bool global_object = IsJSGlobalProxy();
1320        if (constructor->IsJSFunction()) {
1321          if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
1322            accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1323          } else {
1324            Object* constructor_name =
1325                JSFunction::cast(constructor)->shared()->name();
1326            if (constructor_name->IsString()) {
1327              String* str = String::cast(constructor_name);
1328              if (str->length() > 0) {
1329                bool vowel = AnWord(str);
1330                accumulator->Add("<%sa%s ",
1331                       global_object ? "Global Object: " : "",
1332                       vowel ? "n" : "");
1333                accumulator->Put(str);
1334                accumulator->Add(" with %smap %p",
1335                    map_of_this->is_deprecated() ? "deprecated " : "",
1336                    map_of_this);
1337                printed = true;
1338              }
1339            }
1340          }
1341        }
1342        if (!printed) {
1343          accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1344        }
1345      }
1346      if (IsJSValue()) {
1347        accumulator->Add(" value = ");
1348        JSValue::cast(this)->value()->ShortPrint(accumulator);
1349      }
1350      accumulator->Put('>');
1351      break;
1352    }
1353  }
1354}
1355
1356
1357void JSObject::PrintElementsTransition(
1358    FILE* file, Handle<JSObject> object,
1359    ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
1360    ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
1361  if (from_kind != to_kind) {
1362    PrintF(file, "elements transition [");
1363    PrintElementsKind(file, from_kind);
1364    PrintF(file, " -> ");
1365    PrintElementsKind(file, to_kind);
1366    PrintF(file, "] in ");
1367    JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
1368    PrintF(file, " for ");
1369    object->ShortPrint(file);
1370    PrintF(file, " from ");
1371    from_elements->ShortPrint(file);
1372    PrintF(file, " to ");
1373    to_elements->ShortPrint(file);
1374    PrintF(file, "\n");
1375  }
1376}
1377
1378
1379void Map::PrintGeneralization(FILE* file,
1380                              const char* reason,
1381                              int modify_index,
1382                              int split,
1383                              int descriptors,
1384                              bool constant_to_field,
1385                              Representation old_representation,
1386                              Representation new_representation,
1387                              HeapType* old_field_type,
1388                              HeapType* new_field_type) {
1389  PrintF(file, "[generalizing ");
1390  constructor_name()->PrintOn(file);
1391  PrintF(file, "] ");
1392  Name* name = instance_descriptors()->GetKey(modify_index);
1393  if (name->IsString()) {
1394    String::cast(name)->PrintOn(file);
1395  } else {
1396    PrintF(file, "{symbol %p}", static_cast<void*>(name));
1397  }
1398  PrintF(file, ":");
1399  if (constant_to_field) {
1400    PrintF(file, "c");
1401  } else {
1402    PrintF(file, "%s", old_representation.Mnemonic());
1403    PrintF(file, "{");
1404    old_field_type->TypePrint(file, HeapType::SEMANTIC_DIM);
1405    PrintF(file, "}");
1406  }
1407  PrintF(file, "->%s", new_representation.Mnemonic());
1408  PrintF(file, "{");
1409  new_field_type->TypePrint(file, HeapType::SEMANTIC_DIM);
1410  PrintF(file, "}");
1411  PrintF(file, " (");
1412  if (strlen(reason) > 0) {
1413    PrintF(file, "%s", reason);
1414  } else {
1415    PrintF(file, "+%i maps", descriptors - split);
1416  }
1417  PrintF(file, ") [");
1418  JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
1419  PrintF(file, "]\n");
1420}
1421
1422
1423void JSObject::PrintInstanceMigration(FILE* file,
1424                                      Map* original_map,
1425                                      Map* new_map) {
1426  PrintF(file, "[migrating ");
1427  map()->constructor_name()->PrintOn(file);
1428  PrintF(file, "] ");
1429  DescriptorArray* o = original_map->instance_descriptors();
1430  DescriptorArray* n = new_map->instance_descriptors();
1431  for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
1432    Representation o_r = o->GetDetails(i).representation();
1433    Representation n_r = n->GetDetails(i).representation();
1434    if (!o_r.Equals(n_r)) {
1435      String::cast(o->GetKey(i))->PrintOn(file);
1436      PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
1437    } else if (o->GetDetails(i).type() == CONSTANT &&
1438               n->GetDetails(i).type() == FIELD) {
1439      Name* name = o->GetKey(i);
1440      if (name->IsString()) {
1441        String::cast(name)->PrintOn(file);
1442      } else {
1443        PrintF(file, "{symbol %p}", static_cast<void*>(name));
1444      }
1445      PrintF(file, " ");
1446    }
1447  }
1448  PrintF(file, "\n");
1449}
1450
1451
1452void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
1453  Heap* heap = GetHeap();
1454  if (!heap->Contains(this)) {
1455    accumulator->Add("!!!INVALID POINTER!!!");
1456    return;
1457  }
1458  if (!heap->Contains(map())) {
1459    accumulator->Add("!!!INVALID MAP!!!");
1460    return;
1461  }
1462
1463  accumulator->Add("%p ", this);
1464
1465  if (IsString()) {
1466    String::cast(this)->StringShortPrint(accumulator);
1467    return;
1468  }
1469  if (IsJSObject()) {
1470    JSObject::cast(this)->JSObjectShortPrint(accumulator);
1471    return;
1472  }
1473  switch (map()->instance_type()) {
1474    case MAP_TYPE:
1475      accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
1476      break;
1477    case FIXED_ARRAY_TYPE:
1478      accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1479      break;
1480    case FIXED_DOUBLE_ARRAY_TYPE:
1481      accumulator->Add("<FixedDoubleArray[%u]>",
1482                       FixedDoubleArray::cast(this)->length());
1483      break;
1484    case BYTE_ARRAY_TYPE:
1485      accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1486      break;
1487    case FREE_SPACE_TYPE:
1488      accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1489      break;
1490#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size)                 \
1491    case EXTERNAL_##TYPE##_ARRAY_TYPE:                                         \
1492      accumulator->Add("<External" #Type "Array[%u]>",                         \
1493                       External##Type##Array::cast(this)->length());           \
1494      break;                                                                   \
1495    case FIXED_##TYPE##_ARRAY_TYPE:                                            \
1496      accumulator->Add("<Fixed" #Type "Array[%u]>",                            \
1497                       Fixed##Type##Array::cast(this)->length());              \
1498      break;
1499
1500    TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
1501#undef TYPED_ARRAY_SHORT_PRINT
1502
1503    case SHARED_FUNCTION_INFO_TYPE: {
1504      SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
1505      SmartArrayPointer<char> debug_name =
1506          shared->DebugName()->ToCString();
1507      if (debug_name[0] != 0) {
1508        accumulator->Add("<SharedFunctionInfo %s>", debug_name.get());
1509      } else {
1510        accumulator->Add("<SharedFunctionInfo>");
1511      }
1512      break;
1513    }
1514    case JS_MESSAGE_OBJECT_TYPE:
1515      accumulator->Add("<JSMessageObject>");
1516      break;
1517#define MAKE_STRUCT_CASE(NAME, Name, name) \
1518  case NAME##_TYPE:                        \
1519    accumulator->Put('<');                 \
1520    accumulator->Add(#Name);               \
1521    accumulator->Put('>');                 \
1522    break;
1523  STRUCT_LIST(MAKE_STRUCT_CASE)
1524#undef MAKE_STRUCT_CASE
1525    case CODE_TYPE:
1526      accumulator->Add("<Code>");
1527      break;
1528    case ODDBALL_TYPE: {
1529      if (IsUndefined())
1530        accumulator->Add("<undefined>");
1531      else if (IsTheHole())
1532        accumulator->Add("<the hole>");
1533      else if (IsNull())
1534        accumulator->Add("<null>");
1535      else if (IsTrue())
1536        accumulator->Add("<true>");
1537      else if (IsFalse())
1538        accumulator->Add("<false>");
1539      else
1540        accumulator->Add("<Odd Oddball>");
1541      break;
1542    }
1543    case SYMBOL_TYPE: {
1544      Symbol* symbol = Symbol::cast(this);
1545      accumulator->Add("<Symbol: %d", symbol->Hash());
1546      if (!symbol->name()->IsUndefined()) {
1547        accumulator->Add(" ");
1548        String::cast(symbol->name())->StringShortPrint(accumulator);
1549      }
1550      accumulator->Add(">");
1551      break;
1552    }
1553    case HEAP_NUMBER_TYPE:
1554      accumulator->Add("<Number: ");
1555      HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1556      accumulator->Put('>');
1557      break;
1558    case JS_PROXY_TYPE:
1559      accumulator->Add("<JSProxy>");
1560      break;
1561    case JS_FUNCTION_PROXY_TYPE:
1562      accumulator->Add("<JSFunctionProxy>");
1563      break;
1564    case FOREIGN_TYPE:
1565      accumulator->Add("<Foreign>");
1566      break;
1567    case CELL_TYPE:
1568      accumulator->Add("Cell for ");
1569      Cell::cast(this)->value()->ShortPrint(accumulator);
1570      break;
1571    case PROPERTY_CELL_TYPE:
1572      accumulator->Add("PropertyCell for ");
1573      PropertyCell::cast(this)->value()->ShortPrint(accumulator);
1574      break;
1575    default:
1576      accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1577      break;
1578  }
1579}
1580
1581
1582void HeapObject::Iterate(ObjectVisitor* v) {
1583  // Handle header
1584  IteratePointer(v, kMapOffset);
1585  // Handle object body
1586  Map* m = map();
1587  IterateBody(m->instance_type(), SizeFromMap(m), v);
1588}
1589
1590
1591void HeapObject::IterateBody(InstanceType type, int object_size,
1592                             ObjectVisitor* v) {
1593  // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1594  // During GC, the map pointer field is encoded.
1595  if (type < FIRST_NONSTRING_TYPE) {
1596    switch (type & kStringRepresentationMask) {
1597      case kSeqStringTag:
1598        break;
1599      case kConsStringTag:
1600        ConsString::BodyDescriptor::IterateBody(this, v);
1601        break;
1602      case kSlicedStringTag:
1603        SlicedString::BodyDescriptor::IterateBody(this, v);
1604        break;
1605      case kExternalStringTag:
1606        if ((type & kStringEncodingMask) == kOneByteStringTag) {
1607          reinterpret_cast<ExternalAsciiString*>(this)->
1608              ExternalAsciiStringIterateBody(v);
1609        } else {
1610          reinterpret_cast<ExternalTwoByteString*>(this)->
1611              ExternalTwoByteStringIterateBody(v);
1612        }
1613        break;
1614    }
1615    return;
1616  }
1617
1618  switch (type) {
1619    case FIXED_ARRAY_TYPE:
1620      FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
1621      break;
1622    case CONSTANT_POOL_ARRAY_TYPE:
1623      reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v);
1624      break;
1625    case FIXED_DOUBLE_ARRAY_TYPE:
1626      break;
1627    case JS_OBJECT_TYPE:
1628    case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1629    case JS_GENERATOR_OBJECT_TYPE:
1630    case JS_MODULE_TYPE:
1631    case JS_VALUE_TYPE:
1632    case JS_DATE_TYPE:
1633    case JS_ARRAY_TYPE:
1634    case JS_ARRAY_BUFFER_TYPE:
1635    case JS_TYPED_ARRAY_TYPE:
1636    case JS_DATA_VIEW_TYPE:
1637    case JS_SET_TYPE:
1638    case JS_MAP_TYPE:
1639    case JS_SET_ITERATOR_TYPE:
1640    case JS_MAP_ITERATOR_TYPE:
1641    case JS_WEAK_MAP_TYPE:
1642    case JS_WEAK_SET_TYPE:
1643    case JS_REGEXP_TYPE:
1644    case JS_GLOBAL_PROXY_TYPE:
1645    case JS_GLOBAL_OBJECT_TYPE:
1646    case JS_BUILTINS_OBJECT_TYPE:
1647    case JS_MESSAGE_OBJECT_TYPE:
1648      JSObject::BodyDescriptor::IterateBody(this, object_size, v);
1649      break;
1650    case JS_FUNCTION_TYPE:
1651      reinterpret_cast<JSFunction*>(this)
1652          ->JSFunctionIterateBody(object_size, v);
1653      break;
1654    case ODDBALL_TYPE:
1655      Oddball::BodyDescriptor::IterateBody(this, v);
1656      break;
1657    case JS_PROXY_TYPE:
1658      JSProxy::BodyDescriptor::IterateBody(this, v);
1659      break;
1660    case JS_FUNCTION_PROXY_TYPE:
1661      JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1662      break;
1663    case FOREIGN_TYPE:
1664      reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
1665      break;
1666    case MAP_TYPE:
1667      Map::BodyDescriptor::IterateBody(this, v);
1668      break;
1669    case CODE_TYPE:
1670      reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1671      break;
1672    case CELL_TYPE:
1673      Cell::BodyDescriptor::IterateBody(this, v);
1674      break;
1675    case PROPERTY_CELL_TYPE:
1676      PropertyCell::BodyDescriptor::IterateBody(this, v);
1677      break;
1678    case SYMBOL_TYPE:
1679      Symbol::BodyDescriptor::IterateBody(this, v);
1680      break;
1681
1682    case HEAP_NUMBER_TYPE:
1683    case FILLER_TYPE:
1684    case BYTE_ARRAY_TYPE:
1685    case FREE_SPACE_TYPE:
1686      break;
1687
1688#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
1689    case EXTERNAL_##TYPE##_ARRAY_TYPE:                                         \
1690    case FIXED_##TYPE##_ARRAY_TYPE:                                            \
1691      break;
1692
1693    TYPED_ARRAYS(TYPED_ARRAY_CASE)
1694#undef TYPED_ARRAY_CASE
1695
1696    case SHARED_FUNCTION_INFO_TYPE: {
1697      SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
1698      break;
1699    }
1700
1701#define MAKE_STRUCT_CASE(NAME, Name, name) \
1702        case NAME##_TYPE:
1703      STRUCT_LIST(MAKE_STRUCT_CASE)
1704#undef MAKE_STRUCT_CASE
1705      if (type == ALLOCATION_SITE_TYPE) {
1706        AllocationSite::BodyDescriptor::IterateBody(this, v);
1707      } else {
1708        StructBodyDescriptor::IterateBody(this, object_size, v);
1709      }
1710      break;
1711    default:
1712      PrintF("Unknown type: %d\n", type);
1713      UNREACHABLE();
1714  }
1715}
1716
1717
1718bool HeapNumber::HeapNumberBooleanValue() {
1719  // NaN, +0, and -0 should return the false object
1720#if __BYTE_ORDER == __LITTLE_ENDIAN
1721  union IeeeDoubleLittleEndianArchType u;
1722#elif __BYTE_ORDER == __BIG_ENDIAN
1723  union IeeeDoubleBigEndianArchType u;
1724#endif
1725  u.d = value();
1726  if (u.bits.exp == 2047) {
1727    // Detect NaN for IEEE double precision floating point.
1728    if ((u.bits.man_low | u.bits.man_high) != 0) return false;
1729  }
1730  if (u.bits.exp == 0) {
1731    // Detect +0, and -0 for IEEE double precision floating point.
1732    if ((u.bits.man_low | u.bits.man_high) == 0) return false;
1733  }
1734  return true;
1735}
1736
1737
1738void HeapNumber::HeapNumberPrint(FILE* out) {
1739  PrintF(out, "%.16g", Number());
1740}
1741
1742
1743void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1744  // The Windows version of vsnprintf can allocate when printing a %g string
1745  // into a buffer that may not be big enough.  We don't want random memory
1746  // allocation when producing post-crash stack traces, so we print into a
1747  // buffer that is plenty big enough for any floating point number, then
1748  // print that using vsnprintf (which may truncate but never allocate if
1749  // there is no more space in the buffer).
1750  EmbeddedVector<char, 100> buffer;
1751  SNPrintF(buffer, "%.16g", Number());
1752  accumulator->Add("%s", buffer.start());
1753}
1754
1755
1756String* JSReceiver::class_name() {
1757  if (IsJSFunction() && IsJSFunctionProxy()) {
1758    return GetHeap()->function_class_string();
1759  }
1760  if (map()->constructor()->IsJSFunction()) {
1761    JSFunction* constructor = JSFunction::cast(map()->constructor());
1762    return String::cast(constructor->shared()->instance_class_name());
1763  }
1764  // If the constructor is not present, return "Object".
1765  return GetHeap()->Object_string();
1766}
1767
1768
1769String* Map::constructor_name() {
1770  if (constructor()->IsJSFunction()) {
1771    JSFunction* constructor = JSFunction::cast(this->constructor());
1772    String* name = String::cast(constructor->shared()->name());
1773    if (name->length() > 0) return name;
1774    String* inferred_name = constructor->shared()->inferred_name();
1775    if (inferred_name->length() > 0) return inferred_name;
1776    Object* proto = prototype();
1777    if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
1778  }
1779  // TODO(rossberg): what about proxies?
1780  // If the constructor is not present, return "Object".
1781  return GetHeap()->Object_string();
1782}
1783
1784
1785String* JSReceiver::constructor_name() {
1786  return map()->constructor_name();
1787}
1788
1789
1790MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
1791                                    Handle<Name> name,
1792                                    Handle<HeapType> type,
1793                                    PropertyAttributes attributes,
1794                                    Representation representation,
1795                                    TransitionFlag flag) {
1796  ASSERT(DescriptorArray::kNotFound ==
1797         map->instance_descriptors()->Search(
1798             *name, map->NumberOfOwnDescriptors()));
1799
1800  // Ensure the descriptor array does not get too big.
1801  if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1802    return MaybeHandle<Map>();
1803  }
1804
1805  Isolate* isolate = map->GetIsolate();
1806
1807  // Compute the new index for new field.
1808  int index = map->NextFreePropertyIndex();
1809
1810  if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
1811    representation = Representation::Tagged();
1812    type = HeapType::Any(isolate);
1813  }
1814
1815  FieldDescriptor new_field_desc(name, index, type, attributes, representation);
1816  Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
1817  int unused_property_fields = new_map->unused_property_fields() - 1;
1818  if (unused_property_fields < 0) {
1819    unused_property_fields += JSObject::kFieldsAdded;
1820  }
1821  new_map->set_unused_property_fields(unused_property_fields);
1822  return new_map;
1823}
1824
1825
1826MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
1827                                       Handle<Name> name,
1828                                       Handle<Object> constant,
1829                                       PropertyAttributes attributes,
1830                                       TransitionFlag flag) {
1831  // Ensure the descriptor array does not get too big.
1832  if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1833    return MaybeHandle<Map>();
1834  }
1835
1836  // Allocate new instance descriptors with (name, constant) added.
1837  ConstantDescriptor new_constant_desc(name, constant, attributes);
1838  return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
1839}
1840
1841
1842void JSObject::AddFastProperty(Handle<JSObject> object,
1843                               Handle<Name> name,
1844                               Handle<Object> value,
1845                               PropertyAttributes attributes,
1846                               StoreFromKeyed store_mode,
1847                               ValueType value_type,
1848                               TransitionFlag flag) {
1849  ASSERT(!object->IsJSGlobalProxy());
1850
1851  MaybeHandle<Map> maybe_map;
1852  if (value->IsJSFunction()) {
1853    maybe_map = Map::CopyWithConstant(
1854        handle(object->map()), name, value, attributes, flag);
1855  } else if (!object->TooManyFastProperties(store_mode)) {
1856    Isolate* isolate = object->GetIsolate();
1857    Representation representation = value->OptimalRepresentation(value_type);
1858    maybe_map = Map::CopyWithField(
1859        handle(object->map(), isolate), name,
1860        value->OptimalType(isolate, representation),
1861        attributes, representation, flag);
1862  }
1863
1864  Handle<Map> new_map;
1865  if (!maybe_map.ToHandle(&new_map)) {
1866    NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
1867    return;
1868  }
1869
1870  JSObject::MigrateToNewProperty(object, new_map, value);
1871}
1872
1873
1874void JSObject::AddSlowProperty(Handle<JSObject> object,
1875                               Handle<Name> name,
1876                               Handle<Object> value,
1877                               PropertyAttributes attributes) {
1878  ASSERT(!object->HasFastProperties());
1879  Isolate* isolate = object->GetIsolate();
1880  Handle<NameDictionary> dict(object->property_dictionary());
1881  if (object->IsGlobalObject()) {
1882    // In case name is an orphaned property reuse the cell.
1883    int entry = dict->FindEntry(name);
1884    if (entry != NameDictionary::kNotFound) {
1885      Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry)));
1886      PropertyCell::SetValueInferType(cell, value);
1887      // Assign an enumeration index to the property and update
1888      // SetNextEnumerationIndex.
1889      int index = dict->NextEnumerationIndex();
1890      PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1891      dict->SetNextEnumerationIndex(index + 1);
1892      dict->SetEntry(entry, name, cell, details);
1893      return;
1894    }
1895    Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
1896    PropertyCell::SetValueInferType(cell, value);
1897    value = cell;
1898  }
1899  PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
1900  Handle<NameDictionary> result =
1901      NameDictionary::Add(dict, name, value, details);
1902  if (*dict != *result) object->set_properties(*result);
1903}
1904
1905
1906MaybeHandle<Object> JSObject::AddProperty(
1907    Handle<JSObject> object,
1908    Handle<Name> name,
1909    Handle<Object> value,
1910    PropertyAttributes attributes,
1911    StrictMode strict_mode,
1912    JSReceiver::StoreFromKeyed store_mode,
1913    ExtensibilityCheck extensibility_check,
1914    ValueType value_type,
1915    StoreMode mode,
1916    TransitionFlag transition_flag) {
1917  ASSERT(!object->IsJSGlobalProxy());
1918  Isolate* isolate = object->GetIsolate();
1919
1920  if (!name->IsUniqueName()) {
1921    name = isolate->factory()->InternalizeString(
1922        Handle<String>::cast(name));
1923  }
1924
1925  if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
1926      !object->map()->is_extensible()) {
1927    if (strict_mode == SLOPPY) {
1928      return value;
1929    } else {
1930      Handle<Object> args[1] = { name };
1931      Handle<Object> error = isolate->factory()->NewTypeError(
1932          "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
1933      return isolate->Throw<Object>(error);
1934    }
1935  }
1936
1937  if (object->HasFastProperties()) {
1938    AddFastProperty(object, name, value, attributes, store_mode,
1939                    value_type, transition_flag);
1940  }
1941
1942  if (!object->HasFastProperties()) {
1943    AddSlowProperty(object, name, value, attributes);
1944  }
1945
1946  if (object->map()->is_observed() &&
1947      *name != isolate->heap()->hidden_string()) {
1948    Handle<Object> old_value = isolate->factory()->the_hole_value();
1949    EnqueueChangeRecord(object, "add", name, old_value);
1950  }
1951
1952  return value;
1953}
1954
1955
1956Context* JSObject::GetCreationContext() {
1957  Object* constructor = this->map()->constructor();
1958  JSFunction* function;
1959  if (!constructor->IsJSFunction()) {
1960    // Functions have null as a constructor,
1961    // but any JSFunction knows its context immediately.
1962    function = JSFunction::cast(this);
1963  } else {
1964    function = JSFunction::cast(constructor);
1965  }
1966
1967  return function->context()->native_context();
1968}
1969
1970
1971void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
1972                                   const char* type_str,
1973                                   Handle<Name> name,
1974                                   Handle<Object> old_value) {
1975  ASSERT(!object->IsJSGlobalProxy());
1976  ASSERT(!object->IsJSGlobalObject());
1977  Isolate* isolate = object->GetIsolate();
1978  HandleScope scope(isolate);
1979  Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
1980  Handle<Object> args[] = { type, object, name, old_value };
1981  int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
1982
1983  Execution::Call(isolate,
1984                  Handle<JSFunction>(isolate->observers_notify_change()),
1985                  isolate->factory()->undefined_value(),
1986                  argc, args).Assert();
1987}
1988
1989
1990MaybeHandle<Object> JSObject::SetPropertyPostInterceptor(
1991    Handle<JSObject> object,
1992    Handle<Name> name,
1993    Handle<Object> value,
1994    PropertyAttributes attributes,
1995    StrictMode strict_mode) {
1996  // Check own property, ignore interceptor.
1997  Isolate* isolate = object->GetIsolate();
1998  LookupResult result(isolate);
1999  object->LookupOwnRealNamedProperty(name, &result);
2000  if (!result.IsFound()) {
2001    object->map()->LookupTransition(*object, *name, &result);
2002  }
2003  return SetPropertyForResult(object, &result, name, value, attributes,
2004                              strict_mode, MAY_BE_STORE_FROM_KEYED);
2005}
2006
2007
2008static void ReplaceSlowProperty(Handle<JSObject> object,
2009                                Handle<Name> name,
2010                                Handle<Object> value,
2011                                PropertyAttributes attributes) {
2012  NameDictionary* dictionary = object->property_dictionary();
2013  int old_index = dictionary->FindEntry(name);
2014  int new_enumeration_index = 0;  // 0 means "Use the next available index."
2015  if (old_index != -1) {
2016    // All calls to ReplaceSlowProperty have had all transitions removed.
2017    new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index();
2018  }
2019
2020  PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
2021  JSObject::SetNormalizedProperty(object, name, value, new_details);
2022}
2023
2024
2025const char* Representation::Mnemonic() const {
2026  switch (kind_) {
2027    case kNone: return "v";
2028    case kTagged: return "t";
2029    case kSmi: return "s";
2030    case kDouble: return "d";
2031    case kInteger32: return "i";
2032    case kHeapObject: return "h";
2033    case kExternal: return "x";
2034    default:
2035      UNREACHABLE();
2036      return NULL;
2037  }
2038}
2039
2040
2041static void ZapEndOfFixedArray(Address new_end, int to_trim) {
2042  // If we are doing a big trim in old space then we zap the space.
2043  Object** zap = reinterpret_cast<Object**>(new_end);
2044  zap++;  // Header of filler must be at least one word so skip that.
2045  for (int i = 1; i < to_trim; i++) {
2046    *zap++ = Smi::FromInt(0);
2047  }
2048}
2049
2050
2051template<Heap::InvocationMode mode>
2052static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
2053  ASSERT(elms->map() != heap->fixed_cow_array_map());
2054  // For now this trick is only applied to fixed arrays in new and paged space.
2055  ASSERT(!heap->lo_space()->Contains(elms));
2056
2057  const int len = elms->length();
2058
2059  ASSERT(to_trim < len);
2060
2061  Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
2062
2063  if (mode != Heap::FROM_GC || Heap::ShouldZapGarbage()) {
2064    ZapEndOfFixedArray(new_end, to_trim);
2065  }
2066
2067  int size_delta = to_trim * kPointerSize;
2068
2069  // Technically in new space this write might be omitted (except for
2070  // debug mode which iterates through the heap), but to play safer
2071  // we still do it.
2072  heap->CreateFillerObjectAt(new_end, size_delta);
2073
2074  // We are storing the new length using release store after creating a filler
2075  // for the left-over space to avoid races with the sweeper thread.
2076  elms->synchronized_set_length(len - to_trim);
2077
2078  heap->AdjustLiveBytes(elms->address(), -size_delta, mode);
2079
2080  // The array may not be moved during GC,
2081  // and size has to be adjusted nevertheless.
2082  HeapProfiler* profiler = heap->isolate()->heap_profiler();
2083  if (profiler->is_tracking_allocations()) {
2084    profiler->UpdateObjectSizeEvent(elms->address(), elms->Size());
2085  }
2086}
2087
2088
2089bool Map::InstancesNeedRewriting(Map* target,
2090                                 int target_number_of_fields,
2091                                 int target_inobject,
2092                                 int target_unused) {
2093  // If fields were added (or removed), rewrite the instance.
2094  int number_of_fields = NumberOfFields();
2095  ASSERT(target_number_of_fields >= number_of_fields);
2096  if (target_number_of_fields != number_of_fields) return true;
2097
2098  // If smi descriptors were replaced by double descriptors, rewrite.
2099  DescriptorArray* old_desc = instance_descriptors();
2100  DescriptorArray* new_desc = target->instance_descriptors();
2101  int limit = NumberOfOwnDescriptors();
2102  for (int i = 0; i < limit; i++) {
2103    if (new_desc->GetDetails(i).representation().IsDouble() &&
2104        !old_desc->GetDetails(i).representation().IsDouble()) {
2105      return true;
2106    }
2107  }
2108
2109  // If no fields were added, and no inobject properties were removed, setting
2110  // the map is sufficient.
2111  if (target_inobject == inobject_properties()) return false;
2112  // In-object slack tracking may have reduced the object size of the new map.
2113  // In that case, succeed if all existing fields were inobject, and they still
2114  // fit within the new inobject size.
2115  ASSERT(target_inobject < inobject_properties());
2116  if (target_number_of_fields <= target_inobject) {
2117    ASSERT(target_number_of_fields + target_unused == target_inobject);
2118    return false;
2119  }
2120  // Otherwise, properties will need to be moved to the backing store.
2121  return true;
2122}
2123
2124
2125Handle<TransitionArray> Map::SetElementsTransitionMap(
2126    Handle<Map> map, Handle<Map> transitioned_map) {
2127  Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
2128      map,
2129      map->GetIsolate()->factory()->elements_transition_symbol(),
2130      transitioned_map,
2131      FULL_TRANSITION);
2132  map->set_transitions(*transitions);
2133  return transitions;
2134}
2135
2136
2137// To migrate an instance to a map:
2138// - First check whether the instance needs to be rewritten. If not, simply
2139//   change the map.
2140// - Otherwise, allocate a fixed array large enough to hold all fields, in
2141//   addition to unused space.
2142// - Copy all existing properties in, in the following order: backing store
2143//   properties, unused fields, inobject properties.
2144// - If all allocation succeeded, commit the state atomically:
2145//   * Copy inobject properties from the backing store back into the object.
2146//   * Trim the difference in instance size of the object. This also cleanly
2147//     frees inobject properties that moved to the backing store.
2148//   * If there are properties left in the backing store, trim of the space used
2149//     to temporarily store the inobject properties.
2150//   * If there are properties left in the backing store, install the backing
2151//     store.
2152void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
2153  Isolate* isolate = object->GetIsolate();
2154  Handle<Map> old_map(object->map());
2155  int number_of_fields = new_map->NumberOfFields();
2156  int inobject = new_map->inobject_properties();
2157  int unused = new_map->unused_property_fields();
2158
2159  // Nothing to do if no functions were converted to fields and no smis were
2160  // converted to doubles.
2161  if (!old_map->InstancesNeedRewriting(
2162          *new_map, number_of_fields, inobject, unused)) {
2163    // Writing the new map here does not require synchronization since it does
2164    // not change the actual object size.
2165    object->synchronized_set_map(*new_map);
2166    return;
2167  }
2168
2169  int total_size = number_of_fields + unused;
2170  int external = total_size - inobject;
2171  Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
2172
2173  Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
2174  Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
2175  int old_nof = old_map->NumberOfOwnDescriptors();
2176  int new_nof = new_map->NumberOfOwnDescriptors();
2177
2178  // This method only supports generalizing instances to at least the same
2179  // number of properties.
2180  ASSERT(old_nof <= new_nof);
2181
2182  for (int i = 0; i < old_nof; i++) {
2183    PropertyDetails details = new_descriptors->GetDetails(i);
2184    if (details.type() != FIELD) continue;
2185    PropertyDetails old_details = old_descriptors->GetDetails(i);
2186    if (old_details.type() == CALLBACKS) {
2187      ASSERT(details.representation().IsTagged());
2188      continue;
2189    }
2190    ASSERT(old_details.type() == CONSTANT ||
2191           old_details.type() == FIELD);
2192    Object* raw_value = old_details.type() == CONSTANT
2193        ? old_descriptors->GetValue(i)
2194        : object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i));
2195    Handle<Object> value(raw_value, isolate);
2196    if (!old_details.representation().IsDouble() &&
2197        details.representation().IsDouble()) {
2198      if (old_details.representation().IsNone()) {
2199        value = handle(Smi::FromInt(0), isolate);
2200      }
2201      value = Object::NewStorageFor(isolate, value, details.representation());
2202    }
2203    ASSERT(!(details.representation().IsDouble() && value->IsSmi()));
2204    int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2205    if (target_index < 0) target_index += total_size;
2206    array->set(target_index, *value);
2207  }
2208
2209  for (int i = old_nof; i < new_nof; i++) {
2210    PropertyDetails details = new_descriptors->GetDetails(i);
2211    if (details.type() != FIELD) continue;
2212    Handle<Object> value;
2213    if (details.representation().IsDouble()) {
2214      value = isolate->factory()->NewHeapNumber(0);
2215    } else {
2216      value = isolate->factory()->uninitialized_value();
2217    }
2218    int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2219    if (target_index < 0) target_index += total_size;
2220    array->set(target_index, *value);
2221  }
2222
2223  // From here on we cannot fail and we shouldn't GC anymore.
2224  DisallowHeapAllocation no_allocation;
2225
2226  // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2227  // avoid overwriting |one_pointer_filler_map|.
2228  int limit = Min(inobject, number_of_fields);
2229  for (int i = 0; i < limit; i++) {
2230    FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
2231    object->FastPropertyAtPut(index, array->get(external + i));
2232  }
2233
2234  // Create filler object past the new instance size.
2235  int new_instance_size = new_map->instance_size();
2236  int instance_size_delta = old_map->instance_size() - new_instance_size;
2237  ASSERT(instance_size_delta >= 0);
2238  Address address = object->address() + new_instance_size;
2239
2240  // The trimming is performed on a newly allocated object, which is on a
2241  // fresly allocated page or on an already swept page. Hence, the sweeper
2242  // thread can not get confused with the filler creation. No synchronization
2243  // needed.
2244  isolate->heap()->CreateFillerObjectAt(address, instance_size_delta);
2245
2246  // If there are properties in the new backing store, trim it to the correct
2247  // size and install the backing store into the object.
2248  if (external > 0) {
2249    RightTrimFixedArray<Heap::FROM_MUTATOR>(isolate->heap(), *array, inobject);
2250    object->set_properties(*array);
2251  }
2252
2253  // The trimming is performed on a newly allocated object, which is on a
2254  // fresly allocated page or on an already swept page. Hence, the sweeper
2255  // thread can not get confused with the filler creation. No synchronization
2256  // needed.
2257  object->set_map(*new_map);
2258}
2259
2260
2261void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
2262                                             int modify_index,
2263                                             Representation new_representation,
2264                                             Handle<HeapType> new_field_type,
2265                                             StoreMode store_mode) {
2266  Handle<Map> new_map = Map::GeneralizeRepresentation(
2267      handle(object->map()), modify_index, new_representation,
2268      new_field_type, store_mode);
2269  if (object->map() == *new_map) return;
2270  return MigrateToMap(object, new_map);
2271}
2272
2273
2274int Map::NumberOfFields() {
2275  DescriptorArray* descriptors = instance_descriptors();
2276  int result = 0;
2277  for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
2278    if (descriptors->GetDetails(i).type() == FIELD) result++;
2279  }
2280  return result;
2281}
2282
2283
2284Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2285                                                  int modify_index,
2286                                                  StoreMode store_mode,
2287                                                  PropertyAttributes attributes,
2288                                                  const char* reason) {
2289  Isolate* isolate = map->GetIsolate();
2290  Handle<Map> new_map = Copy(map);
2291
2292  DescriptorArray* descriptors = new_map->instance_descriptors();
2293  int length = descriptors->number_of_descriptors();
2294  for (int i = 0; i < length; i++) {
2295    descriptors->SetRepresentation(i, Representation::Tagged());
2296    if (descriptors->GetDetails(i).type() == FIELD) {
2297      descriptors->SetValue(i, HeapType::Any());
2298    }
2299  }
2300
2301  // Unless the instance is being migrated, ensure that modify_index is a field.
2302  PropertyDetails details = descriptors->GetDetails(modify_index);
2303  if (store_mode == FORCE_FIELD && details.type() != FIELD) {
2304    FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
2305                      new_map->NumberOfFields(),
2306                      attributes,
2307                      Representation::Tagged());
2308    descriptors->Replace(modify_index, &d);
2309    int unused_property_fields = new_map->unused_property_fields() - 1;
2310    if (unused_property_fields < 0) {
2311      unused_property_fields += JSObject::kFieldsAdded;
2312    }
2313    new_map->set_unused_property_fields(unused_property_fields);
2314  }
2315
2316  if (FLAG_trace_generalization) {
2317    HeapType* field_type = (details.type() == FIELD)
2318        ? map->instance_descriptors()->GetFieldType(modify_index)
2319        : NULL;
2320    map->PrintGeneralization(stdout, reason, modify_index,
2321                        new_map->NumberOfOwnDescriptors(),
2322                        new_map->NumberOfOwnDescriptors(),
2323                        details.type() == CONSTANT && store_mode == FORCE_FIELD,
2324                        details.representation(), Representation::Tagged(),
2325                        field_type, HeapType::Any());
2326  }
2327  return new_map;
2328}
2329
2330
2331// static
2332Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2333                                                  int modify_index,
2334                                                  StoreMode store_mode,
2335                                                  const char* reason) {
2336  PropertyDetails details =
2337      map->instance_descriptors()->GetDetails(modify_index);
2338  return CopyGeneralizeAllRepresentations(map, modify_index, store_mode,
2339                                          details.attributes(), reason);
2340}
2341
2342
2343void Map::DeprecateTransitionTree() {
2344  if (is_deprecated()) return;
2345  if (HasTransitionArray()) {
2346    TransitionArray* transitions = this->transitions();
2347    for (int i = 0; i < transitions->number_of_transitions(); i++) {
2348      transitions->GetTarget(i)->DeprecateTransitionTree();
2349    }
2350  }
2351  deprecate();
2352  dependent_code()->DeoptimizeDependentCodeGroup(
2353      GetIsolate(), DependentCode::kTransitionGroup);
2354  NotifyLeafMapLayoutChange();
2355}
2356
2357
2358// Invalidates a transition target at |key|, and installs |new_descriptors| over
2359// the current instance_descriptors to ensure proper sharing of descriptor
2360// arrays.
2361void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
2362  if (HasTransitionArray()) {
2363    TransitionArray* transitions = this->transitions();
2364    int transition = transitions->Search(key);
2365    if (transition != TransitionArray::kNotFound) {
2366      transitions->GetTarget(transition)->DeprecateTransitionTree();
2367    }
2368  }
2369
2370  // Don't overwrite the empty descriptor array.
2371  if (NumberOfOwnDescriptors() == 0) return;
2372
2373  DescriptorArray* to_replace = instance_descriptors();
2374  Map* current = this;
2375  GetHeap()->incremental_marking()->RecordWrites(to_replace);
2376  while (current->instance_descriptors() == to_replace) {
2377    current->SetEnumLength(kInvalidEnumCacheSentinel);
2378    current->set_instance_descriptors(new_descriptors);
2379    Object* next = current->GetBackPointer();
2380    if (next->IsUndefined()) break;
2381    current = Map::cast(next);
2382  }
2383
2384  set_owns_descriptors(false);
2385}
2386
2387
2388Map* Map::FindRootMap() {
2389  Map* result = this;
2390  while (true) {
2391    Object* back = result->GetBackPointer();
2392    if (back->IsUndefined()) return result;
2393    result = Map::cast(back);
2394  }
2395}
2396
2397
2398Map* Map::FindLastMatchMap(int verbatim,
2399                           int length,
2400                           DescriptorArray* descriptors) {
2401  DisallowHeapAllocation no_allocation;
2402
2403  // This can only be called on roots of transition trees.
2404  ASSERT(GetBackPointer()->IsUndefined());
2405
2406  Map* current = this;
2407
2408  for (int i = verbatim; i < length; i++) {
2409    if (!current->HasTransitionArray()) break;
2410    Name* name = descriptors->GetKey(i);
2411    TransitionArray* transitions = current->transitions();
2412    int transition = transitions->Search(name);
2413    if (transition == TransitionArray::kNotFound) break;
2414
2415    Map* next = transitions->GetTarget(transition);
2416    DescriptorArray* next_descriptors = next->instance_descriptors();
2417
2418    PropertyDetails details = descriptors->GetDetails(i);
2419    PropertyDetails next_details = next_descriptors->GetDetails(i);
2420    if (details.type() != next_details.type()) break;
2421    if (details.attributes() != next_details.attributes()) break;
2422    if (!details.representation().Equals(next_details.representation())) break;
2423    if (next_details.type() == FIELD) {
2424      if (!descriptors->GetFieldType(i)->NowIs(
2425              next_descriptors->GetFieldType(i))) break;
2426    } else {
2427      if (descriptors->GetValue(i) != next_descriptors->GetValue(i)) break;
2428    }
2429
2430    current = next;
2431  }
2432  return current;
2433}
2434
2435
2436Map* Map::FindFieldOwner(int descriptor) {
2437  DisallowHeapAllocation no_allocation;
2438  ASSERT_EQ(FIELD, instance_descriptors()->GetDetails(descriptor).type());
2439  Map* result = this;
2440  while (true) {
2441    Object* back = result->GetBackPointer();
2442    if (back->IsUndefined()) break;
2443    Map* parent = Map::cast(back);
2444    if (parent->NumberOfOwnDescriptors() <= descriptor) break;
2445    result = parent;
2446  }
2447  return result;
2448}
2449
2450
2451void Map::UpdateDescriptor(int descriptor_number, Descriptor* desc) {
2452  DisallowHeapAllocation no_allocation;
2453  if (HasTransitionArray()) {
2454    TransitionArray* transitions = this->transitions();
2455    for (int i = 0; i < transitions->number_of_transitions(); ++i) {
2456      transitions->GetTarget(i)->UpdateDescriptor(descriptor_number, desc);
2457    }
2458  }
2459  instance_descriptors()->Replace(descriptor_number, desc);;
2460}
2461
2462
2463// static
2464Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> type1,
2465                                          Handle<HeapType> type2,
2466                                          Isolate* isolate) {
2467  static const int kMaxClassesPerFieldType = 5;
2468  if (type1->NowIs(type2)) return type2;
2469  if (type2->NowIs(type1)) return type1;
2470  if (type1->NowStable() && type2->NowStable()) {
2471    Handle<HeapType> type = HeapType::Union(type1, type2, isolate);
2472    if (type->NumClasses() <= kMaxClassesPerFieldType) {
2473      ASSERT(type->NowStable());
2474      ASSERT(type1->NowIs(type));
2475      ASSERT(type2->NowIs(type));
2476      return type;
2477    }
2478  }
2479  return HeapType::Any(isolate);
2480}
2481
2482
2483// static
2484void Map::GeneralizeFieldType(Handle<Map> map,
2485                              int modify_index,
2486                              Handle<HeapType> new_field_type) {
2487  Isolate* isolate = map->GetIsolate();
2488
2489  // Check if we actually need to generalize the field type at all.
2490  Handle<HeapType> old_field_type(
2491      map->instance_descriptors()->GetFieldType(modify_index), isolate);
2492  if (new_field_type->NowIs(old_field_type)) {
2493    ASSERT(Map::GeneralizeFieldType(old_field_type,
2494                                    new_field_type,
2495                                    isolate)->NowIs(old_field_type));
2496    return;
2497  }
2498
2499  // Determine the field owner.
2500  Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
2501  Handle<DescriptorArray> descriptors(
2502      field_owner->instance_descriptors(), isolate);
2503  ASSERT_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
2504
2505  // Determine the generalized new field type.
2506  new_field_type = Map::GeneralizeFieldType(
2507      old_field_type, new_field_type, isolate);
2508
2509  PropertyDetails details = descriptors->GetDetails(modify_index);
2510  FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
2511                    descriptors->GetFieldIndex(modify_index),
2512                    new_field_type,
2513                    details.attributes(),
2514                    details.representation());
2515  field_owner->UpdateDescriptor(modify_index, &d);
2516  field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
2517      isolate, DependentCode::kFieldTypeGroup);
2518
2519  if (FLAG_trace_generalization) {
2520    map->PrintGeneralization(
2521        stdout, "field type generalization",
2522        modify_index, map->NumberOfOwnDescriptors(),
2523        map->NumberOfOwnDescriptors(), false,
2524        details.representation(), details.representation(),
2525        *old_field_type, *new_field_type);
2526  }
2527}
2528
2529
2530// Generalize the representation of the descriptor at |modify_index|.
2531// This method rewrites the transition tree to reflect the new change. To avoid
2532// high degrees over polymorphism, and to stabilize quickly, on every rewrite
2533// the new type is deduced by merging the current type with any potential new
2534// (partial) version of the type in the transition tree.
2535// To do this, on each rewrite:
2536// - Search the root of the transition tree using FindRootMap.
2537// - Find |target_map|, the newest matching version of this map using the keys
2538//   in the |old_map|'s descriptor array to walk the transition tree.
2539// - Merge/generalize the descriptor array of the |old_map| and |target_map|.
2540// - Generalize the |modify_index| descriptor using |new_representation| and
2541//   |new_field_type|.
2542// - Walk the tree again starting from the root towards |target_map|. Stop at
2543//   |split_map|, the first map who's descriptor array does not match the merged
2544//   descriptor array.
2545// - If |target_map| == |split_map|, |target_map| is in the expected state.
2546//   Return it.
2547// - Otherwise, invalidate the outdated transition target from |target_map|, and
2548//   replace its transition tree with a new branch for the updated descriptors.
2549Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
2550                                          int modify_index,
2551                                          Representation new_representation,
2552                                          Handle<HeapType> new_field_type,
2553                                          StoreMode store_mode) {
2554  Isolate* isolate = old_map->GetIsolate();
2555
2556  Handle<DescriptorArray> old_descriptors(
2557      old_map->instance_descriptors(), isolate);
2558  int old_nof = old_map->NumberOfOwnDescriptors();
2559  PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2560  Representation old_representation = old_details.representation();
2561
2562  // It's fine to transition from None to anything but double without any
2563  // modification to the object, because the default uninitialized value for
2564  // representation None can be overwritten by both smi and tagged values.
2565  // Doubles, however, would require a box allocation.
2566  if (old_representation.IsNone() &&
2567      !new_representation.IsNone() &&
2568      !new_representation.IsDouble()) {
2569    ASSERT(old_details.type() == FIELD);
2570    ASSERT(old_descriptors->GetFieldType(modify_index)->NowIs(
2571            HeapType::None()));
2572    if (FLAG_trace_generalization) {
2573      old_map->PrintGeneralization(
2574          stdout, "uninitialized field",
2575          modify_index, old_map->NumberOfOwnDescriptors(),
2576          old_map->NumberOfOwnDescriptors(), false,
2577          old_representation, new_representation,
2578          old_descriptors->GetFieldType(modify_index), *new_field_type);
2579    }
2580    old_descriptors->SetRepresentation(modify_index, new_representation);
2581    old_descriptors->SetValue(modify_index, *new_field_type);
2582    return old_map;
2583  }
2584
2585  // Check the state of the root map.
2586  Handle<Map> root_map(old_map->FindRootMap(), isolate);
2587  if (!old_map->EquivalentToForTransition(*root_map)) {
2588    return CopyGeneralizeAllRepresentations(
2589        old_map, modify_index, store_mode, "not equivalent");
2590  }
2591  int root_nof = root_map->NumberOfOwnDescriptors();
2592  if (modify_index < root_nof) {
2593    PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2594    if ((old_details.type() != FIELD && store_mode == FORCE_FIELD) ||
2595        (old_details.type() == FIELD &&
2596         (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
2597          !new_representation.fits_into(old_details.representation())))) {
2598      return CopyGeneralizeAllRepresentations(
2599          old_map, modify_index, store_mode, "root modification");
2600    }
2601  }
2602
2603  Handle<Map> target_map = root_map;
2604  for (int i = root_nof; i < old_nof; ++i) {
2605    int j = target_map->SearchTransition(old_descriptors->GetKey(i));
2606    if (j == TransitionArray::kNotFound) break;
2607    Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2608    Handle<DescriptorArray> tmp_descriptors = handle(
2609        tmp_map->instance_descriptors(), isolate);
2610
2611    // Check if target map is incompatible.
2612    PropertyDetails old_details = old_descriptors->GetDetails(i);
2613    PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
2614    PropertyType old_type = old_details.type();
2615    PropertyType tmp_type = tmp_details.type();
2616    if (tmp_details.attributes() != old_details.attributes() ||
2617        ((tmp_type == CALLBACKS || old_type == CALLBACKS) &&
2618         (tmp_type != old_type ||
2619          tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
2620      return CopyGeneralizeAllRepresentations(
2621          old_map, modify_index, store_mode, "incompatible");
2622    }
2623    Representation old_representation = old_details.representation();
2624    Representation tmp_representation = tmp_details.representation();
2625    if (!old_representation.fits_into(tmp_representation) ||
2626        (!new_representation.fits_into(tmp_representation) &&
2627         modify_index == i)) {
2628      break;
2629    }
2630    if (tmp_type == FIELD) {
2631      // Generalize the field type as necessary.
2632      Handle<HeapType> old_field_type = (old_type == FIELD)
2633          ? handle(old_descriptors->GetFieldType(i), isolate)
2634          : old_descriptors->GetValue(i)->OptimalType(
2635              isolate, tmp_representation);
2636      if (modify_index == i) {
2637        old_field_type = GeneralizeFieldType(
2638            new_field_type, old_field_type, isolate);
2639      }
2640      GeneralizeFieldType(tmp_map, i, old_field_type);
2641    } else if (tmp_type == CONSTANT) {
2642      if (old_type != CONSTANT ||
2643          old_descriptors->GetConstant(i) != tmp_descriptors->GetConstant(i)) {
2644        break;
2645      }
2646    } else {
2647      ASSERT_EQ(tmp_type, old_type);
2648      ASSERT_EQ(tmp_descriptors->GetValue(i), old_descriptors->GetValue(i));
2649    }
2650    target_map = tmp_map;
2651  }
2652
2653  // Directly change the map if the target map is more general.
2654  Handle<DescriptorArray> target_descriptors(
2655      target_map->instance_descriptors(), isolate);
2656  int target_nof = target_map->NumberOfOwnDescriptors();
2657  if (target_nof == old_nof &&
2658      (store_mode != FORCE_FIELD ||
2659       target_descriptors->GetDetails(modify_index).type() == FIELD)) {
2660    ASSERT(modify_index < target_nof);
2661    ASSERT(new_representation.fits_into(
2662            target_descriptors->GetDetails(modify_index).representation()));
2663    ASSERT(target_descriptors->GetDetails(modify_index).type() != FIELD ||
2664           new_field_type->NowIs(
2665               target_descriptors->GetFieldType(modify_index)));
2666    return target_map;
2667  }
2668
2669  // Find the last compatible target map in the transition tree.
2670  for (int i = target_nof; i < old_nof; ++i) {
2671    int j = target_map->SearchTransition(old_descriptors->GetKey(i));
2672    if (j == TransitionArray::kNotFound) break;
2673    Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2674    Handle<DescriptorArray> tmp_descriptors(
2675        tmp_map->instance_descriptors(), isolate);
2676
2677    // Check if target map is compatible.
2678    PropertyDetails old_details = old_descriptors->GetDetails(i);
2679    PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
2680    if (tmp_details.attributes() != old_details.attributes() ||
2681        ((tmp_details.type() == CALLBACKS || old_details.type() == CALLBACKS) &&
2682         (tmp_details.type() != old_details.type() ||
2683          tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
2684      return CopyGeneralizeAllRepresentations(
2685          old_map, modify_index, store_mode, "incompatible");
2686    }
2687    target_map = tmp_map;
2688  }
2689  target_nof = target_map->NumberOfOwnDescriptors();
2690  target_descriptors = handle(target_map->instance_descriptors(), isolate);
2691
2692  // Allocate a new descriptor array large enough to hold the required
2693  // descriptors, with minimally the exact same size as the old descriptor
2694  // array.
2695  int new_slack = Max(
2696      old_nof, old_descriptors->number_of_descriptors()) - old_nof;
2697  Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
2698      isolate, old_nof, new_slack);
2699  ASSERT(new_descriptors->length() > target_descriptors->length() ||
2700         new_descriptors->NumberOfSlackDescriptors() > 0 ||
2701         new_descriptors->number_of_descriptors() ==
2702         old_descriptors->number_of_descriptors());
2703  ASSERT(new_descriptors->number_of_descriptors() == old_nof);
2704
2705  // 0 -> |root_nof|
2706  int current_offset = 0;
2707  for (int i = 0; i < root_nof; ++i) {
2708    PropertyDetails old_details = old_descriptors->GetDetails(i);
2709    if (old_details.type() == FIELD) current_offset++;
2710    Descriptor d(handle(old_descriptors->GetKey(i), isolate),
2711                 handle(old_descriptors->GetValue(i), isolate),
2712                 old_details);
2713    new_descriptors->Set(i, &d);
2714  }
2715
2716  // |root_nof| -> |target_nof|
2717  for (int i = root_nof; i < target_nof; ++i) {
2718    Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
2719    PropertyDetails old_details = old_descriptors->GetDetails(i);
2720    PropertyDetails target_details = target_descriptors->GetDetails(i);
2721    target_details = target_details.CopyWithRepresentation(
2722        old_details.representation().generalize(
2723            target_details.representation()));
2724    if (modify_index == i) {
2725      target_details = target_details.CopyWithRepresentation(
2726          new_representation.generalize(target_details.representation()));
2727    }
2728    ASSERT_EQ(old_details.attributes(), target_details.attributes());
2729    if (old_details.type() == FIELD ||
2730        target_details.type() == FIELD ||
2731        (modify_index == i && store_mode == FORCE_FIELD) ||
2732        (target_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
2733      Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2734          ? handle(old_descriptors->GetFieldType(i), isolate)
2735          : old_descriptors->GetValue(i)->OptimalType(
2736              isolate, target_details.representation());
2737      Handle<HeapType> target_field_type = (target_details.type() == FIELD)
2738          ? handle(target_descriptors->GetFieldType(i), isolate)
2739          : target_descriptors->GetValue(i)->OptimalType(
2740              isolate, target_details.representation());
2741      target_field_type = GeneralizeFieldType(
2742          target_field_type, old_field_type, isolate);
2743      if (modify_index == i) {
2744        target_field_type = GeneralizeFieldType(
2745            target_field_type, new_field_type, isolate);
2746      }
2747      FieldDescriptor d(target_key,
2748                        current_offset++,
2749                        target_field_type,
2750                        target_details.attributes(),
2751                        target_details.representation());
2752      new_descriptors->Set(i, &d);
2753    } else {
2754      ASSERT_NE(FIELD, target_details.type());
2755      Descriptor d(target_key,
2756                   handle(target_descriptors->GetValue(i), isolate),
2757                   target_details);
2758      new_descriptors->Set(i, &d);
2759    }
2760  }
2761
2762  // |target_nof| -> |old_nof|
2763  for (int i = target_nof; i < old_nof; ++i) {
2764    PropertyDetails old_details = old_descriptors->GetDetails(i);
2765    Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
2766    if (modify_index == i) {
2767      old_details = old_details.CopyWithRepresentation(
2768          new_representation.generalize(old_details.representation()));
2769    }
2770    if (old_details.type() == FIELD) {
2771      Handle<HeapType> old_field_type(
2772          old_descriptors->GetFieldType(i), isolate);
2773      if (modify_index == i) {
2774        old_field_type = GeneralizeFieldType(
2775            old_field_type, new_field_type, isolate);
2776      }
2777      FieldDescriptor d(old_key,
2778                        current_offset++,
2779                        old_field_type,
2780                        old_details.attributes(),
2781                        old_details.representation());
2782      new_descriptors->Set(i, &d);
2783    } else {
2784      ASSERT(old_details.type() == CONSTANT || old_details.type() == CALLBACKS);
2785      if (modify_index == i && store_mode == FORCE_FIELD) {
2786        FieldDescriptor d(old_key,
2787                          current_offset++,
2788                          GeneralizeFieldType(
2789                              old_descriptors->GetValue(i)->OptimalType(
2790                                  isolate, old_details.representation()),
2791                              new_field_type, isolate),
2792                          old_details.attributes(),
2793                          old_details.representation());
2794        new_descriptors->Set(i, &d);
2795      } else {
2796        ASSERT_NE(FIELD, old_details.type());
2797        Descriptor d(old_key,
2798                     handle(old_descriptors->GetValue(i), isolate),
2799                     old_details);
2800        new_descriptors->Set(i, &d);
2801      }
2802    }
2803  }
2804
2805  new_descriptors->Sort();
2806
2807  ASSERT(store_mode != FORCE_FIELD ||
2808         new_descriptors->GetDetails(modify_index).type() == FIELD);
2809
2810  Handle<Map> split_map(root_map->FindLastMatchMap(
2811          root_nof, old_nof, *new_descriptors), isolate);
2812  int split_nof = split_map->NumberOfOwnDescriptors();
2813  ASSERT_NE(old_nof, split_nof);
2814
2815  split_map->DeprecateTarget(
2816      old_descriptors->GetKey(split_nof), *new_descriptors);
2817
2818  if (FLAG_trace_generalization) {
2819    PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2820    PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
2821    Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2822        ? handle(old_descriptors->GetFieldType(modify_index), isolate)
2823        : HeapType::Constant(handle(old_descriptors->GetValue(modify_index),
2824                                    isolate), isolate);
2825    Handle<HeapType> new_field_type = (new_details.type() == FIELD)
2826        ? handle(new_descriptors->GetFieldType(modify_index), isolate)
2827        : HeapType::Constant(handle(new_descriptors->GetValue(modify_index),
2828                                    isolate), isolate);
2829    old_map->PrintGeneralization(
2830        stdout, "", modify_index, split_nof, old_nof,
2831        old_details.type() == CONSTANT && store_mode == FORCE_FIELD,
2832        old_details.representation(), new_details.representation(),
2833        *old_field_type, *new_field_type);
2834  }
2835
2836  // Add missing transitions.
2837  Handle<Map> new_map = split_map;
2838  for (int i = split_nof; i < old_nof; ++i) {
2839    new_map = CopyInstallDescriptors(new_map, i, new_descriptors);
2840  }
2841  new_map->set_owns_descriptors(true);
2842  return new_map;
2843}
2844
2845
2846// Generalize the representation of all FIELD descriptors.
2847Handle<Map> Map::GeneralizeAllFieldRepresentations(
2848    Handle<Map> map) {
2849  Handle<DescriptorArray> descriptors(map->instance_descriptors());
2850  for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
2851    if (descriptors->GetDetails(i).type() == FIELD) {
2852      map = GeneralizeRepresentation(map, i, Representation::Tagged(),
2853                                     HeapType::Any(map->GetIsolate()),
2854                                     FORCE_FIELD);
2855    }
2856  }
2857  return map;
2858}
2859
2860
2861// static
2862MaybeHandle<Map> Map::CurrentMapForDeprecated(Handle<Map> map) {
2863  Handle<Map> proto_map(map);
2864  while (proto_map->prototype()->IsJSObject()) {
2865    Handle<JSObject> holder(JSObject::cast(proto_map->prototype()));
2866    proto_map = Handle<Map>(holder->map());
2867    if (proto_map->is_deprecated() && JSObject::TryMigrateInstance(holder)) {
2868      proto_map = Handle<Map>(holder->map());
2869    }
2870  }
2871  return CurrentMapForDeprecatedInternal(map);
2872}
2873
2874
2875// static
2876MaybeHandle<Map> Map::CurrentMapForDeprecatedInternal(Handle<Map> old_map) {
2877  DisallowHeapAllocation no_allocation;
2878  DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
2879
2880  if (!old_map->is_deprecated()) return old_map;
2881
2882  // Check the state of the root map.
2883  Map* root_map = old_map->FindRootMap();
2884  if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
2885  int root_nof = root_map->NumberOfOwnDescriptors();
2886
2887  int old_nof = old_map->NumberOfOwnDescriptors();
2888  DescriptorArray* old_descriptors = old_map->instance_descriptors();
2889
2890  Map* new_map = root_map;
2891  for (int i = root_nof; i < old_nof; ++i) {
2892    int j = new_map->SearchTransition(old_descriptors->GetKey(i));
2893    if (j == TransitionArray::kNotFound) return MaybeHandle<Map>();
2894    new_map = new_map->GetTransition(j);
2895    DescriptorArray* new_descriptors = new_map->instance_descriptors();
2896
2897    PropertyDetails new_details = new_descriptors->GetDetails(i);
2898    PropertyDetails old_details = old_descriptors->GetDetails(i);
2899    if (old_details.attributes() != new_details.attributes() ||
2900        !old_details.representation().fits_into(new_details.representation())) {
2901      return MaybeHandle<Map>();
2902    }
2903    PropertyType new_type = new_details.type();
2904    PropertyType old_type = old_details.type();
2905    Object* new_value = new_descriptors->GetValue(i);
2906    Object* old_value = old_descriptors->GetValue(i);
2907    switch (new_type) {
2908      case FIELD:
2909        if ((old_type == FIELD &&
2910             !HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) ||
2911            (old_type == CONSTANT &&
2912             !HeapType::cast(new_value)->NowContains(old_value)) ||
2913            (old_type == CALLBACKS &&
2914             !HeapType::Any()->Is(HeapType::cast(new_value)))) {
2915          return MaybeHandle<Map>();
2916        }
2917        break;
2918
2919      case CONSTANT:
2920      case CALLBACKS:
2921        if (old_type != new_type || old_value != new_value) {
2922          return MaybeHandle<Map>();
2923        }
2924        break;
2925
2926      case NORMAL:
2927      case HANDLER:
2928      case INTERCEPTOR:
2929      case NONEXISTENT:
2930        UNREACHABLE();
2931    }
2932  }
2933  if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
2934  return handle(new_map);
2935}
2936
2937
2938MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(
2939    Handle<JSObject> object,
2940    Handle<Name> name,
2941    Handle<Object> value,
2942    PropertyAttributes attributes,
2943    StrictMode strict_mode) {
2944  // TODO(rossberg): Support symbols in the API.
2945  if (name->IsSymbol()) return value;
2946  Isolate* isolate = object->GetIsolate();
2947  Handle<String> name_string = Handle<String>::cast(name);
2948  Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
2949  if (!interceptor->setter()->IsUndefined()) {
2950    LOG(isolate,
2951        ApiNamedPropertyAccess("interceptor-named-set", *object, *name));
2952    PropertyCallbackArguments args(
2953        isolate, interceptor->data(), *object, *object);
2954    v8::NamedPropertySetterCallback setter =
2955        v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
2956    Handle<Object> value_unhole = value->IsTheHole()
2957        ? Handle<Object>(isolate->factory()->undefined_value()) : value;
2958    v8::Handle<v8::Value> result = args.Call(setter,
2959                                             v8::Utils::ToLocal(name_string),
2960                                             v8::Utils::ToLocal(value_unhole));
2961    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
2962    if (!result.IsEmpty()) return value;
2963  }
2964  return SetPropertyPostInterceptor(
2965      object, name, value, attributes, strict_mode);
2966}
2967
2968
2969MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
2970                                            Handle<Name> name,
2971                                            Handle<Object> value,
2972                                            PropertyAttributes attributes,
2973                                            StrictMode strict_mode,
2974                                            StoreFromKeyed store_mode) {
2975  LookupResult result(object->GetIsolate());
2976  object->LookupOwn(name, &result, true);
2977  if (!result.IsFound()) {
2978    object->map()->LookupTransition(JSObject::cast(*object), *name, &result);
2979  }
2980  return SetProperty(object, &result, name, value, attributes, strict_mode,
2981                     store_mode);
2982}
2983
2984
2985MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
2986    Handle<JSObject> object,
2987    uint32_t index,
2988    Handle<Object> value,
2989    bool* found,
2990    StrictMode strict_mode) {
2991  Isolate *isolate = object->GetIsolate();
2992  for (Handle<Object> proto = handle(object->GetPrototype(), isolate);
2993       !proto->IsNull();
2994       proto = handle(proto->GetPrototype(isolate), isolate)) {
2995    if (proto->IsJSProxy()) {
2996      return JSProxy::SetPropertyViaPrototypesWithHandler(
2997          Handle<JSProxy>::cast(proto),
2998          object,
2999          isolate->factory()->Uint32ToString(index),  // name
3000          value,
3001          NONE,
3002          strict_mode,
3003          found);
3004    }
3005    Handle<JSObject> js_proto = Handle<JSObject>::cast(proto);
3006    if (!js_proto->HasDictionaryElements()) {
3007      continue;
3008    }
3009    Handle<SeededNumberDictionary> dictionary(js_proto->element_dictionary());
3010    int entry = dictionary->FindEntry(index);
3011    if (entry != SeededNumberDictionary::kNotFound) {
3012      PropertyDetails details = dictionary->DetailsAt(entry);
3013      if (details.type() == CALLBACKS) {
3014        *found = true;
3015        Handle<Object> structure(dictionary->ValueAt(entry), isolate);
3016        return SetElementWithCallback(object, structure, index, value, js_proto,
3017                                      strict_mode);
3018      }
3019    }
3020  }
3021  *found = false;
3022  return isolate->factory()->the_hole_value();
3023}
3024
3025
3026MaybeHandle<Object> JSObject::SetPropertyViaPrototypes(
3027    Handle<JSObject> object,
3028    Handle<Name> name,
3029    Handle<Object> value,
3030    PropertyAttributes attributes,
3031    StrictMode strict_mode,
3032    bool* done) {
3033  Isolate* isolate = object->GetIsolate();
3034
3035  *done = false;
3036  // We could not find an own property, so let's check whether there is an
3037  // accessor that wants to handle the property, or whether the property is
3038  // read-only on the prototype chain.
3039  LookupResult result(isolate);
3040  object->LookupRealNamedPropertyInPrototypes(name, &result);
3041  if (result.IsFound()) {
3042    switch (result.type()) {
3043      case NORMAL:
3044      case FIELD:
3045      case CONSTANT:
3046        *done = result.IsReadOnly();
3047        break;
3048      case INTERCEPTOR: {
3049        LookupIterator it(object, name, handle(result.holder()));
3050        PropertyAttributes attr = GetPropertyAttributes(&it);
3051        *done = !!(attr & READ_ONLY);
3052        break;
3053      }
3054      case CALLBACKS: {
3055        *done = true;
3056        if (!result.IsReadOnly()) {
3057          Handle<Object> callback_object(result.GetCallbackObject(), isolate);
3058          return SetPropertyWithCallback(object, name, value,
3059                                         handle(result.holder()),
3060                                         callback_object, strict_mode);
3061        }
3062        break;
3063      }
3064      case HANDLER: {
3065        Handle<JSProxy> proxy(result.proxy());
3066        return JSProxy::SetPropertyViaPrototypesWithHandler(
3067            proxy, object, name, value, attributes, strict_mode, done);
3068      }
3069      case NONEXISTENT:
3070        UNREACHABLE();
3071        break;
3072    }
3073  }
3074
3075  // If we get here with *done true, we have encountered a read-only property.
3076  if (*done) {
3077    if (strict_mode == SLOPPY) return value;
3078    Handle<Object> args[] = { name, object };
3079    Handle<Object> error = isolate->factory()->NewTypeError(
3080        "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
3081    return isolate->Throw<Object>(error);
3082  }
3083  return isolate->factory()->the_hole_value();
3084}
3085
3086
3087void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
3088  // Only supports adding slack to owned descriptors.
3089  ASSERT(map->owns_descriptors());
3090
3091  Handle<DescriptorArray> descriptors(map->instance_descriptors());
3092  int old_size = map->NumberOfOwnDescriptors();
3093  if (slack <= descriptors->NumberOfSlackDescriptors()) return;
3094
3095  Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
3096      descriptors, old_size, slack);
3097
3098  if (old_size == 0) {
3099    map->set_instance_descriptors(*new_descriptors);
3100    return;
3101  }
3102
3103  // If the source descriptors had an enum cache we copy it. This ensures
3104  // that the maps to which we push the new descriptor array back can rely
3105  // on a cache always being available once it is set. If the map has more
3106  // enumerated descriptors than available in the original cache, the cache
3107  // will be lazily replaced by the extended cache when needed.
3108  if (descriptors->HasEnumCache()) {
3109    new_descriptors->CopyEnumCacheFrom(*descriptors);
3110  }
3111
3112  // Replace descriptors by new_descriptors in all maps that share it.
3113  map->GetHeap()->incremental_marking()->RecordWrites(*descriptors);
3114
3115  Map* walk_map;
3116  for (Object* current = map->GetBackPointer();
3117       !current->IsUndefined();
3118       current = walk_map->GetBackPointer()) {
3119    walk_map = Map::cast(current);
3120    if (walk_map->instance_descriptors() != *descriptors) break;
3121    walk_map->set_instance_descriptors(*new_descriptors);
3122  }
3123
3124  map->set_instance_descriptors(*new_descriptors);
3125}
3126
3127
3128template<class T>
3129static int AppendUniqueCallbacks(NeanderArray* callbacks,
3130                                 Handle<typename T::Array> array,
3131                                 int valid_descriptors) {
3132  int nof_callbacks = callbacks->length();
3133
3134  Isolate* isolate = array->GetIsolate();
3135  // Ensure the keys are unique names before writing them into the
3136  // instance descriptor. Since it may cause a GC, it has to be done before we
3137  // temporarily put the heap in an invalid state while appending descriptors.
3138  for (int i = 0; i < nof_callbacks; ++i) {
3139    Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3140    if (entry->name()->IsUniqueName()) continue;
3141    Handle<String> key =
3142        isolate->factory()->InternalizeString(
3143            Handle<String>(String::cast(entry->name())));
3144    entry->set_name(*key);
3145  }
3146
3147  // Fill in new callback descriptors.  Process the callbacks from
3148  // back to front so that the last callback with a given name takes
3149  // precedence over previously added callbacks with that name.
3150  for (int i = nof_callbacks - 1; i >= 0; i--) {
3151    Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3152    Handle<Name> key(Name::cast(entry->name()));
3153    // Check if a descriptor with this name already exists before writing.
3154    if (!T::Contains(key, entry, valid_descriptors, array)) {
3155      T::Insert(key, entry, valid_descriptors, array);
3156      valid_descriptors++;
3157    }
3158  }
3159
3160  return valid_descriptors;
3161}
3162
3163struct DescriptorArrayAppender {
3164  typedef DescriptorArray Array;
3165  static bool Contains(Handle<Name> key,
3166                       Handle<AccessorInfo> entry,
3167                       int valid_descriptors,
3168                       Handle<DescriptorArray> array) {
3169    DisallowHeapAllocation no_gc;
3170    return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
3171  }
3172  static void Insert(Handle<Name> key,
3173                     Handle<AccessorInfo> entry,
3174                     int valid_descriptors,
3175                     Handle<DescriptorArray> array) {
3176    DisallowHeapAllocation no_gc;
3177    CallbacksDescriptor desc(key, entry, entry->property_attributes());
3178    array->Append(&desc);
3179  }
3180};
3181
3182
3183struct FixedArrayAppender {
3184  typedef FixedArray Array;
3185  static bool Contains(Handle<Name> key,
3186                       Handle<AccessorInfo> entry,
3187                       int valid_descriptors,
3188                       Handle<FixedArray> array) {
3189    for (int i = 0; i < valid_descriptors; i++) {
3190      if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
3191    }
3192    return false;
3193  }
3194  static void Insert(Handle<Name> key,
3195                     Handle<AccessorInfo> entry,
3196                     int valid_descriptors,
3197                     Handle<FixedArray> array) {
3198    DisallowHeapAllocation no_gc;
3199    array->set(valid_descriptors, *entry);
3200  }
3201};
3202
3203
3204void Map::AppendCallbackDescriptors(Handle<Map> map,
3205                                    Handle<Object> descriptors) {
3206  int nof = map->NumberOfOwnDescriptors();
3207  Handle<DescriptorArray> array(map->instance_descriptors());
3208  NeanderArray callbacks(descriptors);
3209  ASSERT(array->NumberOfSlackDescriptors() >= callbacks.length());
3210  nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
3211  map->SetNumberOfOwnDescriptors(nof);
3212}
3213
3214
3215int AccessorInfo::AppendUnique(Handle<Object> descriptors,
3216                               Handle<FixedArray> array,
3217                               int valid_descriptors) {
3218  NeanderArray callbacks(descriptors);
3219  ASSERT(array->length() >= callbacks.length() + valid_descriptors);
3220  return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
3221                                                   array,
3222                                                   valid_descriptors);
3223}
3224
3225
3226static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
3227  ASSERT(!map.is_null());
3228  for (int i = 0; i < maps->length(); ++i) {
3229    if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
3230  }
3231  return false;
3232}
3233
3234
3235template <class T>
3236static Handle<T> MaybeNull(T* p) {
3237  if (p == NULL) return Handle<T>::null();
3238  return Handle<T>(p);
3239}
3240
3241
3242Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
3243  ElementsKind kind = elements_kind();
3244  Handle<Map> transitioned_map = Handle<Map>::null();
3245  Handle<Map> current_map(this);
3246  bool packed = IsFastPackedElementsKind(kind);
3247  if (IsTransitionableFastElementsKind(kind)) {
3248    while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
3249      kind = GetNextMoreGeneralFastElementsKind(kind, false);
3250      Handle<Map> maybe_transitioned_map =
3251          MaybeNull(current_map->LookupElementsTransitionMap(kind));
3252      if (maybe_transitioned_map.is_null()) break;
3253      if (ContainsMap(candidates, maybe_transitioned_map) &&
3254          (packed || !IsFastPackedElementsKind(kind))) {
3255        transitioned_map = maybe_transitioned_map;
3256        if (!IsFastPackedElementsKind(kind)) packed = false;
3257      }
3258      current_map = maybe_transitioned_map;
3259    }
3260  }
3261  return transitioned_map;
3262}
3263
3264
3265static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
3266  Map* current_map = map;
3267  int target_kind =
3268      IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind)
3269      ? to_kind
3270      : TERMINAL_FAST_ELEMENTS_KIND;
3271
3272  // Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data
3273  // allows to change elements from arbitrary kind to any ExternalArray
3274  // elements kind. Satisfy its requirements, checking whether we already
3275  // have the cached transition.
3276  if (IsExternalArrayElementsKind(to_kind) &&
3277      !IsFixedTypedArrayElementsKind(map->elements_kind())) {
3278    if (map->HasElementsTransition()) {
3279        Map* next_map = map->elements_transition_map();
3280        if (next_map->elements_kind() == to_kind) return next_map;
3281    }
3282    return map;
3283  }
3284
3285  ElementsKind kind = map->elements_kind();
3286  while (kind != target_kind) {
3287    kind = GetNextTransitionElementsKind(kind);
3288    if (!current_map->HasElementsTransition()) return current_map;
3289    current_map = current_map->elements_transition_map();
3290  }
3291
3292  if (to_kind != kind && current_map->HasElementsTransition()) {
3293    ASSERT(to_kind == DICTIONARY_ELEMENTS);
3294    Map* next_map = current_map->elements_transition_map();
3295    if (next_map->elements_kind() == to_kind) return next_map;
3296  }
3297
3298  ASSERT(current_map->elements_kind() == target_kind);
3299  return current_map;
3300}
3301
3302
3303Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
3304  Map* to_map = FindClosestElementsTransition(this, to_kind);
3305  if (to_map->elements_kind() == to_kind) return to_map;
3306  return NULL;
3307}
3308
3309
3310bool Map::IsMapInArrayPrototypeChain() {
3311  Isolate* isolate = GetIsolate();
3312  if (isolate->initial_array_prototype()->map() == this) {
3313    return true;
3314  }
3315
3316  if (isolate->initial_object_prototype()->map() == this) {
3317    return true;
3318  }
3319
3320  return false;
3321}
3322
3323
3324static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
3325                                                 ElementsKind to_kind) {
3326  ASSERT(IsTransitionElementsKind(map->elements_kind()));
3327
3328  Handle<Map> current_map = map;
3329
3330  ElementsKind kind = map->elements_kind();
3331  while (kind != to_kind && !IsTerminalElementsKind(kind)) {
3332    kind = GetNextTransitionElementsKind(kind);
3333    current_map = Map::CopyAsElementsKind(
3334        current_map, kind, INSERT_TRANSITION);
3335  }
3336
3337  // In case we are exiting the fast elements kind system, just add the map in
3338  // the end.
3339  if (kind != to_kind) {
3340    current_map = Map::CopyAsElementsKind(
3341        current_map, to_kind, INSERT_TRANSITION);
3342  }
3343
3344  ASSERT(current_map->elements_kind() == to_kind);
3345  return current_map;
3346}
3347
3348
3349Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
3350                                      ElementsKind to_kind) {
3351  ElementsKind from_kind = map->elements_kind();
3352  if (from_kind == to_kind) return map;
3353
3354  Isolate* isolate = map->GetIsolate();
3355  Context* native_context = isolate->context()->native_context();
3356  Object* maybe_array_maps = native_context->js_array_maps();
3357  if (maybe_array_maps->IsFixedArray()) {
3358    DisallowHeapAllocation no_gc;
3359    FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
3360    if (array_maps->get(from_kind) == *map) {
3361      Object* maybe_transitioned_map = array_maps->get(to_kind);
3362      if (maybe_transitioned_map->IsMap()) {
3363        return handle(Map::cast(maybe_transitioned_map));
3364      }
3365    }
3366  }
3367
3368  return TransitionElementsToSlow(map, to_kind);
3369}
3370
3371
3372Handle<Map> Map::TransitionElementsToSlow(Handle<Map> map,
3373                                          ElementsKind to_kind) {
3374  ElementsKind from_kind = map->elements_kind();
3375
3376  if (from_kind == to_kind) {
3377    return map;
3378  }
3379
3380  bool allow_store_transition =
3381      // Only remember the map transition if there is not an already existing
3382      // non-matching element transition.
3383      !map->IsUndefined() && !map->is_shared() &&
3384      IsTransitionElementsKind(from_kind);
3385
3386  // Only store fast element maps in ascending generality.
3387  if (IsFastElementsKind(to_kind)) {
3388    allow_store_transition &=
3389        IsTransitionableFastElementsKind(from_kind) &&
3390        IsMoreGeneralElementsKindTransition(from_kind, to_kind);
3391  }
3392
3393  if (!allow_store_transition) {
3394    return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
3395  }
3396
3397  return Map::AsElementsKind(map, to_kind);
3398}
3399
3400
3401// static
3402Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
3403  Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
3404
3405  if (closest_map->elements_kind() == kind) {
3406    return closest_map;
3407  }
3408
3409  return AddMissingElementsTransitions(closest_map, kind);
3410}
3411
3412
3413Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3414                                               ElementsKind to_kind) {
3415  Handle<Map> map(object->map());
3416  return Map::TransitionElementsTo(map, to_kind);
3417}
3418
3419
3420void JSObject::LookupOwnRealNamedProperty(Handle<Name> name,
3421                                          LookupResult* result) {
3422  DisallowHeapAllocation no_gc;
3423  if (IsJSGlobalProxy()) {
3424    Object* proto = GetPrototype();
3425    if (proto->IsNull()) return result->NotFound();
3426    ASSERT(proto->IsJSGlobalObject());
3427    return JSObject::cast(proto)->LookupOwnRealNamedProperty(name, result);
3428  }
3429
3430  if (HasFastProperties()) {
3431    map()->LookupDescriptor(this, *name, result);
3432    // A property or a map transition was found. We return all of these result
3433    // types because LookupOwnRealNamedProperty is used when setting
3434    // properties where map transitions are handled.
3435    ASSERT(!result->IsFound() ||
3436           (result->holder() == this && result->IsFastPropertyType()));
3437    // Disallow caching for uninitialized constants. These can only
3438    // occur as fields.
3439    if (result->IsField() &&
3440        result->IsReadOnly() &&
3441        RawFastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
3442      result->DisallowCaching();
3443    }
3444    return;
3445  }
3446
3447  int entry = property_dictionary()->FindEntry(name);
3448  if (entry != NameDictionary::kNotFound) {
3449    Object* value = property_dictionary()->ValueAt(entry);
3450    if (IsGlobalObject()) {
3451      PropertyDetails d = property_dictionary()->DetailsAt(entry);
3452      if (d.IsDeleted()) {
3453        result->NotFound();
3454        return;
3455      }
3456      value = PropertyCell::cast(value)->value();
3457    }
3458    // Make sure to disallow caching for uninitialized constants
3459    // found in the dictionary-mode objects.
3460    if (value->IsTheHole()) result->DisallowCaching();
3461    result->DictionaryResult(this, entry);
3462    return;
3463  }
3464
3465  result->NotFound();
3466}
3467
3468
3469void JSObject::LookupRealNamedProperty(Handle<Name> name,
3470                                       LookupResult* result) {
3471  DisallowHeapAllocation no_gc;
3472  LookupOwnRealNamedProperty(name, result);
3473  if (result->IsFound()) return;
3474
3475  LookupRealNamedPropertyInPrototypes(name, result);
3476}
3477
3478
3479void JSObject::LookupRealNamedPropertyInPrototypes(Handle<Name> name,
3480                                                   LookupResult* result) {
3481  DisallowHeapAllocation no_gc;
3482  Isolate* isolate = GetIsolate();
3483  Heap* heap = isolate->heap();
3484  for (Object* pt = GetPrototype();
3485       pt != heap->null_value();
3486       pt = pt->GetPrototype(isolate)) {
3487    if (pt->IsJSProxy()) {
3488      return result->HandlerResult(JSProxy::cast(pt));
3489    }
3490    JSObject::cast(pt)->LookupOwnRealNamedProperty(name, result);
3491    ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR));
3492    if (result->IsFound()) return;
3493  }
3494  result->NotFound();
3495}
3496
3497
3498MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
3499                                            LookupResult* result,
3500                                            Handle<Name> key,
3501                                            Handle<Object> value,
3502                                            PropertyAttributes attributes,
3503                                            StrictMode strict_mode,
3504                                            StoreFromKeyed store_mode) {
3505  if (result->IsHandler()) {
3506    return JSProxy::SetPropertyWithHandler(handle(result->proxy()),
3507        object, key, value, attributes, strict_mode);
3508  } else {
3509    return JSObject::SetPropertyForResult(Handle<JSObject>::cast(object),
3510        result, key, value, attributes, strict_mode, store_mode);
3511  }
3512}
3513
3514
3515bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) {
3516  Isolate* isolate = proxy->GetIsolate();
3517
3518  // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3519  if (name->IsSymbol()) return false;
3520
3521  Handle<Object> args[] = { name };
3522  Handle<Object> result;
3523  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3524      isolate, result,
3525      CallTrap(proxy,
3526               "has",
3527               isolate->derived_has_trap(),
3528               ARRAY_SIZE(args),
3529               args),
3530      false);
3531
3532  return result->BooleanValue();
3533}
3534
3535
3536MaybeHandle<Object> JSProxy::SetPropertyWithHandler(
3537    Handle<JSProxy> proxy,
3538    Handle<JSReceiver> receiver,
3539    Handle<Name> name,
3540    Handle<Object> value,
3541    PropertyAttributes attributes,
3542    StrictMode strict_mode) {
3543  Isolate* isolate = proxy->GetIsolate();
3544
3545  // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3546  if (name->IsSymbol()) return value;
3547
3548  Handle<Object> args[] = { receiver, name, value };
3549  RETURN_ON_EXCEPTION(
3550      isolate,
3551      CallTrap(proxy,
3552               "set",
3553               isolate->derived_set_trap(),
3554               ARRAY_SIZE(args),
3555               args),
3556      Object);
3557
3558  return value;
3559}
3560
3561
3562MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
3563    Handle<JSProxy> proxy,
3564    Handle<JSReceiver> receiver,
3565    Handle<Name> name,
3566    Handle<Object> value,
3567    PropertyAttributes attributes,
3568    StrictMode strict_mode,
3569    bool* done) {
3570  Isolate* isolate = proxy->GetIsolate();
3571  Handle<Object> handler(proxy->handler(), isolate);  // Trap might morph proxy.
3572
3573  // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3574  if (name->IsSymbol()) {
3575    *done = false;
3576    return isolate->factory()->the_hole_value();
3577  }
3578
3579  *done = true;  // except where redefined...
3580  Handle<Object> args[] = { name };
3581  Handle<Object> result;
3582  ASSIGN_RETURN_ON_EXCEPTION(
3583      isolate, result,
3584      CallTrap(proxy,
3585               "getPropertyDescriptor",
3586               Handle<Object>(),
3587               ARRAY_SIZE(args),
3588               args),
3589      Object);
3590
3591  if (result->IsUndefined()) {
3592    *done = false;
3593    return isolate->factory()->the_hole_value();
3594  }
3595
3596  // Emulate [[GetProperty]] semantics for proxies.
3597  Handle<Object> argv[] = { result };
3598  Handle<Object> desc;
3599  ASSIGN_RETURN_ON_EXCEPTION(
3600      isolate, desc,
3601      Execution::Call(isolate,
3602                      isolate->to_complete_property_descriptor(),
3603                      result,
3604                      ARRAY_SIZE(argv),
3605                      argv),
3606      Object);
3607
3608  // [[GetProperty]] requires to check that all properties are configurable.
3609  Handle<String> configurable_name =
3610      isolate->factory()->InternalizeOneByteString(
3611          STATIC_ASCII_VECTOR("configurable_"));
3612  Handle<Object> configurable =
3613      Object::GetProperty(desc, configurable_name).ToHandleChecked();
3614  ASSERT(configurable->IsBoolean());
3615  if (configurable->IsFalse()) {
3616    Handle<String> trap =
3617        isolate->factory()->InternalizeOneByteString(
3618            STATIC_ASCII_VECTOR("getPropertyDescriptor"));
3619    Handle<Object> args[] = { handler, trap, name };
3620    Handle<Object> error = isolate->factory()->NewTypeError(
3621        "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
3622    return isolate->Throw<Object>(error);
3623  }
3624  ASSERT(configurable->IsTrue());
3625
3626  // Check for DataDescriptor.
3627  Handle<String> hasWritable_name =
3628      isolate->factory()->InternalizeOneByteString(
3629          STATIC_ASCII_VECTOR("hasWritable_"));
3630  Handle<Object> hasWritable =
3631      Object::GetProperty(desc, hasWritable_name).ToHandleChecked();
3632  ASSERT(hasWritable->IsBoolean());
3633  if (hasWritable->IsTrue()) {
3634    Handle<String> writable_name =
3635        isolate->factory()->InternalizeOneByteString(
3636            STATIC_ASCII_VECTOR("writable_"));
3637    Handle<Object> writable =
3638        Object::GetProperty(desc, writable_name).ToHandleChecked();
3639    ASSERT(writable->IsBoolean());
3640    *done = writable->IsFalse();
3641    if (!*done) return isolate->factory()->the_hole_value();
3642    if (strict_mode == SLOPPY) return value;
3643    Handle<Object> args[] = { name, receiver };
3644    Handle<Object> error = isolate->factory()->NewTypeError(
3645        "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
3646    return isolate->Throw<Object>(error);
3647  }
3648
3649  // We have an AccessorDescriptor.
3650  Handle<String> set_name = isolate->factory()->InternalizeOneByteString(
3651      STATIC_ASCII_VECTOR("set_"));
3652  Handle<Object> setter = Object::GetProperty(desc, set_name).ToHandleChecked();
3653  if (!setter->IsUndefined()) {
3654    // TODO(rossberg): nicer would be to cast to some JSCallable here...
3655    return SetPropertyWithDefinedSetter(
3656        receiver, Handle<JSReceiver>::cast(setter), value);
3657  }
3658
3659  if (strict_mode == SLOPPY) return value;
3660  Handle<Object> args2[] = { name, proxy };
3661  Handle<Object> error = isolate->factory()->NewTypeError(
3662      "no_setter_in_callback", HandleVector(args2, ARRAY_SIZE(args2)));
3663  return isolate->Throw<Object>(error);
3664}
3665
3666
3667MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
3668    Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
3669  Isolate* isolate = proxy->GetIsolate();
3670
3671  // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3672  if (name->IsSymbol()) return isolate->factory()->false_value();
3673
3674  Handle<Object> args[] = { name };
3675  Handle<Object> result;
3676  ASSIGN_RETURN_ON_EXCEPTION(
3677      isolate, result,
3678      CallTrap(proxy,
3679               "delete",
3680               Handle<Object>(),
3681               ARRAY_SIZE(args),
3682               args),
3683      Object);
3684
3685  bool result_bool = result->BooleanValue();
3686  if (mode == STRICT_DELETION && !result_bool) {
3687    Handle<Object> handler(proxy->handler(), isolate);
3688    Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
3689        STATIC_ASCII_VECTOR("delete"));
3690    Handle<Object> args[] = { handler, trap_name };
3691    Handle<Object> error = isolate->factory()->NewTypeError(
3692        "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
3693    return isolate->Throw<Object>(error);
3694  }
3695  return isolate->factory()->ToBoolean(result_bool);
3696}
3697
3698
3699MaybeHandle<Object> JSProxy::DeleteElementWithHandler(
3700    Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
3701  Isolate* isolate = proxy->GetIsolate();
3702  Handle<String> name = isolate->factory()->Uint32ToString(index);
3703  return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
3704}
3705
3706
3707PropertyAttributes JSProxy::GetPropertyAttributesWithHandler(
3708    Handle<JSProxy> proxy,
3709    Handle<Object> receiver,
3710    Handle<Name> name) {
3711  Isolate* isolate = proxy->GetIsolate();
3712  HandleScope scope(isolate);
3713
3714  // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3715  if (name->IsSymbol()) return ABSENT;
3716
3717  Handle<Object> args[] = { name };
3718  Handle<Object> result;
3719  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3720      isolate, result,
3721      proxy->CallTrap(proxy,
3722                      "getPropertyDescriptor",
3723                      Handle<Object>(),
3724                      ARRAY_SIZE(args),
3725                      args),
3726      NONE);
3727
3728  if (result->IsUndefined()) return ABSENT;
3729
3730  Handle<Object> argv[] = { result };
3731  Handle<Object> desc;
3732  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3733      isolate, desc,
3734      Execution::Call(isolate,
3735                      isolate->to_complete_property_descriptor(),
3736                      result,
3737                      ARRAY_SIZE(argv),
3738                      argv),
3739      NONE);
3740
3741  // Convert result to PropertyAttributes.
3742  Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
3743      STATIC_ASCII_VECTOR("enumerable_"));
3744  Handle<Object> enumerable;
3745  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3746      isolate, enumerable, Object::GetProperty(desc, enum_n), NONE);
3747  Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
3748      STATIC_ASCII_VECTOR("configurable_"));
3749  Handle<Object> configurable;
3750  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3751      isolate, configurable, Object::GetProperty(desc, conf_n), NONE);
3752  Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
3753      STATIC_ASCII_VECTOR("writable_"));
3754  Handle<Object> writable;
3755  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3756      isolate, writable, Object::GetProperty(desc, writ_n), NONE);
3757  if (!writable->BooleanValue()) {
3758    Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
3759        STATIC_ASCII_VECTOR("set_"));
3760    Handle<Object> setter;
3761    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3762        isolate, setter, Object::GetProperty(desc, set_n), NONE);
3763    writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
3764  }
3765
3766  if (configurable->IsFalse()) {
3767    Handle<Object> handler(proxy->handler(), isolate);
3768    Handle<String> trap = isolate->factory()->InternalizeOneByteString(
3769        STATIC_ASCII_VECTOR("getPropertyDescriptor"));
3770    Handle<Object> args[] = { handler, trap, name };
3771    Handle<Object> error = isolate->factory()->NewTypeError(
3772        "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
3773    isolate->Throw(*error);
3774    return NONE;
3775  }
3776
3777  int attributes = NONE;
3778  if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
3779  if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
3780  if (!writable->BooleanValue()) attributes |= READ_ONLY;
3781  return static_cast<PropertyAttributes>(attributes);
3782}
3783
3784
3785PropertyAttributes JSProxy::GetElementAttributeWithHandler(
3786    Handle<JSProxy> proxy,
3787    Handle<JSReceiver> receiver,
3788    uint32_t index) {
3789  Isolate* isolate = proxy->GetIsolate();
3790  Handle<String> name = isolate->factory()->Uint32ToString(index);
3791  return GetPropertyAttributesWithHandler(proxy, receiver, name);
3792}
3793
3794
3795void JSProxy::Fix(Handle<JSProxy> proxy) {
3796  Isolate* isolate = proxy->GetIsolate();
3797
3798  // Save identity hash.
3799  Handle<Object> hash(proxy->GetIdentityHash(), isolate);
3800
3801  if (proxy->IsJSFunctionProxy()) {
3802    isolate->factory()->BecomeJSFunction(proxy);
3803    // Code will be set on the JavaScript side.
3804  } else {
3805    isolate->factory()->BecomeJSObject(proxy);
3806  }
3807  ASSERT(proxy->IsJSObject());
3808
3809  // Inherit identity, if it was present.
3810  if (hash->IsSmi()) {
3811    JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy),
3812                              Handle<Smi>::cast(hash));
3813  }
3814}
3815
3816
3817MaybeHandle<Object> JSProxy::CallTrap(Handle<JSProxy> proxy,
3818                                      const char* name,
3819                                      Handle<Object> derived,
3820                                      int argc,
3821                                      Handle<Object> argv[]) {
3822  Isolate* isolate = proxy->GetIsolate();
3823  Handle<Object> handler(proxy->handler(), isolate);
3824
3825  Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
3826  Handle<Object> trap;
3827  ASSIGN_RETURN_ON_EXCEPTION(
3828      isolate, trap,
3829      Object::GetPropertyOrElement(handler, trap_name),
3830      Object);
3831
3832  if (trap->IsUndefined()) {
3833    if (derived.is_null()) {
3834      Handle<Object> args[] = { handler, trap_name };
3835      Handle<Object> error = isolate->factory()->NewTypeError(
3836        "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
3837      return isolate->Throw<Object>(error);
3838    }
3839    trap = Handle<Object>(derived);
3840  }
3841
3842  return Execution::Call(isolate, trap, handler, argc, argv);
3843}
3844
3845
3846void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
3847  ASSERT(object->map()->inobject_properties() == map->inobject_properties());
3848  ElementsKind obj_kind = object->map()->elements_kind();
3849  ElementsKind map_kind = map->elements_kind();
3850  if (map_kind != obj_kind) {
3851    ElementsKind to_kind = map_kind;
3852    if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) ||
3853        IsDictionaryElementsKind(obj_kind)) {
3854      to_kind = obj_kind;
3855    }
3856    if (IsDictionaryElementsKind(to_kind)) {
3857      NormalizeElements(object);
3858    } else {
3859      TransitionElementsKind(object, to_kind);
3860    }
3861    map = Map::AsElementsKind(map, to_kind);
3862  }
3863  JSObject::MigrateToMap(object, map);
3864}
3865
3866
3867void JSObject::MigrateInstance(Handle<JSObject> object) {
3868  // Converting any field to the most specific type will cause the
3869  // GeneralizeFieldRepresentation algorithm to create the most general existing
3870  // transition that matches the object. This achieves what is needed.
3871  Handle<Map> original_map(object->map());
3872  GeneralizeFieldRepresentation(
3873      object, 0, Representation::None(),
3874      HeapType::None(object->GetIsolate()),
3875      ALLOW_AS_CONSTANT);
3876  object->map()->set_migration_target(true);
3877  if (FLAG_trace_migration) {
3878    object->PrintInstanceMigration(stdout, *original_map, object->map());
3879  }
3880}
3881
3882
3883// static
3884bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
3885  Isolate* isolate = object->GetIsolate();
3886  DisallowDeoptimization no_deoptimization(isolate);
3887  Handle<Map> original_map(object->map(), isolate);
3888  Handle<Map> new_map;
3889  if (!Map::CurrentMapForDeprecatedInternal(original_map).ToHandle(&new_map)) {
3890    return false;
3891  }
3892  JSObject::MigrateToMap(object, new_map);
3893  if (FLAG_trace_migration) {
3894    object->PrintInstanceMigration(stdout, *original_map, object->map());
3895  }
3896  return true;
3897}
3898
3899
3900MaybeHandle<Object> JSObject::SetPropertyUsingTransition(
3901    Handle<JSObject> object,
3902    LookupResult* lookup,
3903    Handle<Name> name,
3904    Handle<Object> value,
3905    PropertyAttributes attributes) {
3906  Handle<Map> transition_map(lookup->GetTransitionTarget());
3907  int descriptor = transition_map->LastAdded();
3908
3909  Handle<DescriptorArray> descriptors(transition_map->instance_descriptors());
3910  PropertyDetails details = descriptors->GetDetails(descriptor);
3911
3912  if (details.type() == CALLBACKS || attributes != details.attributes()) {
3913    // AddProperty will either normalize the object, or create a new fast copy
3914    // of the map. If we get a fast copy of the map, all field representations
3915    // will be tagged since the transition is omitted.
3916    return JSObject::AddProperty(
3917        object, name, value, attributes, SLOPPY,
3918        JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
3919        JSReceiver::OMIT_EXTENSIBILITY_CHECK,
3920        JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION);
3921  }
3922
3923  // Keep the target CONSTANT if the same value is stored.
3924  // TODO(verwaest): Also support keeping the placeholder
3925  // (value->IsUninitialized) as constant.
3926  if (!lookup->CanHoldValue(value)) {
3927    Representation field_representation = value->OptimalRepresentation();
3928    Handle<HeapType> field_type = value->OptimalType(
3929        lookup->isolate(), field_representation);
3930    transition_map = Map::GeneralizeRepresentation(
3931        transition_map, descriptor,
3932        field_representation, field_type, FORCE_FIELD);
3933  }
3934
3935  JSObject::MigrateToNewProperty(object, transition_map, value);
3936  return value;
3937}
3938
3939
3940void JSObject::MigrateToNewProperty(Handle<JSObject> object,
3941                                    Handle<Map> map,
3942                                    Handle<Object> value) {
3943  JSObject::MigrateToMap(object, map);
3944  if (map->GetLastDescriptorDetails().type() != FIELD) return;
3945  object->WriteToField(map->LastAdded(), *value);
3946}
3947
3948
3949void JSObject::WriteToField(int descriptor, Object* value) {
3950  DisallowHeapAllocation no_gc;
3951
3952  DescriptorArray* desc = map()->instance_descriptors();
3953  PropertyDetails details = desc->GetDetails(descriptor);
3954
3955  ASSERT(details.type() == FIELD);
3956
3957  FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
3958  if (details.representation().IsDouble()) {
3959    // Nothing more to be done.
3960    if (value->IsUninitialized()) return;
3961    HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
3962    box->set_value(value->Number());
3963  } else {
3964    FastPropertyAtPut(index, value);
3965  }
3966}
3967
3968
3969static void SetPropertyToField(LookupResult* lookup,
3970                               Handle<Object> value) {
3971  if (lookup->type() == CONSTANT || !lookup->CanHoldValue(value)) {
3972    Representation field_representation = value->OptimalRepresentation();
3973    Handle<HeapType> field_type = value->OptimalType(
3974        lookup->isolate(), field_representation);
3975    JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()),
3976                                            lookup->GetDescriptorIndex(),
3977                                            field_representation, field_type,
3978                                            FORCE_FIELD);
3979  }
3980  lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value);
3981}
3982
3983
3984static void ConvertAndSetOwnProperty(LookupResult* lookup,
3985                                     Handle<Name> name,
3986                                     Handle<Object> value,
3987                                     PropertyAttributes attributes) {
3988  Handle<JSObject> object(lookup->holder());
3989  if (object->TooManyFastProperties()) {
3990    JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
3991  }
3992
3993  if (!object->HasFastProperties()) {
3994    ReplaceSlowProperty(object, name, value, attributes);
3995    return;
3996  }
3997
3998  int descriptor_index = lookup->GetDescriptorIndex();
3999  if (lookup->GetAttributes() == attributes) {
4000    JSObject::GeneralizeFieldRepresentation(
4001        object, descriptor_index, Representation::Tagged(),
4002        HeapType::Any(lookup->isolate()), FORCE_FIELD);
4003  } else {
4004    Handle<Map> old_map(object->map());
4005    Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map,
4006        descriptor_index, FORCE_FIELD, attributes, "attributes mismatch");
4007    JSObject::MigrateToMap(object, new_map);
4008  }
4009
4010  object->WriteToField(descriptor_index, *value);
4011}
4012
4013
4014static void SetPropertyToFieldWithAttributes(LookupResult* lookup,
4015                                             Handle<Name> name,
4016                                             Handle<Object> value,
4017                                             PropertyAttributes attributes) {
4018  if (lookup->GetAttributes() == attributes) {
4019    if (value->IsUninitialized()) return;
4020    SetPropertyToField(lookup, value);
4021  } else {
4022    ConvertAndSetOwnProperty(lookup, name, value, attributes);
4023  }
4024}
4025
4026
4027MaybeHandle<Object> JSObject::SetPropertyForResult(
4028    Handle<JSObject> object,
4029    LookupResult* lookup,
4030    Handle<Name> name,
4031    Handle<Object> value,
4032    PropertyAttributes attributes,
4033    StrictMode strict_mode,
4034    StoreFromKeyed store_mode) {
4035  Isolate* isolate = object->GetIsolate();
4036
4037  // Make sure that the top context does not change when doing callbacks or
4038  // interceptor calls.
4039  AssertNoContextChange ncc(isolate);
4040
4041  // Optimization for 2-byte strings often used as keys in a decompression
4042  // dictionary.  We internalize these short keys to avoid constantly
4043  // reallocating them.
4044  if (name->IsString() && !name->IsInternalizedString() &&
4045      Handle<String>::cast(name)->length() <= 2) {
4046    name = isolate->factory()->InternalizeString(Handle<String>::cast(name));
4047  }
4048
4049  // Check access rights if needed.
4050  if (object->IsAccessCheckNeeded()) {
4051    if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
4052      return SetPropertyWithFailedAccessCheck(object, lookup, name, value,
4053                                              true, strict_mode);
4054    }
4055  }
4056
4057  if (object->IsJSGlobalProxy()) {
4058    Handle<Object> proto(object->GetPrototype(), isolate);
4059    if (proto->IsNull()) return value;
4060    ASSERT(proto->IsJSGlobalObject());
4061    return SetPropertyForResult(Handle<JSObject>::cast(proto),
4062        lookup, name, value, attributes, strict_mode, store_mode);
4063  }
4064
4065  ASSERT(!lookup->IsFound() || lookup->holder() == *object ||
4066         lookup->holder()->map()->is_hidden_prototype());
4067
4068  if (!lookup->IsProperty() && !object->IsJSContextExtensionObject()) {
4069    bool done = false;
4070    Handle<Object> result_object;
4071    ASSIGN_RETURN_ON_EXCEPTION(
4072        isolate, result_object,
4073        SetPropertyViaPrototypes(
4074            object, name, value, attributes, strict_mode, &done),
4075        Object);
4076    if (done) return result_object;
4077  }
4078
4079  if (!lookup->IsFound()) {
4080    // Neither properties nor transitions found.
4081    return AddProperty(
4082        object, name, value, attributes, strict_mode, store_mode);
4083  }
4084
4085  if (lookup->IsProperty() && lookup->IsReadOnly()) {
4086    if (strict_mode == STRICT) {
4087      Handle<Object> args[] = { name, object };
4088      Handle<Object> error = isolate->factory()->NewTypeError(
4089          "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
4090      return isolate->Throw<Object>(error);
4091    } else {
4092      return value;
4093    }
4094  }
4095
4096  Handle<Object> old_value = isolate->factory()->the_hole_value();
4097  bool is_observed = object->map()->is_observed() &&
4098                     *name != isolate->heap()->hidden_string();
4099  if (is_observed && lookup->IsDataProperty()) {
4100    old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked();
4101  }
4102
4103  // This is a real property that is not read-only, or it is a
4104  // transition or null descriptor and there are no setters in the prototypes.
4105  MaybeHandle<Object> maybe_result = value;
4106  if (lookup->IsTransition()) {
4107    maybe_result = SetPropertyUsingTransition(handle(lookup->holder()), lookup,
4108                                              name, value, attributes);
4109  } else {
4110    switch (lookup->type()) {
4111      case NORMAL:
4112        SetNormalizedProperty(handle(lookup->holder()), lookup, value);
4113        break;
4114      case FIELD:
4115        SetPropertyToField(lookup, value);
4116        break;
4117      case CONSTANT:
4118        // Only replace the constant if necessary.
4119        if (*value == lookup->GetConstant()) return value;
4120        SetPropertyToField(lookup, value);
4121        break;
4122      case CALLBACKS: {
4123        Handle<Object> callback_object(lookup->GetCallbackObject(), isolate);
4124        return SetPropertyWithCallback(object, name, value,
4125                                       handle(lookup->holder()),
4126                                       callback_object, strict_mode);
4127      }
4128      case INTERCEPTOR:
4129        maybe_result = SetPropertyWithInterceptor(
4130            handle(lookup->holder()), name, value, attributes, strict_mode);
4131        break;
4132      case HANDLER:
4133      case NONEXISTENT:
4134        UNREACHABLE();
4135    }
4136  }
4137
4138  Handle<Object> result;
4139  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
4140
4141  if (is_observed) {
4142    if (lookup->IsTransition()) {
4143      EnqueueChangeRecord(object, "add", name, old_value);
4144    } else {
4145      LookupResult new_lookup(isolate);
4146      object->LookupOwn(name, &new_lookup, true);
4147      if (new_lookup.IsDataProperty()) {
4148        Handle<Object> new_value =
4149            Object::GetPropertyOrElement(object, name).ToHandleChecked();
4150        if (!new_value->SameValue(*old_value)) {
4151          EnqueueChangeRecord(object, "update", name, old_value);
4152        }
4153      }
4154    }
4155  }
4156
4157  return result;
4158}
4159
4160
4161// Set a real own property, even if it is READ_ONLY.  If the property is not
4162// present, add it with attributes NONE.  This code is an exact clone of
4163// SetProperty, with the check for IsReadOnly and the check for a
4164// callback setter removed.  The two lines looking up the LookupResult
4165// result are also added.  If one of the functions is changed, the other
4166// should be.
4167MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
4168    Handle<JSObject> object,
4169    Handle<Name> name,
4170    Handle<Object> value,
4171    PropertyAttributes attributes,
4172    ValueType value_type,
4173    StoreMode mode,
4174    ExtensibilityCheck extensibility_check,
4175    StoreFromKeyed store_from_keyed,
4176    ExecutableAccessorInfoHandling handling) {
4177  Isolate* isolate = object->GetIsolate();
4178
4179  // Make sure that the top context does not change when doing callbacks or
4180  // interceptor calls.
4181  AssertNoContextChange ncc(isolate);
4182
4183  LookupResult lookup(isolate);
4184  object->LookupOwn(name, &lookup, true);
4185  if (!lookup.IsFound()) {
4186    object->map()->LookupTransition(*object, *name, &lookup);
4187  }
4188
4189  // Check access rights if needed.
4190  if (object->IsAccessCheckNeeded()) {
4191    if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
4192      return SetPropertyWithFailedAccessCheck(object, &lookup, name, value,
4193                                              false, SLOPPY);
4194    }
4195  }
4196
4197  if (object->IsJSGlobalProxy()) {
4198    Handle<Object> proto(object->GetPrototype(), isolate);
4199    if (proto->IsNull()) return value;
4200    ASSERT(proto->IsJSGlobalObject());
4201    return SetOwnPropertyIgnoreAttributes(Handle<JSObject>::cast(proto),
4202        name, value, attributes, value_type, mode, extensibility_check);
4203  }
4204
4205  if (lookup.IsInterceptor() ||
4206      (lookup.IsDescriptorOrDictionary() && lookup.type() == CALLBACKS)) {
4207    object->LookupOwnRealNamedProperty(name, &lookup);
4208  }
4209
4210  // Check for accessor in prototype chain removed here in clone.
4211  if (!lookup.IsFound()) {
4212    object->map()->LookupTransition(*object, *name, &lookup);
4213    TransitionFlag flag = lookup.IsFound()
4214        ? OMIT_TRANSITION : INSERT_TRANSITION;
4215    // Neither properties nor transitions found.
4216    return AddProperty(object, name, value, attributes, SLOPPY,
4217        store_from_keyed, extensibility_check, value_type, mode, flag);
4218  }
4219
4220  Handle<Object> old_value = isolate->factory()->the_hole_value();
4221  PropertyAttributes old_attributes = ABSENT;
4222  bool is_observed = object->map()->is_observed() &&
4223                     *name != isolate->heap()->hidden_string();
4224  if (is_observed && lookup.IsProperty()) {
4225    if (lookup.IsDataProperty()) {
4226      old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked();
4227    }
4228    old_attributes = lookup.GetAttributes();
4229  }
4230
4231  bool executed_set_prototype = false;
4232
4233  // Check of IsReadOnly removed from here in clone.
4234  if (lookup.IsTransition()) {
4235    Handle<Object> result;
4236    ASSIGN_RETURN_ON_EXCEPTION(
4237        isolate, result,
4238        SetPropertyUsingTransition(
4239            handle(lookup.holder()), &lookup, name, value, attributes),
4240        Object);
4241  } else {
4242    switch (lookup.type()) {
4243      case NORMAL:
4244        ReplaceSlowProperty(object, name, value, attributes);
4245        break;
4246      case FIELD:
4247        SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
4248        break;
4249      case CONSTANT:
4250        // Only replace the constant if necessary.
4251        if (lookup.GetAttributes() != attributes ||
4252            *value != lookup.GetConstant()) {
4253          SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
4254        }
4255        break;
4256      case CALLBACKS:
4257      {
4258        Handle<Object> callback(lookup.GetCallbackObject(), isolate);
4259        if (callback->IsExecutableAccessorInfo() &&
4260            handling == DONT_FORCE_FIELD) {
4261          Handle<Object> result;
4262          ASSIGN_RETURN_ON_EXCEPTION(
4263              isolate, result,
4264              JSObject::SetPropertyWithCallback(object,
4265                                                name,
4266                                                value,
4267                                                handle(lookup.holder()),
4268                                                callback,
4269                                                STRICT),
4270              Object);
4271
4272          if (attributes != lookup.GetAttributes()) {
4273            Handle<ExecutableAccessorInfo> new_data =
4274                Accessors::CloneAccessor(
4275                    isolate, Handle<ExecutableAccessorInfo>::cast(callback));
4276            new_data->set_property_attributes(attributes);
4277            if (attributes & READ_ONLY) {
4278              // This way we don't have to introduce a lookup to the setter,
4279              // simply make it unavailable to reflect the attributes.
4280              new_data->clear_setter();
4281            }
4282
4283            SetPropertyCallback(object, name, new_data, attributes);
4284          }
4285          if (is_observed) {
4286            // If we are setting the prototype of a function and are observed,
4287            // don't send change records because the prototype handles that
4288            // itself.
4289            executed_set_prototype = object->IsJSFunction() &&
4290                String::Equals(isolate->factory()->prototype_string(),
4291                               Handle<String>::cast(name)) &&
4292                Handle<JSFunction>::cast(object)->should_have_prototype();
4293          }
4294        } else {
4295          ConvertAndSetOwnProperty(&lookup, name, value, attributes);
4296        }
4297        break;
4298      }
4299      case NONEXISTENT:
4300      case HANDLER:
4301      case INTERCEPTOR:
4302        UNREACHABLE();
4303    }
4304  }
4305
4306  if (is_observed && !executed_set_prototype) {
4307    if (lookup.IsTransition()) {
4308      EnqueueChangeRecord(object, "add", name, old_value);
4309    } else if (old_value->IsTheHole()) {
4310      EnqueueChangeRecord(object, "reconfigure", name, old_value);
4311    } else {
4312      LookupResult new_lookup(isolate);
4313      object->LookupOwn(name, &new_lookup, true);
4314      bool value_changed = false;
4315      if (new_lookup.IsDataProperty()) {
4316        Handle<Object> new_value =
4317            Object::GetPropertyOrElement(object, name).ToHandleChecked();
4318        value_changed = !old_value->SameValue(*new_value);
4319      }
4320      if (new_lookup.GetAttributes() != old_attributes) {
4321        if (!value_changed) old_value = isolate->factory()->the_hole_value();
4322        EnqueueChangeRecord(object, "reconfigure", name, old_value);
4323      } else if (value_changed) {
4324        EnqueueChangeRecord(object, "update", name, old_value);
4325      }
4326    }
4327  }
4328
4329  return value;
4330}
4331
4332
4333Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
4334    Handle<JSObject> holder,
4335    Handle<Object> receiver,
4336    Handle<Name> name) {
4337  // TODO(rossberg): Support symbols in the API.
4338  if (name->IsSymbol()) return Maybe<PropertyAttributes>(ABSENT);
4339
4340  Isolate* isolate = holder->GetIsolate();
4341  HandleScope scope(isolate);
4342
4343  // Make sure that the top context does not change when doing
4344  // callbacks or interceptor calls.
4345  AssertNoContextChange ncc(isolate);
4346
4347  Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
4348  PropertyCallbackArguments args(
4349      isolate, interceptor->data(), *receiver, *holder);
4350  if (!interceptor->query()->IsUndefined()) {
4351    v8::NamedPropertyQueryCallback query =
4352        v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query());
4353    LOG(isolate,
4354        ApiNamedPropertyAccess("interceptor-named-has", *holder, *name));
4355    v8::Handle<v8::Integer> result =
4356        args.Call(query, v8::Utils::ToLocal(Handle<String>::cast(name)));
4357    if (!result.IsEmpty()) {
4358      ASSERT(result->IsInt32());
4359      return Maybe<PropertyAttributes>(
4360          static_cast<PropertyAttributes>(result->Int32Value()));
4361    }
4362  } else if (!interceptor->getter()->IsUndefined()) {
4363    v8::NamedPropertyGetterCallback getter =
4364        v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
4365    LOG(isolate,
4366        ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
4367    v8::Handle<v8::Value> result =
4368        args.Call(getter, v8::Utils::ToLocal(Handle<String>::cast(name)));
4369    if (!result.IsEmpty()) return Maybe<PropertyAttributes>(DONT_ENUM);
4370  }
4371  return Maybe<PropertyAttributes>();
4372}
4373
4374
4375PropertyAttributes JSReceiver::GetOwnPropertyAttributes(
4376    Handle<JSReceiver> object, Handle<Name> name) {
4377  // Check whether the name is an array index.
4378  uint32_t index = 0;
4379  if (object->IsJSObject() && name->AsArrayIndex(&index)) {
4380    return GetOwnElementAttribute(object, index);
4381  }
4382  LookupIterator it(object, name, LookupIterator::CHECK_OWN);
4383  return GetPropertyAttributes(&it);
4384}
4385
4386
4387PropertyAttributes JSReceiver::GetPropertyAttributes(LookupIterator* it) {
4388  for (; it->IsFound(); it->Next()) {
4389    switch (it->state()) {
4390      case LookupIterator::NOT_FOUND:
4391        UNREACHABLE();
4392      case LookupIterator::JSPROXY:
4393        return JSProxy::GetPropertyAttributesWithHandler(
4394            it->GetJSProxy(), it->GetReceiver(), it->name());
4395      case LookupIterator::INTERCEPTOR: {
4396        Maybe<PropertyAttributes> result =
4397            JSObject::GetPropertyAttributesWithInterceptor(
4398                it->GetHolder(), it->GetReceiver(), it->name());
4399        if (result.has_value) return result.value;
4400        break;
4401      }
4402      case LookupIterator::ACCESS_CHECK:
4403        if (it->HasAccess(v8::ACCESS_HAS)) break;
4404        return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
4405      case LookupIterator::PROPERTY:
4406        if (it->HasProperty()) return it->property_details().attributes();
4407        break;
4408    }
4409  }
4410  return ABSENT;
4411}
4412
4413
4414PropertyAttributes JSObject::GetElementAttributeWithReceiver(
4415    Handle<JSObject> object,
4416    Handle<JSReceiver> receiver,
4417    uint32_t index,
4418    bool check_prototype) {
4419  Isolate* isolate = object->GetIsolate();
4420
4421  // Check access rights if needed.
4422  if (object->IsAccessCheckNeeded()) {
4423    if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
4424      isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
4425      // TODO(yangguo): Issue 3269, check for scheduled exception missing?
4426      return ABSENT;
4427    }
4428  }
4429
4430  if (object->IsJSGlobalProxy()) {
4431    Handle<Object> proto(object->GetPrototype(), isolate);
4432    if (proto->IsNull()) return ABSENT;
4433    ASSERT(proto->IsJSGlobalObject());
4434    return JSObject::GetElementAttributeWithReceiver(
4435        Handle<JSObject>::cast(proto), receiver, index, check_prototype);
4436  }
4437
4438  // Check for lookup interceptor except when bootstrapping.
4439  if (object->HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) {
4440    return JSObject::GetElementAttributeWithInterceptor(
4441        object, receiver, index, check_prototype);
4442  }
4443
4444  return GetElementAttributeWithoutInterceptor(
4445      object, receiver, index, check_prototype);
4446}
4447
4448
4449PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
4450    Handle<JSObject> object,
4451    Handle<JSReceiver> receiver,
4452    uint32_t index,
4453    bool check_prototype) {
4454  Isolate* isolate = object->GetIsolate();
4455  HandleScope scope(isolate);
4456
4457  // Make sure that the top context does not change when doing
4458  // callbacks or interceptor calls.
4459  AssertNoContextChange ncc(isolate);
4460
4461  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
4462  PropertyCallbackArguments args(
4463      isolate, interceptor->data(), *receiver, *object);
4464  if (!interceptor->query()->IsUndefined()) {
4465    v8::IndexedPropertyQueryCallback query =
4466        v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
4467    LOG(isolate,
4468        ApiIndexedPropertyAccess("interceptor-indexed-has", *object, index));
4469    v8::Handle<v8::Integer> result = args.Call(query, index);
4470    if (!result.IsEmpty())
4471      return static_cast<PropertyAttributes>(result->Int32Value());
4472  } else if (!interceptor->getter()->IsUndefined()) {
4473    v8::IndexedPropertyGetterCallback getter =
4474        v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
4475    LOG(isolate,
4476        ApiIndexedPropertyAccess(
4477            "interceptor-indexed-get-has", *object, index));
4478    v8::Handle<v8::Value> result = args.Call(getter, index);
4479    if (!result.IsEmpty()) return NONE;
4480  }
4481
4482  return GetElementAttributeWithoutInterceptor(
4483       object, receiver, index, check_prototype);
4484}
4485
4486
4487PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor(
4488    Handle<JSObject> object,
4489    Handle<JSReceiver> receiver,
4490    uint32_t index,
4491    bool check_prototype) {
4492  PropertyAttributes attr = object->GetElementsAccessor()->GetAttributes(
4493      receiver, object, index);
4494  if (attr != ABSENT) return attr;
4495
4496  // Handle [] on String objects.
4497  if (object->IsStringObjectWithCharacterAt(index)) {
4498    return static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
4499  }
4500
4501  if (!check_prototype) return ABSENT;
4502
4503  Handle<Object> proto(object->GetPrototype(), object->GetIsolate());
4504  if (proto->IsJSProxy()) {
4505    // We need to follow the spec and simulate a call to [[GetOwnProperty]].
4506    return JSProxy::GetElementAttributeWithHandler(
4507        Handle<JSProxy>::cast(proto), receiver, index);
4508  }
4509  if (proto->IsNull()) return ABSENT;
4510  return GetElementAttributeWithReceiver(
4511      Handle<JSObject>::cast(proto), receiver, index, true);
4512}
4513
4514
4515Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
4516  Handle<FixedArray> array(
4517      isolate->factory()->NewFixedArray(kEntries, TENURED));
4518  return Handle<NormalizedMapCache>::cast(array);
4519}
4520
4521
4522MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
4523                                         PropertyNormalizationMode mode) {
4524  DisallowHeapAllocation no_gc;
4525  Object* value = FixedArray::get(GetIndex(fast_map));
4526  if (!value->IsMap() ||
4527      !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
4528    return MaybeHandle<Map>();
4529  }
4530  return handle(Map::cast(value));
4531}
4532
4533
4534void NormalizedMapCache::Set(Handle<Map> fast_map,
4535                             Handle<Map> normalized_map) {
4536  DisallowHeapAllocation no_gc;
4537  ASSERT(normalized_map->is_dictionary_map());
4538  FixedArray::set(GetIndex(fast_map), *normalized_map);
4539}
4540
4541
4542void NormalizedMapCache::Clear() {
4543  int entries = length();
4544  for (int i = 0; i != entries; i++) {
4545    set_undefined(i);
4546  }
4547}
4548
4549
4550void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
4551                                    Handle<Name> name,
4552                                    Handle<Code> code) {
4553  Handle<Map> map(object->map());
4554  Map::UpdateCodeCache(map, name, code);
4555}
4556
4557
4558void JSObject::NormalizeProperties(Handle<JSObject> object,
4559                                   PropertyNormalizationMode mode,
4560                                   int expected_additional_properties) {
4561  if (!object->HasFastProperties()) return;
4562
4563  // The global object is always normalized.
4564  ASSERT(!object->IsGlobalObject());
4565  // JSGlobalProxy must never be normalized
4566  ASSERT(!object->IsJSGlobalProxy());
4567
4568  Isolate* isolate = object->GetIsolate();
4569  HandleScope scope(isolate);
4570  Handle<Map> map(object->map());
4571  Handle<Map> new_map = Map::Normalize(map, mode);
4572
4573  // Allocate new content.
4574  int real_size = map->NumberOfOwnDescriptors();
4575  int property_count = real_size;
4576  if (expected_additional_properties > 0) {
4577    property_count += expected_additional_properties;
4578  } else {
4579    property_count += 2;  // Make space for two more properties.
4580  }
4581  Handle<NameDictionary> dictionary =
4582      NameDictionary::New(isolate, property_count);
4583
4584  Handle<DescriptorArray> descs(map->instance_descriptors());
4585  for (int i = 0; i < real_size; i++) {
4586    PropertyDetails details = descs->GetDetails(i);
4587    switch (details.type()) {
4588      case CONSTANT: {
4589        Handle<Name> key(descs->GetKey(i));
4590        Handle<Object> value(descs->GetConstant(i), isolate);
4591        PropertyDetails d = PropertyDetails(
4592            details.attributes(), NORMAL, i + 1);
4593        dictionary = NameDictionary::Add(dictionary, key, value, d);
4594        break;
4595      }
4596      case FIELD: {
4597        Handle<Name> key(descs->GetKey(i));
4598        FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4599        Handle<Object> value(
4600            object->RawFastPropertyAt(index), isolate);
4601        PropertyDetails d =
4602            PropertyDetails(details.attributes(), NORMAL, i + 1);
4603        dictionary = NameDictionary::Add(dictionary, key, value, d);
4604        break;
4605      }
4606      case CALLBACKS: {
4607        Handle<Name> key(descs->GetKey(i));
4608        Handle<Object> value(descs->GetCallbacksObject(i), isolate);
4609        PropertyDetails d = PropertyDetails(
4610            details.attributes(), CALLBACKS, i + 1);
4611        dictionary = NameDictionary::Add(dictionary, key, value, d);
4612        break;
4613      }
4614      case INTERCEPTOR:
4615        break;
4616      case HANDLER:
4617      case NORMAL:
4618      case NONEXISTENT:
4619        UNREACHABLE();
4620        break;
4621    }
4622  }
4623
4624  // Copy the next enumeration index from instance descriptor.
4625  dictionary->SetNextEnumerationIndex(real_size + 1);
4626
4627  // From here on we cannot fail and we shouldn't GC anymore.
4628  DisallowHeapAllocation no_allocation;
4629
4630  // Resize the object in the heap if necessary.
4631  int new_instance_size = new_map->instance_size();
4632  int instance_size_delta = map->instance_size() - new_instance_size;
4633  ASSERT(instance_size_delta >= 0);
4634  Heap* heap = isolate->heap();
4635  heap->CreateFillerObjectAt(object->address() + new_instance_size,
4636                             instance_size_delta);
4637  heap->AdjustLiveBytes(object->address(),
4638                        -instance_size_delta,
4639                        Heap::FROM_MUTATOR);
4640
4641  // We are storing the new map using release store after creating a filler for
4642  // the left-over space to avoid races with the sweeper thread.
4643  object->synchronized_set_map(*new_map);
4644
4645  object->set_properties(*dictionary);
4646
4647  isolate->counters()->props_to_dictionary()->Increment();
4648
4649#ifdef DEBUG
4650  if (FLAG_trace_normalization) {
4651    PrintF("Object properties have been normalized:\n");
4652    object->Print();
4653  }
4654#endif
4655}
4656
4657
4658void JSObject::TransformToFastProperties(Handle<JSObject> object,
4659                                         int unused_property_fields) {
4660  if (object->HasFastProperties()) return;
4661  ASSERT(!object->IsGlobalObject());
4662  Isolate* isolate = object->GetIsolate();
4663  Factory* factory = isolate->factory();
4664  Handle<NameDictionary> dictionary(object->property_dictionary());
4665
4666  // Make sure we preserve dictionary representation if there are too many
4667  // descriptors.
4668  int number_of_elements = dictionary->NumberOfElements();
4669  if (number_of_elements > kMaxNumberOfDescriptors) return;
4670
4671  if (number_of_elements != dictionary->NextEnumerationIndex()) {
4672    NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
4673  }
4674
4675  int instance_descriptor_length = 0;
4676  int number_of_fields = 0;
4677
4678  // Compute the length of the instance descriptor.
4679  int capacity = dictionary->Capacity();
4680  for (int i = 0; i < capacity; i++) {
4681    Object* k = dictionary->KeyAt(i);
4682    if (dictionary->IsKey(k)) {
4683      Object* value = dictionary->ValueAt(i);
4684      PropertyType type = dictionary->DetailsAt(i).type();
4685      ASSERT(type != FIELD);
4686      instance_descriptor_length++;
4687      if (type == NORMAL && !value->IsJSFunction()) {
4688        number_of_fields += 1;
4689      }
4690    }
4691  }
4692
4693  int inobject_props = object->map()->inobject_properties();
4694
4695  // Allocate new map.
4696  Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
4697  new_map->set_dictionary_map(false);
4698
4699  if (instance_descriptor_length == 0) {
4700    DisallowHeapAllocation no_gc;
4701    ASSERT_LE(unused_property_fields, inobject_props);
4702    // Transform the object.
4703    new_map->set_unused_property_fields(inobject_props);
4704    object->set_map(*new_map);
4705    object->set_properties(isolate->heap()->empty_fixed_array());
4706    // Check that it really works.
4707    ASSERT(object->HasFastProperties());
4708    return;
4709  }
4710
4711  // Allocate the instance descriptor.
4712  Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
4713      isolate, instance_descriptor_length);
4714
4715  int number_of_allocated_fields =
4716      number_of_fields + unused_property_fields - inobject_props;
4717  if (number_of_allocated_fields < 0) {
4718    // There is enough inobject space for all fields (including unused).
4719    number_of_allocated_fields = 0;
4720    unused_property_fields = inobject_props - number_of_fields;
4721  }
4722
4723  // Allocate the fixed array for the fields.
4724  Handle<FixedArray> fields = factory->NewFixedArray(
4725      number_of_allocated_fields);
4726
4727  // Fill in the instance descriptor and the fields.
4728  int current_offset = 0;
4729  for (int i = 0; i < capacity; i++) {
4730    Object* k = dictionary->KeyAt(i);
4731    if (dictionary->IsKey(k)) {
4732      Object* value = dictionary->ValueAt(i);
4733      Handle<Name> key;
4734      if (k->IsSymbol()) {
4735        key = handle(Symbol::cast(k));
4736      } else {
4737        // Ensure the key is a unique name before writing into the
4738        // instance descriptor.
4739        key = factory->InternalizeString(handle(String::cast(k)));
4740      }
4741
4742      PropertyDetails details = dictionary->DetailsAt(i);
4743      int enumeration_index = details.dictionary_index();
4744      PropertyType type = details.type();
4745
4746      if (value->IsJSFunction()) {
4747        ConstantDescriptor d(key,
4748                             handle(value, isolate),
4749                             details.attributes());
4750        descriptors->Set(enumeration_index - 1, &d);
4751      } else if (type == NORMAL) {
4752        if (current_offset < inobject_props) {
4753          object->InObjectPropertyAtPut(current_offset,
4754                                        value,
4755                                        UPDATE_WRITE_BARRIER);
4756        } else {
4757          int offset = current_offset - inobject_props;
4758          fields->set(offset, value);
4759        }
4760        FieldDescriptor d(key,
4761                          current_offset++,
4762                          details.attributes(),
4763                          // TODO(verwaest): value->OptimalRepresentation();
4764                          Representation::Tagged());
4765        descriptors->Set(enumeration_index - 1, &d);
4766      } else if (type == CALLBACKS) {
4767        CallbacksDescriptor d(key,
4768                              handle(value, isolate),
4769                              details.attributes());
4770        descriptors->Set(enumeration_index - 1, &d);
4771      } else {
4772        UNREACHABLE();
4773      }
4774    }
4775  }
4776  ASSERT(current_offset == number_of_fields);
4777
4778  descriptors->Sort();
4779
4780  DisallowHeapAllocation no_gc;
4781  new_map->InitializeDescriptors(*descriptors);
4782  new_map->set_unused_property_fields(unused_property_fields);
4783
4784  // Transform the object.
4785  object->set_map(*new_map);
4786
4787  object->set_properties(*fields);
4788  ASSERT(object->IsJSObject());
4789
4790  // Check that it really works.
4791  ASSERT(object->HasFastProperties());
4792}
4793
4794
4795void JSObject::ResetElements(Handle<JSObject> object) {
4796  Heap* heap = object->GetIsolate()->heap();
4797  CHECK(object->map() != heap->sloppy_arguments_elements_map());
4798  object->set_elements(object->map()->GetInitialElements());
4799}
4800
4801
4802static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
4803    Handle<FixedArrayBase> array,
4804    int length,
4805    Handle<SeededNumberDictionary> dictionary) {
4806  Isolate* isolate = array->GetIsolate();
4807  Factory* factory = isolate->factory();
4808  bool has_double_elements = array->IsFixedDoubleArray();
4809  for (int i = 0; i < length; i++) {
4810    Handle<Object> value;
4811    if (has_double_elements) {
4812      Handle<FixedDoubleArray> double_array =
4813          Handle<FixedDoubleArray>::cast(array);
4814      if (double_array->is_the_hole(i)) {
4815        value = factory->the_hole_value();
4816      } else {
4817        value = factory->NewHeapNumber(double_array->get_scalar(i));
4818      }
4819    } else {
4820      value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
4821    }
4822    if (!value->IsTheHole()) {
4823      PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
4824      dictionary =
4825          SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
4826    }
4827  }
4828  return dictionary;
4829}
4830
4831
4832Handle<SeededNumberDictionary> JSObject::NormalizeElements(
4833    Handle<JSObject> object) {
4834  ASSERT(!object->HasExternalArrayElements() &&
4835         !object->HasFixedTypedArrayElements());
4836  Isolate* isolate = object->GetIsolate();
4837
4838  // Find the backing store.
4839  Handle<FixedArrayBase> array(FixedArrayBase::cast(object->elements()));
4840  bool is_arguments =
4841      (array->map() == isolate->heap()->sloppy_arguments_elements_map());
4842  if (is_arguments) {
4843    array = handle(FixedArrayBase::cast(
4844        Handle<FixedArray>::cast(array)->get(1)));
4845  }
4846  if (array->IsDictionary()) return Handle<SeededNumberDictionary>::cast(array);
4847
4848  ASSERT(object->HasFastSmiOrObjectElements() ||
4849         object->HasFastDoubleElements() ||
4850         object->HasFastArgumentsElements());
4851  // Compute the effective length and allocate a new backing store.
4852  int length = object->IsJSArray()
4853      ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
4854      : array->length();
4855  int old_capacity = 0;
4856  int used_elements = 0;
4857  object->GetElementsCapacityAndUsage(&old_capacity, &used_elements);
4858  Handle<SeededNumberDictionary> dictionary =
4859      SeededNumberDictionary::New(isolate, used_elements);
4860
4861  dictionary = CopyFastElementsToDictionary(array, length, dictionary);
4862
4863  // Switch to using the dictionary as the backing storage for elements.
4864  if (is_arguments) {
4865    FixedArray::cast(object->elements())->set(1, *dictionary);
4866  } else {
4867    // Set the new map first to satify the elements type assert in
4868    // set_elements().
4869    Handle<Map> new_map =
4870        JSObject::GetElementsTransitionMap(object, DICTIONARY_ELEMENTS);
4871
4872    JSObject::MigrateToMap(object, new_map);
4873    object->set_elements(*dictionary);
4874  }
4875
4876  isolate->counters()->elements_to_dictionary()->Increment();
4877
4878#ifdef DEBUG
4879  if (FLAG_trace_normalization) {
4880    PrintF("Object elements have been normalized:\n");
4881    object->Print();
4882  }
4883#endif
4884
4885  ASSERT(object->HasDictionaryElements() ||
4886         object->HasDictionaryArgumentsElements());
4887  return dictionary;
4888}
4889
4890
4891static Smi* GenerateIdentityHash(Isolate* isolate) {
4892  int hash_value;
4893  int attempts = 0;
4894  do {
4895    // Generate a random 32-bit hash value but limit range to fit
4896    // within a smi.
4897    hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
4898    attempts++;
4899  } while (hash_value == 0 && attempts < 30);
4900  hash_value = hash_value != 0 ? hash_value : 1;  // never return 0
4901
4902  return Smi::FromInt(hash_value);
4903}
4904
4905
4906void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
4907  ASSERT(!object->IsJSGlobalProxy());
4908  Isolate* isolate = object->GetIsolate();
4909  SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
4910}
4911
4912
4913template<typename ProxyType>
4914static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
4915  Isolate* isolate = proxy->GetIsolate();
4916
4917  Handle<Object> maybe_hash(proxy->hash(), isolate);
4918  if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
4919
4920  Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4921  proxy->set_hash(*hash);
4922  return hash;
4923}
4924
4925
4926Object* JSObject::GetIdentityHash() {
4927  DisallowHeapAllocation no_gc;
4928  Isolate* isolate = GetIsolate();
4929  if (IsJSGlobalProxy()) {
4930    return JSGlobalProxy::cast(this)->hash();
4931  }
4932  Object* stored_value =
4933      GetHiddenProperty(isolate->factory()->identity_hash_string());
4934  return stored_value->IsSmi()
4935      ? stored_value
4936      : isolate->heap()->undefined_value();
4937}
4938
4939
4940Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
4941  if (object->IsJSGlobalProxy()) {
4942    return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
4943  }
4944
4945  Isolate* isolate = object->GetIsolate();
4946
4947  Handle<Object> maybe_hash(object->GetIdentityHash(), isolate);
4948  if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
4949
4950  Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4951  SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
4952  return hash;
4953}
4954
4955
4956Object* JSProxy::GetIdentityHash() {
4957  return this->hash();
4958}
4959
4960
4961Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
4962  return GetOrCreateIdentityHashHelper(proxy);
4963}
4964
4965
4966Object* JSObject::GetHiddenProperty(Handle<Name> key) {
4967  DisallowHeapAllocation no_gc;
4968  ASSERT(key->IsUniqueName());
4969  if (IsJSGlobalProxy()) {
4970    // JSGlobalProxies store their hash internally.
4971    ASSERT(*key != GetHeap()->identity_hash_string());
4972    // For a proxy, use the prototype as target object.
4973    Object* proxy_parent = GetPrototype();
4974    // If the proxy is detached, return undefined.
4975    if (proxy_parent->IsNull()) return GetHeap()->the_hole_value();
4976    ASSERT(proxy_parent->IsJSGlobalObject());
4977    return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
4978  }
4979  ASSERT(!IsJSGlobalProxy());
4980  Object* inline_value = GetHiddenPropertiesHashTable();
4981
4982  if (inline_value->IsSmi()) {
4983    // Handle inline-stored identity hash.
4984    if (*key == GetHeap()->identity_hash_string()) {
4985      return inline_value;
4986    } else {
4987      return GetHeap()->the_hole_value();
4988    }
4989  }
4990
4991  if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
4992
4993  ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
4994  Object* entry = hashtable->Lookup(key);
4995  return entry;
4996}
4997
4998
4999Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
5000                                           Handle<Name> key,
5001                                           Handle<Object> value) {
5002  Isolate* isolate = object->GetIsolate();
5003
5004  ASSERT(key->IsUniqueName());
5005  if (object->IsJSGlobalProxy()) {
5006    // JSGlobalProxies store their hash internally.
5007    ASSERT(*key != *isolate->factory()->identity_hash_string());
5008    // For a proxy, use the prototype as target object.
5009    Handle<Object> proxy_parent(object->GetPrototype(), isolate);
5010    // If the proxy is detached, return undefined.
5011    if (proxy_parent->IsNull()) return isolate->factory()->undefined_value();
5012    ASSERT(proxy_parent->IsJSGlobalObject());
5013    return SetHiddenProperty(Handle<JSObject>::cast(proxy_parent), key, value);
5014  }
5015  ASSERT(!object->IsJSGlobalProxy());
5016
5017  Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
5018
5019  // If there is no backing store yet, store the identity hash inline.
5020  if (value->IsSmi() &&
5021      *key == *isolate->factory()->identity_hash_string() &&
5022      (inline_value->IsUndefined() || inline_value->IsSmi())) {
5023    return JSObject::SetHiddenPropertiesHashTable(object, value);
5024  }
5025
5026  Handle<ObjectHashTable> hashtable =
5027      GetOrCreateHiddenPropertiesHashtable(object);
5028
5029  // If it was found, check if the key is already in the dictionary.
5030  Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
5031                                                           value);
5032  if (*new_table != *hashtable) {
5033    // If adding the key expanded the dictionary (i.e., Add returned a new
5034    // dictionary), store it back to the object.
5035    SetHiddenPropertiesHashTable(object, new_table);
5036  }
5037
5038  // Return this to mark success.
5039  return object;
5040}
5041
5042
5043void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
5044  Isolate* isolate = object->GetIsolate();
5045  ASSERT(key->IsUniqueName());
5046
5047  if (object->IsJSGlobalProxy()) {
5048    Handle<Object> proto(object->GetPrototype(), isolate);
5049    if (proto->IsNull()) return;
5050    ASSERT(proto->IsJSGlobalObject());
5051    return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key);
5052  }
5053
5054  Object* inline_value = object->GetHiddenPropertiesHashTable();
5055
5056  // We never delete (inline-stored) identity hashes.
5057  ASSERT(*key != *isolate->factory()->identity_hash_string());
5058  if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
5059
5060  Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
5061  bool was_present = false;
5062  ObjectHashTable::Remove(hashtable, key, &was_present);
5063}
5064
5065
5066bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
5067  Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
5068  LookupIterator it(object, hidden, LookupIterator::CHECK_OWN_REAL);
5069  return GetPropertyAttributes(&it) != ABSENT;
5070}
5071
5072
5073Object* JSObject::GetHiddenPropertiesHashTable() {
5074  ASSERT(!IsJSGlobalProxy());
5075  if (HasFastProperties()) {
5076    // If the object has fast properties, check whether the first slot
5077    // in the descriptor array matches the hidden string. Since the
5078    // hidden strings hash code is zero (and no other name has hash
5079    // code zero) it will always occupy the first entry if present.
5080    DescriptorArray* descriptors = this->map()->instance_descriptors();
5081    if (descriptors->number_of_descriptors() > 0) {
5082      int sorted_index = descriptors->GetSortedKeyIndex(0);
5083      if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
5084          sorted_index < map()->NumberOfOwnDescriptors()) {
5085        ASSERT(descriptors->GetType(sorted_index) == FIELD);
5086        ASSERT(descriptors->GetDetails(sorted_index).representation().
5087               IsCompatibleForLoad(Representation::Tagged()));
5088        FieldIndex index = FieldIndex::ForDescriptor(this->map(),
5089                                                     sorted_index);
5090        return this->RawFastPropertyAt(index);
5091      } else {
5092        return GetHeap()->undefined_value();
5093      }
5094    } else {
5095      return GetHeap()->undefined_value();
5096    }
5097  } else {
5098    Isolate* isolate = GetIsolate();
5099    LookupResult result(isolate);
5100    LookupOwnRealNamedProperty(isolate->factory()->hidden_string(), &result);
5101    if (result.IsFound()) {
5102      ASSERT(result.IsNormal());
5103      ASSERT(result.holder() == this);
5104      Object* value = GetNormalizedProperty(&result);
5105      if (!value->IsTheHole()) return value;
5106    }
5107    return GetHeap()->undefined_value();
5108  }
5109}
5110
5111Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
5112    Handle<JSObject> object) {
5113  Isolate* isolate = object->GetIsolate();
5114
5115  static const int kInitialCapacity = 4;
5116  Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
5117  if (inline_value->IsHashTable()) {
5118    return Handle<ObjectHashTable>::cast(inline_value);
5119  }
5120
5121  Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
5122      isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
5123
5124  if (inline_value->IsSmi()) {
5125    // We were storing the identity hash inline and now allocated an actual
5126    // dictionary.  Put the identity hash into the new dictionary.
5127    hashtable = ObjectHashTable::Put(hashtable,
5128                                     isolate->factory()->identity_hash_string(),
5129                                     inline_value);
5130  }
5131
5132  JSObject::SetOwnPropertyIgnoreAttributes(
5133      object,
5134      isolate->factory()->hidden_string(),
5135      hashtable,
5136      DONT_ENUM,
5137      OPTIMAL_REPRESENTATION,
5138      ALLOW_AS_CONSTANT,
5139      OMIT_EXTENSIBILITY_CHECK).Assert();
5140
5141  return hashtable;
5142}
5143
5144
5145Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
5146                                                      Handle<Object> value) {
5147  ASSERT(!object->IsJSGlobalProxy());
5148
5149  Isolate* isolate = object->GetIsolate();
5150
5151  // We can store the identity hash inline iff there is no backing store
5152  // for hidden properties yet.
5153  ASSERT(JSObject::HasHiddenProperties(object) != value->IsSmi());
5154  if (object->HasFastProperties()) {
5155    // If the object has fast properties, check whether the first slot
5156    // in the descriptor array matches the hidden string. Since the
5157    // hidden strings hash code is zero (and no other name has hash
5158    // code zero) it will always occupy the first entry if present.
5159    DescriptorArray* descriptors = object->map()->instance_descriptors();
5160    if (descriptors->number_of_descriptors() > 0) {
5161      int sorted_index = descriptors->GetSortedKeyIndex(0);
5162      if (descriptors->GetKey(sorted_index) == isolate->heap()->hidden_string()
5163          && sorted_index < object->map()->NumberOfOwnDescriptors()) {
5164        object->WriteToField(sorted_index, *value);
5165        return object;
5166      }
5167    }
5168  }
5169
5170  SetOwnPropertyIgnoreAttributes(object,
5171                                 isolate->factory()->hidden_string(),
5172                                 value,
5173                                 DONT_ENUM,
5174                                 OPTIMAL_REPRESENTATION,
5175                                 ALLOW_AS_CONSTANT,
5176                                 OMIT_EXTENSIBILITY_CHECK).Assert();
5177  return object;
5178}
5179
5180
5181Handle<Object> JSObject::DeletePropertyPostInterceptor(Handle<JSObject> object,
5182                                                       Handle<Name> name,
5183                                                       DeleteMode mode) {
5184  // Check own property, ignore interceptor.
5185  Isolate* isolate = object->GetIsolate();
5186  LookupResult result(isolate);
5187  object->LookupOwnRealNamedProperty(name, &result);
5188  if (!result.IsFound()) return isolate->factory()->true_value();
5189
5190  // Normalize object if needed.
5191  NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
5192
5193  return DeleteNormalizedProperty(object, name, mode);
5194}
5195
5196
5197MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
5198    Handle<JSObject> object, Handle<Name> name) {
5199  Isolate* isolate = object->GetIsolate();
5200
5201  // TODO(rossberg): Support symbols in the API.
5202  if (name->IsSymbol()) return isolate->factory()->false_value();
5203
5204  Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
5205  if (!interceptor->deleter()->IsUndefined()) {
5206    v8::NamedPropertyDeleterCallback deleter =
5207        v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter());
5208    LOG(isolate,
5209        ApiNamedPropertyAccess("interceptor-named-delete", *object, *name));
5210    PropertyCallbackArguments args(
5211        isolate, interceptor->data(), *object, *object);
5212    v8::Handle<v8::Boolean> result =
5213        args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name)));
5214    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5215    if (!result.IsEmpty()) {
5216      ASSERT(result->IsBoolean());
5217      Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5218      result_internal->VerifyApiCallResultType();
5219      // Rebox CustomArguments::kReturnValueOffset before returning.
5220      return handle(*result_internal, isolate);
5221    }
5222  }
5223  Handle<Object> result =
5224      DeletePropertyPostInterceptor(object, name, NORMAL_DELETION);
5225  return result;
5226}
5227
5228
5229MaybeHandle<Object> JSObject::DeleteElementWithInterceptor(
5230    Handle<JSObject> object,
5231    uint32_t index) {
5232  Isolate* isolate = object->GetIsolate();
5233  Factory* factory = isolate->factory();
5234
5235  // Make sure that the top context does not change when doing
5236  // callbacks or interceptor calls.
5237  AssertNoContextChange ncc(isolate);
5238
5239  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
5240  if (interceptor->deleter()->IsUndefined()) return factory->false_value();
5241  v8::IndexedPropertyDeleterCallback deleter =
5242      v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5243  LOG(isolate,
5244      ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index));
5245  PropertyCallbackArguments args(
5246      isolate, interceptor->data(), *object, *object);
5247  v8::Handle<v8::Boolean> result = args.Call(deleter, index);
5248  RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5249  if (!result.IsEmpty()) {
5250    ASSERT(result->IsBoolean());
5251    Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5252    result_internal->VerifyApiCallResultType();
5253    // Rebox CustomArguments::kReturnValueOffset before returning.
5254    return handle(*result_internal, isolate);
5255  }
5256  MaybeHandle<Object> delete_result = object->GetElementsAccessor()->Delete(
5257      object, index, NORMAL_DELETION);
5258  return delete_result;
5259}
5260
5261
5262MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
5263                                            uint32_t index,
5264                                            DeleteMode mode) {
5265  Isolate* isolate = object->GetIsolate();
5266  Factory* factory = isolate->factory();
5267
5268  // Check access rights if needed.
5269  if (object->IsAccessCheckNeeded() &&
5270      !isolate->MayIndexedAccess(object, index, v8::ACCESS_DELETE)) {
5271    isolate->ReportFailedAccessCheck(object, v8::ACCESS_DELETE);
5272    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5273    return factory->false_value();
5274  }
5275
5276  if (object->IsStringObjectWithCharacterAt(index)) {
5277    if (mode == STRICT_DELETION) {
5278      // Deleting a non-configurable property in strict mode.
5279      Handle<Object> name = factory->NewNumberFromUint(index);
5280      Handle<Object> args[2] = { name, object };
5281      Handle<Object> error =
5282          factory->NewTypeError("strict_delete_property",
5283                                HandleVector(args, 2));
5284      isolate->Throw(*error);
5285      return Handle<Object>();
5286    }
5287    return factory->false_value();
5288  }
5289
5290  if (object->IsJSGlobalProxy()) {
5291    Handle<Object> proto(object->GetPrototype(), isolate);
5292    if (proto->IsNull()) return factory->false_value();
5293    ASSERT(proto->IsJSGlobalObject());
5294    return DeleteElement(Handle<JSObject>::cast(proto), index, mode);
5295  }
5296
5297  Handle<Object> old_value;
5298  bool should_enqueue_change_record = false;
5299  if (object->map()->is_observed()) {
5300    should_enqueue_change_record = HasOwnElement(object, index);
5301    if (should_enqueue_change_record) {
5302      if (!GetOwnElementAccessorPair(object, index).is_null()) {
5303        old_value = Handle<Object>::cast(factory->the_hole_value());
5304      } else {
5305        old_value = Object::GetElement(
5306            isolate, object, index).ToHandleChecked();
5307      }
5308    }
5309  }
5310
5311  // Skip interceptor if forcing deletion.
5312  MaybeHandle<Object> maybe_result;
5313  if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
5314    maybe_result = DeleteElementWithInterceptor(object, index);
5315  } else {
5316    maybe_result = object->GetElementsAccessor()->Delete(object, index, mode);
5317  }
5318  Handle<Object> result;
5319  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
5320
5321  if (should_enqueue_change_record && !HasOwnElement(object, index)) {
5322    Handle<String> name = factory->Uint32ToString(index);
5323    EnqueueChangeRecord(object, "delete", name, old_value);
5324  }
5325
5326  return result;
5327}
5328
5329
5330MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
5331                                             Handle<Name> name,
5332                                             DeleteMode mode) {
5333  Isolate* isolate = object->GetIsolate();
5334  // ECMA-262, 3rd, 8.6.2.5
5335  ASSERT(name->IsName());
5336
5337  // Check access rights if needed.
5338  if (object->IsAccessCheckNeeded() &&
5339      !isolate->MayNamedAccess(object, name, v8::ACCESS_DELETE)) {
5340    isolate->ReportFailedAccessCheck(object, v8::ACCESS_DELETE);
5341    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5342    return isolate->factory()->false_value();
5343  }
5344
5345  if (object->IsJSGlobalProxy()) {
5346    Object* proto = object->GetPrototype();
5347    if (proto->IsNull()) return isolate->factory()->false_value();
5348    ASSERT(proto->IsJSGlobalObject());
5349    return JSGlobalObject::DeleteProperty(
5350        handle(JSGlobalObject::cast(proto)), name, mode);
5351  }
5352
5353  uint32_t index = 0;
5354  if (name->AsArrayIndex(&index)) {
5355    return DeleteElement(object, index, mode);
5356  }
5357
5358  LookupResult lookup(isolate);
5359  object->LookupOwn(name, &lookup, true);
5360  if (!lookup.IsFound()) return isolate->factory()->true_value();
5361  // Ignore attributes if forcing a deletion.
5362  if (lookup.IsDontDelete() && mode != FORCE_DELETION) {
5363    if (mode == STRICT_DELETION) {
5364      // Deleting a non-configurable property in strict mode.
5365      Handle<Object> args[2] = { name, object };
5366      Handle<Object> error = isolate->factory()->NewTypeError(
5367          "strict_delete_property", HandleVector(args, ARRAY_SIZE(args)));
5368      isolate->Throw(*error);
5369      return Handle<Object>();
5370    }
5371    return isolate->factory()->false_value();
5372  }
5373
5374  Handle<Object> old_value = isolate->factory()->the_hole_value();
5375  bool is_observed = object->map()->is_observed() &&
5376                     *name != isolate->heap()->hidden_string();
5377  if (is_observed && lookup.IsDataProperty()) {
5378    old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked();
5379  }
5380  Handle<Object> result;
5381
5382  // Check for interceptor.
5383  if (lookup.IsInterceptor()) {
5384    // Skip interceptor if forcing a deletion.
5385    if (mode == FORCE_DELETION) {
5386      result = DeletePropertyPostInterceptor(object, name, mode);
5387    } else {
5388      ASSIGN_RETURN_ON_EXCEPTION(
5389          isolate, result,
5390          DeletePropertyWithInterceptor(object, name),
5391          Object);
5392    }
5393  } else {
5394    // Normalize object if needed.
5395    NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
5396    // Make sure the properties are normalized before removing the entry.
5397    result = DeleteNormalizedProperty(object, name, mode);
5398  }
5399
5400  if (is_observed && !HasOwnProperty(object, name)) {
5401    EnqueueChangeRecord(object, "delete", name, old_value);
5402  }
5403
5404  return result;
5405}
5406
5407
5408MaybeHandle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
5409                                              uint32_t index,
5410                                              DeleteMode mode) {
5411  if (object->IsJSProxy()) {
5412    return JSProxy::DeleteElementWithHandler(
5413        Handle<JSProxy>::cast(object), index, mode);
5414  }
5415  return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
5416}
5417
5418
5419MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
5420                                               Handle<Name> name,
5421                                               DeleteMode mode) {
5422  if (object->IsJSProxy()) {
5423    return JSProxy::DeletePropertyWithHandler(
5424        Handle<JSProxy>::cast(object), name, mode);
5425  }
5426  return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
5427}
5428
5429
5430bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5431                                            ElementsKind kind,
5432                                            Object* object) {
5433  ASSERT(IsFastObjectElementsKind(kind) ||
5434         kind == DICTIONARY_ELEMENTS);
5435  if (IsFastObjectElementsKind(kind)) {
5436    int length = IsJSArray()
5437        ? Smi::cast(JSArray::cast(this)->length())->value()
5438        : elements->length();
5439    for (int i = 0; i < length; ++i) {
5440      Object* element = elements->get(i);
5441      if (!element->IsTheHole() && element == object) return true;
5442    }
5443  } else {
5444    Object* key =
5445        SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
5446    if (!key->IsUndefined()) return true;
5447  }
5448  return false;
5449}
5450
5451
5452// Check whether this object references another object.
5453bool JSObject::ReferencesObject(Object* obj) {
5454  Map* map_of_this = map();
5455  Heap* heap = GetHeap();
5456  DisallowHeapAllocation no_allocation;
5457
5458  // Is the object the constructor for this object?
5459  if (map_of_this->constructor() == obj) {
5460    return true;
5461  }
5462
5463  // Is the object the prototype for this object?
5464  if (map_of_this->prototype() == obj) {
5465    return true;
5466  }
5467
5468  // Check if the object is among the named properties.
5469  Object* key = SlowReverseLookup(obj);
5470  if (!key->IsUndefined()) {
5471    return true;
5472  }
5473
5474  // Check if the object is among the indexed properties.
5475  ElementsKind kind = GetElementsKind();
5476  switch (kind) {
5477    // Raw pixels and external arrays do not reference other
5478    // objects.
5479#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
5480    case EXTERNAL_##TYPE##_ELEMENTS:                                           \
5481    case TYPE##_ELEMENTS:                                                      \
5482      break;
5483
5484    TYPED_ARRAYS(TYPED_ARRAY_CASE)
5485#undef TYPED_ARRAY_CASE
5486
5487    case FAST_DOUBLE_ELEMENTS:
5488    case FAST_HOLEY_DOUBLE_ELEMENTS:
5489      break;
5490    case FAST_SMI_ELEMENTS:
5491    case FAST_HOLEY_SMI_ELEMENTS:
5492      break;
5493    case FAST_ELEMENTS:
5494    case FAST_HOLEY_ELEMENTS:
5495    case DICTIONARY_ELEMENTS: {
5496      FixedArray* elements = FixedArray::cast(this->elements());
5497      if (ReferencesObjectFromElements(elements, kind, obj)) return true;
5498      break;
5499    }
5500    case SLOPPY_ARGUMENTS_ELEMENTS: {
5501      FixedArray* parameter_map = FixedArray::cast(elements());
5502      // Check the mapped parameters.
5503      int length = parameter_map->length();
5504      for (int i = 2; i < length; ++i) {
5505        Object* value = parameter_map->get(i);
5506        if (!value->IsTheHole() && value == obj) return true;
5507      }
5508      // Check the arguments.
5509      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
5510      kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
5511          FAST_HOLEY_ELEMENTS;
5512      if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
5513      break;
5514    }
5515  }
5516
5517  // For functions check the context.
5518  if (IsJSFunction()) {
5519    // Get the constructor function for arguments array.
5520    JSObject* arguments_boilerplate =
5521        heap->isolate()->context()->native_context()->
5522            sloppy_arguments_boilerplate();
5523    JSFunction* arguments_function =
5524        JSFunction::cast(arguments_boilerplate->map()->constructor());
5525
5526    // Get the context and don't check if it is the native context.
5527    JSFunction* f = JSFunction::cast(this);
5528    Context* context = f->context();
5529    if (context->IsNativeContext()) {
5530      return false;
5531    }
5532
5533    // Check the non-special context slots.
5534    for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
5535      // Only check JS objects.
5536      if (context->get(i)->IsJSObject()) {
5537        JSObject* ctxobj = JSObject::cast(context->get(i));
5538        // If it is an arguments array check the content.
5539        if (ctxobj->map()->constructor() == arguments_function) {
5540          if (ctxobj->ReferencesObject(obj)) {
5541            return true;
5542          }
5543        } else if (ctxobj == obj) {
5544          return true;
5545        }
5546      }
5547    }
5548
5549    // Check the context extension (if any) if it can have references.
5550    if (context->has_extension() && !context->IsCatchContext()) {
5551      // With harmony scoping, a JSFunction may have a global context.
5552      // TODO(mvstanton): walk into the ScopeInfo.
5553      if (FLAG_harmony_scoping && context->IsGlobalContext()) {
5554        return false;
5555      }
5556
5557      return JSObject::cast(context->extension())->ReferencesObject(obj);
5558    }
5559  }
5560
5561  // No references to object.
5562  return false;
5563}
5564
5565
5566MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
5567  Isolate* isolate = object->GetIsolate();
5568
5569  if (!object->map()->is_extensible()) return object;
5570
5571  if (object->IsAccessCheckNeeded() &&
5572      !isolate->MayNamedAccess(
5573          object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5574    isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5575    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5576    return isolate->factory()->false_value();
5577  }
5578
5579  if (object->IsJSGlobalProxy()) {
5580    Handle<Object> proto(object->GetPrototype(), isolate);
5581    if (proto->IsNull()) return object;
5582    ASSERT(proto->IsJSGlobalObject());
5583    return PreventExtensions(Handle<JSObject>::cast(proto));
5584  }
5585
5586  // It's not possible to seal objects with external array elements
5587  if (object->HasExternalArrayElements() ||
5588      object->HasFixedTypedArrayElements()) {
5589    Handle<Object> error  =
5590        isolate->factory()->NewTypeError(
5591            "cant_prevent_ext_external_array_elements",
5592            HandleVector(&object, 1));
5593    return isolate->Throw<Object>(error);
5594  }
5595
5596  // If there are fast elements we normalize.
5597  Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
5598  ASSERT(object->HasDictionaryElements() ||
5599         object->HasDictionaryArgumentsElements());
5600
5601  // Make sure that we never go back to fast case.
5602  dictionary->set_requires_slow_elements();
5603
5604  // Do a map transition, other objects with this map may still
5605  // be extensible.
5606  // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
5607  Handle<Map> new_map = Map::Copy(handle(object->map()));
5608
5609  new_map->set_is_extensible(false);
5610  JSObject::MigrateToMap(object, new_map);
5611  ASSERT(!object->map()->is_extensible());
5612
5613  if (object->map()->is_observed()) {
5614    EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
5615                        isolate->factory()->the_hole_value());
5616  }
5617  return object;
5618}
5619
5620
5621template<typename Dictionary>
5622static void FreezeDictionary(Dictionary* dictionary) {
5623  int capacity = dictionary->Capacity();
5624  for (int i = 0; i < capacity; i++) {
5625    Object* k = dictionary->KeyAt(i);
5626    if (dictionary->IsKey(k)) {
5627      PropertyDetails details = dictionary->DetailsAt(i);
5628      int attrs = DONT_DELETE;
5629      // READ_ONLY is an invalid attribute for JS setters/getters.
5630      if (details.type() == CALLBACKS) {
5631        Object* v = dictionary->ValueAt(i);
5632        if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
5633        if (!v->IsAccessorPair()) attrs |= READ_ONLY;
5634      } else {
5635        attrs |= READ_ONLY;
5636      }
5637      details = details.CopyAddAttributes(
5638          static_cast<PropertyAttributes>(attrs));
5639      dictionary->DetailsAtPut(i, details);
5640    }
5641  }
5642}
5643
5644
5645MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
5646  // Freezing sloppy arguments should be handled elsewhere.
5647  ASSERT(!object->HasSloppyArgumentsElements());
5648  ASSERT(!object->map()->is_observed());
5649
5650  if (object->map()->is_frozen()) return object;
5651
5652  Isolate* isolate = object->GetIsolate();
5653  if (object->IsAccessCheckNeeded() &&
5654      !isolate->MayNamedAccess(
5655          object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5656    isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5657    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5658    return isolate->factory()->false_value();
5659  }
5660
5661  if (object->IsJSGlobalProxy()) {
5662    Handle<Object> proto(object->GetPrototype(), isolate);
5663    if (proto->IsNull()) return object;
5664    ASSERT(proto->IsJSGlobalObject());
5665    return Freeze(Handle<JSObject>::cast(proto));
5666  }
5667
5668  // It's not possible to freeze objects with external array elements
5669  if (object->HasExternalArrayElements() ||
5670      object->HasFixedTypedArrayElements()) {
5671    Handle<Object> error  =
5672        isolate->factory()->NewTypeError(
5673            "cant_prevent_ext_external_array_elements",
5674            HandleVector(&object, 1));
5675    return isolate->Throw<Object>(error);
5676  }
5677
5678  Handle<SeededNumberDictionary> new_element_dictionary;
5679  if (!object->elements()->IsDictionary()) {
5680    int length = object->IsJSArray()
5681        ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5682        : object->elements()->length();
5683    if (length > 0) {
5684      int capacity = 0;
5685      int used = 0;
5686      object->GetElementsCapacityAndUsage(&capacity, &used);
5687      new_element_dictionary = SeededNumberDictionary::New(isolate, used);
5688
5689      // Move elements to a dictionary; avoid calling NormalizeElements to avoid
5690      // unnecessary transitions.
5691      new_element_dictionary = CopyFastElementsToDictionary(
5692          handle(object->elements()), length, new_element_dictionary);
5693    } else {
5694      // No existing elements, use a pre-allocated empty backing store
5695      new_element_dictionary =
5696          isolate->factory()->empty_slow_element_dictionary();
5697    }
5698  }
5699
5700  Handle<Map> old_map(object->map(), isolate);
5701  int transition_index = old_map->SearchTransition(
5702      isolate->heap()->frozen_symbol());
5703  if (transition_index != TransitionArray::kNotFound) {
5704    Handle<Map> transition_map(old_map->GetTransition(transition_index));
5705    ASSERT(transition_map->has_dictionary_elements());
5706    ASSERT(transition_map->is_frozen());
5707    ASSERT(!transition_map->is_extensible());
5708    JSObject::MigrateToMap(object, transition_map);
5709  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
5710    // Create a new descriptor array with fully-frozen properties
5711    Handle<Map> new_map = Map::CopyForFreeze(old_map);
5712    JSObject::MigrateToMap(object, new_map);
5713  } else {
5714    // Slow path: need to normalize properties for safety
5715    NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
5716
5717    // Create a new map, since other objects with this map may be extensible.
5718    // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
5719    Handle<Map> new_map = Map::Copy(handle(object->map()));
5720    new_map->freeze();
5721    new_map->set_is_extensible(false);
5722    new_map->set_elements_kind(DICTIONARY_ELEMENTS);
5723    JSObject::MigrateToMap(object, new_map);
5724
5725    // Freeze dictionary-mode properties
5726    FreezeDictionary(object->property_dictionary());
5727  }
5728
5729  ASSERT(object->map()->has_dictionary_elements());
5730  if (!new_element_dictionary.is_null()) {
5731    object->set_elements(*new_element_dictionary);
5732  }
5733
5734  if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
5735    SeededNumberDictionary* dictionary = object->element_dictionary();
5736    // Make sure we never go back to the fast case
5737    dictionary->set_requires_slow_elements();
5738    // Freeze all elements in the dictionary
5739    FreezeDictionary(dictionary);
5740  }
5741
5742  return object;
5743}
5744
5745
5746void JSObject::SetObserved(Handle<JSObject> object) {
5747  ASSERT(!object->IsJSGlobalProxy());
5748  ASSERT(!object->IsJSGlobalObject());
5749  Isolate* isolate = object->GetIsolate();
5750  Handle<Map> new_map;
5751  Handle<Map> old_map(object->map(), isolate);
5752  ASSERT(!old_map->is_observed());
5753  int transition_index = old_map->SearchTransition(
5754      isolate->heap()->observed_symbol());
5755  if (transition_index != TransitionArray::kNotFound) {
5756    new_map = handle(old_map->GetTransition(transition_index), isolate);
5757    ASSERT(new_map->is_observed());
5758  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
5759    new_map = Map::CopyForObserved(old_map);
5760  } else {
5761    new_map = Map::Copy(old_map);
5762    new_map->set_is_observed();
5763  }
5764  JSObject::MigrateToMap(object, new_map);
5765}
5766
5767
5768Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
5769                                        Representation representation,
5770                                        FieldIndex index) {
5771  Isolate* isolate = object->GetIsolate();
5772  Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
5773  return Object::NewStorageFor(isolate, raw_value, representation);
5774}
5775
5776
5777template<class ContextObject>
5778class JSObjectWalkVisitor {
5779 public:
5780  JSObjectWalkVisitor(ContextObject* site_context, bool copying,
5781                      JSObject::DeepCopyHints hints)
5782    : site_context_(site_context),
5783      copying_(copying),
5784      hints_(hints) {}
5785
5786  MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
5787
5788 protected:
5789  MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
5790      Handle<JSObject> object,
5791      Handle<JSObject> value) {
5792    Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5793    MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
5794    site_context()->ExitScope(current_site, value);
5795    return copy_of_value;
5796  }
5797
5798  inline ContextObject* site_context() { return site_context_; }
5799  inline Isolate* isolate() { return site_context()->isolate(); }
5800
5801  inline bool copying() const { return copying_; }
5802
5803 private:
5804  ContextObject* site_context_;
5805  const bool copying_;
5806  const JSObject::DeepCopyHints hints_;
5807};
5808
5809
5810template <class ContextObject>
5811MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
5812    Handle<JSObject> object) {
5813  Isolate* isolate = this->isolate();
5814  bool copying = this->copying();
5815  bool shallow = hints_ == JSObject::kObjectIsShallowArray;
5816
5817  if (!shallow) {
5818    StackLimitCheck check(isolate);
5819
5820    if (check.HasOverflowed()) {
5821      isolate->StackOverflow();
5822      return MaybeHandle<JSObject>();
5823    }
5824  }
5825
5826  if (object->map()->is_deprecated()) {
5827    JSObject::MigrateInstance(object);
5828  }
5829
5830  Handle<JSObject> copy;
5831  if (copying) {
5832    Handle<AllocationSite> site_to_pass;
5833    if (site_context()->ShouldCreateMemento(object)) {
5834      site_to_pass = site_context()->current();
5835    }
5836    copy = isolate->factory()->CopyJSObjectWithAllocationSite(
5837        object, site_to_pass);
5838  } else {
5839    copy = object;
5840  }
5841
5842  ASSERT(copying || copy.is_identical_to(object));
5843
5844  ElementsKind kind = copy->GetElementsKind();
5845  if (copying && IsFastSmiOrObjectElementsKind(kind) &&
5846      FixedArray::cast(copy->elements())->map() ==
5847        isolate->heap()->fixed_cow_array_map()) {
5848    isolate->counters()->cow_arrays_created_runtime()->Increment();
5849  }
5850
5851  if (!shallow) {
5852    HandleScope scope(isolate);
5853
5854    // Deep copy own properties.
5855    if (copy->HasFastProperties()) {
5856      Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
5857      int limit = copy->map()->NumberOfOwnDescriptors();
5858      for (int i = 0; i < limit; i++) {
5859        PropertyDetails details = descriptors->GetDetails(i);
5860        if (details.type() != FIELD) continue;
5861        FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
5862        Handle<Object> value(object->RawFastPropertyAt(index), isolate);
5863        if (value->IsJSObject()) {
5864          ASSIGN_RETURN_ON_EXCEPTION(
5865              isolate, value,
5866              VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5867              JSObject);
5868        } else {
5869          Representation representation = details.representation();
5870          value = Object::NewStorageFor(isolate, value, representation);
5871        }
5872        if (copying) {
5873          copy->FastPropertyAtPut(index, *value);
5874        }
5875      }
5876    } else {
5877      Handle<FixedArray> names =
5878          isolate->factory()->NewFixedArray(copy->NumberOfOwnProperties());
5879      copy->GetOwnPropertyNames(*names, 0);
5880      for (int i = 0; i < names->length(); i++) {
5881        ASSERT(names->get(i)->IsString());
5882        Handle<String> key_string(String::cast(names->get(i)));
5883        PropertyAttributes attributes =
5884            JSReceiver::GetOwnPropertyAttributes(copy, key_string);
5885        // Only deep copy fields from the object literal expression.
5886        // In particular, don't try to copy the length attribute of
5887        // an array.
5888        if (attributes != NONE) continue;
5889        Handle<Object> value =
5890            Object::GetProperty(copy, key_string).ToHandleChecked();
5891        if (value->IsJSObject()) {
5892          Handle<JSObject> result;
5893          ASSIGN_RETURN_ON_EXCEPTION(
5894              isolate, result,
5895              VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5896              JSObject);
5897          if (copying) {
5898            // Creating object copy for literals. No strict mode needed.
5899            JSObject::SetProperty(
5900                copy, key_string, result, NONE, SLOPPY).Assert();
5901          }
5902        }
5903      }
5904    }
5905
5906    // Deep copy own elements.
5907    // Pixel elements cannot be created using an object literal.
5908    ASSERT(!copy->HasExternalArrayElements());
5909    switch (kind) {
5910      case FAST_SMI_ELEMENTS:
5911      case FAST_ELEMENTS:
5912      case FAST_HOLEY_SMI_ELEMENTS:
5913      case FAST_HOLEY_ELEMENTS: {
5914        Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
5915        if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
5916#ifdef DEBUG
5917          for (int i = 0; i < elements->length(); i++) {
5918            ASSERT(!elements->get(i)->IsJSObject());
5919          }
5920#endif
5921        } else {
5922          for (int i = 0; i < elements->length(); i++) {
5923            Handle<Object> value(elements->get(i), isolate);
5924            ASSERT(value->IsSmi() ||
5925                   value->IsTheHole() ||
5926                   (IsFastObjectElementsKind(copy->GetElementsKind())));
5927            if (value->IsJSObject()) {
5928              Handle<JSObject> result;
5929              ASSIGN_RETURN_ON_EXCEPTION(
5930                  isolate, result,
5931                  VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5932                  JSObject);
5933              if (copying) {
5934                elements->set(i, *result);
5935              }
5936            }
5937          }
5938        }
5939        break;
5940      }
5941      case DICTIONARY_ELEMENTS: {
5942        Handle<SeededNumberDictionary> element_dictionary(
5943            copy->element_dictionary());
5944        int capacity = element_dictionary->Capacity();
5945        for (int i = 0; i < capacity; i++) {
5946          Object* k = element_dictionary->KeyAt(i);
5947          if (element_dictionary->IsKey(k)) {
5948            Handle<Object> value(element_dictionary->ValueAt(i), isolate);
5949            if (value->IsJSObject()) {
5950              Handle<JSObject> result;
5951              ASSIGN_RETURN_ON_EXCEPTION(
5952                  isolate, result,
5953                  VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5954                  JSObject);
5955              if (copying) {
5956                element_dictionary->ValueAtPut(i, *result);
5957              }
5958            }
5959          }
5960        }
5961        break;
5962      }
5963      case SLOPPY_ARGUMENTS_ELEMENTS:
5964        UNIMPLEMENTED();
5965        break;
5966
5967
5968#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
5969      case EXTERNAL_##TYPE##_ELEMENTS:                                         \
5970      case TYPE##_ELEMENTS:                                                    \
5971
5972      TYPED_ARRAYS(TYPED_ARRAY_CASE)
5973#undef TYPED_ARRAY_CASE
5974
5975      case FAST_DOUBLE_ELEMENTS:
5976      case FAST_HOLEY_DOUBLE_ELEMENTS:
5977        // No contained objects, nothing to do.
5978        break;
5979    }
5980  }
5981
5982  return copy;
5983}
5984
5985
5986MaybeHandle<JSObject> JSObject::DeepWalk(
5987    Handle<JSObject> object,
5988    AllocationSiteCreationContext* site_context) {
5989  JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
5990                                                       kNoHints);
5991  MaybeHandle<JSObject> result = v.StructureWalk(object);
5992  Handle<JSObject> for_assert;
5993  ASSERT(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
5994  return result;
5995}
5996
5997
5998MaybeHandle<JSObject> JSObject::DeepCopy(
5999    Handle<JSObject> object,
6000    AllocationSiteUsageContext* site_context,
6001    DeepCopyHints hints) {
6002  JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
6003  MaybeHandle<JSObject> copy = v.StructureWalk(object);
6004  Handle<JSObject> for_assert;
6005  ASSERT(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
6006  return copy;
6007}
6008
6009
6010Handle<Object> JSObject::GetDataProperty(Handle<JSObject> object,
6011                                         Handle<Name> key) {
6012  Isolate* isolate = object->GetIsolate();
6013  LookupResult lookup(isolate);
6014  {
6015    DisallowHeapAllocation no_allocation;
6016    object->LookupRealNamedProperty(key, &lookup);
6017  }
6018  Handle<Object> result = isolate->factory()->undefined_value();
6019  if (lookup.IsFound() && !lookup.IsTransition()) {
6020    switch (lookup.type()) {
6021      case NORMAL:
6022        result = GetNormalizedProperty(
6023            Handle<JSObject>(lookup.holder(), isolate), &lookup);
6024        break;
6025      case FIELD:
6026        result = FastPropertyAt(Handle<JSObject>(lookup.holder(), isolate),
6027                                lookup.representation(),
6028                                lookup.GetFieldIndex());
6029        break;
6030      case CONSTANT:
6031        result = Handle<Object>(lookup.GetConstant(), isolate);
6032        break;
6033      case CALLBACKS:
6034      case HANDLER:
6035      case INTERCEPTOR:
6036        break;
6037      case NONEXISTENT:
6038        UNREACHABLE();
6039    }
6040  }
6041  return result;
6042}
6043
6044
6045// Tests for the fast common case for property enumeration:
6046// - This object and all prototypes has an enum cache (which means that
6047//   it is no proxy, has no interceptors and needs no access checks).
6048// - This object has no elements.
6049// - No prototype has enumerable properties/elements.
6050bool JSReceiver::IsSimpleEnum() {
6051  Heap* heap = GetHeap();
6052  for (Object* o = this;
6053       o != heap->null_value();
6054       o = JSObject::cast(o)->GetPrototype()) {
6055    if (!o->IsJSObject()) return false;
6056    JSObject* curr = JSObject::cast(o);
6057    int enum_length = curr->map()->EnumLength();
6058    if (enum_length == kInvalidEnumCacheSentinel) return false;
6059    if (curr->IsAccessCheckNeeded()) return false;
6060    ASSERT(!curr->HasNamedInterceptor());
6061    ASSERT(!curr->HasIndexedInterceptor());
6062    if (curr->NumberOfEnumElements() > 0) return false;
6063    if (curr != this && enum_length != 0) return false;
6064  }
6065  return true;
6066}
6067
6068
6069static bool FilterKey(Object* key, PropertyAttributes filter) {
6070  if ((filter & SYMBOLIC) && key->IsSymbol()) {
6071    return true;
6072  }
6073
6074  if ((filter & PRIVATE_SYMBOL) &&
6075      key->IsSymbol() && Symbol::cast(key)->is_private()) {
6076    return true;
6077  }
6078
6079  if ((filter & STRING) && !key->IsSymbol()) {
6080    return true;
6081  }
6082
6083  return false;
6084}
6085
6086
6087int Map::NumberOfDescribedProperties(DescriptorFlag which,
6088                                     PropertyAttributes filter) {
6089  int result = 0;
6090  DescriptorArray* descs = instance_descriptors();
6091  int limit = which == ALL_DESCRIPTORS
6092      ? descs->number_of_descriptors()
6093      : NumberOfOwnDescriptors();
6094  for (int i = 0; i < limit; i++) {
6095    if ((descs->GetDetails(i).attributes() & filter) == 0 &&
6096        !FilterKey(descs->GetKey(i), filter)) {
6097      result++;
6098    }
6099  }
6100  return result;
6101}
6102
6103
6104int Map::NextFreePropertyIndex() {
6105  int max_index = -1;
6106  int number_of_own_descriptors = NumberOfOwnDescriptors();
6107  DescriptorArray* descs = instance_descriptors();
6108  for (int i = 0; i < number_of_own_descriptors; i++) {
6109    if (descs->GetType(i) == FIELD) {
6110      int current_index = descs->GetFieldIndex(i);
6111      if (current_index > max_index) max_index = current_index;
6112    }
6113  }
6114  return max_index + 1;
6115}
6116
6117
6118void JSReceiver::LookupOwn(
6119    Handle<Name> name, LookupResult* result, bool search_hidden_prototypes) {
6120  DisallowHeapAllocation no_gc;
6121  ASSERT(name->IsName());
6122
6123  if (IsJSGlobalProxy()) {
6124    Object* proto = GetPrototype();
6125    if (proto->IsNull()) return result->NotFound();
6126    ASSERT(proto->IsJSGlobalObject());
6127    return JSReceiver::cast(proto)->LookupOwn(
6128        name, result, search_hidden_prototypes);
6129  }
6130
6131  if (IsJSProxy()) {
6132    result->HandlerResult(JSProxy::cast(this));
6133    return;
6134  }
6135
6136  // Do not use inline caching if the object is a non-global object
6137  // that requires access checks.
6138  if (IsAccessCheckNeeded()) {
6139    result->DisallowCaching();
6140  }
6141
6142  JSObject* js_object = JSObject::cast(this);
6143
6144  // Check for lookup interceptor except when bootstrapping.
6145  if (js_object->HasNamedInterceptor() &&
6146      !GetIsolate()->bootstrapper()->IsActive()) {
6147    result->InterceptorResult(js_object);
6148    return;
6149  }
6150
6151  js_object->LookupOwnRealNamedProperty(name, result);
6152  if (result->IsFound() || !search_hidden_prototypes) return;
6153
6154  Object* proto = js_object->GetPrototype();
6155  if (!proto->IsJSReceiver()) return;
6156  JSReceiver* receiver = JSReceiver::cast(proto);
6157  if (receiver->map()->is_hidden_prototype()) {
6158    receiver->LookupOwn(name, result, search_hidden_prototypes);
6159  }
6160}
6161
6162
6163void JSReceiver::Lookup(Handle<Name> name, LookupResult* result) {
6164  DisallowHeapAllocation no_gc;
6165  // Ecma-262 3rd 8.6.2.4
6166  Handle<Object> null_value = GetIsolate()->factory()->null_value();
6167  for (Object* current = this;
6168       current != *null_value;
6169       current = JSObject::cast(current)->GetPrototype()) {
6170    JSReceiver::cast(current)->LookupOwn(name, result, false);
6171    if (result->IsFound()) return;
6172  }
6173  result->NotFound();
6174}
6175
6176
6177static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
6178  int len = array->length();
6179  for (int i = 0; i < len; i++) {
6180    Object* e = array->get(i);
6181    if (!(e->IsString() || e->IsNumber())) return false;
6182  }
6183  return true;
6184}
6185
6186
6187static Handle<FixedArray> ReduceFixedArrayTo(
6188    Handle<FixedArray> array, int length) {
6189  ASSERT(array->length() >= length);
6190  if (array->length() == length) return array;
6191
6192  Handle<FixedArray> new_array =
6193      array->GetIsolate()->factory()->NewFixedArray(length);
6194  for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
6195  return new_array;
6196}
6197
6198
6199static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
6200                                              bool cache_result) {
6201  Isolate* isolate = object->GetIsolate();
6202  if (object->HasFastProperties()) {
6203    int own_property_count = object->map()->EnumLength();
6204    // If the enum length of the given map is set to kInvalidEnumCache, this
6205    // means that the map itself has never used the present enum cache. The
6206    // first step to using the cache is to set the enum length of the map by
6207    // counting the number of own descriptors that are not DONT_ENUM or
6208    // SYMBOLIC.
6209    if (own_property_count == kInvalidEnumCacheSentinel) {
6210      own_property_count = object->map()->NumberOfDescribedProperties(
6211          OWN_DESCRIPTORS, DONT_SHOW);
6212    } else {
6213      ASSERT(own_property_count == object->map()->NumberOfDescribedProperties(
6214          OWN_DESCRIPTORS, DONT_SHOW));
6215    }
6216
6217    if (object->map()->instance_descriptors()->HasEnumCache()) {
6218      DescriptorArray* desc = object->map()->instance_descriptors();
6219      Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
6220
6221      // In case the number of properties required in the enum are actually
6222      // present, we can reuse the enum cache. Otherwise, this means that the
6223      // enum cache was generated for a previous (smaller) version of the
6224      // Descriptor Array. In that case we regenerate the enum cache.
6225      if (own_property_count <= keys->length()) {
6226        if (cache_result) object->map()->SetEnumLength(own_property_count);
6227        isolate->counters()->enum_cache_hits()->Increment();
6228        return ReduceFixedArrayTo(keys, own_property_count);
6229      }
6230    }
6231
6232    Handle<Map> map(object->map());
6233
6234    if (map->instance_descriptors()->IsEmpty()) {
6235      isolate->counters()->enum_cache_hits()->Increment();
6236      if (cache_result) map->SetEnumLength(0);
6237      return isolate->factory()->empty_fixed_array();
6238    }
6239
6240    isolate->counters()->enum_cache_misses()->Increment();
6241
6242    Handle<FixedArray> storage = isolate->factory()->NewFixedArray(
6243        own_property_count);
6244    Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
6245        own_property_count);
6246
6247    Handle<DescriptorArray> descs =
6248        Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
6249
6250    int size = map->NumberOfOwnDescriptors();
6251    int index = 0;
6252
6253    for (int i = 0; i < size; i++) {
6254      PropertyDetails details = descs->GetDetails(i);
6255      Object* key = descs->GetKey(i);
6256      if (!(details.IsDontEnum() || key->IsSymbol())) {
6257        storage->set(index, key);
6258        if (!indices.is_null()) {
6259          if (details.type() != FIELD) {
6260            indices = Handle<FixedArray>();
6261          } else {
6262            FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
6263            int load_by_field_index = field_index.GetLoadByFieldIndex();
6264            indices->set(index, Smi::FromInt(load_by_field_index));
6265          }
6266        }
6267        index++;
6268      }
6269    }
6270    ASSERT(index == storage->length());
6271
6272    Handle<FixedArray> bridge_storage =
6273        isolate->factory()->NewFixedArray(
6274            DescriptorArray::kEnumCacheBridgeLength);
6275    DescriptorArray* desc = object->map()->instance_descriptors();
6276    desc->SetEnumCache(*bridge_storage,
6277                       *storage,
6278                       indices.is_null() ? Object::cast(Smi::FromInt(0))
6279                                         : Object::cast(*indices));
6280    if (cache_result) {
6281      object->map()->SetEnumLength(own_property_count);
6282    }
6283    return storage;
6284  } else {
6285    Handle<NameDictionary> dictionary(object->property_dictionary());
6286    int length = dictionary->NumberOfEnumElements();
6287    if (length == 0) {
6288      return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
6289    }
6290    Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
6291    dictionary->CopyEnumKeysTo(*storage);
6292    return storage;
6293  }
6294}
6295
6296
6297MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
6298                                            KeyCollectionType type) {
6299  USE(ContainsOnlyValidKeys);
6300  Isolate* isolate = object->GetIsolate();
6301  Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
6302  Handle<JSObject> arguments_boilerplate = Handle<JSObject>(
6303      isolate->context()->native_context()->sloppy_arguments_boilerplate(),
6304      isolate);
6305  Handle<JSFunction> arguments_function = Handle<JSFunction>(
6306      JSFunction::cast(arguments_boilerplate->map()->constructor()),
6307      isolate);
6308
6309  // Only collect keys if access is permitted.
6310  for (Handle<Object> p = object;
6311       *p != isolate->heap()->null_value();
6312       p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
6313    if (p->IsJSProxy()) {
6314      Handle<JSProxy> proxy(JSProxy::cast(*p), isolate);
6315      Handle<Object> args[] = { proxy };
6316      Handle<Object> names;
6317      ASSIGN_RETURN_ON_EXCEPTION(
6318          isolate, names,
6319          Execution::Call(isolate,
6320                          isolate->proxy_enumerate(),
6321                          object,
6322                          ARRAY_SIZE(args),
6323                          args),
6324          FixedArray);
6325      ASSIGN_RETURN_ON_EXCEPTION(
6326          isolate, content,
6327          FixedArray::AddKeysFromArrayLike(
6328              content, Handle<JSObject>::cast(names)),
6329          FixedArray);
6330      break;
6331    }
6332
6333    Handle<JSObject> current(JSObject::cast(*p), isolate);
6334
6335    // Check access rights if required.
6336    if (current->IsAccessCheckNeeded() &&
6337        !isolate->MayNamedAccess(
6338            current, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
6339      isolate->ReportFailedAccessCheck(current, v8::ACCESS_KEYS);
6340      RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
6341      break;
6342    }
6343
6344    // Compute the element keys.
6345    Handle<FixedArray> element_keys =
6346        isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
6347    current->GetEnumElementKeys(*element_keys);
6348    ASSIGN_RETURN_ON_EXCEPTION(
6349        isolate, content,
6350        FixedArray::UnionOfKeys(content, element_keys),
6351        FixedArray);
6352    ASSERT(ContainsOnlyValidKeys(content));
6353
6354    // Add the element keys from the interceptor.
6355    if (current->HasIndexedInterceptor()) {
6356      Handle<JSObject> result;
6357      if (JSObject::GetKeysForIndexedInterceptor(
6358              current, object).ToHandle(&result)) {
6359        ASSIGN_RETURN_ON_EXCEPTION(
6360            isolate, content,
6361            FixedArray::AddKeysFromArrayLike(content, result),
6362            FixedArray);
6363      }
6364      ASSERT(ContainsOnlyValidKeys(content));
6365    }
6366
6367    // We can cache the computed property keys if access checks are
6368    // not needed and no interceptors are involved.
6369    //
6370    // We do not use the cache if the object has elements and
6371    // therefore it does not make sense to cache the property names
6372    // for arguments objects.  Arguments objects will always have
6373    // elements.
6374    // Wrapped strings have elements, but don't have an elements
6375    // array or dictionary.  So the fast inline test for whether to
6376    // use the cache says yes, so we should not create a cache.
6377    bool cache_enum_keys =
6378        ((current->map()->constructor() != *arguments_function) &&
6379         !current->IsJSValue() &&
6380         !current->IsAccessCheckNeeded() &&
6381         !current->HasNamedInterceptor() &&
6382         !current->HasIndexedInterceptor());
6383    // Compute the property keys and cache them if possible.
6384    ASSIGN_RETURN_ON_EXCEPTION(
6385        isolate, content,
6386        FixedArray::UnionOfKeys(
6387            content, GetEnumPropertyKeys(current, cache_enum_keys)),
6388        FixedArray);
6389    ASSERT(ContainsOnlyValidKeys(content));
6390
6391    // Add the property keys from the interceptor.
6392    if (current->HasNamedInterceptor()) {
6393      Handle<JSObject> result;
6394      if (JSObject::GetKeysForNamedInterceptor(
6395              current, object).ToHandle(&result)) {
6396        ASSIGN_RETURN_ON_EXCEPTION(
6397            isolate, content,
6398            FixedArray::AddKeysFromArrayLike(content, result),
6399            FixedArray);
6400      }
6401      ASSERT(ContainsOnlyValidKeys(content));
6402    }
6403
6404    // If we only want own properties we bail out after the first
6405    // iteration.
6406    if (type == OWN_ONLY) break;
6407  }
6408  return content;
6409}
6410
6411
6412// Try to update an accessor in an elements dictionary. Return true if the
6413// update succeeded, and false otherwise.
6414static bool UpdateGetterSetterInDictionary(
6415    SeededNumberDictionary* dictionary,
6416    uint32_t index,
6417    Object* getter,
6418    Object* setter,
6419    PropertyAttributes attributes) {
6420  int entry = dictionary->FindEntry(index);
6421  if (entry != SeededNumberDictionary::kNotFound) {
6422    Object* result = dictionary->ValueAt(entry);
6423    PropertyDetails details = dictionary->DetailsAt(entry);
6424    if (details.type() == CALLBACKS && result->IsAccessorPair()) {
6425      ASSERT(!details.IsDontDelete());
6426      if (details.attributes() != attributes) {
6427        dictionary->DetailsAtPut(
6428            entry,
6429            PropertyDetails(attributes, CALLBACKS, index));
6430      }
6431      AccessorPair::cast(result)->SetComponents(getter, setter);
6432      return true;
6433    }
6434  }
6435  return false;
6436}
6437
6438
6439void JSObject::DefineElementAccessor(Handle<JSObject> object,
6440                                     uint32_t index,
6441                                     Handle<Object> getter,
6442                                     Handle<Object> setter,
6443                                     PropertyAttributes attributes,
6444                                     v8::AccessControl access_control) {
6445  switch (object->GetElementsKind()) {
6446    case FAST_SMI_ELEMENTS:
6447    case FAST_ELEMENTS:
6448    case FAST_DOUBLE_ELEMENTS:
6449    case FAST_HOLEY_SMI_ELEMENTS:
6450    case FAST_HOLEY_ELEMENTS:
6451    case FAST_HOLEY_DOUBLE_ELEMENTS:
6452      break;
6453
6454#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
6455    case EXTERNAL_##TYPE##_ELEMENTS:                                           \
6456    case TYPE##_ELEMENTS:                                                      \
6457
6458    TYPED_ARRAYS(TYPED_ARRAY_CASE)
6459#undef TYPED_ARRAY_CASE
6460      // Ignore getters and setters on pixel and external array elements.
6461      return;
6462
6463    case DICTIONARY_ELEMENTS:
6464      if (UpdateGetterSetterInDictionary(object->element_dictionary(),
6465                                         index,
6466                                         *getter,
6467                                         *setter,
6468                                         attributes)) {
6469        return;
6470      }
6471      break;
6472    case SLOPPY_ARGUMENTS_ELEMENTS: {
6473      // Ascertain whether we have read-only properties or an existing
6474      // getter/setter pair in an arguments elements dictionary backing
6475      // store.
6476      FixedArray* parameter_map = FixedArray::cast(object->elements());
6477      uint32_t length = parameter_map->length();
6478      Object* probe =
6479          index < (length - 2) ? parameter_map->get(index + 2) : NULL;
6480      if (probe == NULL || probe->IsTheHole()) {
6481        FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
6482        if (arguments->IsDictionary()) {
6483          SeededNumberDictionary* dictionary =
6484              SeededNumberDictionary::cast(arguments);
6485          if (UpdateGetterSetterInDictionary(dictionary,
6486                                             index,
6487                                             *getter,
6488                                             *setter,
6489                                             attributes)) {
6490            return;
6491          }
6492        }
6493      }
6494      break;
6495    }
6496  }
6497
6498  Isolate* isolate = object->GetIsolate();
6499  Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
6500  accessors->SetComponents(*getter, *setter);
6501  accessors->set_access_flags(access_control);
6502
6503  SetElementCallback(object, index, accessors, attributes);
6504}
6505
6506
6507Handle<AccessorPair> JSObject::CreateAccessorPairFor(Handle<JSObject> object,
6508                                                     Handle<Name> name) {
6509  Isolate* isolate = object->GetIsolate();
6510  LookupResult result(isolate);
6511  object->LookupOwnRealNamedProperty(name, &result);
6512  if (result.IsPropertyCallbacks()) {
6513    // Note that the result can actually have IsDontDelete() == true when we
6514    // e.g. have to fall back to the slow case while adding a setter after
6515    // successfully reusing a map transition for a getter. Nevertheless, this is
6516    // OK, because the assertion only holds for the whole addition of both
6517    // accessors, not for the addition of each part. See first comment in
6518    // DefinePropertyAccessor below.
6519    Object* obj = result.GetCallbackObject();
6520    if (obj->IsAccessorPair()) {
6521      return AccessorPair::Copy(handle(AccessorPair::cast(obj), isolate));
6522    }
6523  }
6524  return isolate->factory()->NewAccessorPair();
6525}
6526
6527
6528void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
6529                                      Handle<Name> name,
6530                                      Handle<Object> getter,
6531                                      Handle<Object> setter,
6532                                      PropertyAttributes attributes,
6533                                      v8::AccessControl access_control) {
6534  // We could assert that the property is configurable here, but we would need
6535  // to do a lookup, which seems to be a bit of overkill.
6536  bool only_attribute_changes = getter->IsNull() && setter->IsNull();
6537  if (object->HasFastProperties() && !only_attribute_changes &&
6538      access_control == v8::DEFAULT &&
6539      (object->map()->NumberOfOwnDescriptors() <= kMaxNumberOfDescriptors)) {
6540    bool getterOk = getter->IsNull() ||
6541        DefineFastAccessor(object, name, ACCESSOR_GETTER, getter, attributes);
6542    bool setterOk = !getterOk || setter->IsNull() ||
6543        DefineFastAccessor(object, name, ACCESSOR_SETTER, setter, attributes);
6544    if (getterOk && setterOk) return;
6545  }
6546
6547  Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
6548  accessors->SetComponents(*getter, *setter);
6549  accessors->set_access_flags(access_control);
6550
6551  SetPropertyCallback(object, name, accessors, attributes);
6552}
6553
6554
6555bool Map::DictionaryElementsInPrototypeChainOnly() {
6556  Heap* heap = GetHeap();
6557
6558  if (IsDictionaryElementsKind(elements_kind())) {
6559    return false;
6560  }
6561
6562  for (Object* prototype = this->prototype();
6563       prototype != heap->null_value();
6564       prototype = prototype->GetPrototype(GetIsolate())) {
6565    if (prototype->IsJSProxy()) {
6566      // Be conservative, don't walk into proxies.
6567      return true;
6568    }
6569
6570    if (IsDictionaryElementsKind(
6571            JSObject::cast(prototype)->map()->elements_kind())) {
6572      return true;
6573    }
6574  }
6575
6576  return false;
6577}
6578
6579
6580void JSObject::SetElementCallback(Handle<JSObject> object,
6581                                  uint32_t index,
6582                                  Handle<Object> structure,
6583                                  PropertyAttributes attributes) {
6584  Heap* heap = object->GetHeap();
6585  PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
6586
6587  // Normalize elements to make this operation simple.
6588  bool had_dictionary_elements = object->HasDictionaryElements();
6589  Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
6590  ASSERT(object->HasDictionaryElements() ||
6591         object->HasDictionaryArgumentsElements());
6592  // Update the dictionary with the new CALLBACKS property.
6593  dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
6594                                           details);
6595  dictionary->set_requires_slow_elements();
6596
6597  // Update the dictionary backing store on the object.
6598  if (object->elements()->map() == heap->sloppy_arguments_elements_map()) {
6599    // Also delete any parameter alias.
6600    //
6601    // TODO(kmillikin): when deleting the last parameter alias we could
6602    // switch to a direct backing store without the parameter map.  This
6603    // would allow GC of the context.
6604    FixedArray* parameter_map = FixedArray::cast(object->elements());
6605    if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
6606      parameter_map->set(index + 2, heap->the_hole_value());
6607    }
6608    parameter_map->set(1, *dictionary);
6609  } else {
6610    object->set_elements(*dictionary);
6611
6612    if (!had_dictionary_elements) {
6613      // KeyedStoreICs (at least the non-generic ones) need a reset.
6614      heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
6615    }
6616  }
6617}
6618
6619
6620void JSObject::SetPropertyCallback(Handle<JSObject> object,
6621                                   Handle<Name> name,
6622                                   Handle<Object> structure,
6623                                   PropertyAttributes attributes) {
6624  // Normalize object to make this operation simple.
6625  NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
6626
6627  // For the global object allocate a new map to invalidate the global inline
6628  // caches which have a global property cell reference directly in the code.
6629  if (object->IsGlobalObject()) {
6630    Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
6631    ASSERT(new_map->is_dictionary_map());
6632    object->set_map(*new_map);
6633
6634    // When running crankshaft, changing the map is not enough. We
6635    // need to deoptimize all functions that rely on this global
6636    // object.
6637    Deoptimizer::DeoptimizeGlobalObject(*object);
6638  }
6639
6640  // Update the dictionary with the new CALLBACKS property.
6641  PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
6642  SetNormalizedProperty(object, name, structure, details);
6643}
6644
6645
6646void JSObject::DefineAccessor(Handle<JSObject> object,
6647                              Handle<Name> name,
6648                              Handle<Object> getter,
6649                              Handle<Object> setter,
6650                              PropertyAttributes attributes,
6651                              v8::AccessControl access_control) {
6652  Isolate* isolate = object->GetIsolate();
6653  // Check access rights if needed.
6654  if (object->IsAccessCheckNeeded() &&
6655      !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6656    isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6657    // TODO(yangguo): Issue 3269, check for scheduled exception missing?
6658    return;
6659  }
6660
6661  if (object->IsJSGlobalProxy()) {
6662    Handle<Object> proto(object->GetPrototype(), isolate);
6663    if (proto->IsNull()) return;
6664    ASSERT(proto->IsJSGlobalObject());
6665    DefineAccessor(Handle<JSObject>::cast(proto),
6666                   name,
6667                   getter,
6668                   setter,
6669                   attributes,
6670                   access_control);
6671    return;
6672  }
6673
6674  // Make sure that the top context does not change when doing callbacks or
6675  // interceptor calls.
6676  AssertNoContextChange ncc(isolate);
6677
6678  // Try to flatten before operating on the string.
6679  if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
6680
6681  uint32_t index = 0;
6682  bool is_element = name->AsArrayIndex(&index);
6683
6684  Handle<Object> old_value = isolate->factory()->the_hole_value();
6685  bool is_observed = object->map()->is_observed() &&
6686                     *name != isolate->heap()->hidden_string();
6687  bool preexists = false;
6688  if (is_observed) {
6689    if (is_element) {
6690      preexists = HasOwnElement(object, index);
6691      if (preexists && GetOwnElementAccessorPair(object, index).is_null()) {
6692        old_value =
6693            Object::GetElement(isolate, object, index).ToHandleChecked();
6694      }
6695    } else {
6696      LookupResult lookup(isolate);
6697      object->LookupOwn(name, &lookup, true);
6698      preexists = lookup.IsProperty();
6699      if (preexists && lookup.IsDataProperty()) {
6700        old_value =
6701            Object::GetPropertyOrElement(object, name).ToHandleChecked();
6702      }
6703    }
6704  }
6705
6706  if (is_element) {
6707    DefineElementAccessor(
6708        object, index, getter, setter, attributes, access_control);
6709  } else {
6710    DefinePropertyAccessor(
6711        object, name, getter, setter, attributes, access_control);
6712  }
6713
6714  if (is_observed) {
6715    const char* type = preexists ? "reconfigure" : "add";
6716    EnqueueChangeRecord(object, type, name, old_value);
6717  }
6718}
6719
6720
6721static bool TryAccessorTransition(Handle<JSObject> self,
6722                                  Handle<Map> transitioned_map,
6723                                  int target_descriptor,
6724                                  AccessorComponent component,
6725                                  Handle<Object> accessor,
6726                                  PropertyAttributes attributes) {
6727  DescriptorArray* descs = transitioned_map->instance_descriptors();
6728  PropertyDetails details = descs->GetDetails(target_descriptor);
6729
6730  // If the transition target was not callbacks, fall back to the slow case.
6731  if (details.type() != CALLBACKS) return false;
6732  Object* descriptor = descs->GetCallbacksObject(target_descriptor);
6733  if (!descriptor->IsAccessorPair()) return false;
6734
6735  Object* target_accessor = AccessorPair::cast(descriptor)->get(component);
6736  PropertyAttributes target_attributes = details.attributes();
6737
6738  // Reuse transition if adding same accessor with same attributes.
6739  if (target_accessor == *accessor && target_attributes == attributes) {
6740    JSObject::MigrateToMap(self, transitioned_map);
6741    return true;
6742  }
6743
6744  // If either not the same accessor, or not the same attributes, fall back to
6745  // the slow case.
6746  return false;
6747}
6748
6749
6750bool JSObject::DefineFastAccessor(Handle<JSObject> object,
6751                                  Handle<Name> name,
6752                                  AccessorComponent component,
6753                                  Handle<Object> accessor,
6754                                  PropertyAttributes attributes) {
6755  ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
6756  Isolate* isolate = object->GetIsolate();
6757  LookupResult result(isolate);
6758  object->LookupOwn(name, &result);
6759
6760  if (result.IsFound() && !result.IsPropertyCallbacks()) {
6761    return false;
6762  }
6763
6764  // Return success if the same accessor with the same attributes already exist.
6765  AccessorPair* source_accessors = NULL;
6766  if (result.IsPropertyCallbacks()) {
6767    Object* callback_value = result.GetCallbackObject();
6768    if (callback_value->IsAccessorPair()) {
6769      source_accessors = AccessorPair::cast(callback_value);
6770      Object* entry = source_accessors->get(component);
6771      if (entry == *accessor && result.GetAttributes() == attributes) {
6772        return true;
6773      }
6774    } else {
6775      return false;
6776    }
6777
6778    int descriptor_number = result.GetDescriptorIndex();
6779
6780    object->map()->LookupTransition(*object, *name, &result);
6781
6782    if (result.IsFound()) {
6783      Handle<Map> target(result.GetTransitionTarget());
6784      ASSERT(target->NumberOfOwnDescriptors() ==
6785             object->map()->NumberOfOwnDescriptors());
6786      // This works since descriptors are sorted in order of addition.
6787      ASSERT(Name::Equals(handle(object->map()->instance_descriptors()->
6788             GetKey(descriptor_number)), name));
6789      return TryAccessorTransition(object, target, descriptor_number,
6790                                   component, accessor, attributes);
6791    }
6792  } else {
6793    // If not, lookup a transition.
6794    object->map()->LookupTransition(*object, *name, &result);
6795
6796    // If there is a transition, try to follow it.
6797    if (result.IsFound()) {
6798      Handle<Map> target(result.GetTransitionTarget());
6799      int descriptor_number = target->LastAdded();
6800      ASSERT(Name::Equals(name,
6801          handle(target->instance_descriptors()->GetKey(descriptor_number))));
6802      return TryAccessorTransition(object, target, descriptor_number,
6803                                   component, accessor, attributes);
6804    }
6805  }
6806
6807  // If there is no transition yet, add a transition to the a new accessor pair
6808  // containing the accessor.  Allocate a new pair if there were no source
6809  // accessors.  Otherwise, copy the pair and modify the accessor.
6810  Handle<AccessorPair> accessors = source_accessors != NULL
6811      ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
6812      : isolate->factory()->NewAccessorPair();
6813  accessors->set(component, *accessor);
6814
6815  CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
6816  Handle<Map> new_map = Map::CopyInsertDescriptor(
6817      handle(object->map()), &new_accessors_desc, INSERT_TRANSITION);
6818
6819  JSObject::MigrateToMap(object, new_map);
6820  return true;
6821}
6822
6823
6824MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
6825                                          Handle<AccessorInfo> info) {
6826  Isolate* isolate = object->GetIsolate();
6827  Factory* factory = isolate->factory();
6828  Handle<Name> name(Name::cast(info->name()));
6829
6830  // Check access rights if needed.
6831  if (object->IsAccessCheckNeeded() &&
6832      !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6833    isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6834    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6835    return factory->undefined_value();
6836  }
6837
6838  if (object->IsJSGlobalProxy()) {
6839    Handle<Object> proto(object->GetPrototype(), isolate);
6840    if (proto->IsNull()) return object;
6841    ASSERT(proto->IsJSGlobalObject());
6842    return SetAccessor(Handle<JSObject>::cast(proto), info);
6843  }
6844
6845  // Make sure that the top context does not change when doing callbacks or
6846  // interceptor calls.
6847  AssertNoContextChange ncc(isolate);
6848
6849  // Try to flatten before operating on the string.
6850  if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
6851
6852  uint32_t index = 0;
6853  bool is_element = name->AsArrayIndex(&index);
6854
6855  if (is_element) {
6856    if (object->IsJSArray()) return factory->undefined_value();
6857
6858    // Accessors overwrite previous callbacks (cf. with getters/setters).
6859    switch (object->GetElementsKind()) {
6860      case FAST_SMI_ELEMENTS:
6861      case FAST_ELEMENTS:
6862      case FAST_DOUBLE_ELEMENTS:
6863      case FAST_HOLEY_SMI_ELEMENTS:
6864      case FAST_HOLEY_ELEMENTS:
6865      case FAST_HOLEY_DOUBLE_ELEMENTS:
6866        break;
6867
6868#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
6869      case EXTERNAL_##TYPE##_ELEMENTS:                                         \
6870      case TYPE##_ELEMENTS:                                                    \
6871
6872      TYPED_ARRAYS(TYPED_ARRAY_CASE)
6873#undef TYPED_ARRAY_CASE
6874        // Ignore getters and setters on pixel and external array
6875        // elements.
6876        return factory->undefined_value();
6877
6878      case DICTIONARY_ELEMENTS:
6879        break;
6880      case SLOPPY_ARGUMENTS_ELEMENTS:
6881        UNIMPLEMENTED();
6882        break;
6883    }
6884
6885    SetElementCallback(object, index, info, info->property_attributes());
6886  } else {
6887    // Lookup the name.
6888    LookupResult result(isolate);
6889    object->LookupOwn(name, &result, true);
6890    // ES5 forbids turning a property into an accessor if it's not
6891    // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
6892    if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) {
6893      return factory->undefined_value();
6894    }
6895
6896    SetPropertyCallback(object, name, info, info->property_attributes());
6897  }
6898
6899  return object;
6900}
6901
6902
6903MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
6904                                          Handle<Name> name,
6905                                          AccessorComponent component) {
6906  Isolate* isolate = object->GetIsolate();
6907
6908  // Make sure that the top context does not change when doing callbacks or
6909  // interceptor calls.
6910  AssertNoContextChange ncc(isolate);
6911
6912  // Make the lookup and include prototypes.
6913  uint32_t index = 0;
6914  if (name->AsArrayIndex(&index)) {
6915    for (Handle<Object> obj = object;
6916         !obj->IsNull();
6917         obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
6918      if (obj->IsAccessCheckNeeded() &&
6919          !isolate->MayNamedAccess(Handle<JSObject>::cast(obj), name,
6920                                   v8::ACCESS_HAS)) {
6921        isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(obj),
6922                                         v8::ACCESS_HAS);
6923        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6924        return isolate->factory()->undefined_value();
6925      }
6926
6927      if (obj->IsJSObject() && JSObject::cast(*obj)->HasDictionaryElements()) {
6928        JSObject* js_object = JSObject::cast(*obj);
6929        SeededNumberDictionary* dictionary = js_object->element_dictionary();
6930        int entry = dictionary->FindEntry(index);
6931        if (entry != SeededNumberDictionary::kNotFound) {
6932          Object* element = dictionary->ValueAt(entry);
6933          if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
6934              element->IsAccessorPair()) {
6935            return handle(AccessorPair::cast(element)->GetComponent(component),
6936                          isolate);
6937          }
6938        }
6939      }
6940    }
6941  } else {
6942    for (Handle<Object> obj = object;
6943         !obj->IsNull();
6944         obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
6945      if (obj->IsAccessCheckNeeded() &&
6946          !isolate->MayNamedAccess(Handle<JSObject>::cast(obj), name,
6947                                   v8::ACCESS_HAS)) {
6948        isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(obj),
6949                                         v8::ACCESS_HAS);
6950        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6951        return isolate->factory()->undefined_value();
6952      }
6953      LookupResult result(isolate);
6954      JSReceiver::cast(*obj)->LookupOwn(name, &result);
6955      if (result.IsFound()) {
6956        if (result.IsReadOnly()) return isolate->factory()->undefined_value();
6957        if (result.IsPropertyCallbacks()) {
6958          Object* obj = result.GetCallbackObject();
6959          if (obj->IsAccessorPair()) {
6960            return handle(AccessorPair::cast(obj)->GetComponent(component),
6961                          isolate);
6962          }
6963        }
6964      }
6965    }
6966  }
6967  return isolate->factory()->undefined_value();
6968}
6969
6970
6971Object* JSObject::SlowReverseLookup(Object* value) {
6972  if (HasFastProperties()) {
6973    int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
6974    DescriptorArray* descs = map()->instance_descriptors();
6975    for (int i = 0; i < number_of_own_descriptors; i++) {
6976      if (descs->GetType(i) == FIELD) {
6977        Object* property =
6978            RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i));
6979        if (descs->GetDetails(i).representation().IsDouble()) {
6980          ASSERT(property->IsHeapNumber());
6981          if (value->IsNumber() && property->Number() == value->Number()) {
6982            return descs->GetKey(i);
6983          }
6984        } else if (property == value) {
6985          return descs->GetKey(i);
6986        }
6987      } else if (descs->GetType(i) == CONSTANT) {
6988        if (descs->GetConstant(i) == value) {
6989          return descs->GetKey(i);
6990        }
6991      }
6992    }
6993    return GetHeap()->undefined_value();
6994  } else {
6995    return property_dictionary()->SlowReverseLookup(value);
6996  }
6997}
6998
6999
7000Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
7001  Handle<Map> result = map->GetIsolate()->factory()->NewMap(
7002      map->instance_type(), instance_size);
7003  result->set_prototype(map->prototype());
7004  result->set_constructor(map->constructor());
7005  result->set_bit_field(map->bit_field());
7006  result->set_bit_field2(map->bit_field2());
7007  int new_bit_field3 = map->bit_field3();
7008  new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
7009  new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
7010  new_bit_field3 = EnumLengthBits::update(new_bit_field3,
7011                                          kInvalidEnumCacheSentinel);
7012  new_bit_field3 = Deprecated::update(new_bit_field3, false);
7013  if (!map->is_dictionary_map()) {
7014    new_bit_field3 = IsUnstable::update(new_bit_field3, false);
7015  }
7016  new_bit_field3 = ConstructionCount::update(new_bit_field3,
7017                                             JSFunction::kNoSlackTracking);
7018  result->set_bit_field3(new_bit_field3);
7019  return result;
7020}
7021
7022
7023Handle<Map> Map::Normalize(Handle<Map> fast_map,
7024                           PropertyNormalizationMode mode) {
7025  ASSERT(!fast_map->is_dictionary_map());
7026
7027  Isolate* isolate = fast_map->GetIsolate();
7028  Handle<NormalizedMapCache> cache(
7029      isolate->context()->native_context()->normalized_map_cache());
7030
7031  Handle<Map> new_map;
7032  if (cache->Get(fast_map, mode).ToHandle(&new_map)) {
7033#ifdef VERIFY_HEAP
7034    if (FLAG_verify_heap) {
7035      new_map->SharedMapVerify();
7036    }
7037#endif
7038#ifdef ENABLE_SLOW_ASSERTS
7039    if (FLAG_enable_slow_asserts) {
7040      // The cached map should match newly created normalized map bit-by-bit,
7041      // except for the code cache, which can contain some ics which can be
7042      // applied to the shared map.
7043      Handle<Map> fresh = Map::CopyNormalized(
7044          fast_map, mode, SHARED_NORMALIZED_MAP);
7045
7046      ASSERT(memcmp(fresh->address(),
7047                    new_map->address(),
7048                    Map::kCodeCacheOffset) == 0);
7049      STATIC_ASSERT(Map::kDependentCodeOffset ==
7050                    Map::kCodeCacheOffset + kPointerSize);
7051      int offset = Map::kDependentCodeOffset + kPointerSize;
7052      ASSERT(memcmp(fresh->address() + offset,
7053                    new_map->address() + offset,
7054                    Map::kSize - offset) == 0);
7055    }
7056#endif
7057  } else {
7058    new_map = Map::CopyNormalized(fast_map, mode, SHARED_NORMALIZED_MAP);
7059    cache->Set(fast_map, new_map);
7060    isolate->counters()->normalized_maps()->Increment();
7061  }
7062  fast_map->NotifyLeafMapLayoutChange();
7063  return new_map;
7064}
7065
7066
7067Handle<Map> Map::CopyNormalized(Handle<Map> map,
7068                                PropertyNormalizationMode mode,
7069                                NormalizedMapSharingMode sharing) {
7070  int new_instance_size = map->instance_size();
7071  if (mode == CLEAR_INOBJECT_PROPERTIES) {
7072    new_instance_size -= map->inobject_properties() * kPointerSize;
7073  }
7074
7075  Handle<Map> result = RawCopy(map, new_instance_size);
7076
7077  if (mode != CLEAR_INOBJECT_PROPERTIES) {
7078    result->set_inobject_properties(map->inobject_properties());
7079  }
7080
7081  result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
7082  result->set_dictionary_map(true);
7083  result->set_migration_target(false);
7084
7085#ifdef VERIFY_HEAP
7086  if (FLAG_verify_heap && result->is_shared()) {
7087    result->SharedMapVerify();
7088  }
7089#endif
7090
7091  return result;
7092}
7093
7094
7095Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
7096  Handle<Map> result = RawCopy(map, map->instance_size());
7097
7098  // Please note instance_type and instance_size are set when allocated.
7099  result->set_inobject_properties(map->inobject_properties());
7100  result->set_unused_property_fields(map->unused_property_fields());
7101
7102  result->set_pre_allocated_property_fields(
7103      map->pre_allocated_property_fields());
7104  result->set_is_shared(false);
7105  result->ClearCodeCache(map->GetHeap());
7106  map->NotifyLeafMapLayoutChange();
7107  return result;
7108}
7109
7110
7111Handle<Map> Map::ShareDescriptor(Handle<Map> map,
7112                                 Handle<DescriptorArray> descriptors,
7113                                 Descriptor* descriptor) {
7114  // Sanity check. This path is only to be taken if the map owns its descriptor
7115  // array, implying that its NumberOfOwnDescriptors equals the number of
7116  // descriptors in the descriptor array.
7117  ASSERT(map->NumberOfOwnDescriptors() ==
7118         map->instance_descriptors()->number_of_descriptors());
7119
7120  Handle<Map> result = CopyDropDescriptors(map);
7121  Handle<Name> name = descriptor->GetKey();
7122  Handle<TransitionArray> transitions =
7123      TransitionArray::CopyInsert(map, name, result, SIMPLE_TRANSITION);
7124
7125  // Ensure there's space for the new descriptor in the shared descriptor array.
7126  if (descriptors->NumberOfSlackDescriptors() == 0) {
7127    int old_size = descriptors->number_of_descriptors();
7128    if (old_size == 0) {
7129      descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
7130    } else {
7131      EnsureDescriptorSlack(map, old_size < 4 ? 1 : old_size / 2);
7132      descriptors = handle(map->instance_descriptors());
7133    }
7134  }
7135
7136  // Commit the state atomically.
7137  DisallowHeapAllocation no_gc;
7138
7139  descriptors->Append(descriptor);
7140  result->SetBackPointer(*map);
7141  result->InitializeDescriptors(*descriptors);
7142
7143  ASSERT(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
7144
7145  map->set_transitions(*transitions);
7146  map->set_owns_descriptors(false);
7147
7148  return result;
7149}
7150
7151
7152Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
7153                                        Handle<DescriptorArray> descriptors,
7154                                        TransitionFlag flag,
7155                                        MaybeHandle<Name> maybe_name,
7156                                        SimpleTransitionFlag simple_flag) {
7157  ASSERT(descriptors->IsSortedNoDuplicates());
7158
7159  Handle<Map> result = CopyDropDescriptors(map);
7160  result->InitializeDescriptors(*descriptors);
7161
7162  if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
7163    Handle<Name> name;
7164    CHECK(maybe_name.ToHandle(&name));
7165    Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
7166        map, name, result, simple_flag);
7167    map->set_transitions(*transitions);
7168    result->SetBackPointer(*map);
7169  } else {
7170    int length = descriptors->number_of_descriptors();
7171    for (int i = 0; i < length; i++) {
7172      descriptors->SetRepresentation(i, Representation::Tagged());
7173      if (descriptors->GetDetails(i).type() == FIELD) {
7174        descriptors->SetValue(i, HeapType::Any());
7175      }
7176    }
7177  }
7178
7179  return result;
7180}
7181
7182
7183// Since this method is used to rewrite an existing transition tree, it can
7184// always insert transitions without checking.
7185Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
7186                                        int new_descriptor,
7187                                        Handle<DescriptorArray> descriptors) {
7188  ASSERT(descriptors->IsSortedNoDuplicates());
7189
7190  Handle<Map> result = CopyDropDescriptors(map);
7191
7192  result->InitializeDescriptors(*descriptors);
7193  result->SetNumberOfOwnDescriptors(new_descriptor + 1);
7194
7195  int unused_property_fields = map->unused_property_fields();
7196  if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
7197    unused_property_fields = map->unused_property_fields() - 1;
7198    if (unused_property_fields < 0) {
7199      unused_property_fields += JSObject::kFieldsAdded;
7200    }
7201  }
7202
7203  result->set_unused_property_fields(unused_property_fields);
7204  result->set_owns_descriptors(false);
7205
7206  Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
7207  Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
7208      map, name, result, SIMPLE_TRANSITION);
7209
7210  map->set_transitions(*transitions);
7211  result->SetBackPointer(*map);
7212
7213  return result;
7214}
7215
7216
7217Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
7218                                    TransitionFlag flag) {
7219  if (flag == INSERT_TRANSITION) {
7220    ASSERT(!map->HasElementsTransition() ||
7221        ((map->elements_transition_map()->elements_kind() ==
7222          DICTIONARY_ELEMENTS ||
7223          IsExternalArrayElementsKind(
7224              map->elements_transition_map()->elements_kind())) &&
7225         (kind == DICTIONARY_ELEMENTS ||
7226          IsExternalArrayElementsKind(kind))));
7227    ASSERT(!IsFastElementsKind(kind) ||
7228           IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
7229    ASSERT(kind != map->elements_kind());
7230  }
7231
7232  bool insert_transition =
7233      flag == INSERT_TRANSITION && !map->HasElementsTransition();
7234
7235  if (insert_transition && map->owns_descriptors()) {
7236    // In case the map owned its own descriptors, share the descriptors and
7237    // transfer ownership to the new map.
7238    Handle<Map> new_map = CopyDropDescriptors(map);
7239
7240    SetElementsTransitionMap(map, new_map);
7241
7242    new_map->set_elements_kind(kind);
7243    new_map->InitializeDescriptors(map->instance_descriptors());
7244    new_map->SetBackPointer(*map);
7245    map->set_owns_descriptors(false);
7246    return new_map;
7247  }
7248
7249  // In case the map did not own its own descriptors, a split is forced by
7250  // copying the map; creating a new descriptor array cell.
7251  // Create a new free-floating map only if we are not allowed to store it.
7252  Handle<Map> new_map = Copy(map);
7253
7254  new_map->set_elements_kind(kind);
7255
7256  if (insert_transition) {
7257    SetElementsTransitionMap(map, new_map);
7258    new_map->SetBackPointer(*map);
7259  }
7260
7261  return new_map;
7262}
7263
7264
7265Handle<Map> Map::CopyForObserved(Handle<Map> map) {
7266  ASSERT(!map->is_observed());
7267
7268  Isolate* isolate = map->GetIsolate();
7269
7270  // In case the map owned its own descriptors, share the descriptors and
7271  // transfer ownership to the new map.
7272  Handle<Map> new_map;
7273  if (map->owns_descriptors()) {
7274    new_map = CopyDropDescriptors(map);
7275  } else {
7276    new_map = Copy(map);
7277  }
7278
7279  Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
7280      map, isolate->factory()->observed_symbol(), new_map, FULL_TRANSITION);
7281
7282  map->set_transitions(*transitions);
7283
7284  new_map->set_is_observed();
7285
7286  if (map->owns_descriptors()) {
7287    new_map->InitializeDescriptors(map->instance_descriptors());
7288    map->set_owns_descriptors(false);
7289  }
7290
7291  new_map->SetBackPointer(*map);
7292  return new_map;
7293}
7294
7295
7296Handle<Map> Map::Copy(Handle<Map> map) {
7297  Handle<DescriptorArray> descriptors(map->instance_descriptors());
7298  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
7299  Handle<DescriptorArray> new_descriptors =
7300      DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
7301  return CopyReplaceDescriptors(
7302      map, new_descriptors, OMIT_TRANSITION, MaybeHandle<Name>());
7303}
7304
7305
7306Handle<Map> Map::Create(Handle<JSFunction> constructor,
7307                        int extra_inobject_properties) {
7308  Handle<Map> copy = Copy(handle(constructor->initial_map()));
7309
7310  // Check that we do not overflow the instance size when adding the
7311  // extra inobject properties.
7312  int instance_size_delta = extra_inobject_properties * kPointerSize;
7313  int max_instance_size_delta =
7314      JSObject::kMaxInstanceSize - copy->instance_size();
7315  int max_extra_properties = max_instance_size_delta >> kPointerSizeLog2;
7316
7317  // If the instance size overflows, we allocate as many properties as we can as
7318  // inobject properties.
7319  if (extra_inobject_properties > max_extra_properties) {
7320    instance_size_delta = max_instance_size_delta;
7321    extra_inobject_properties = max_extra_properties;
7322  }
7323
7324  // Adjust the map with the extra inobject properties.
7325  int inobject_properties =
7326      copy->inobject_properties() + extra_inobject_properties;
7327  copy->set_inobject_properties(inobject_properties);
7328  copy->set_unused_property_fields(inobject_properties);
7329  copy->set_instance_size(copy->instance_size() + instance_size_delta);
7330  copy->set_visitor_id(StaticVisitorBase::GetVisitorId(*copy));
7331  return copy;
7332}
7333
7334
7335Handle<Map> Map::CopyForFreeze(Handle<Map> map) {
7336  int num_descriptors = map->NumberOfOwnDescriptors();
7337  Isolate* isolate = map->GetIsolate();
7338  Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
7339      handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN);
7340  Handle<Map> new_map = CopyReplaceDescriptors(
7341      map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol());
7342  new_map->freeze();
7343  new_map->set_is_extensible(false);
7344  new_map->set_elements_kind(DICTIONARY_ELEMENTS);
7345  return new_map;
7346}
7347
7348
7349Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
7350                                   Descriptor* descriptor,
7351                                   TransitionFlag flag) {
7352  Handle<DescriptorArray> descriptors(map->instance_descriptors());
7353
7354  // Ensure the key is unique.
7355  descriptor->KeyToUniqueName();
7356
7357  if (flag == INSERT_TRANSITION &&
7358      map->owns_descriptors() &&
7359      map->CanHaveMoreTransitions()) {
7360    return ShareDescriptor(map, descriptors, descriptor);
7361  }
7362
7363  Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
7364      descriptors, map->NumberOfOwnDescriptors(), 1);
7365  new_descriptors->Append(descriptor);
7366
7367  return CopyReplaceDescriptors(
7368      map, new_descriptors, flag, descriptor->GetKey(), SIMPLE_TRANSITION);
7369}
7370
7371
7372Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
7373                                      Descriptor* descriptor,
7374                                      TransitionFlag flag) {
7375  Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
7376
7377  // Ensure the key is unique.
7378  descriptor->KeyToUniqueName();
7379
7380  // We replace the key if it is already present.
7381  int index = old_descriptors->SearchWithCache(*descriptor->GetKey(), *map);
7382  if (index != DescriptorArray::kNotFound) {
7383    return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
7384  }
7385  return CopyAddDescriptor(map, descriptor, flag);
7386}
7387
7388
7389Handle<DescriptorArray> DescriptorArray::CopyUpTo(
7390    Handle<DescriptorArray> desc,
7391    int enumeration_index,
7392    int slack) {
7393  return DescriptorArray::CopyUpToAddAttributes(
7394      desc, enumeration_index, NONE, slack);
7395}
7396
7397
7398Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
7399    Handle<DescriptorArray> desc,
7400    int enumeration_index,
7401    PropertyAttributes attributes,
7402    int slack) {
7403  if (enumeration_index + slack == 0) {
7404    return desc->GetIsolate()->factory()->empty_descriptor_array();
7405  }
7406
7407  int size = enumeration_index;
7408
7409  Handle<DescriptorArray> descriptors =
7410      DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
7411  DescriptorArray::WhitenessWitness witness(*descriptors);
7412
7413  if (attributes != NONE) {
7414    for (int i = 0; i < size; ++i) {
7415      Object* value = desc->GetValue(i);
7416      PropertyDetails details = desc->GetDetails(i);
7417      int mask = DONT_DELETE | DONT_ENUM;
7418      // READ_ONLY is an invalid attribute for JS setters/getters.
7419      if (details.type() != CALLBACKS || !value->IsAccessorPair()) {
7420        mask |= READ_ONLY;
7421      }
7422      details = details.CopyAddAttributes(
7423          static_cast<PropertyAttributes>(attributes & mask));
7424      Descriptor inner_desc(handle(desc->GetKey(i)),
7425                            handle(value, desc->GetIsolate()),
7426                            details);
7427      descriptors->Set(i, &inner_desc, witness);
7428    }
7429  } else {
7430    for (int i = 0; i < size; ++i) {
7431      descriptors->CopyFrom(i, *desc, witness);
7432    }
7433  }
7434
7435  if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
7436
7437  return descriptors;
7438}
7439
7440
7441Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
7442                                       Handle<DescriptorArray> descriptors,
7443                                       Descriptor* descriptor,
7444                                       int insertion_index,
7445                                       TransitionFlag flag) {
7446  // Ensure the key is unique.
7447  descriptor->KeyToUniqueName();
7448
7449  Handle<Name> key = descriptor->GetKey();
7450  ASSERT(*key == descriptors->GetKey(insertion_index));
7451
7452  Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
7453      descriptors, map->NumberOfOwnDescriptors());
7454
7455  new_descriptors->Replace(insertion_index, descriptor);
7456
7457  SimpleTransitionFlag simple_flag =
7458      (insertion_index == descriptors->number_of_descriptors() - 1)
7459      ? SIMPLE_TRANSITION
7460      : FULL_TRANSITION;
7461  return CopyReplaceDescriptors(map, new_descriptors, flag, key, simple_flag);
7462}
7463
7464
7465void Map::UpdateCodeCache(Handle<Map> map,
7466                          Handle<Name> name,
7467                          Handle<Code> code) {
7468  Isolate* isolate = map->GetIsolate();
7469  HandleScope scope(isolate);
7470  // Allocate the code cache if not present.
7471  if (map->code_cache()->IsFixedArray()) {
7472    Handle<Object> result = isolate->factory()->NewCodeCache();
7473    map->set_code_cache(*result);
7474  }
7475
7476  // Update the code cache.
7477  Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
7478  CodeCache::Update(code_cache, name, code);
7479}
7480
7481
7482Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
7483  // Do a lookup if a code cache exists.
7484  if (!code_cache()->IsFixedArray()) {
7485    return CodeCache::cast(code_cache())->Lookup(name, flags);
7486  } else {
7487    return GetHeap()->undefined_value();
7488  }
7489}
7490
7491
7492int Map::IndexInCodeCache(Object* name, Code* code) {
7493  // Get the internal index if a code cache exists.
7494  if (!code_cache()->IsFixedArray()) {
7495    return CodeCache::cast(code_cache())->GetIndex(name, code);
7496  }
7497  return -1;
7498}
7499
7500
7501void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
7502  // No GC is supposed to happen between a call to IndexInCodeCache and
7503  // RemoveFromCodeCache so the code cache must be there.
7504  ASSERT(!code_cache()->IsFixedArray());
7505  CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
7506}
7507
7508
7509// An iterator over all map transitions in an descriptor array, reusing the
7510// constructor field of the map while it is running. Negative values in
7511// the constructor field indicate an active map transition iteration. The
7512// original constructor is restored after iterating over all entries.
7513class IntrusiveMapTransitionIterator {
7514 public:
7515  IntrusiveMapTransitionIterator(
7516      Map* map, TransitionArray* transition_array, Object* constructor)
7517      : map_(map),
7518        transition_array_(transition_array),
7519        constructor_(constructor) { }
7520
7521  void StartIfNotStarted() {
7522    ASSERT(!(*IteratorField())->IsSmi() || IsIterating());
7523    if (!(*IteratorField())->IsSmi()) {
7524      ASSERT(*IteratorField() == constructor_);
7525      *IteratorField() = Smi::FromInt(-1);
7526    }
7527  }
7528
7529  bool IsIterating() {
7530    return (*IteratorField())->IsSmi() &&
7531           Smi::cast(*IteratorField())->value() < 0;
7532  }
7533
7534  Map* Next() {
7535    ASSERT(IsIterating());
7536    int value = Smi::cast(*IteratorField())->value();
7537    int index = -value - 1;
7538    int number_of_transitions = transition_array_->number_of_transitions();
7539    while (index < number_of_transitions) {
7540      *IteratorField() = Smi::FromInt(value - 1);
7541      return transition_array_->GetTarget(index);
7542    }
7543
7544    *IteratorField() = constructor_;
7545    return NULL;
7546  }
7547
7548 private:
7549  Object** IteratorField() {
7550    return HeapObject::RawField(map_, Map::kConstructorOffset);
7551  }
7552
7553  Map* map_;
7554  TransitionArray* transition_array_;
7555  Object* constructor_;
7556};
7557
7558
7559// An iterator over all prototype transitions, reusing the constructor field
7560// of the map while it is running.  Positive values in the constructor field
7561// indicate an active prototype transition iteration. The original constructor
7562// is restored after iterating over all entries.
7563class IntrusivePrototypeTransitionIterator {
7564 public:
7565  IntrusivePrototypeTransitionIterator(
7566      Map* map, HeapObject* proto_trans, Object* constructor)
7567      : map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
7568
7569  void StartIfNotStarted() {
7570    if (!(*IteratorField())->IsSmi()) {
7571      ASSERT(*IteratorField() == constructor_);
7572      *IteratorField() = Smi::FromInt(0);
7573    }
7574  }
7575
7576  bool IsIterating() {
7577    return (*IteratorField())->IsSmi() &&
7578           Smi::cast(*IteratorField())->value() >= 0;
7579  }
7580
7581  Map* Next() {
7582    ASSERT(IsIterating());
7583    int transitionNumber = Smi::cast(*IteratorField())->value();
7584    if (transitionNumber < NumberOfTransitions()) {
7585      *IteratorField() = Smi::FromInt(transitionNumber + 1);
7586      return GetTransition(transitionNumber);
7587    }
7588    *IteratorField() = constructor_;
7589    return NULL;
7590  }
7591
7592 private:
7593  Object** IteratorField() {
7594    return HeapObject::RawField(map_, Map::kConstructorOffset);
7595  }
7596
7597  int NumberOfTransitions() {
7598    FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7599    Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
7600    return Smi::cast(num)->value();
7601  }
7602
7603  Map* GetTransition(int transitionNumber) {
7604    FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7605    return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
7606  }
7607
7608  int IndexFor(int transitionNumber) {
7609    return Map::kProtoTransitionHeaderSize +
7610        Map::kProtoTransitionMapOffset +
7611        transitionNumber * Map::kProtoTransitionElementsPerEntry;
7612  }
7613
7614  Map* map_;
7615  HeapObject* proto_trans_;
7616  Object* constructor_;
7617};
7618
7619
7620// To traverse the transition tree iteratively, we have to store two kinds of
7621// information in a map: The parent map in the traversal and which children of a
7622// node have already been visited. To do this without additional memory, we
7623// temporarily reuse two fields with known values:
7624//
7625//  (1) The map of the map temporarily holds the parent, and is restored to the
7626//      meta map afterwards.
7627//
7628//  (2) The info which children have already been visited depends on which part
7629//      of the map we currently iterate. We use the constructor field of the
7630//      map to store the current index. We can do that because the constructor
7631//      is the same for all involved maps.
7632//
7633//    (a) If we currently follow normal map transitions, we temporarily store
7634//        the current index in the constructor field, and restore it to the
7635//        original constructor afterwards. Note that a single descriptor can
7636//        have 0, 1, or 2 transitions.
7637//
7638//    (b) If we currently follow prototype transitions, we temporarily store
7639//        the current index in the constructor field, and restore it to the
7640//        original constructor afterwards.
7641//
7642// Note that the child iterator is just a concatenation of two iterators: One
7643// iterating over map transitions and one iterating over prototype transisitons.
7644class TraversableMap : public Map {
7645 public:
7646  // Record the parent in the traversal within this map. Note that this destroys
7647  // this map's map!
7648  void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7649
7650  // Reset the current map's map, returning the parent previously stored in it.
7651  TraversableMap* GetAndResetParent() {
7652    TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7653    set_map_no_write_barrier(GetHeap()->meta_map());
7654    return old_parent;
7655  }
7656
7657  // If we have an unvisited child map, return that one and advance. If we have
7658  // none, return NULL and restore the overwritten constructor field.
7659  TraversableMap* ChildIteratorNext(Object* constructor) {
7660    if (!HasTransitionArray()) return NULL;
7661
7662    TransitionArray* transition_array = transitions();
7663    if (transition_array->HasPrototypeTransitions()) {
7664      HeapObject* proto_transitions =
7665          transition_array->GetPrototypeTransitions();
7666      IntrusivePrototypeTransitionIterator proto_iterator(this,
7667                                                          proto_transitions,
7668                                                          constructor);
7669      proto_iterator.StartIfNotStarted();
7670      if (proto_iterator.IsIterating()) {
7671        Map* next = proto_iterator.Next();
7672        if (next != NULL) return static_cast<TraversableMap*>(next);
7673      }
7674    }
7675
7676    IntrusiveMapTransitionIterator transition_iterator(this,
7677                                                       transition_array,
7678                                                       constructor);
7679    transition_iterator.StartIfNotStarted();
7680    if (transition_iterator.IsIterating()) {
7681      Map* next = transition_iterator.Next();
7682      if (next != NULL) return static_cast<TraversableMap*>(next);
7683    }
7684
7685    return NULL;
7686  }
7687};
7688
7689
7690// Traverse the transition tree in postorder without using the C++ stack by
7691// doing pointer reversal.
7692void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
7693  // Make sure that we do not allocate in the callback.
7694  DisallowHeapAllocation no_allocation;
7695
7696  TraversableMap* current = static_cast<TraversableMap*>(this);
7697  // Get the root constructor here to restore it later when finished iterating
7698  // over maps.
7699  Object* root_constructor = constructor();
7700  while (true) {
7701    TraversableMap* child = current->ChildIteratorNext(root_constructor);
7702    if (child != NULL) {
7703      child->SetParent(current);
7704      current = child;
7705    } else {
7706      TraversableMap* parent = current->GetAndResetParent();
7707      callback(current, data);
7708      if (current == this) break;
7709      current = parent;
7710    }
7711  }
7712}
7713
7714
7715void CodeCache::Update(
7716    Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
7717  // The number of monomorphic stubs for normal load/store/call IC's can grow to
7718  // a large number and therefore they need to go into a hash table. They are
7719  // used to load global properties from cells.
7720  if (code->type() == Code::NORMAL) {
7721    // Make sure that a hash table is allocated for the normal load code cache.
7722    if (code_cache->normal_type_cache()->IsUndefined()) {
7723      Handle<Object> result =
7724          CodeCacheHashTable::New(code_cache->GetIsolate(),
7725                                  CodeCacheHashTable::kInitialSize);
7726      code_cache->set_normal_type_cache(*result);
7727    }
7728    UpdateNormalTypeCache(code_cache, name, code);
7729  } else {
7730    ASSERT(code_cache->default_cache()->IsFixedArray());
7731    UpdateDefaultCache(code_cache, name, code);
7732  }
7733}
7734
7735
7736void CodeCache::UpdateDefaultCache(
7737    Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
7738  // When updating the default code cache we disregard the type encoded in the
7739  // flags. This allows call constant stubs to overwrite call field
7740  // stubs, etc.
7741  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
7742
7743  // First check whether we can update existing code cache without
7744  // extending it.
7745  Handle<FixedArray> cache = handle(code_cache->default_cache());
7746  int length = cache->length();
7747  {
7748    DisallowHeapAllocation no_alloc;
7749    int deleted_index = -1;
7750    for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7751      Object* key = cache->get(i);
7752      if (key->IsNull()) {
7753        if (deleted_index < 0) deleted_index = i;
7754        continue;
7755      }
7756      if (key->IsUndefined()) {
7757        if (deleted_index >= 0) i = deleted_index;
7758        cache->set(i + kCodeCacheEntryNameOffset, *name);
7759        cache->set(i + kCodeCacheEntryCodeOffset, *code);
7760        return;
7761      }
7762      if (name->Equals(Name::cast(key))) {
7763        Code::Flags found =
7764            Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
7765        if (Code::RemoveTypeFromFlags(found) == flags) {
7766          cache->set(i + kCodeCacheEntryCodeOffset, *code);
7767          return;
7768        }
7769      }
7770    }
7771
7772    // Reached the end of the code cache.  If there were deleted
7773    // elements, reuse the space for the first of them.
7774    if (deleted_index >= 0) {
7775      cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
7776      cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
7777      return;
7778    }
7779  }
7780
7781  // Extend the code cache with some new entries (at least one). Must be a
7782  // multiple of the entry size.
7783  int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
7784  new_length = new_length - new_length % kCodeCacheEntrySize;
7785  ASSERT((new_length % kCodeCacheEntrySize) == 0);
7786  cache = FixedArray::CopySize(cache, new_length);
7787
7788  // Add the (name, code) pair to the new cache.
7789  cache->set(length + kCodeCacheEntryNameOffset, *name);
7790  cache->set(length + kCodeCacheEntryCodeOffset, *code);
7791  code_cache->set_default_cache(*cache);
7792}
7793
7794
7795void CodeCache::UpdateNormalTypeCache(
7796    Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
7797  // Adding a new entry can cause a new cache to be allocated.
7798  Handle<CodeCacheHashTable> cache(
7799      CodeCacheHashTable::cast(code_cache->normal_type_cache()));
7800  Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
7801  code_cache->set_normal_type_cache(*new_cache);
7802}
7803
7804
7805Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
7806  Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
7807  if (result->IsCode()) {
7808    if (Code::cast(result)->flags() == flags) return result;
7809    return GetHeap()->undefined_value();
7810  }
7811  return LookupNormalTypeCache(name, flags);
7812}
7813
7814
7815Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
7816  FixedArray* cache = default_cache();
7817  int length = cache->length();
7818  for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7819    Object* key = cache->get(i + kCodeCacheEntryNameOffset);
7820    // Skip deleted elements.
7821    if (key->IsNull()) continue;
7822    if (key->IsUndefined()) return key;
7823    if (name->Equals(Name::cast(key))) {
7824      Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
7825      if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
7826        return code;
7827      }
7828    }
7829  }
7830  return GetHeap()->undefined_value();
7831}
7832
7833
7834Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
7835  if (!normal_type_cache()->IsUndefined()) {
7836    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7837    return cache->Lookup(name, flags);
7838  } else {
7839    return GetHeap()->undefined_value();
7840  }
7841}
7842
7843
7844int CodeCache::GetIndex(Object* name, Code* code) {
7845  if (code->type() == Code::NORMAL) {
7846    if (normal_type_cache()->IsUndefined()) return -1;
7847    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7848    return cache->GetIndex(Name::cast(name), code->flags());
7849  }
7850
7851  FixedArray* array = default_cache();
7852  int len = array->length();
7853  for (int i = 0; i < len; i += kCodeCacheEntrySize) {
7854    if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
7855  }
7856  return -1;
7857}
7858
7859
7860void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
7861  if (code->type() == Code::NORMAL) {
7862    ASSERT(!normal_type_cache()->IsUndefined());
7863    CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7864    ASSERT(cache->GetIndex(Name::cast(name), code->flags()) == index);
7865    cache->RemoveByIndex(index);
7866  } else {
7867    FixedArray* array = default_cache();
7868    ASSERT(array->length() >= index && array->get(index)->IsCode());
7869    // Use null instead of undefined for deleted elements to distinguish
7870    // deleted elements from unused elements.  This distinction is used
7871    // when looking up in the cache and when updating the cache.
7872    ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
7873    array->set_null(index - 1);  // Name.
7874    array->set_null(index);  // Code.
7875  }
7876}
7877
7878
7879// The key in the code cache hash table consists of the property name and the
7880// code object. The actual match is on the name and the code flags. If a key
7881// is created using the flags and not a code object it can only be used for
7882// lookup not to create a new entry.
7883class CodeCacheHashTableKey : public HashTableKey {
7884 public:
7885  CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
7886      : name_(name), flags_(flags), code_() { }
7887
7888  CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
7889      : name_(name), flags_(code->flags()), code_(code) { }
7890
7891  bool IsMatch(Object* other) V8_OVERRIDE {
7892    if (!other->IsFixedArray()) return false;
7893    FixedArray* pair = FixedArray::cast(other);
7894    Name* name = Name::cast(pair->get(0));
7895    Code::Flags flags = Code::cast(pair->get(1))->flags();
7896    if (flags != flags_) {
7897      return false;
7898    }
7899    return name_->Equals(name);
7900  }
7901
7902  static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
7903    return name->Hash() ^ flags;
7904  }
7905
7906  uint32_t Hash() V8_OVERRIDE { return NameFlagsHashHelper(*name_, flags_); }
7907
7908  uint32_t HashForObject(Object* obj) V8_OVERRIDE {
7909    FixedArray* pair = FixedArray::cast(obj);
7910    Name* name = Name::cast(pair->get(0));
7911    Code* code = Code::cast(pair->get(1));
7912    return NameFlagsHashHelper(name, code->flags());
7913  }
7914
7915  MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE {
7916    Handle<Code> code = code_.ToHandleChecked();
7917    Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
7918    pair->set(0, *name_);
7919    pair->set(1, *code);
7920    return pair;
7921  }
7922
7923 private:
7924  Handle<Name> name_;
7925  Code::Flags flags_;
7926  // TODO(jkummerow): We should be able to get by without this.
7927  MaybeHandle<Code> code_;
7928};
7929
7930
7931Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
7932  DisallowHeapAllocation no_alloc;
7933  CodeCacheHashTableKey key(handle(name), flags);
7934  int entry = FindEntry(&key);
7935  if (entry == kNotFound) return GetHeap()->undefined_value();
7936  return get(EntryToIndex(entry) + 1);
7937}
7938
7939
7940Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
7941    Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
7942  CodeCacheHashTableKey key(name, code);
7943
7944  Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
7945
7946  int entry = new_cache->FindInsertionEntry(key.Hash());
7947  Handle<Object> k = key.AsHandle(cache->GetIsolate());
7948
7949  new_cache->set(EntryToIndex(entry), *k);
7950  new_cache->set(EntryToIndex(entry) + 1, *code);
7951  new_cache->ElementAdded();
7952  return new_cache;
7953}
7954
7955
7956int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
7957  DisallowHeapAllocation no_alloc;
7958  CodeCacheHashTableKey key(handle(name), flags);
7959  int entry = FindEntry(&key);
7960  return (entry == kNotFound) ? -1 : entry;
7961}
7962
7963
7964void CodeCacheHashTable::RemoveByIndex(int index) {
7965  ASSERT(index >= 0);
7966  Heap* heap = GetHeap();
7967  set(EntryToIndex(index), heap->the_hole_value());
7968  set(EntryToIndex(index) + 1, heap->the_hole_value());
7969  ElementRemoved();
7970}
7971
7972
7973void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
7974                                  MapHandleList* maps,
7975                                  Code::Flags flags,
7976                                  Handle<Code> code) {
7977  Isolate* isolate = code_cache->GetIsolate();
7978  if (code_cache->cache()->IsUndefined()) {
7979    Handle<PolymorphicCodeCacheHashTable> result =
7980        PolymorphicCodeCacheHashTable::New(
7981            isolate,
7982            PolymorphicCodeCacheHashTable::kInitialSize);
7983    code_cache->set_cache(*result);
7984  } else {
7985    // This entry shouldn't be contained in the cache yet.
7986    ASSERT(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
7987               ->Lookup(maps, flags)->IsUndefined());
7988  }
7989  Handle<PolymorphicCodeCacheHashTable> hash_table =
7990      handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
7991  Handle<PolymorphicCodeCacheHashTable> new_cache =
7992      PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
7993  code_cache->set_cache(*new_cache);
7994}
7995
7996
7997Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
7998                                            Code::Flags flags) {
7999  if (!cache()->IsUndefined()) {
8000    PolymorphicCodeCacheHashTable* hash_table =
8001        PolymorphicCodeCacheHashTable::cast(cache());
8002    return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
8003  } else {
8004    return GetIsolate()->factory()->undefined_value();
8005  }
8006}
8007
8008
8009// Despite their name, object of this class are not stored in the actual
8010// hash table; instead they're temporarily used for lookups. It is therefore
8011// safe to have a weak (non-owning) pointer to a MapList as a member field.
8012class PolymorphicCodeCacheHashTableKey : public HashTableKey {
8013 public:
8014  // Callers must ensure that |maps| outlives the newly constructed object.
8015  PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
8016      : maps_(maps),
8017        code_flags_(code_flags) {}
8018
8019  bool IsMatch(Object* other) V8_OVERRIDE {
8020    MapHandleList other_maps(kDefaultListAllocationSize);
8021    int other_flags;
8022    FromObject(other, &other_flags, &other_maps);
8023    if (code_flags_ != other_flags) return false;
8024    if (maps_->length() != other_maps.length()) return false;
8025    // Compare just the hashes first because it's faster.
8026    int this_hash = MapsHashHelper(maps_, code_flags_);
8027    int other_hash = MapsHashHelper(&other_maps, other_flags);
8028    if (this_hash != other_hash) return false;
8029
8030    // Full comparison: for each map in maps_, look for an equivalent map in
8031    // other_maps. This implementation is slow, but probably good enough for
8032    // now because the lists are short (<= 4 elements currently).
8033    for (int i = 0; i < maps_->length(); ++i) {
8034      bool match_found = false;
8035      for (int j = 0; j < other_maps.length(); ++j) {
8036        if (*(maps_->at(i)) == *(other_maps.at(j))) {
8037          match_found = true;
8038          break;
8039        }
8040      }
8041      if (!match_found) return false;
8042    }
8043    return true;
8044  }
8045
8046  static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
8047    uint32_t hash = code_flags;
8048    for (int i = 0; i < maps->length(); ++i) {
8049      hash ^= maps->at(i)->Hash();
8050    }
8051    return hash;
8052  }
8053
8054  uint32_t Hash() V8_OVERRIDE {
8055    return MapsHashHelper(maps_, code_flags_);
8056  }
8057
8058  uint32_t HashForObject(Object* obj) V8_OVERRIDE {
8059    MapHandleList other_maps(kDefaultListAllocationSize);
8060    int other_flags;
8061    FromObject(obj, &other_flags, &other_maps);
8062    return MapsHashHelper(&other_maps, other_flags);
8063  }
8064
8065  MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE {
8066    // The maps in |maps_| must be copied to a newly allocated FixedArray,
8067    // both because the referenced MapList is short-lived, and because C++
8068    // objects can't be stored in the heap anyway.
8069    Handle<FixedArray> list =
8070        isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
8071    list->set(0, Smi::FromInt(code_flags_));
8072    for (int i = 0; i < maps_->length(); ++i) {
8073      list->set(i + 1, *maps_->at(i));
8074    }
8075    return list;
8076  }
8077
8078 private:
8079  static MapHandleList* FromObject(Object* obj,
8080                                   int* code_flags,
8081                                   MapHandleList* maps) {
8082    FixedArray* list = FixedArray::cast(obj);
8083    maps->Rewind(0);
8084    *code_flags = Smi::cast(list->get(0))->value();
8085    for (int i = 1; i < list->length(); ++i) {
8086      maps->Add(Handle<Map>(Map::cast(list->get(i))));
8087    }
8088    return maps;
8089  }
8090
8091  MapHandleList* maps_;  // weak.
8092  int code_flags_;
8093  static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
8094};
8095
8096
8097Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
8098                                              int code_kind) {
8099  DisallowHeapAllocation no_alloc;
8100  PolymorphicCodeCacheHashTableKey key(maps, code_kind);
8101  int entry = FindEntry(&key);
8102  if (entry == kNotFound) return GetHeap()->undefined_value();
8103  return get(EntryToIndex(entry) + 1);
8104}
8105
8106
8107Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
8108      Handle<PolymorphicCodeCacheHashTable> hash_table,
8109      MapHandleList* maps,
8110      int code_kind,
8111      Handle<Code> code) {
8112  PolymorphicCodeCacheHashTableKey key(maps, code_kind);
8113  Handle<PolymorphicCodeCacheHashTable> cache =
8114      EnsureCapacity(hash_table, 1, &key);
8115  int entry = cache->FindInsertionEntry(key.Hash());
8116
8117  Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
8118  cache->set(EntryToIndex(entry), *obj);
8119  cache->set(EntryToIndex(entry) + 1, *code);
8120  cache->ElementAdded();
8121  return cache;
8122}
8123
8124
8125void FixedArray::Shrink(int new_length) {
8126  ASSERT(0 <= new_length && new_length <= length());
8127  if (new_length < length()) {
8128    RightTrimFixedArray<Heap::FROM_MUTATOR>(
8129        GetHeap(), this, length() - new_length);
8130  }
8131}
8132
8133
8134MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike(
8135    Handle<FixedArray> content,
8136    Handle<JSObject> array) {
8137  ASSERT(array->IsJSArray() || array->HasSloppyArgumentsElements());
8138  ElementsAccessor* accessor = array->GetElementsAccessor();
8139  Handle<FixedArray> result;
8140  ASSIGN_RETURN_ON_EXCEPTION(
8141      array->GetIsolate(), result,
8142      accessor->AddElementsToFixedArray(array, array, content),
8143      FixedArray);
8144
8145#ifdef ENABLE_SLOW_ASSERTS
8146  if (FLAG_enable_slow_asserts) {
8147    DisallowHeapAllocation no_allocation;
8148    for (int i = 0; i < result->length(); i++) {
8149      Object* current = result->get(i);
8150      ASSERT(current->IsNumber() || current->IsName());
8151    }
8152  }
8153#endif
8154  return result;
8155}
8156
8157
8158MaybeHandle<FixedArray> FixedArray::UnionOfKeys(Handle<FixedArray> first,
8159                                                Handle<FixedArray> second) {
8160  ElementsAccessor* accessor = ElementsAccessor::ForArray(second);
8161  Handle<FixedArray> result;
8162  ASSIGN_RETURN_ON_EXCEPTION(
8163      first->GetIsolate(), result,
8164      accessor->AddElementsToFixedArray(
8165          Handle<Object>::null(),     // receiver
8166          Handle<JSObject>::null(),   // holder
8167          first,
8168          Handle<FixedArrayBase>::cast(second)),
8169      FixedArray);
8170
8171#ifdef ENABLE_SLOW_ASSERTS
8172  if (FLAG_enable_slow_asserts) {
8173    DisallowHeapAllocation no_allocation;
8174    for (int i = 0; i < result->length(); i++) {
8175      Object* current = result->get(i);
8176      ASSERT(current->IsNumber() || current->IsName());
8177    }
8178  }
8179#endif
8180  return result;
8181}
8182
8183
8184Handle<FixedArray> FixedArray::CopySize(
8185    Handle<FixedArray> array, int new_length, PretenureFlag pretenure) {
8186  Isolate* isolate = array->GetIsolate();
8187  if (new_length == 0) return isolate->factory()->empty_fixed_array();
8188  Handle<FixedArray> result =
8189      isolate->factory()->NewFixedArray(new_length, pretenure);
8190  // Copy the content
8191  DisallowHeapAllocation no_gc;
8192  int len = array->length();
8193  if (new_length < len) len = new_length;
8194  // We are taking the map from the old fixed array so the map is sure to
8195  // be an immortal immutable object.
8196  result->set_map_no_write_barrier(array->map());
8197  WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
8198  for (int i = 0; i < len; i++) {
8199    result->set(i, array->get(i), mode);
8200  }
8201  return result;
8202}
8203
8204
8205void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
8206  DisallowHeapAllocation no_gc;
8207  WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
8208  for (int index = 0; index < len; index++) {
8209    dest->set(dest_pos+index, get(pos+index), mode);
8210  }
8211}
8212
8213
8214#ifdef DEBUG
8215bool FixedArray::IsEqualTo(FixedArray* other) {
8216  if (length() != other->length()) return false;
8217  for (int i = 0 ; i < length(); ++i) {
8218    if (get(i) != other->get(i)) return false;
8219  }
8220  return true;
8221}
8222#endif
8223
8224
8225Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
8226                                                  int number_of_descriptors,
8227                                                  int slack) {
8228  ASSERT(0 <= number_of_descriptors);
8229  Factory* factory = isolate->factory();
8230  // Do not use DescriptorArray::cast on incomplete object.
8231  int size = number_of_descriptors + slack;
8232  if (size == 0) return factory->empty_descriptor_array();
8233  // Allocate the array of keys.
8234  Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size));
8235
8236  result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
8237  result->set(kEnumCacheIndex, Smi::FromInt(0));
8238  return Handle<DescriptorArray>::cast(result);
8239}
8240
8241
8242void DescriptorArray::ClearEnumCache() {
8243  set(kEnumCacheIndex, Smi::FromInt(0));
8244}
8245
8246
8247void DescriptorArray::Replace(int index, Descriptor* descriptor) {
8248  descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
8249  Set(index, descriptor);
8250}
8251
8252
8253void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
8254                                   FixedArray* new_cache,
8255                                   Object* new_index_cache) {
8256  ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
8257  ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
8258  ASSERT(!IsEmpty());
8259  ASSERT(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
8260  FixedArray::cast(bridge_storage)->
8261    set(kEnumCacheBridgeCacheIndex, new_cache);
8262  FixedArray::cast(bridge_storage)->
8263    set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
8264  set(kEnumCacheIndex, bridge_storage);
8265}
8266
8267
8268void DescriptorArray::CopyFrom(int index,
8269                               DescriptorArray* src,
8270                               const WhitenessWitness& witness) {
8271  Object* value = src->GetValue(index);
8272  PropertyDetails details = src->GetDetails(index);
8273  Descriptor desc(handle(src->GetKey(index)),
8274                  handle(value, src->GetIsolate()),
8275                  details);
8276  Set(index, &desc, witness);
8277}
8278
8279
8280// We need the whiteness witness since sort will reshuffle the entries in the
8281// descriptor array. If the descriptor array were to be black, the shuffling
8282// would move a slot that was already recorded as pointing into an evacuation
8283// candidate. This would result in missing updates upon evacuation.
8284void DescriptorArray::Sort() {
8285  // In-place heap sort.
8286  int len = number_of_descriptors();
8287  // Reset sorting since the descriptor array might contain invalid pointers.
8288  for (int i = 0; i < len; ++i) SetSortedKey(i, i);
8289  // Bottom-up max-heap construction.
8290  // Index of the last node with children
8291  const int max_parent_index = (len / 2) - 1;
8292  for (int i = max_parent_index; i >= 0; --i) {
8293    int parent_index = i;
8294    const uint32_t parent_hash = GetSortedKey(i)->Hash();
8295    while (parent_index <= max_parent_index) {
8296      int child_index = 2 * parent_index + 1;
8297      uint32_t child_hash = GetSortedKey(child_index)->Hash();
8298      if (child_index + 1 < len) {
8299        uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
8300        if (right_child_hash > child_hash) {
8301          child_index++;
8302          child_hash = right_child_hash;
8303        }
8304      }
8305      if (child_hash <= parent_hash) break;
8306      SwapSortedKeys(parent_index, child_index);
8307      // Now element at child_index could be < its children.
8308      parent_index = child_index;  // parent_hash remains correct.
8309    }
8310  }
8311
8312  // Extract elements and create sorted array.
8313  for (int i = len - 1; i > 0; --i) {
8314    // Put max element at the back of the array.
8315    SwapSortedKeys(0, i);
8316    // Shift down the new top element.
8317    int parent_index = 0;
8318    const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
8319    const int max_parent_index = (i / 2) - 1;
8320    while (parent_index <= max_parent_index) {
8321      int child_index = parent_index * 2 + 1;
8322      uint32_t child_hash = GetSortedKey(child_index)->Hash();
8323      if (child_index + 1 < i) {
8324        uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
8325        if (right_child_hash > child_hash) {
8326          child_index++;
8327          child_hash = right_child_hash;
8328        }
8329      }
8330      if (child_hash <= parent_hash) break;
8331      SwapSortedKeys(parent_index, child_index);
8332      parent_index = child_index;
8333    }
8334  }
8335  ASSERT(IsSortedNoDuplicates());
8336}
8337
8338
8339Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
8340  Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
8341  copy->set_getter(pair->getter());
8342  copy->set_setter(pair->setter());
8343  return copy;
8344}
8345
8346
8347Object* AccessorPair::GetComponent(AccessorComponent component) {
8348  Object* accessor = get(component);
8349  return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
8350}
8351
8352
8353Handle<DeoptimizationInputData> DeoptimizationInputData::New(
8354    Isolate* isolate,
8355    int deopt_entry_count,
8356    PretenureFlag pretenure) {
8357  ASSERT(deopt_entry_count > 0);
8358  return Handle<DeoptimizationInputData>::cast(
8359      isolate->factory()->NewFixedArray(
8360          LengthFor(deopt_entry_count), pretenure));
8361}
8362
8363
8364Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
8365    Isolate* isolate,
8366    int number_of_deopt_points,
8367    PretenureFlag pretenure) {
8368  Handle<FixedArray> result;
8369  if (number_of_deopt_points == 0) {
8370    result = isolate->factory()->empty_fixed_array();
8371  } else {
8372    result = isolate->factory()->NewFixedArray(
8373        LengthOfFixedArray(number_of_deopt_points), pretenure);
8374  }
8375  return Handle<DeoptimizationOutputData>::cast(result);
8376}
8377
8378
8379#ifdef DEBUG
8380bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
8381  if (IsEmpty()) return other->IsEmpty();
8382  if (other->IsEmpty()) return false;
8383  if (length() != other->length()) return false;
8384  for (int i = 0; i < length(); ++i) {
8385    if (get(i) != other->get(i)) return false;
8386  }
8387  return true;
8388}
8389#endif
8390
8391
8392bool String::LooksValid() {
8393  if (!GetIsolate()->heap()->Contains(this)) return false;
8394  return true;
8395}
8396
8397
8398String::FlatContent String::GetFlatContent() {
8399  ASSERT(!AllowHeapAllocation::IsAllowed());
8400  int length = this->length();
8401  StringShape shape(this);
8402  String* string = this;
8403  int offset = 0;
8404  if (shape.representation_tag() == kConsStringTag) {
8405    ConsString* cons = ConsString::cast(string);
8406    if (cons->second()->length() != 0) {
8407      return FlatContent();
8408    }
8409    string = cons->first();
8410    shape = StringShape(string);
8411  }
8412  if (shape.representation_tag() == kSlicedStringTag) {
8413    SlicedString* slice = SlicedString::cast(string);
8414    offset = slice->offset();
8415    string = slice->parent();
8416    shape = StringShape(string);
8417    ASSERT(shape.representation_tag() != kConsStringTag &&
8418           shape.representation_tag() != kSlicedStringTag);
8419  }
8420  if (shape.encoding_tag() == kOneByteStringTag) {
8421    const uint8_t* start;
8422    if (shape.representation_tag() == kSeqStringTag) {
8423      start = SeqOneByteString::cast(string)->GetChars();
8424    } else {
8425      start = ExternalAsciiString::cast(string)->GetChars();
8426    }
8427    return FlatContent(start + offset, length);
8428  } else {
8429    ASSERT(shape.encoding_tag() == kTwoByteStringTag);
8430    const uc16* start;
8431    if (shape.representation_tag() == kSeqStringTag) {
8432      start = SeqTwoByteString::cast(string)->GetChars();
8433    } else {
8434      start = ExternalTwoByteString::cast(string)->GetChars();
8435    }
8436    return FlatContent(start + offset, length);
8437  }
8438}
8439
8440
8441SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8442                                          RobustnessFlag robust_flag,
8443                                          int offset,
8444                                          int length,
8445                                          int* length_return) {
8446  if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
8447    return SmartArrayPointer<char>(NULL);
8448  }
8449  Heap* heap = GetHeap();
8450
8451  // Negative length means the to the end of the string.
8452  if (length < 0) length = kMaxInt - offset;
8453
8454  // Compute the size of the UTF-8 string. Start at the specified offset.
8455  Access<ConsStringIteratorOp> op(
8456      heap->isolate()->objects_string_iterator());
8457  StringCharacterStream stream(this, op.value(), offset);
8458  int character_position = offset;
8459  int utf8_bytes = 0;
8460  int last = unibrow::Utf16::kNoPreviousCharacter;
8461  while (stream.HasMore() && character_position++ < offset + length) {
8462    uint16_t character = stream.GetNext();
8463    utf8_bytes += unibrow::Utf8::Length(character, last);
8464    last = character;
8465  }
8466
8467  if (length_return) {
8468    *length_return = utf8_bytes;
8469  }
8470
8471  char* result = NewArray<char>(utf8_bytes + 1);
8472
8473  // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
8474  stream.Reset(this, offset);
8475  character_position = offset;
8476  int utf8_byte_position = 0;
8477  last = unibrow::Utf16::kNoPreviousCharacter;
8478  while (stream.HasMore() && character_position++ < offset + length) {
8479    uint16_t character = stream.GetNext();
8480    if (allow_nulls == DISALLOW_NULLS && character == 0) {
8481      character = ' ';
8482    }
8483    utf8_byte_position +=
8484        unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
8485    last = character;
8486  }
8487  result[utf8_byte_position] = 0;
8488  return SmartArrayPointer<char>(result);
8489}
8490
8491
8492SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8493                                          RobustnessFlag robust_flag,
8494                                          int* length_return) {
8495  return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
8496}
8497
8498
8499const uc16* String::GetTwoByteData(unsigned start) {
8500  ASSERT(!IsOneByteRepresentationUnderneath());
8501  switch (StringShape(this).representation_tag()) {
8502    case kSeqStringTag:
8503      return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
8504    case kExternalStringTag:
8505      return ExternalTwoByteString::cast(this)->
8506        ExternalTwoByteStringGetData(start);
8507    case kSlicedStringTag: {
8508      SlicedString* slice = SlicedString::cast(this);
8509      return slice->parent()->GetTwoByteData(start + slice->offset());
8510    }
8511    case kConsStringTag:
8512      UNREACHABLE();
8513      return NULL;
8514  }
8515  UNREACHABLE();
8516  return NULL;
8517}
8518
8519
8520SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
8521  if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
8522    return SmartArrayPointer<uc16>();
8523  }
8524  Heap* heap = GetHeap();
8525
8526  Access<ConsStringIteratorOp> op(
8527      heap->isolate()->objects_string_iterator());
8528  StringCharacterStream stream(this, op.value());
8529
8530  uc16* result = NewArray<uc16>(length() + 1);
8531
8532  int i = 0;
8533  while (stream.HasMore()) {
8534    uint16_t character = stream.GetNext();
8535    result[i++] = character;
8536  }
8537  result[i] = 0;
8538  return SmartArrayPointer<uc16>(result);
8539}
8540
8541
8542const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
8543  return reinterpret_cast<uc16*>(
8544      reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
8545}
8546
8547
8548void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
8549  Relocatable* current = isolate->relocatable_top();
8550  while (current != NULL) {
8551    current->PostGarbageCollection();
8552    current = current->prev_;
8553  }
8554}
8555
8556
8557// Reserve space for statics needing saving and restoring.
8558int Relocatable::ArchiveSpacePerThread() {
8559  return sizeof(Relocatable*);  // NOLINT
8560}
8561
8562
8563// Archive statics that are thread-local.
8564char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
8565  *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
8566  isolate->set_relocatable_top(NULL);
8567  return to + ArchiveSpacePerThread();
8568}
8569
8570
8571// Restore statics that are thread-local.
8572char* Relocatable::RestoreState(Isolate* isolate, char* from) {
8573  isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
8574  return from + ArchiveSpacePerThread();
8575}
8576
8577
8578char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
8579  Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
8580  Iterate(v, top);
8581  return thread_storage + ArchiveSpacePerThread();
8582}
8583
8584
8585void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
8586  Iterate(v, isolate->relocatable_top());
8587}
8588
8589
8590void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
8591  Relocatable* current = top;
8592  while (current != NULL) {
8593    current->IterateInstance(v);
8594    current = current->prev_;
8595  }
8596}
8597
8598
8599FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
8600    : Relocatable(isolate),
8601      str_(str.location()),
8602      length_(str->length()) {
8603  PostGarbageCollection();
8604}
8605
8606
8607FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
8608    : Relocatable(isolate),
8609      str_(0),
8610      is_ascii_(true),
8611      length_(input.length()),
8612      start_(input.start()) { }
8613
8614
8615void FlatStringReader::PostGarbageCollection() {
8616  if (str_ == NULL) return;
8617  Handle<String> str(str_);
8618  ASSERT(str->IsFlat());
8619  DisallowHeapAllocation no_gc;
8620  // This does not actually prevent the vector from being relocated later.
8621  String::FlatContent content = str->GetFlatContent();
8622  ASSERT(content.IsFlat());
8623  is_ascii_ = content.IsAscii();
8624  if (is_ascii_) {
8625    start_ = content.ToOneByteVector().start();
8626  } else {
8627    start_ = content.ToUC16Vector().start();
8628  }
8629}
8630
8631
8632void ConsStringIteratorOp::Initialize(ConsString* cons_string, int offset) {
8633  ASSERT(cons_string != NULL);
8634  root_ = cons_string;
8635  consumed_ = offset;
8636  // Force stack blown condition to trigger restart.
8637  depth_ = 1;
8638  maximum_depth_ = kStackSize + depth_;
8639  ASSERT(StackBlown());
8640}
8641
8642
8643String* ConsStringIteratorOp::Continue(int* offset_out) {
8644  ASSERT(depth_ != 0);
8645  ASSERT_EQ(0, *offset_out);
8646  bool blew_stack = StackBlown();
8647  String* string = NULL;
8648  // Get the next leaf if there is one.
8649  if (!blew_stack) string = NextLeaf(&blew_stack);
8650  // Restart search from root.
8651  if (blew_stack) {
8652    ASSERT(string == NULL);
8653    string = Search(offset_out);
8654  }
8655  // Ensure future calls return null immediately.
8656  if (string == NULL) Reset(NULL);
8657  return string;
8658}
8659
8660
8661String* ConsStringIteratorOp::Search(int* offset_out) {
8662  ConsString* cons_string = root_;
8663  // Reset the stack, pushing the root string.
8664  depth_ = 1;
8665  maximum_depth_ = 1;
8666  frames_[0] = cons_string;
8667  const int consumed = consumed_;
8668  int offset = 0;
8669  while (true) {
8670    // Loop until the string is found which contains the target offset.
8671    String* string = cons_string->first();
8672    int length = string->length();
8673    int32_t type;
8674    if (consumed < offset + length) {
8675      // Target offset is in the left branch.
8676      // Keep going if we're still in a ConString.
8677      type = string->map()->instance_type();
8678      if ((type & kStringRepresentationMask) == kConsStringTag) {
8679        cons_string = ConsString::cast(string);
8680        PushLeft(cons_string);
8681        continue;
8682      }
8683      // Tell the stack we're done descending.
8684      AdjustMaximumDepth();
8685    } else {
8686      // Descend right.
8687      // Update progress through the string.
8688      offset += length;
8689      // Keep going if we're still in a ConString.
8690      string = cons_string->second();
8691      type = string->map()->instance_type();
8692      if ((type & kStringRepresentationMask) == kConsStringTag) {
8693        cons_string = ConsString::cast(string);
8694        PushRight(cons_string);
8695        continue;
8696      }
8697      // Need this to be updated for the current string.
8698      length = string->length();
8699      // Account for the possibility of an empty right leaf.
8700      // This happens only if we have asked for an offset outside the string.
8701      if (length == 0) {
8702        // Reset so future operations will return null immediately.
8703        Reset(NULL);
8704        return NULL;
8705      }
8706      // Tell the stack we're done descending.
8707      AdjustMaximumDepth();
8708      // Pop stack so next iteration is in correct place.
8709      Pop();
8710    }
8711    ASSERT(length != 0);
8712    // Adjust return values and exit.
8713    consumed_ = offset + length;
8714    *offset_out = consumed - offset;
8715    return string;
8716  }
8717  UNREACHABLE();
8718  return NULL;
8719}
8720
8721
8722String* ConsStringIteratorOp::NextLeaf(bool* blew_stack) {
8723  while (true) {
8724    // Tree traversal complete.
8725    if (depth_ == 0) {
8726      *blew_stack = false;
8727      return NULL;
8728    }
8729    // We've lost track of higher nodes.
8730    if (StackBlown()) {
8731      *blew_stack = true;
8732      return NULL;
8733    }
8734    // Go right.
8735    ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
8736    String* string = cons_string->second();
8737    int32_t type = string->map()->instance_type();
8738    if ((type & kStringRepresentationMask) != kConsStringTag) {
8739      // Pop stack so next iteration is in correct place.
8740      Pop();
8741      int length = string->length();
8742      // Could be a flattened ConsString.
8743      if (length == 0) continue;
8744      consumed_ += length;
8745      return string;
8746    }
8747    cons_string = ConsString::cast(string);
8748    PushRight(cons_string);
8749    // Need to traverse all the way left.
8750    while (true) {
8751      // Continue left.
8752      string = cons_string->first();
8753      type = string->map()->instance_type();
8754      if ((type & kStringRepresentationMask) != kConsStringTag) {
8755        AdjustMaximumDepth();
8756        int length = string->length();
8757        ASSERT(length != 0);
8758        consumed_ += length;
8759        return string;
8760      }
8761      cons_string = ConsString::cast(string);
8762      PushLeft(cons_string);
8763    }
8764  }
8765  UNREACHABLE();
8766  return NULL;
8767}
8768
8769
8770uint16_t ConsString::ConsStringGet(int index) {
8771  ASSERT(index >= 0 && index < this->length());
8772
8773  // Check for a flattened cons string
8774  if (second()->length() == 0) {
8775    String* left = first();
8776    return left->Get(index);
8777  }
8778
8779  String* string = String::cast(this);
8780
8781  while (true) {
8782    if (StringShape(string).IsCons()) {
8783      ConsString* cons_string = ConsString::cast(string);
8784      String* left = cons_string->first();
8785      if (left->length() > index) {
8786        string = left;
8787      } else {
8788        index -= left->length();
8789        string = cons_string->second();
8790      }
8791    } else {
8792      return string->Get(index);
8793    }
8794  }
8795
8796  UNREACHABLE();
8797  return 0;
8798}
8799
8800
8801uint16_t SlicedString::SlicedStringGet(int index) {
8802  return parent()->Get(offset() + index);
8803}
8804
8805
8806template <typename sinkchar>
8807void String::WriteToFlat(String* src,
8808                         sinkchar* sink,
8809                         int f,
8810                         int t) {
8811  String* source = src;
8812  int from = f;
8813  int to = t;
8814  while (true) {
8815    ASSERT(0 <= from && from <= to && to <= source->length());
8816    switch (StringShape(source).full_representation_tag()) {
8817      case kOneByteStringTag | kExternalStringTag: {
8818        CopyChars(sink,
8819                  ExternalAsciiString::cast(source)->GetChars() + from,
8820                  to - from);
8821        return;
8822      }
8823      case kTwoByteStringTag | kExternalStringTag: {
8824        const uc16* data =
8825            ExternalTwoByteString::cast(source)->GetChars();
8826        CopyChars(sink,
8827                  data + from,
8828                  to - from);
8829        return;
8830      }
8831      case kOneByteStringTag | kSeqStringTag: {
8832        CopyChars(sink,
8833                  SeqOneByteString::cast(source)->GetChars() + from,
8834                  to - from);
8835        return;
8836      }
8837      case kTwoByteStringTag | kSeqStringTag: {
8838        CopyChars(sink,
8839                  SeqTwoByteString::cast(source)->GetChars() + from,
8840                  to - from);
8841        return;
8842      }
8843      case kOneByteStringTag | kConsStringTag:
8844      case kTwoByteStringTag | kConsStringTag: {
8845        ConsString* cons_string = ConsString::cast(source);
8846        String* first = cons_string->first();
8847        int boundary = first->length();
8848        if (to - boundary >= boundary - from) {
8849          // Right hand side is longer.  Recurse over left.
8850          if (from < boundary) {
8851            WriteToFlat(first, sink, from, boundary);
8852            sink += boundary - from;
8853            from = 0;
8854          } else {
8855            from -= boundary;
8856          }
8857          to -= boundary;
8858          source = cons_string->second();
8859        } else {
8860          // Left hand side is longer.  Recurse over right.
8861          if (to > boundary) {
8862            String* second = cons_string->second();
8863            // When repeatedly appending to a string, we get a cons string that
8864            // is unbalanced to the left, a list, essentially.  We inline the
8865            // common case of sequential ascii right child.
8866            if (to - boundary == 1) {
8867              sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
8868            } else if (second->IsSeqOneByteString()) {
8869              CopyChars(sink + boundary - from,
8870                        SeqOneByteString::cast(second)->GetChars(),
8871                        to - boundary);
8872            } else {
8873              WriteToFlat(second,
8874                          sink + boundary - from,
8875                          0,
8876                          to - boundary);
8877            }
8878            to = boundary;
8879          }
8880          source = first;
8881        }
8882        break;
8883      }
8884      case kOneByteStringTag | kSlicedStringTag:
8885      case kTwoByteStringTag | kSlicedStringTag: {
8886        SlicedString* slice = SlicedString::cast(source);
8887        unsigned offset = slice->offset();
8888        WriteToFlat(slice->parent(), sink, from + offset, to + offset);
8889        return;
8890      }
8891    }
8892  }
8893}
8894
8895
8896
8897template <typename SourceChar>
8898static void CalculateLineEndsImpl(Isolate* isolate,
8899                                  List<int>* line_ends,
8900                                  Vector<const SourceChar> src,
8901                                  bool include_ending_line) {
8902  const int src_len = src.length();
8903  StringSearch<uint8_t, SourceChar> search(isolate, STATIC_ASCII_VECTOR("\n"));
8904
8905  // Find and record line ends.
8906  int position = 0;
8907  while (position != -1 && position < src_len) {
8908    position = search.Search(src, position);
8909    if (position != -1) {
8910      line_ends->Add(position);
8911      position++;
8912    } else if (include_ending_line) {
8913      // Even if the last line misses a line end, it is counted.
8914      line_ends->Add(src_len);
8915      return;
8916    }
8917  }
8918}
8919
8920
8921Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
8922                                             bool include_ending_line) {
8923  src = Flatten(src);
8924  // Rough estimate of line count based on a roughly estimated average
8925  // length of (unpacked) code.
8926  int line_count_estimate = src->length() >> 4;
8927  List<int> line_ends(line_count_estimate);
8928  Isolate* isolate = src->GetIsolate();
8929  { DisallowHeapAllocation no_allocation;  // ensure vectors stay valid.
8930    // Dispatch on type of strings.
8931    String::FlatContent content = src->GetFlatContent();
8932    ASSERT(content.IsFlat());
8933    if (content.IsAscii()) {
8934      CalculateLineEndsImpl(isolate,
8935                            &line_ends,
8936                            content.ToOneByteVector(),
8937                            include_ending_line);
8938    } else {
8939      CalculateLineEndsImpl(isolate,
8940                            &line_ends,
8941                            content.ToUC16Vector(),
8942                            include_ending_line);
8943    }
8944  }
8945  int line_count = line_ends.length();
8946  Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
8947  for (int i = 0; i < line_count; i++) {
8948    array->set(i, Smi::FromInt(line_ends[i]));
8949  }
8950  return array;
8951}
8952
8953
8954// Compares the contents of two strings by reading and comparing
8955// int-sized blocks of characters.
8956template <typename Char>
8957static inline bool CompareRawStringContents(const Char* const a,
8958                                            const Char* const b,
8959                                            int length) {
8960  int i = 0;
8961#ifndef V8_HOST_CAN_READ_UNALIGNED
8962  // If this architecture isn't comfortable reading unaligned ints
8963  // then we have to check that the strings are aligned before
8964  // comparing them blockwise.
8965  const int kAlignmentMask = sizeof(uint32_t) - 1;  // NOLINT
8966  uint32_t pa_addr = reinterpret_cast<uint32_t>(a);
8967  uint32_t pb_addr = reinterpret_cast<uint32_t>(b);
8968  if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
8969#endif
8970    const int kStepSize = sizeof(int) / sizeof(Char);  // NOLINT
8971    int endpoint = length - kStepSize;
8972    // Compare blocks until we reach near the end of the string.
8973    for (; i <= endpoint; i += kStepSize) {
8974      uint32_t wa = *reinterpret_cast<const uint32_t*>(a + i);
8975      uint32_t wb = *reinterpret_cast<const uint32_t*>(b + i);
8976      if (wa != wb) {
8977        return false;
8978      }
8979    }
8980#ifndef V8_HOST_CAN_READ_UNALIGNED
8981  }
8982#endif
8983  // Compare the remaining characters that didn't fit into a block.
8984  for (; i < length; i++) {
8985    if (a[i] != b[i]) {
8986      return false;
8987    }
8988  }
8989  return true;
8990}
8991
8992
8993template<typename Chars1, typename Chars2>
8994class RawStringComparator : public AllStatic {
8995 public:
8996  static inline bool compare(const Chars1* a, const Chars2* b, int len) {
8997    ASSERT(sizeof(Chars1) != sizeof(Chars2));
8998    for (int i = 0; i < len; i++) {
8999      if (a[i] != b[i]) {
9000        return false;
9001      }
9002    }
9003    return true;
9004  }
9005};
9006
9007
9008template<>
9009class RawStringComparator<uint16_t, uint16_t> {
9010 public:
9011  static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
9012    return CompareRawStringContents(a, b, len);
9013  }
9014};
9015
9016
9017template<>
9018class RawStringComparator<uint8_t, uint8_t> {
9019 public:
9020  static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
9021    return CompareRawStringContents(a, b, len);
9022  }
9023};
9024
9025
9026class StringComparator {
9027  class State {
9028   public:
9029    explicit inline State(ConsStringIteratorOp* op)
9030      : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
9031
9032    inline void Init(String* string) {
9033      ConsString* cons_string = String::VisitFlat(this, string);
9034      op_->Reset(cons_string);
9035      if (cons_string != NULL) {
9036        int offset;
9037        string = op_->Next(&offset);
9038        String::VisitFlat(this, string, offset);
9039      }
9040    }
9041
9042    inline void VisitOneByteString(const uint8_t* chars, int length) {
9043      is_one_byte_ = true;
9044      buffer8_ = chars;
9045      length_ = length;
9046    }
9047
9048    inline void VisitTwoByteString(const uint16_t* chars, int length) {
9049      is_one_byte_ = false;
9050      buffer16_ = chars;
9051      length_ = length;
9052    }
9053
9054    void Advance(int consumed) {
9055      ASSERT(consumed <= length_);
9056      // Still in buffer.
9057      if (length_ != consumed) {
9058        if (is_one_byte_) {
9059          buffer8_ += consumed;
9060        } else {
9061          buffer16_ += consumed;
9062        }
9063        length_ -= consumed;
9064        return;
9065      }
9066      // Advance state.
9067      int offset;
9068      String* next = op_->Next(&offset);
9069      ASSERT_EQ(0, offset);
9070      ASSERT(next != NULL);
9071      String::VisitFlat(this, next);
9072    }
9073
9074    ConsStringIteratorOp* const op_;
9075    bool is_one_byte_;
9076    int length_;
9077    union {
9078      const uint8_t* buffer8_;
9079      const uint16_t* buffer16_;
9080    };
9081
9082   private:
9083    DISALLOW_IMPLICIT_CONSTRUCTORS(State);
9084  };
9085
9086 public:
9087  inline StringComparator(ConsStringIteratorOp* op_1,
9088                          ConsStringIteratorOp* op_2)
9089    : state_1_(op_1),
9090      state_2_(op_2) {
9091  }
9092
9093  template<typename Chars1, typename Chars2>
9094  static inline bool Equals(State* state_1, State* state_2, int to_check) {
9095    const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
9096    const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
9097    return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
9098  }
9099
9100  bool Equals(String* string_1, String* string_2) {
9101    int length = string_1->length();
9102    state_1_.Init(string_1);
9103    state_2_.Init(string_2);
9104    while (true) {
9105      int to_check = Min(state_1_.length_, state_2_.length_);
9106      ASSERT(to_check > 0 && to_check <= length);
9107      bool is_equal;
9108      if (state_1_.is_one_byte_) {
9109        if (state_2_.is_one_byte_) {
9110          is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
9111        } else {
9112          is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
9113        }
9114      } else {
9115        if (state_2_.is_one_byte_) {
9116          is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
9117        } else {
9118          is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
9119        }
9120      }
9121      // Looping done.
9122      if (!is_equal) return false;
9123      length -= to_check;
9124      // Exit condition. Strings are equal.
9125      if (length == 0) return true;
9126      state_1_.Advance(to_check);
9127      state_2_.Advance(to_check);
9128    }
9129  }
9130
9131 private:
9132  State state_1_;
9133  State state_2_;
9134  DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
9135};
9136
9137
9138bool String::SlowEquals(String* other) {
9139  DisallowHeapAllocation no_gc;
9140  // Fast check: negative check with lengths.
9141  int len = length();
9142  if (len != other->length()) return false;
9143  if (len == 0) return true;
9144
9145  // Fast check: if hash code is computed for both strings
9146  // a fast negative check can be performed.
9147  if (HasHashCode() && other->HasHashCode()) {
9148#ifdef ENABLE_SLOW_ASSERTS
9149    if (FLAG_enable_slow_asserts) {
9150      if (Hash() != other->Hash()) {
9151        bool found_difference = false;
9152        for (int i = 0; i < len; i++) {
9153          if (Get(i) != other->Get(i)) {
9154            found_difference = true;
9155            break;
9156          }
9157        }
9158        ASSERT(found_difference);
9159      }
9160    }
9161#endif
9162    if (Hash() != other->Hash()) return false;
9163  }
9164
9165  // We know the strings are both non-empty. Compare the first chars
9166  // before we try to flatten the strings.
9167  if (this->Get(0) != other->Get(0)) return false;
9168
9169  if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
9170    const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
9171    const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
9172    return CompareRawStringContents(str1, str2, len);
9173  }
9174
9175  Isolate* isolate = GetIsolate();
9176  StringComparator comparator(isolate->objects_string_compare_iterator_a(),
9177                              isolate->objects_string_compare_iterator_b());
9178
9179  return comparator.Equals(this, other);
9180}
9181
9182
9183bool String::SlowEquals(Handle<String> one, Handle<String> two) {
9184  // Fast check: negative check with lengths.
9185  int one_length = one->length();
9186  if (one_length != two->length()) return false;
9187  if (one_length == 0) return true;
9188
9189  // Fast check: if hash code is computed for both strings
9190  // a fast negative check can be performed.
9191  if (one->HasHashCode() && two->HasHashCode()) {
9192#ifdef ENABLE_SLOW_ASSERTS
9193    if (FLAG_enable_slow_asserts) {
9194      if (one->Hash() != two->Hash()) {
9195        bool found_difference = false;
9196        for (int i = 0; i < one_length; i++) {
9197          if (one->Get(i) != two->Get(i)) {
9198            found_difference = true;
9199            break;
9200          }
9201        }
9202        ASSERT(found_difference);
9203      }
9204    }
9205#endif
9206    if (one->Hash() != two->Hash()) return false;
9207  }
9208
9209  // We know the strings are both non-empty. Compare the first chars
9210  // before we try to flatten the strings.
9211  if (one->Get(0) != two->Get(0)) return false;
9212
9213  one = String::Flatten(one);
9214  two = String::Flatten(two);
9215
9216  DisallowHeapAllocation no_gc;
9217  String::FlatContent flat1 = one->GetFlatContent();
9218  String::FlatContent flat2 = two->GetFlatContent();
9219
9220  if (flat1.IsAscii() && flat2.IsAscii()) {
9221      return CompareRawStringContents(flat1.ToOneByteVector().start(),
9222                                      flat2.ToOneByteVector().start(),
9223                                      one_length);
9224  } else {
9225    for (int i = 0; i < one_length; i++) {
9226      if (flat1.Get(i) != flat2.Get(i)) return false;
9227    }
9228    return true;
9229  }
9230}
9231
9232
9233bool String::MarkAsUndetectable() {
9234  if (StringShape(this).IsInternalized()) return false;
9235
9236  Map* map = this->map();
9237  Heap* heap = GetHeap();
9238  if (map == heap->string_map()) {
9239    this->set_map(heap->undetectable_string_map());
9240    return true;
9241  } else if (map == heap->ascii_string_map()) {
9242    this->set_map(heap->undetectable_ascii_string_map());
9243    return true;
9244  }
9245  // Rest cannot be marked as undetectable
9246  return false;
9247}
9248
9249
9250bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
9251  int slen = length();
9252  // Can't check exact length equality, but we can check bounds.
9253  int str_len = str.length();
9254  if (!allow_prefix_match &&
9255      (str_len < slen ||
9256          str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
9257    return false;
9258  }
9259  int i;
9260  unsigned remaining_in_str = static_cast<unsigned>(str_len);
9261  const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
9262  for (i = 0; i < slen && remaining_in_str > 0; i++) {
9263    unsigned cursor = 0;
9264    uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
9265    ASSERT(cursor > 0 && cursor <= remaining_in_str);
9266    if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
9267      if (i > slen - 1) return false;
9268      if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
9269      if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
9270    } else {
9271      if (Get(i) != r) return false;
9272    }
9273    utf8_data += cursor;
9274    remaining_in_str -= cursor;
9275  }
9276  return (allow_prefix_match || i == slen) && remaining_in_str == 0;
9277}
9278
9279
9280bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
9281  int slen = length();
9282  if (str.length() != slen) return false;
9283  DisallowHeapAllocation no_gc;
9284  FlatContent content = GetFlatContent();
9285  if (content.IsAscii()) {
9286    return CompareChars(content.ToOneByteVector().start(),
9287                        str.start(), slen) == 0;
9288  }
9289  for (int i = 0; i < slen; i++) {
9290    if (Get(i) != static_cast<uint16_t>(str[i])) return false;
9291  }
9292  return true;
9293}
9294
9295
9296bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
9297  int slen = length();
9298  if (str.length() != slen) return false;
9299  DisallowHeapAllocation no_gc;
9300  FlatContent content = GetFlatContent();
9301  if (content.IsTwoByte()) {
9302    return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
9303  }
9304  for (int i = 0; i < slen; i++) {
9305    if (Get(i) != str[i]) return false;
9306  }
9307  return true;
9308}
9309
9310
9311class IteratingStringHasher: public StringHasher {
9312 public:
9313  static inline uint32_t Hash(String* string, uint32_t seed) {
9314    IteratingStringHasher hasher(string->length(), seed);
9315    // Nothing to do.
9316    if (hasher.has_trivial_hash()) return hasher.GetHashField();
9317    ConsString* cons_string = String::VisitFlat(&hasher, string);
9318    // The string was flat.
9319    if (cons_string == NULL) return hasher.GetHashField();
9320    // This is a ConsString, iterate across it.
9321    ConsStringIteratorOp op(cons_string);
9322    int offset;
9323    while (NULL != (string = op.Next(&offset))) {
9324      String::VisitFlat(&hasher, string, offset);
9325    }
9326    return hasher.GetHashField();
9327  }
9328  inline void VisitOneByteString(const uint8_t* chars, int length) {
9329    AddCharacters(chars, length);
9330  }
9331  inline void VisitTwoByteString(const uint16_t* chars, int length) {
9332    AddCharacters(chars, length);
9333  }
9334
9335 private:
9336  inline IteratingStringHasher(int len, uint32_t seed)
9337      : StringHasher(len, seed) {
9338  }
9339  DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
9340};
9341
9342
9343uint32_t String::ComputeAndSetHash() {
9344  // Should only be called if hash code has not yet been computed.
9345  ASSERT(!HasHashCode());
9346
9347  // Store the hash code in the object.
9348  uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
9349  set_hash_field(field);
9350
9351  // Check the hash code is there.
9352  ASSERT(HasHashCode());
9353  uint32_t result = field >> kHashShift;
9354  ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
9355  return result;
9356}
9357
9358
9359bool String::ComputeArrayIndex(uint32_t* index) {
9360  int length = this->length();
9361  if (length == 0 || length > kMaxArrayIndexSize) return false;
9362  ConsStringIteratorOp op;
9363  StringCharacterStream stream(this, &op);
9364  uint16_t ch = stream.GetNext();
9365
9366  // If the string begins with a '0' character, it must only consist
9367  // of it to be a legal array index.
9368  if (ch == '0') {
9369    *index = 0;
9370    return length == 1;
9371  }
9372
9373  // Convert string to uint32 array index; character by character.
9374  int d = ch - '0';
9375  if (d < 0 || d > 9) return false;
9376  uint32_t result = d;
9377  while (stream.HasMore()) {
9378    d = stream.GetNext() - '0';
9379    if (d < 0 || d > 9) return false;
9380    // Check that the new result is below the 32 bit limit.
9381    if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
9382    result = (result * 10) + d;
9383  }
9384
9385  *index = result;
9386  return true;
9387}
9388
9389
9390bool String::SlowAsArrayIndex(uint32_t* index) {
9391  if (length() <= kMaxCachedArrayIndexLength) {
9392    Hash();  // force computation of hash code
9393    uint32_t field = hash_field();
9394    if ((field & kIsNotArrayIndexMask) != 0) return false;
9395    // Isolate the array index form the full hash field.
9396    *index = ArrayIndexValueBits::decode(field);
9397    return true;
9398  } else {
9399    return ComputeArrayIndex(index);
9400  }
9401}
9402
9403
9404Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
9405  int new_size, old_size;
9406  int old_length = string->length();
9407  if (old_length <= new_length) return string;
9408
9409  if (string->IsSeqOneByteString()) {
9410    old_size = SeqOneByteString::SizeFor(old_length);
9411    new_size = SeqOneByteString::SizeFor(new_length);
9412  } else {
9413    ASSERT(string->IsSeqTwoByteString());
9414    old_size = SeqTwoByteString::SizeFor(old_length);
9415    new_size = SeqTwoByteString::SizeFor(new_length);
9416  }
9417
9418  int delta = old_size - new_size;
9419
9420  Address start_of_string = string->address();
9421  ASSERT_OBJECT_ALIGNED(start_of_string);
9422  ASSERT_OBJECT_ALIGNED(start_of_string + new_size);
9423
9424  Heap* heap = string->GetHeap();
9425  NewSpace* newspace = heap->new_space();
9426  if (newspace->Contains(start_of_string) &&
9427      newspace->top() == start_of_string + old_size) {
9428    // Last allocated object in new space.  Simply lower allocation top.
9429    newspace->set_top(start_of_string + new_size);
9430  } else {
9431    // Sizes are pointer size aligned, so that we can use filler objects
9432    // that are a multiple of pointer size.
9433    heap->CreateFillerObjectAt(start_of_string + new_size, delta);
9434  }
9435  heap->AdjustLiveBytes(start_of_string, -delta, Heap::FROM_MUTATOR);
9436
9437  // We are storing the new length using release store after creating a filler
9438  // for the left-over space to avoid races with the sweeper thread.
9439  string->synchronized_set_length(new_length);
9440
9441  if (new_length == 0) return heap->isolate()->factory()->empty_string();
9442  return string;
9443}
9444
9445
9446uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
9447  // For array indexes mix the length into the hash as an array index could
9448  // be zero.
9449  ASSERT(length > 0);
9450  ASSERT(length <= String::kMaxArrayIndexSize);
9451  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
9452         (1 << String::kArrayIndexValueBits));
9453
9454  value <<= String::ArrayIndexValueBits::kShift;
9455  value |= length << String::ArrayIndexLengthBits::kShift;
9456
9457  ASSERT((value & String::kIsNotArrayIndexMask) == 0);
9458  ASSERT((length > String::kMaxCachedArrayIndexLength) ||
9459         (value & String::kContainsCachedArrayIndexMask) == 0);
9460  return value;
9461}
9462
9463
9464uint32_t StringHasher::GetHashField() {
9465  if (length_ <= String::kMaxHashCalcLength) {
9466    if (is_array_index_) {
9467      return MakeArrayIndexHash(array_index_, length_);
9468    }
9469    return (GetHashCore(raw_running_hash_) << String::kHashShift) |
9470           String::kIsNotArrayIndexMask;
9471  } else {
9472    return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
9473  }
9474}
9475
9476
9477uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
9478                                       uint32_t seed,
9479                                       int* utf16_length_out) {
9480  int vector_length = chars.length();
9481  // Handle some edge cases
9482  if (vector_length <= 1) {
9483    ASSERT(vector_length == 0 ||
9484           static_cast<uint8_t>(chars.start()[0]) <=
9485               unibrow::Utf8::kMaxOneByteChar);
9486    *utf16_length_out = vector_length;
9487    return HashSequentialString(chars.start(), vector_length, seed);
9488  }
9489  // Start with a fake length which won't affect computation.
9490  // It will be updated later.
9491  StringHasher hasher(String::kMaxArrayIndexSize, seed);
9492  unsigned remaining = static_cast<unsigned>(vector_length);
9493  const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
9494  int utf16_length = 0;
9495  bool is_index = true;
9496  ASSERT(hasher.is_array_index_);
9497  while (remaining > 0) {
9498    unsigned consumed = 0;
9499    uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
9500    ASSERT(consumed > 0 && consumed <= remaining);
9501    stream += consumed;
9502    remaining -= consumed;
9503    bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
9504    utf16_length += is_two_characters ? 2 : 1;
9505    // No need to keep hashing. But we do need to calculate utf16_length.
9506    if (utf16_length > String::kMaxHashCalcLength) continue;
9507    if (is_two_characters) {
9508      uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
9509      uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
9510      hasher.AddCharacter(c1);
9511      hasher.AddCharacter(c2);
9512      if (is_index) is_index = hasher.UpdateIndex(c1);
9513      if (is_index) is_index = hasher.UpdateIndex(c2);
9514    } else {
9515      hasher.AddCharacter(c);
9516      if (is_index) is_index = hasher.UpdateIndex(c);
9517    }
9518  }
9519  *utf16_length_out = static_cast<int>(utf16_length);
9520  // Must set length here so that hash computation is correct.
9521  hasher.length_ = utf16_length;
9522  return hasher.GetHashField();
9523}
9524
9525
9526void String::PrintOn(FILE* file) {
9527  int length = this->length();
9528  for (int i = 0; i < length; i++) {
9529    PrintF(file, "%c", Get(i));
9530  }
9531}
9532
9533
9534static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) {
9535  int live_enum = map->EnumLength();
9536  if (live_enum == kInvalidEnumCacheSentinel) {
9537    live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM);
9538  }
9539  if (live_enum == 0) return descriptors->ClearEnumCache();
9540
9541  FixedArray* enum_cache = descriptors->GetEnumCache();
9542
9543  int to_trim = enum_cache->length() - live_enum;
9544  if (to_trim <= 0) return;
9545  RightTrimFixedArray<Heap::FROM_GC>(
9546      heap, descriptors->GetEnumCache(), to_trim);
9547
9548  if (!descriptors->HasEnumIndicesCache()) return;
9549  FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache();
9550  RightTrimFixedArray<Heap::FROM_GC>(heap, enum_indices_cache, to_trim);
9551}
9552
9553
9554static void TrimDescriptorArray(Heap* heap,
9555                                Map* map,
9556                                DescriptorArray* descriptors,
9557                                int number_of_own_descriptors) {
9558  int number_of_descriptors = descriptors->number_of_descriptors_storage();
9559  int to_trim = number_of_descriptors - number_of_own_descriptors;
9560  if (to_trim == 0) return;
9561
9562  RightTrimFixedArray<Heap::FROM_GC>(
9563      heap, descriptors, to_trim * DescriptorArray::kDescriptorSize);
9564  descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
9565
9566  if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors);
9567  descriptors->Sort();
9568}
9569
9570
9571// Clear a possible back pointer in case the transition leads to a dead map.
9572// Return true in case a back pointer has been cleared and false otherwise.
9573static bool ClearBackPointer(Heap* heap, Map* target) {
9574  if (Marking::MarkBitFrom(target).Get()) return false;
9575  target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
9576  return true;
9577}
9578
9579
9580// TODO(mstarzinger): This method should be moved into MarkCompactCollector,
9581// because it cannot be called from outside the GC and we already have methods
9582// depending on the transitions layout in the GC anyways.
9583void Map::ClearNonLiveTransitions(Heap* heap) {
9584  // If there are no transitions to be cleared, return.
9585  // TODO(verwaest) Should be an assert, otherwise back pointers are not
9586  // properly cleared.
9587  if (!HasTransitionArray()) return;
9588
9589  TransitionArray* t = transitions();
9590  MarkCompactCollector* collector = heap->mark_compact_collector();
9591
9592  int transition_index = 0;
9593
9594  DescriptorArray* descriptors = instance_descriptors();
9595  bool descriptors_owner_died = false;
9596
9597  // Compact all live descriptors to the left.
9598  for (int i = 0; i < t->number_of_transitions(); ++i) {
9599    Map* target = t->GetTarget(i);
9600    if (ClearBackPointer(heap, target)) {
9601      if (target->instance_descriptors() == descriptors) {
9602        descriptors_owner_died = true;
9603      }
9604    } else {
9605      if (i != transition_index) {
9606        Name* key = t->GetKey(i);
9607        t->SetKey(transition_index, key);
9608        Object** key_slot = t->GetKeySlot(transition_index);
9609        collector->RecordSlot(key_slot, key_slot, key);
9610        // Target slots do not need to be recorded since maps are not compacted.
9611        t->SetTarget(transition_index, t->GetTarget(i));
9612      }
9613      transition_index++;
9614    }
9615  }
9616
9617  // If there are no transitions to be cleared, return.
9618  // TODO(verwaest) Should be an assert, otherwise back pointers are not
9619  // properly cleared.
9620  if (transition_index == t->number_of_transitions()) return;
9621
9622  int number_of_own_descriptors = NumberOfOwnDescriptors();
9623
9624  if (descriptors_owner_died) {
9625    if (number_of_own_descriptors > 0) {
9626      TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
9627      ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
9628      set_owns_descriptors(true);
9629    } else {
9630      ASSERT(descriptors == GetHeap()->empty_descriptor_array());
9631    }
9632  }
9633
9634  // Note that we never eliminate a transition array, though we might right-trim
9635  // such that number_of_transitions() == 0. If this assumption changes,
9636  // TransitionArray::CopyInsert() will need to deal with the case that a
9637  // transition array disappeared during GC.
9638  int trim = t->number_of_transitions() - transition_index;
9639  if (trim > 0) {
9640    RightTrimFixedArray<Heap::FROM_GC>(heap, t, t->IsSimpleTransition()
9641        ? trim : trim * TransitionArray::kTransitionSize);
9642  }
9643  ASSERT(HasTransitionArray());
9644}
9645
9646
9647int Map::Hash() {
9648  // For performance reasons we only hash the 3 most variable fields of a map:
9649  // constructor, prototype and bit_field2.
9650
9651  // Shift away the tag.
9652  int hash = (static_cast<uint32_t>(
9653        reinterpret_cast<uintptr_t>(constructor())) >> 2);
9654
9655  // XOR-ing the prototype and constructor directly yields too many zero bits
9656  // when the two pointers are close (which is fairly common).
9657  // To avoid this we shift the prototype 4 bits relatively to the constructor.
9658  hash ^= (static_cast<uint32_t>(
9659        reinterpret_cast<uintptr_t>(prototype())) << 2);
9660
9661  return hash ^ (hash >> 16) ^ bit_field2();
9662}
9663
9664
9665static bool CheckEquivalent(Map* first, Map* second) {
9666  return
9667    first->constructor() == second->constructor() &&
9668    first->prototype() == second->prototype() &&
9669    first->instance_type() == second->instance_type() &&
9670    first->bit_field() == second->bit_field() &&
9671    first->bit_field2() == second->bit_field2() &&
9672    first->is_frozen() == second->is_frozen() &&
9673    first->has_instance_call_handler() == second->has_instance_call_handler();
9674}
9675
9676
9677bool Map::EquivalentToForTransition(Map* other) {
9678  return CheckEquivalent(this, other);
9679}
9680
9681
9682bool Map::EquivalentToForNormalization(Map* other,
9683                                       PropertyNormalizationMode mode) {
9684  int properties = mode == CLEAR_INOBJECT_PROPERTIES
9685      ? 0 : other->inobject_properties();
9686  return CheckEquivalent(this, other) && inobject_properties() == properties;
9687}
9688
9689
9690void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) {
9691  ConstantPoolArray::Iterator code_iter(this, ConstantPoolArray::CODE_PTR);
9692  while (!code_iter.is_finished()) {
9693    v->VisitCodeEntry(reinterpret_cast<Address>(
9694        RawFieldOfElementAt(code_iter.next_index())));
9695  }
9696
9697  ConstantPoolArray::Iterator heap_iter(this, ConstantPoolArray::HEAP_PTR);
9698  while (!heap_iter.is_finished()) {
9699    v->VisitPointer(RawFieldOfElementAt(heap_iter.next_index()));
9700  }
9701}
9702
9703
9704void ConstantPoolArray::ClearPtrEntries(Isolate* isolate) {
9705  Type type[] = { CODE_PTR, HEAP_PTR };
9706  Address default_value[] = {
9707        isolate->builtins()->builtin(Builtins::kIllegal)->entry(),
9708        reinterpret_cast<Address>(isolate->heap()->undefined_value()) };
9709
9710  for (int i = 0; i < 2; ++i) {
9711    for (int s = 0; s <= final_section(); ++s) {
9712      LayoutSection section = static_cast<LayoutSection>(s);
9713      if (number_of_entries(type[i], section) > 0) {
9714        int offset = OffsetOfElementAt(first_index(type[i], section));
9715        MemsetPointer(
9716          reinterpret_cast<Address*>(HeapObject::RawField(this, offset)),
9717          default_value[i],
9718          number_of_entries(type[i], section));
9719      }
9720    }
9721  }
9722}
9723
9724
9725void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
9726  // Iterate over all fields in the body but take care in dealing with
9727  // the code entry.
9728  IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
9729  v->VisitCodeEntry(this->address() + kCodeEntryOffset);
9730  IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
9731}
9732
9733
9734void JSFunction::MarkForOptimization() {
9735  ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
9736  ASSERT(!IsOptimized());
9737  ASSERT(shared()->allows_lazy_compilation() ||
9738         code()->optimizable());
9739  ASSERT(!shared()->is_generator());
9740  set_code_no_write_barrier(
9741      GetIsolate()->builtins()->builtin(Builtins::kCompileOptimized));
9742  // No write barrier required, since the builtin is part of the root set.
9743}
9744
9745
9746void JSFunction::MarkForConcurrentOptimization() {
9747  ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
9748  ASSERT(!IsOptimized());
9749  ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
9750  ASSERT(!shared()->is_generator());
9751  ASSERT(GetIsolate()->concurrent_recompilation_enabled());
9752  if (FLAG_trace_concurrent_recompilation) {
9753    PrintF("  ** Marking ");
9754    PrintName();
9755    PrintF(" for concurrent recompilation.\n");
9756  }
9757  set_code_no_write_barrier(
9758      GetIsolate()->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
9759  // No write barrier required, since the builtin is part of the root set.
9760}
9761
9762
9763void JSFunction::MarkInOptimizationQueue() {
9764  // We can only arrive here via the concurrent-recompilation builtin.  If
9765  // break points were set, the code would point to the lazy-compile builtin.
9766  ASSERT(!GetIsolate()->DebuggerHasBreakPoints());
9767  ASSERT(IsMarkedForConcurrentOptimization() && !IsOptimized());
9768  ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
9769  ASSERT(GetIsolate()->concurrent_recompilation_enabled());
9770  if (FLAG_trace_concurrent_recompilation) {
9771    PrintF("  ** Queueing ");
9772    PrintName();
9773    PrintF(" for concurrent recompilation.\n");
9774  }
9775  set_code_no_write_barrier(
9776      GetIsolate()->builtins()->builtin(Builtins::kInOptimizationQueue));
9777  // No write barrier required, since the builtin is part of the root set.
9778}
9779
9780
9781void SharedFunctionInfo::AddToOptimizedCodeMap(
9782    Handle<SharedFunctionInfo> shared,
9783    Handle<Context> native_context,
9784    Handle<Code> code,
9785    Handle<FixedArray> literals,
9786    BailoutId osr_ast_id) {
9787  Isolate* isolate = shared->GetIsolate();
9788  ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
9789  ASSERT(native_context->IsNativeContext());
9790  STATIC_ASSERT(kEntryLength == 4);
9791  Handle<FixedArray> new_code_map;
9792  Handle<Object> value(shared->optimized_code_map(), isolate);
9793  int old_length;
9794  if (value->IsSmi()) {
9795    // No optimized code map.
9796    ASSERT_EQ(0, Smi::cast(*value)->value());
9797    // Create 3 entries per context {context, code, literals}.
9798    new_code_map = isolate->factory()->NewFixedArray(kInitialLength);
9799    old_length = kEntriesStart;
9800  } else {
9801    // Copy old map and append one new entry.
9802    Handle<FixedArray> old_code_map = Handle<FixedArray>::cast(value);
9803    ASSERT_EQ(-1, shared->SearchOptimizedCodeMap(*native_context, osr_ast_id));
9804    old_length = old_code_map->length();
9805    new_code_map = FixedArray::CopySize(
9806        old_code_map, old_length + kEntryLength);
9807    // Zap the old map for the sake of the heap verifier.
9808    if (Heap::ShouldZapGarbage()) {
9809      Object** data = old_code_map->data_start();
9810      MemsetPointer(data, isolate->heap()->the_hole_value(), old_length);
9811    }
9812  }
9813  new_code_map->set(old_length + kContextOffset, *native_context);
9814  new_code_map->set(old_length + kCachedCodeOffset, *code);
9815  new_code_map->set(old_length + kLiteralsOffset, *literals);
9816  new_code_map->set(old_length + kOsrAstIdOffset,
9817                    Smi::FromInt(osr_ast_id.ToInt()));
9818
9819#ifdef DEBUG
9820  for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
9821    ASSERT(new_code_map->get(i + kContextOffset)->IsNativeContext());
9822    ASSERT(new_code_map->get(i + kCachedCodeOffset)->IsCode());
9823    ASSERT(Code::cast(new_code_map->get(i + kCachedCodeOffset))->kind() ==
9824           Code::OPTIMIZED_FUNCTION);
9825    ASSERT(new_code_map->get(i + kLiteralsOffset)->IsFixedArray());
9826    ASSERT(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
9827  }
9828#endif
9829  shared->set_optimized_code_map(*new_code_map);
9830}
9831
9832
9833FixedArray* SharedFunctionInfo::GetLiteralsFromOptimizedCodeMap(int index) {
9834  ASSERT(index > kEntriesStart);
9835  FixedArray* code_map = FixedArray::cast(optimized_code_map());
9836  if (!bound()) {
9837    FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
9838    ASSERT_NE(NULL, cached_literals);
9839    return cached_literals;
9840  }
9841  return NULL;
9842}
9843
9844
9845Code* SharedFunctionInfo::GetCodeFromOptimizedCodeMap(int index) {
9846  ASSERT(index > kEntriesStart);
9847  FixedArray* code_map = FixedArray::cast(optimized_code_map());
9848  Code* code = Code::cast(code_map->get(index));
9849  ASSERT_NE(NULL, code);
9850  return code;
9851}
9852
9853
9854void SharedFunctionInfo::ClearOptimizedCodeMap() {
9855  FixedArray* code_map = FixedArray::cast(optimized_code_map());
9856
9857  // If the next map link slot is already used then the function was
9858  // enqueued with code flushing and we remove it now.
9859  if (!code_map->get(kNextMapIndex)->IsUndefined()) {
9860    CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
9861    flusher->EvictOptimizedCodeMap(this);
9862  }
9863
9864  ASSERT(code_map->get(kNextMapIndex)->IsUndefined());
9865  set_optimized_code_map(Smi::FromInt(0));
9866}
9867
9868
9869void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
9870                                                   const char* reason) {
9871  DisallowHeapAllocation no_gc;
9872  if (optimized_code_map()->IsSmi()) return;
9873
9874  FixedArray* code_map = FixedArray::cast(optimized_code_map());
9875  int dst = kEntriesStart;
9876  int length = code_map->length();
9877  for (int src = kEntriesStart; src < length; src += kEntryLength) {
9878    ASSERT(code_map->get(src)->IsNativeContext());
9879    if (Code::cast(code_map->get(src + kCachedCodeOffset)) == optimized_code) {
9880      // Evict the src entry by not copying it to the dst entry.
9881      if (FLAG_trace_opt) {
9882        PrintF("[evicting entry from optimizing code map (%s) for ", reason);
9883        ShortPrint();
9884        BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
9885        if (osr.IsNone()) {
9886          PrintF("]\n");
9887        } else {
9888          PrintF(" (osr ast id %d)]\n", osr.ToInt());
9889        }
9890      }
9891    } else {
9892      // Keep the src entry by copying it to the dst entry.
9893      if (dst != src) {
9894        code_map->set(dst + kContextOffset,
9895                      code_map->get(src + kContextOffset));
9896        code_map->set(dst + kCachedCodeOffset,
9897                      code_map->get(src + kCachedCodeOffset));
9898        code_map->set(dst + kLiteralsOffset,
9899                      code_map->get(src + kLiteralsOffset));
9900        code_map->set(dst + kOsrAstIdOffset,
9901                      code_map->get(src + kOsrAstIdOffset));
9902      }
9903      dst += kEntryLength;
9904    }
9905  }
9906  if (dst != length) {
9907    // Always trim even when array is cleared because of heap verifier.
9908    RightTrimFixedArray<Heap::FROM_MUTATOR>(GetHeap(), code_map, length - dst);
9909    if (code_map->length() == kEntriesStart) ClearOptimizedCodeMap();
9910  }
9911}
9912
9913
9914void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
9915  FixedArray* code_map = FixedArray::cast(optimized_code_map());
9916  ASSERT(shrink_by % kEntryLength == 0);
9917  ASSERT(shrink_by <= code_map->length() - kEntriesStart);
9918  // Always trim even when array is cleared because of heap verifier.
9919  RightTrimFixedArray<Heap::FROM_GC>(GetHeap(), code_map, shrink_by);
9920  if (code_map->length() == kEntriesStart) {
9921    ClearOptimizedCodeMap();
9922  }
9923}
9924
9925
9926void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
9927  if (object->IsGlobalObject()) return;
9928
9929  // Make sure prototypes are fast objects and their maps have the bit set
9930  // so they remain fast.
9931  if (!object->HasFastProperties()) {
9932    TransformToFastProperties(object, 0);
9933  }
9934}
9935
9936
9937Handle<Object> CacheInitialJSArrayMaps(
9938    Handle<Context> native_context, Handle<Map> initial_map) {
9939  // Replace all of the cached initial array maps in the native context with
9940  // the appropriate transitioned elements kind maps.
9941  Factory* factory = native_context->GetIsolate()->factory();
9942  Handle<FixedArray> maps = factory->NewFixedArrayWithHoles(
9943      kElementsKindCount, TENURED);
9944
9945  Handle<Map> current_map = initial_map;
9946  ElementsKind kind = current_map->elements_kind();
9947  ASSERT(kind == GetInitialFastElementsKind());
9948  maps->set(kind, *current_map);
9949  for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
9950       i < kFastElementsKindCount; ++i) {
9951    Handle<Map> new_map;
9952    ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
9953    if (current_map->HasElementsTransition()) {
9954      new_map = handle(current_map->elements_transition_map());
9955      ASSERT(new_map->elements_kind() == next_kind);
9956    } else {
9957      new_map = Map::CopyAsElementsKind(
9958          current_map, next_kind, INSERT_TRANSITION);
9959    }
9960    maps->set(next_kind, *new_map);
9961    current_map = new_map;
9962  }
9963  native_context->set_js_array_maps(*maps);
9964  return initial_map;
9965}
9966
9967
9968void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
9969                                      Handle<Object> value) {
9970  Isolate* isolate = function->GetIsolate();
9971
9972  ASSERT(value->IsJSReceiver());
9973
9974  // First some logic for the map of the prototype to make sure it is in fast
9975  // mode.
9976  if (value->IsJSObject()) {
9977    JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
9978  }
9979
9980  // Now some logic for the maps of the objects that are created by using this
9981  // function as a constructor.
9982  if (function->has_initial_map()) {
9983    // If the function has allocated the initial map replace it with a
9984    // copy containing the new prototype.  Also complete any in-object
9985    // slack tracking that is in progress at this point because it is
9986    // still tracking the old copy.
9987    if (function->IsInobjectSlackTrackingInProgress()) {
9988      function->CompleteInobjectSlackTracking();
9989    }
9990    Handle<Map> initial_map(function->initial_map(), isolate);
9991    Handle<Map> new_map = Map::Copy(initial_map);
9992    new_map->set_prototype(*value);
9993
9994    // If the function is used as the global Array function, cache the
9995    // initial map (and transitioned versions) in the native context.
9996    Context* native_context = function->context()->native_context();
9997    Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX);
9998    if (array_function->IsJSFunction() &&
9999        *function == JSFunction::cast(array_function)) {
10000      CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
10001    }
10002
10003    function->set_initial_map(*new_map);
10004
10005    // Deoptimize all code that embeds the previous initial map.
10006    initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
10007        isolate, DependentCode::kInitialMapChangedGroup);
10008  } else {
10009    // Put the value in the initial map field until an initial map is
10010    // needed.  At that point, a new initial map is created and the
10011    // prototype is put into the initial map where it belongs.
10012    function->set_prototype_or_initial_map(*value);
10013  }
10014  isolate->heap()->ClearInstanceofCache();
10015}
10016
10017
10018void JSFunction::SetPrototype(Handle<JSFunction> function,
10019                              Handle<Object> value) {
10020  ASSERT(function->should_have_prototype());
10021  Handle<Object> construct_prototype = value;
10022
10023  // If the value is not a JSReceiver, store the value in the map's
10024  // constructor field so it can be accessed.  Also, set the prototype
10025  // used for constructing objects to the original object prototype.
10026  // See ECMA-262 13.2.2.
10027  if (!value->IsJSReceiver()) {
10028    // Copy the map so this does not affect unrelated functions.
10029    // Remove map transitions because they point to maps with a
10030    // different prototype.
10031    Handle<Map> new_map = Map::Copy(handle(function->map()));
10032
10033    JSObject::MigrateToMap(function, new_map);
10034    new_map->set_constructor(*value);
10035    new_map->set_non_instance_prototype(true);
10036    Isolate* isolate = new_map->GetIsolate();
10037    construct_prototype = handle(
10038        isolate->context()->native_context()->initial_object_prototype(),
10039        isolate);
10040  } else {
10041    function->map()->set_non_instance_prototype(false);
10042  }
10043
10044  return SetInstancePrototype(function, construct_prototype);
10045}
10046
10047
10048bool JSFunction::RemovePrototype() {
10049  Context* native_context = context()->native_context();
10050  Map* no_prototype_map = shared()->strict_mode() == SLOPPY
10051      ? native_context->sloppy_function_without_prototype_map()
10052      : native_context->strict_function_without_prototype_map();
10053
10054  if (map() == no_prototype_map) return true;
10055
10056#ifdef DEBUG
10057  if (map() != (shared()->strict_mode() == SLOPPY
10058                   ? native_context->sloppy_function_map()
10059                   : native_context->strict_function_map())) {
10060    return false;
10061  }
10062#endif
10063
10064  set_map(no_prototype_map);
10065  set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
10066  return true;
10067}
10068
10069
10070void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
10071  if (function->has_initial_map()) return;
10072  Isolate* isolate = function->GetIsolate();
10073
10074  // First create a new map with the size and number of in-object properties
10075  // suggested by the function.
10076  InstanceType instance_type;
10077  int instance_size;
10078  int in_object_properties;
10079  if (function->shared()->is_generator()) {
10080    instance_type = JS_GENERATOR_OBJECT_TYPE;
10081    instance_size = JSGeneratorObject::kSize;
10082    in_object_properties = 0;
10083  } else {
10084    instance_type = JS_OBJECT_TYPE;
10085    instance_size = function->shared()->CalculateInstanceSize();
10086    in_object_properties = function->shared()->CalculateInObjectProperties();
10087  }
10088  Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
10089
10090  // Fetch or allocate prototype.
10091  Handle<Object> prototype;
10092  if (function->has_instance_prototype()) {
10093    prototype = handle(function->instance_prototype(), isolate);
10094    for (Handle<Object> p = prototype; !p->IsNull() && !p->IsJSProxy();
10095         p = Object::GetPrototype(isolate, p)) {
10096      JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(p));
10097    }
10098  } else {
10099    prototype = isolate->factory()->NewFunctionPrototype(function);
10100  }
10101  map->set_inobject_properties(in_object_properties);
10102  map->set_unused_property_fields(in_object_properties);
10103  map->set_prototype(*prototype);
10104  ASSERT(map->has_fast_object_elements());
10105
10106  // Finally link initial map and constructor function.
10107  function->set_initial_map(*map);
10108  map->set_constructor(*function);
10109
10110  if (!function->shared()->is_generator()) {
10111    function->StartInobjectSlackTracking();
10112  }
10113}
10114
10115
10116void JSFunction::SetInstanceClassName(String* name) {
10117  shared()->set_instance_class_name(name);
10118}
10119
10120
10121void JSFunction::PrintName(FILE* out) {
10122  SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
10123  PrintF(out, "%s", name.get());
10124}
10125
10126
10127Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
10128  return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
10129}
10130
10131
10132// The filter is a pattern that matches function names in this way:
10133//   "*"      all; the default
10134//   "-"      all but the top-level function
10135//   "-name"  all but the function "name"
10136//   ""       only the top-level function
10137//   "name"   only the function "name"
10138//   "name*"  only functions starting with "name"
10139bool JSFunction::PassesFilter(const char* raw_filter) {
10140  if (*raw_filter == '*') return true;
10141  String* name = shared()->DebugName();
10142  Vector<const char> filter = CStrVector(raw_filter);
10143  if (filter.length() == 0) return name->length() == 0;
10144  if (filter[0] == '-') {
10145    // Negative filter.
10146    if (filter.length() == 1) {
10147      return (name->length() != 0);
10148    } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
10149      return false;
10150    }
10151    if (filter[filter.length() - 1] == '*' &&
10152        name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
10153      return false;
10154    }
10155    return true;
10156
10157  } else if (name->IsUtf8EqualTo(filter)) {
10158    return true;
10159  }
10160  if (filter[filter.length() - 1] == '*' &&
10161      name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
10162    return true;
10163  }
10164  return false;
10165}
10166
10167
10168void Oddball::Initialize(Isolate* isolate,
10169                         Handle<Oddball> oddball,
10170                         const char* to_string,
10171                         Handle<Object> to_number,
10172                         byte kind) {
10173  Handle<String> internalized_to_string =
10174      isolate->factory()->InternalizeUtf8String(to_string);
10175  oddball->set_to_string(*internalized_to_string);
10176  oddball->set_to_number(*to_number);
10177  oddball->set_kind(kind);
10178}
10179
10180
10181void Script::InitLineEnds(Handle<Script> script) {
10182  if (!script->line_ends()->IsUndefined()) return;
10183
10184  Isolate* isolate = script->GetIsolate();
10185
10186  if (!script->source()->IsString()) {
10187    ASSERT(script->source()->IsUndefined());
10188    Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
10189    script->set_line_ends(*empty);
10190    ASSERT(script->line_ends()->IsFixedArray());
10191    return;
10192  }
10193
10194  Handle<String> src(String::cast(script->source()), isolate);
10195
10196  Handle<FixedArray> array = String::CalculateLineEnds(src, true);
10197
10198  if (*array != isolate->heap()->empty_fixed_array()) {
10199    array->set_map(isolate->heap()->fixed_cow_array_map());
10200  }
10201
10202  script->set_line_ends(*array);
10203  ASSERT(script->line_ends()->IsFixedArray());
10204}
10205
10206
10207int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
10208  int line_number = GetLineNumber(script, code_pos);
10209  if (line_number == -1) return -1;
10210
10211  DisallowHeapAllocation no_allocation;
10212  FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
10213  line_number = line_number - script->line_offset()->value();
10214  if (line_number == 0) return code_pos + script->column_offset()->value();
10215  int prev_line_end_pos =
10216      Smi::cast(line_ends_array->get(line_number - 1))->value();
10217  return code_pos - (prev_line_end_pos + 1);
10218}
10219
10220
10221int Script::GetLineNumberWithArray(int code_pos) {
10222  DisallowHeapAllocation no_allocation;
10223  ASSERT(line_ends()->IsFixedArray());
10224  FixedArray* line_ends_array = FixedArray::cast(line_ends());
10225  int line_ends_len = line_ends_array->length();
10226  if (line_ends_len == 0) return -1;
10227
10228  if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
10229    return line_offset()->value();
10230  }
10231
10232  int left = 0;
10233  int right = line_ends_len;
10234  while (int half = (right - left) / 2) {
10235    if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
10236      right -= half;
10237    } else {
10238      left += half;
10239    }
10240  }
10241  return right + line_offset()->value();
10242}
10243
10244
10245int Script::GetLineNumber(Handle<Script> script, int code_pos) {
10246  InitLineEnds(script);
10247  return script->GetLineNumberWithArray(code_pos);
10248}
10249
10250
10251int Script::GetLineNumber(int code_pos) {
10252  DisallowHeapAllocation no_allocation;
10253  if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
10254
10255  // Slow mode: we do not have line_ends. We have to iterate through source.
10256  if (!source()->IsString()) return -1;
10257
10258  String* source_string = String::cast(source());
10259  int line = 0;
10260  int len = source_string->length();
10261  for (int pos = 0; pos < len; pos++) {
10262    if (pos == code_pos) break;
10263    if (source_string->Get(pos) == '\n') line++;
10264  }
10265  return line;
10266}
10267
10268
10269Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
10270  Isolate* isolate = script->GetIsolate();
10271  Handle<String> name_or_source_url_key =
10272      isolate->factory()->InternalizeOneByteString(
10273          STATIC_ASCII_VECTOR("nameOrSourceURL"));
10274  Handle<JSObject> script_wrapper = Script::GetWrapper(script);
10275  Handle<Object> property = Object::GetProperty(
10276      script_wrapper, name_or_source_url_key).ToHandleChecked();
10277  ASSERT(property->IsJSFunction());
10278  Handle<JSFunction> method = Handle<JSFunction>::cast(property);
10279  Handle<Object> result;
10280  // Do not check against pending exception, since this function may be called
10281  // when an exception has already been pending.
10282  if (!Execution::TryCall(method, script_wrapper, 0, NULL).ToHandle(&result)) {
10283    return isolate->factory()->undefined_value();
10284  }
10285  return result;
10286}
10287
10288
10289// Wrappers for scripts are kept alive and cached in weak global
10290// handles referred from foreign objects held by the scripts as long as
10291// they are used. When they are not used anymore, the garbage
10292// collector will call the weak callback on the global handle
10293// associated with the wrapper and get rid of both the wrapper and the
10294// handle.
10295static void ClearWrapperCache(
10296    const v8::WeakCallbackData<v8::Value, void>& data) {
10297  Object** location = reinterpret_cast<Object**>(data.GetParameter());
10298  JSValue* wrapper = JSValue::cast(*location);
10299  Foreign* foreign = Script::cast(wrapper->value())->wrapper();
10300  ASSERT_EQ(foreign->foreign_address(), reinterpret_cast<Address>(location));
10301  foreign->set_foreign_address(0);
10302  GlobalHandles::Destroy(location);
10303  Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
10304  isolate->counters()->script_wrappers()->Decrement();
10305}
10306
10307
10308Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
10309  if (script->wrapper()->foreign_address() != NULL) {
10310    // Return a handle for the existing script wrapper from the cache.
10311    return Handle<JSValue>(
10312        *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
10313  }
10314  Isolate* isolate = script->GetIsolate();
10315  // Construct a new script wrapper.
10316  isolate->counters()->script_wrappers()->Increment();
10317  Handle<JSFunction> constructor = isolate->script_function();
10318  Handle<JSValue> result =
10319      Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
10320
10321  result->set_value(*script);
10322
10323  // Create a new weak global handle and use it to cache the wrapper
10324  // for future use. The cache will automatically be cleared by the
10325  // garbage collector when it is not used anymore.
10326  Handle<Object> handle = isolate->global_handles()->Create(*result);
10327  GlobalHandles::MakeWeak(handle.location(),
10328                          reinterpret_cast<void*>(handle.location()),
10329                          &ClearWrapperCache);
10330  script->wrapper()->set_foreign_address(
10331      reinterpret_cast<Address>(handle.location()));
10332  return result;
10333}
10334
10335
10336String* SharedFunctionInfo::DebugName() {
10337  Object* n = name();
10338  if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
10339  return String::cast(n);
10340}
10341
10342
10343bool SharedFunctionInfo::HasSourceCode() {
10344  return !script()->IsUndefined() &&
10345         !reinterpret_cast<Script*>(script())->source()->IsUndefined();
10346}
10347
10348
10349Handle<Object> SharedFunctionInfo::GetSourceCode() {
10350  if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
10351  Handle<String> source(String::cast(Script::cast(script())->source()));
10352  return GetIsolate()->factory()->NewSubString(
10353      source, start_position(), end_position());
10354}
10355
10356
10357bool SharedFunctionInfo::IsInlineable() {
10358  // Check that the function has a script associated with it.
10359  if (!script()->IsScript()) return false;
10360  if (optimization_disabled()) return false;
10361  // If we never ran this (unlikely) then lets try to optimize it.
10362  if (code()->kind() != Code::FUNCTION) return true;
10363  return code()->optimizable();
10364}
10365
10366
10367int SharedFunctionInfo::SourceSize() {
10368  return end_position() - start_position();
10369}
10370
10371
10372int SharedFunctionInfo::CalculateInstanceSize() {
10373  int instance_size =
10374      JSObject::kHeaderSize +
10375      expected_nof_properties() * kPointerSize;
10376  if (instance_size > JSObject::kMaxInstanceSize) {
10377    instance_size = JSObject::kMaxInstanceSize;
10378  }
10379  return instance_size;
10380}
10381
10382
10383int SharedFunctionInfo::CalculateInObjectProperties() {
10384  return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
10385}
10386
10387
10388// Support function for printing the source code to a StringStream
10389// without any allocation in the heap.
10390void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
10391                                         int max_length) {
10392  // For some native functions there is no source.
10393  if (!HasSourceCode()) {
10394    accumulator->Add("<No Source>");
10395    return;
10396  }
10397
10398  // Get the source for the script which this function came from.
10399  // Don't use String::cast because we don't want more assertion errors while
10400  // we are already creating a stack dump.
10401  String* script_source =
10402      reinterpret_cast<String*>(Script::cast(script())->source());
10403
10404  if (!script_source->LooksValid()) {
10405    accumulator->Add("<Invalid Source>");
10406    return;
10407  }
10408
10409  if (!is_toplevel()) {
10410    accumulator->Add("function ");
10411    Object* name = this->name();
10412    if (name->IsString() && String::cast(name)->length() > 0) {
10413      accumulator->PrintName(name);
10414    }
10415  }
10416
10417  int len = end_position() - start_position();
10418  if (len <= max_length || max_length < 0) {
10419    accumulator->Put(script_source, start_position(), end_position());
10420  } else {
10421    accumulator->Put(script_source,
10422                     start_position(),
10423                     start_position() + max_length);
10424    accumulator->Add("...\n");
10425  }
10426}
10427
10428
10429static bool IsCodeEquivalent(Code* code, Code* recompiled) {
10430  if (code->instruction_size() != recompiled->instruction_size()) return false;
10431  ByteArray* code_relocation = code->relocation_info();
10432  ByteArray* recompiled_relocation = recompiled->relocation_info();
10433  int length = code_relocation->length();
10434  if (length != recompiled_relocation->length()) return false;
10435  int compare = memcmp(code_relocation->GetDataStartAddress(),
10436                       recompiled_relocation->GetDataStartAddress(),
10437                       length);
10438  return compare == 0;
10439}
10440
10441
10442void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
10443  ASSERT(!has_deoptimization_support());
10444  DisallowHeapAllocation no_allocation;
10445  Code* code = this->code();
10446  if (IsCodeEquivalent(code, recompiled)) {
10447    // Copy the deoptimization data from the recompiled code.
10448    code->set_deoptimization_data(recompiled->deoptimization_data());
10449    code->set_has_deoptimization_support(true);
10450  } else {
10451    // TODO(3025757): In case the recompiled isn't equivalent to the
10452    // old code, we have to replace it. We should try to avoid this
10453    // altogether because it flushes valuable type feedback by
10454    // effectively resetting all IC state.
10455    ReplaceCode(recompiled);
10456  }
10457  ASSERT(has_deoptimization_support());
10458}
10459
10460
10461void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
10462  // Disable optimization for the shared function info and mark the
10463  // code as non-optimizable. The marker on the shared function info
10464  // is there because we flush non-optimized code thereby loosing the
10465  // non-optimizable information for the code. When the code is
10466  // regenerated and set on the shared function info it is marked as
10467  // non-optimizable if optimization is disabled for the shared
10468  // function info.
10469  set_optimization_disabled(true);
10470  set_bailout_reason(reason);
10471  // Code should be the lazy compilation stub or else unoptimized.  If the
10472  // latter, disable optimization for the code too.
10473  ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
10474  if (code()->kind() == Code::FUNCTION) {
10475    code()->set_optimizable(false);
10476  }
10477  PROFILE(GetIsolate(), CodeDisableOptEvent(code(), this));
10478  if (FLAG_trace_opt) {
10479    PrintF("[disabled optimization for ");
10480    ShortPrint();
10481    PrintF(", reason: %s]\n", GetBailoutReason(reason));
10482  }
10483}
10484
10485
10486bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
10487  ASSERT(!id.IsNone());
10488  Code* unoptimized = code();
10489  DeoptimizationOutputData* data =
10490      DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
10491  unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
10492  USE(ignore);
10493  return true;  // Return true if there was no ASSERT.
10494}
10495
10496
10497void JSFunction::StartInobjectSlackTracking() {
10498  ASSERT(has_initial_map() && !IsInobjectSlackTrackingInProgress());
10499
10500  if (!FLAG_clever_optimizations) return;
10501  Map* map = initial_map();
10502
10503  // Only initiate the tracking the first time.
10504  if (map->done_inobject_slack_tracking()) return;
10505  map->set_done_inobject_slack_tracking(true);
10506
10507  // No tracking during the snapshot construction phase.
10508  Isolate* isolate = GetIsolate();
10509  if (isolate->serializer_enabled()) return;
10510
10511  if (map->unused_property_fields() == 0) return;
10512
10513  map->set_construction_count(kGenerousAllocationCount);
10514}
10515
10516
10517void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
10518  code()->ClearInlineCaches();
10519  // If we clear ICs, we need to clear the type feedback vector too, since
10520  // CallICs are synced with a feedback vector slot.
10521  ClearTypeFeedbackInfo();
10522  set_ic_age(new_ic_age);
10523  if (code()->kind() == Code::FUNCTION) {
10524    code()->set_profiler_ticks(0);
10525    if (optimization_disabled() &&
10526        opt_count() >= FLAG_max_opt_count) {
10527      // Re-enable optimizations if they were disabled due to opt_count limit.
10528      set_optimization_disabled(false);
10529      code()->set_optimizable(true);
10530    }
10531    set_opt_count(0);
10532    set_deopt_count(0);
10533  }
10534}
10535
10536
10537static void GetMinInobjectSlack(Map* map, void* data) {
10538  int slack = map->unused_property_fields();
10539  if (*reinterpret_cast<int*>(data) > slack) {
10540    *reinterpret_cast<int*>(data) = slack;
10541  }
10542}
10543
10544
10545static void ShrinkInstanceSize(Map* map, void* data) {
10546  int slack = *reinterpret_cast<int*>(data);
10547  map->set_inobject_properties(map->inobject_properties() - slack);
10548  map->set_unused_property_fields(map->unused_property_fields() - slack);
10549  map->set_instance_size(map->instance_size() - slack * kPointerSize);
10550
10551  // Visitor id might depend on the instance size, recalculate it.
10552  map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
10553}
10554
10555
10556void JSFunction::CompleteInobjectSlackTracking() {
10557  ASSERT(has_initial_map());
10558  Map* map = initial_map();
10559
10560  ASSERT(map->done_inobject_slack_tracking());
10561  map->set_construction_count(kNoSlackTracking);
10562
10563  int slack = map->unused_property_fields();
10564  map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
10565  if (slack != 0) {
10566    // Resize the initial map and all maps in its transition tree.
10567    map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
10568  }
10569}
10570
10571
10572int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
10573                                               BailoutId osr_ast_id) {
10574  DisallowHeapAllocation no_gc;
10575  ASSERT(native_context->IsNativeContext());
10576  if (!FLAG_cache_optimized_code) return -1;
10577  Object* value = optimized_code_map();
10578  if (!value->IsSmi()) {
10579    FixedArray* optimized_code_map = FixedArray::cast(value);
10580    int length = optimized_code_map->length();
10581    Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
10582    for (int i = kEntriesStart; i < length; i += kEntryLength) {
10583      if (optimized_code_map->get(i + kContextOffset) == native_context &&
10584          optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
10585        return i + kCachedCodeOffset;
10586      }
10587    }
10588    if (FLAG_trace_opt) {
10589      PrintF("[didn't find optimized code in optimized code map for ");
10590      ShortPrint();
10591      PrintF("]\n");
10592    }
10593  }
10594  return -1;
10595}
10596
10597
10598#define DECLARE_TAG(ignore1, name, ignore2) name,
10599const char* const VisitorSynchronization::kTags[
10600    VisitorSynchronization::kNumberOfSyncTags] = {
10601  VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10602};
10603#undef DECLARE_TAG
10604
10605
10606#define DECLARE_TAG(ignore1, ignore2, name) name,
10607const char* const VisitorSynchronization::kTagNames[
10608    VisitorSynchronization::kNumberOfSyncTags] = {
10609  VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10610};
10611#undef DECLARE_TAG
10612
10613
10614void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
10615  ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
10616  Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
10617  Object* old_target = target;
10618  VisitPointer(&target);
10619  CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
10620}
10621
10622
10623void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
10624  ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
10625  Object* stub = rinfo->code_age_stub();
10626  if (stub) {
10627    VisitPointer(&stub);
10628  }
10629}
10630
10631
10632void ObjectVisitor::VisitCodeEntry(Address entry_address) {
10633  Object* code = Code::GetObjectFromEntryAddress(entry_address);
10634  Object* old_code = code;
10635  VisitPointer(&code);
10636  if (code != old_code) {
10637    Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
10638  }
10639}
10640
10641
10642void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
10643  ASSERT(rinfo->rmode() == RelocInfo::CELL);
10644  Object* cell = rinfo->target_cell();
10645  Object* old_cell = cell;
10646  VisitPointer(&cell);
10647  if (cell != old_cell) {
10648    rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
10649  }
10650}
10651
10652
10653void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
10654  ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
10655          rinfo->IsPatchedReturnSequence()) ||
10656         (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
10657          rinfo->IsPatchedDebugBreakSlotSequence()));
10658  Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
10659  Object* old_target = target;
10660  VisitPointer(&target);
10661  CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
10662}
10663
10664
10665void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
10666  ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
10667  Object* p = rinfo->target_object();
10668  VisitPointer(&p);
10669}
10670
10671
10672void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
10673  Address p = rinfo->target_reference();
10674  VisitExternalReference(&p);
10675}
10676
10677
10678void Code::InvalidateRelocation() {
10679  set_relocation_info(GetHeap()->empty_byte_array());
10680}
10681
10682
10683void Code::InvalidateEmbeddedObjects() {
10684  Object* undefined = GetHeap()->undefined_value();
10685  Cell* undefined_cell = GetHeap()->undefined_cell();
10686  int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
10687                  RelocInfo::ModeMask(RelocInfo::CELL);
10688  for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10689    RelocInfo::Mode mode = it.rinfo()->rmode();
10690    if (mode == RelocInfo::EMBEDDED_OBJECT) {
10691      it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
10692    } else if (mode == RelocInfo::CELL) {
10693      it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
10694    }
10695  }
10696}
10697
10698
10699void Code::Relocate(intptr_t delta) {
10700  for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
10701    it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
10702  }
10703  CPU::FlushICache(instruction_start(), instruction_size());
10704}
10705
10706
10707void Code::CopyFrom(const CodeDesc& desc) {
10708  ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
10709
10710  // copy code
10711  CopyBytes(instruction_start(), desc.buffer,
10712            static_cast<size_t>(desc.instr_size));
10713
10714  // copy reloc info
10715  CopyBytes(relocation_start(),
10716            desc.buffer + desc.buffer_size - desc.reloc_size,
10717            static_cast<size_t>(desc.reloc_size));
10718
10719  // unbox handles and relocate
10720  intptr_t delta = instruction_start() - desc.buffer;
10721  int mode_mask = RelocInfo::kCodeTargetMask |
10722                  RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
10723                  RelocInfo::ModeMask(RelocInfo::CELL) |
10724                  RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
10725                  RelocInfo::kApplyMask;
10726  // Needed to find target_object and runtime_entry on X64
10727  Assembler* origin = desc.origin;
10728  AllowDeferredHandleDereference embedding_raw_address;
10729  for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10730    RelocInfo::Mode mode = it.rinfo()->rmode();
10731    if (mode == RelocInfo::EMBEDDED_OBJECT) {
10732      Handle<Object> p = it.rinfo()->target_object_handle(origin);
10733      it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
10734    } else if (mode == RelocInfo::CELL) {
10735      Handle<Cell> cell  = it.rinfo()->target_cell_handle();
10736      it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
10737    } else if (RelocInfo::IsCodeTarget(mode)) {
10738      // rewrite code handles in inline cache targets to direct
10739      // pointers to the first instruction in the code object
10740      Handle<Object> p = it.rinfo()->target_object_handle(origin);
10741      Code* code = Code::cast(*p);
10742      it.rinfo()->set_target_address(code->instruction_start(),
10743                                     SKIP_WRITE_BARRIER,
10744                                     SKIP_ICACHE_FLUSH);
10745    } else if (RelocInfo::IsRuntimeEntry(mode)) {
10746      Address p = it.rinfo()->target_runtime_entry(origin);
10747      it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER,
10748                                           SKIP_ICACHE_FLUSH);
10749    } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
10750      Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
10751      Code* code = Code::cast(*p);
10752      it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
10753    } else {
10754      it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
10755    }
10756  }
10757  CPU::FlushICache(instruction_start(), instruction_size());
10758}
10759
10760
10761// Locate the source position which is closest to the address in the code. This
10762// is using the source position information embedded in the relocation info.
10763// The position returned is relative to the beginning of the script where the
10764// source for this function is found.
10765int Code::SourcePosition(Address pc) {
10766  int distance = kMaxInt;
10767  int position = RelocInfo::kNoPosition;  // Initially no position found.
10768  // Run through all the relocation info to find the best matching source
10769  // position. All the code needs to be considered as the sequence of the
10770  // instructions in the code does not necessarily follow the same order as the
10771  // source.
10772  RelocIterator it(this, RelocInfo::kPositionMask);
10773  while (!it.done()) {
10774    // Only look at positions after the current pc.
10775    if (it.rinfo()->pc() < pc) {
10776      // Get position and distance.
10777
10778      int dist = static_cast<int>(pc - it.rinfo()->pc());
10779      int pos = static_cast<int>(it.rinfo()->data());
10780      // If this position is closer than the current candidate or if it has the
10781      // same distance as the current candidate and the position is higher then
10782      // this position is the new candidate.
10783      if ((dist < distance) ||
10784          (dist == distance && pos > position)) {
10785        position = pos;
10786        distance = dist;
10787      }
10788    }
10789    it.next();
10790  }
10791  return position;
10792}
10793
10794
10795// Same as Code::SourcePosition above except it only looks for statement
10796// positions.
10797int Code::SourceStatementPosition(Address pc) {
10798  // First find the position as close as possible using all position
10799  // information.
10800  int position = SourcePosition(pc);
10801  // Now find the closest statement position before the position.
10802  int statement_position = 0;
10803  RelocIterator it(this, RelocInfo::kPositionMask);
10804  while (!it.done()) {
10805    if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
10806      int p = static_cast<int>(it.rinfo()->data());
10807      if (statement_position < p && p <= position) {
10808        statement_position = p;
10809      }
10810    }
10811    it.next();
10812  }
10813  return statement_position;
10814}
10815
10816
10817SafepointEntry Code::GetSafepointEntry(Address pc) {
10818  SafepointTable table(this);
10819  return table.FindEntry(pc);
10820}
10821
10822
10823Object* Code::FindNthObject(int n, Map* match_map) {
10824  ASSERT(is_inline_cache_stub());
10825  DisallowHeapAllocation no_allocation;
10826  int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10827  for (RelocIterator it(this, mask); !it.done(); it.next()) {
10828    RelocInfo* info = it.rinfo();
10829    Object* object = info->target_object();
10830    if (object->IsHeapObject()) {
10831      if (HeapObject::cast(object)->map() == match_map) {
10832        if (--n == 0) return object;
10833      }
10834    }
10835  }
10836  return NULL;
10837}
10838
10839
10840AllocationSite* Code::FindFirstAllocationSite() {
10841  Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
10842  return (result != NULL) ? AllocationSite::cast(result) : NULL;
10843}
10844
10845
10846Map* Code::FindFirstMap() {
10847  Object* result = FindNthObject(1, GetHeap()->meta_map());
10848  return (result != NULL) ? Map::cast(result) : NULL;
10849}
10850
10851
10852void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
10853  ASSERT(is_inline_cache_stub() || is_handler());
10854  DisallowHeapAllocation no_allocation;
10855  int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10856  STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
10857  int current_pattern = 0;
10858  for (RelocIterator it(this, mask); !it.done(); it.next()) {
10859    RelocInfo* info = it.rinfo();
10860    Object* object = info->target_object();
10861    if (object->IsHeapObject()) {
10862      Map* map = HeapObject::cast(object)->map();
10863      if (map == *pattern.find_[current_pattern]) {
10864        info->set_target_object(*pattern.replace_[current_pattern]);
10865        if (++current_pattern == pattern.count_) return;
10866      }
10867    }
10868  }
10869  UNREACHABLE();
10870}
10871
10872
10873void Code::FindAllMaps(MapHandleList* maps) {
10874  ASSERT(is_inline_cache_stub());
10875  DisallowHeapAllocation no_allocation;
10876  int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10877  for (RelocIterator it(this, mask); !it.done(); it.next()) {
10878    RelocInfo* info = it.rinfo();
10879    Object* object = info->target_object();
10880    if (object->IsMap()) maps->Add(handle(Map::cast(object)));
10881  }
10882}
10883
10884
10885Code* Code::FindFirstHandler() {
10886  ASSERT(is_inline_cache_stub());
10887  DisallowHeapAllocation no_allocation;
10888  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10889  for (RelocIterator it(this, mask); !it.done(); it.next()) {
10890    RelocInfo* info = it.rinfo();
10891    Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10892    if (code->kind() == Code::HANDLER) return code;
10893  }
10894  return NULL;
10895}
10896
10897
10898bool Code::FindHandlers(CodeHandleList* code_list, int length) {
10899  ASSERT(is_inline_cache_stub());
10900  DisallowHeapAllocation no_allocation;
10901  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10902  int i = 0;
10903  for (RelocIterator it(this, mask); !it.done(); it.next()) {
10904    if (i == length) return true;
10905    RelocInfo* info = it.rinfo();
10906    Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10907    // IC stubs with handlers never contain non-handler code objects before
10908    // handler targets.
10909    if (code->kind() != Code::HANDLER) break;
10910    code_list->Add(Handle<Code>(code));
10911    i++;
10912  }
10913  return i == length;
10914}
10915
10916
10917Name* Code::FindFirstName() {
10918  ASSERT(is_inline_cache_stub());
10919  DisallowHeapAllocation no_allocation;
10920  int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10921  for (RelocIterator it(this, mask); !it.done(); it.next()) {
10922    RelocInfo* info = it.rinfo();
10923    Object* object = info->target_object();
10924    if (object->IsName()) return Name::cast(object);
10925  }
10926  return NULL;
10927}
10928
10929
10930void Code::ClearInlineCaches() {
10931  ClearInlineCaches(NULL);
10932}
10933
10934
10935void Code::ClearInlineCaches(Code::Kind kind) {
10936  ClearInlineCaches(&kind);
10937}
10938
10939
10940void Code::ClearInlineCaches(Code::Kind* kind) {
10941  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10942             RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
10943             RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
10944  for (RelocIterator it(this, mask); !it.done(); it.next()) {
10945    RelocInfo* info = it.rinfo();
10946    Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
10947    if (target->is_inline_cache_stub()) {
10948      if (kind == NULL || *kind == target->kind()) {
10949        IC::Clear(this->GetIsolate(), info->pc(),
10950                  info->host()->constant_pool());
10951      }
10952    }
10953  }
10954}
10955
10956
10957void SharedFunctionInfo::ClearTypeFeedbackInfo() {
10958  FixedArray* vector = feedback_vector();
10959  Heap* heap = GetHeap();
10960  int length = vector->length();
10961
10962  for (int i = 0; i < length; i++) {
10963    Object* obj = vector->get(i);
10964    if (obj->IsHeapObject()) {
10965      InstanceType instance_type =
10966          HeapObject::cast(obj)->map()->instance_type();
10967      switch (instance_type) {
10968        case ALLOCATION_SITE_TYPE:
10969          // AllocationSites are not cleared because they do not store
10970          // information that leaks.
10971          break;
10972          // Fall through...
10973        default:
10974          vector->set(i, TypeFeedbackInfo::RawUninitializedSentinel(heap),
10975                      SKIP_WRITE_BARRIER);
10976      }
10977    }
10978  }
10979}
10980
10981
10982BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
10983  DisallowHeapAllocation no_gc;
10984  ASSERT(kind() == FUNCTION);
10985  BackEdgeTable back_edges(this, &no_gc);
10986  for (uint32_t i = 0; i < back_edges.length(); i++) {
10987    if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
10988  }
10989  return BailoutId::None();
10990}
10991
10992
10993uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
10994  DisallowHeapAllocation no_gc;
10995  ASSERT(kind() == FUNCTION);
10996  BackEdgeTable back_edges(this, &no_gc);
10997  for (uint32_t i = 0; i < back_edges.length(); i++) {
10998    if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
10999  }
11000  UNREACHABLE();  // We expect to find the back edge.
11001  return 0;
11002}
11003
11004
11005void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
11006  PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
11007}
11008
11009
11010void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
11011  PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
11012      NO_MARKING_PARITY);
11013}
11014
11015
11016static Code::Age EffectiveAge(Code::Age age) {
11017  if (age == Code::kNotExecutedCodeAge) {
11018    // Treat that's never been executed as old immediately.
11019    age = Code::kIsOldCodeAge;
11020  } else if (age == Code::kExecutedOnceCodeAge) {
11021    // Pre-age code that has only been executed once.
11022    age = Code::kPreAgedCodeAge;
11023  }
11024  return age;
11025}
11026
11027
11028void Code::MakeOlder(MarkingParity current_parity) {
11029  byte* sequence = FindCodeAgeSequence();
11030  if (sequence != NULL) {
11031    Age age;
11032    MarkingParity code_parity;
11033    Isolate* isolate = GetIsolate();
11034    GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
11035    age = EffectiveAge(age);
11036    if (age != kLastCodeAge && code_parity != current_parity) {
11037      PatchPlatformCodeAge(isolate,
11038                           sequence,
11039                           static_cast<Age>(age + 1),
11040                           current_parity);
11041    }
11042  }
11043}
11044
11045
11046bool Code::IsOld() {
11047  return GetAge() >= kIsOldCodeAge;
11048}
11049
11050
11051byte* Code::FindCodeAgeSequence() {
11052  return FLAG_age_code &&
11053      prologue_offset() != Code::kPrologueOffsetNotSet &&
11054      (kind() == OPTIMIZED_FUNCTION ||
11055       (kind() == FUNCTION && !has_debug_break_slots()))
11056      ? instruction_start() + prologue_offset()
11057      : NULL;
11058}
11059
11060
11061Code::Age Code::GetAge() {
11062  return EffectiveAge(GetRawAge());
11063}
11064
11065
11066Code::Age Code::GetRawAge() {
11067  byte* sequence = FindCodeAgeSequence();
11068  if (sequence == NULL) {
11069    return kNoAgeCodeAge;
11070  }
11071  Age age;
11072  MarkingParity parity;
11073  GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
11074  return age;
11075}
11076
11077
11078void Code::GetCodeAgeAndParity(Code* code, Age* age,
11079                               MarkingParity* parity) {
11080  Isolate* isolate = code->GetIsolate();
11081  Builtins* builtins = isolate->builtins();
11082  Code* stub = NULL;
11083#define HANDLE_CODE_AGE(AGE)                                            \
11084  stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking();             \
11085  if (code == stub) {                                                   \
11086    *age = k##AGE##CodeAge;                                             \
11087    *parity = EVEN_MARKING_PARITY;                                      \
11088    return;                                                             \
11089  }                                                                     \
11090  stub = *builtins->Make##AGE##CodeYoungAgainOddMarking();              \
11091  if (code == stub) {                                                   \
11092    *age = k##AGE##CodeAge;                                             \
11093    *parity = ODD_MARKING_PARITY;                                       \
11094    return;                                                             \
11095  }
11096  CODE_AGE_LIST(HANDLE_CODE_AGE)
11097#undef HANDLE_CODE_AGE
11098  stub = *builtins->MarkCodeAsExecutedOnce();
11099  if (code == stub) {
11100    *age = kNotExecutedCodeAge;
11101    *parity = NO_MARKING_PARITY;
11102    return;
11103  }
11104  stub = *builtins->MarkCodeAsExecutedTwice();
11105  if (code == stub) {
11106    *age = kExecutedOnceCodeAge;
11107    *parity = NO_MARKING_PARITY;
11108    return;
11109  }
11110  UNREACHABLE();
11111}
11112
11113
11114Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
11115  Builtins* builtins = isolate->builtins();
11116  switch (age) {
11117#define HANDLE_CODE_AGE(AGE)                                            \
11118    case k##AGE##CodeAge: {                                             \
11119      Code* stub = parity == EVEN_MARKING_PARITY                        \
11120          ? *builtins->Make##AGE##CodeYoungAgainEvenMarking()           \
11121          : *builtins->Make##AGE##CodeYoungAgainOddMarking();           \
11122      return stub;                                                      \
11123    }
11124    CODE_AGE_LIST(HANDLE_CODE_AGE)
11125#undef HANDLE_CODE_AGE
11126    case kNotExecutedCodeAge: {
11127      ASSERT(parity == NO_MARKING_PARITY);
11128      return *builtins->MarkCodeAsExecutedOnce();
11129    }
11130    case kExecutedOnceCodeAge: {
11131      ASSERT(parity == NO_MARKING_PARITY);
11132      return *builtins->MarkCodeAsExecutedTwice();
11133    }
11134    default:
11135      UNREACHABLE();
11136      break;
11137  }
11138  return NULL;
11139}
11140
11141
11142void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
11143  const char* last_comment = NULL;
11144  int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
11145      | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
11146  for (RelocIterator it(this, mask); !it.done(); it.next()) {
11147    RelocInfo* info = it.rinfo();
11148    if (info->rmode() == RelocInfo::COMMENT) {
11149      last_comment = reinterpret_cast<const char*>(info->data());
11150    } else if (last_comment != NULL) {
11151      if ((bailout_id == Deoptimizer::GetDeoptimizationId(
11152              GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
11153          (bailout_id == Deoptimizer::GetDeoptimizationId(
11154              GetIsolate(), info->target_address(), Deoptimizer::SOFT))) {
11155        CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
11156        PrintF(out, "            %s\n", last_comment);
11157        return;
11158      }
11159    }
11160  }
11161}
11162
11163
11164bool Code::CanDeoptAt(Address pc) {
11165  DeoptimizationInputData* deopt_data =
11166      DeoptimizationInputData::cast(deoptimization_data());
11167  Address code_start_address = instruction_start();
11168  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
11169    if (deopt_data->Pc(i)->value() == -1) continue;
11170    Address address = code_start_address + deopt_data->Pc(i)->value();
11171    if (address == pc) return true;
11172  }
11173  return false;
11174}
11175
11176
11177// Identify kind of code.
11178const char* Code::Kind2String(Kind kind) {
11179  switch (kind) {
11180#define CASE(name) case name: return #name;
11181    CODE_KIND_LIST(CASE)
11182#undef CASE
11183    case NUMBER_OF_KINDS: break;
11184  }
11185  UNREACHABLE();
11186  return NULL;
11187}
11188
11189
11190#ifdef ENABLE_DISASSEMBLER
11191
11192void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
11193  disasm::NameConverter converter;
11194  int deopt_count = DeoptCount();
11195  PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
11196  if (0 == deopt_count) return;
11197
11198  PrintF(out, "%6s  %6s  %6s %6s %12s\n", "index", "ast id", "argc", "pc",
11199         FLAG_print_code_verbose ? "commands" : "");
11200  for (int i = 0; i < deopt_count; i++) {
11201    PrintF(out, "%6d  %6d  %6d %6d",
11202           i,
11203           AstId(i).ToInt(),
11204           ArgumentsStackHeight(i)->value(),
11205           Pc(i)->value());
11206
11207    if (!FLAG_print_code_verbose) {
11208      PrintF(out, "\n");
11209      continue;
11210    }
11211    // Print details of the frame translation.
11212    int translation_index = TranslationIndex(i)->value();
11213    TranslationIterator iterator(TranslationByteArray(), translation_index);
11214    Translation::Opcode opcode =
11215        static_cast<Translation::Opcode>(iterator.Next());
11216    ASSERT(Translation::BEGIN == opcode);
11217    int frame_count = iterator.Next();
11218    int jsframe_count = iterator.Next();
11219    PrintF(out, "  %s {frame count=%d, js frame count=%d}\n",
11220           Translation::StringFor(opcode),
11221           frame_count,
11222           jsframe_count);
11223
11224    while (iterator.HasNext() &&
11225           Translation::BEGIN !=
11226           (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
11227      PrintF(out, "%24s    %s ", "", Translation::StringFor(opcode));
11228
11229      switch (opcode) {
11230        case Translation::BEGIN:
11231          UNREACHABLE();
11232          break;
11233
11234        case Translation::JS_FRAME: {
11235          int ast_id = iterator.Next();
11236          int function_id = iterator.Next();
11237          unsigned height = iterator.Next();
11238          PrintF(out, "{ast_id=%d, function=", ast_id);
11239          if (function_id != Translation::kSelfLiteralId) {
11240            Object* function = LiteralArray()->get(function_id);
11241            JSFunction::cast(function)->PrintName(out);
11242          } else {
11243            PrintF(out, "<self>");
11244          }
11245          PrintF(out, ", height=%u}", height);
11246          break;
11247        }
11248
11249        case Translation::COMPILED_STUB_FRAME: {
11250          Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
11251          PrintF(out, "{kind=%d}", stub_kind);
11252          break;
11253        }
11254
11255        case Translation::ARGUMENTS_ADAPTOR_FRAME:
11256        case Translation::CONSTRUCT_STUB_FRAME: {
11257          int function_id = iterator.Next();
11258          JSFunction* function =
11259              JSFunction::cast(LiteralArray()->get(function_id));
11260          unsigned height = iterator.Next();
11261          PrintF(out, "{function=");
11262          function->PrintName(out);
11263          PrintF(out, ", height=%u}", height);
11264          break;
11265        }
11266
11267        case Translation::GETTER_STUB_FRAME:
11268        case Translation::SETTER_STUB_FRAME: {
11269          int function_id = iterator.Next();
11270          JSFunction* function =
11271              JSFunction::cast(LiteralArray()->get(function_id));
11272          PrintF(out, "{function=");
11273          function->PrintName(out);
11274          PrintF(out, "}");
11275          break;
11276        }
11277
11278        case Translation::REGISTER: {
11279          int reg_code = iterator.Next();
11280            PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
11281          break;
11282        }
11283
11284        case Translation::INT32_REGISTER: {
11285          int reg_code = iterator.Next();
11286          PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
11287          break;
11288        }
11289
11290        case Translation::UINT32_REGISTER: {
11291          int reg_code = iterator.Next();
11292          PrintF(out, "{input=%s (unsigned)}",
11293                 converter.NameOfCPURegister(reg_code));
11294          break;
11295        }
11296
11297        case Translation::DOUBLE_REGISTER: {
11298          int reg_code = iterator.Next();
11299          PrintF(out, "{input=%s}",
11300                 DoubleRegister::AllocationIndexToString(reg_code));
11301          break;
11302        }
11303
11304        case Translation::STACK_SLOT: {
11305          int input_slot_index = iterator.Next();
11306          PrintF(out, "{input=%d}", input_slot_index);
11307          break;
11308        }
11309
11310        case Translation::INT32_STACK_SLOT: {
11311          int input_slot_index = iterator.Next();
11312          PrintF(out, "{input=%d}", input_slot_index);
11313          break;
11314        }
11315
11316        case Translation::UINT32_STACK_SLOT: {
11317          int input_slot_index = iterator.Next();
11318          PrintF(out, "{input=%d (unsigned)}", input_slot_index);
11319          break;
11320        }
11321
11322        case Translation::DOUBLE_STACK_SLOT: {
11323          int input_slot_index = iterator.Next();
11324          PrintF(out, "{input=%d}", input_slot_index);
11325          break;
11326        }
11327
11328        case Translation::LITERAL: {
11329          unsigned literal_index = iterator.Next();
11330          PrintF(out, "{literal_id=%u}", literal_index);
11331          break;
11332        }
11333
11334        case Translation::DUPLICATED_OBJECT: {
11335          int object_index = iterator.Next();
11336          PrintF(out, "{object_index=%d}", object_index);
11337          break;
11338        }
11339
11340        case Translation::ARGUMENTS_OBJECT:
11341        case Translation::CAPTURED_OBJECT: {
11342          int args_length = iterator.Next();
11343          PrintF(out, "{length=%d}", args_length);
11344          break;
11345        }
11346      }
11347      PrintF(out, "\n");
11348    }
11349  }
11350}
11351
11352
11353void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
11354  PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
11355         this->DeoptPoints());
11356  if (this->DeoptPoints() == 0) return;
11357
11358  PrintF(out, "%6s  %8s  %s\n", "ast id", "pc", "state");
11359  for (int i = 0; i < this->DeoptPoints(); i++) {
11360    int pc_and_state = this->PcAndState(i)->value();
11361    PrintF(out, "%6d  %8d  %s\n",
11362           this->AstId(i).ToInt(),
11363           FullCodeGenerator::PcField::decode(pc_and_state),
11364           FullCodeGenerator::State2String(
11365               FullCodeGenerator::StateField::decode(pc_and_state)));
11366  }
11367}
11368
11369
11370const char* Code::ICState2String(InlineCacheState state) {
11371  switch (state) {
11372    case UNINITIALIZED: return "UNINITIALIZED";
11373    case PREMONOMORPHIC: return "PREMONOMORPHIC";
11374    case MONOMORPHIC: return "MONOMORPHIC";
11375    case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
11376    case POLYMORPHIC: return "POLYMORPHIC";
11377    case MEGAMORPHIC: return "MEGAMORPHIC";
11378    case GENERIC: return "GENERIC";
11379    case DEBUG_STUB: return "DEBUG_STUB";
11380  }
11381  UNREACHABLE();
11382  return NULL;
11383}
11384
11385
11386const char* Code::StubType2String(StubType type) {
11387  switch (type) {
11388    case NORMAL: return "NORMAL";
11389    case FAST: return "FAST";
11390  }
11391  UNREACHABLE();  // keep the compiler happy
11392  return NULL;
11393}
11394
11395
11396void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
11397  PrintF(out, "extra_ic_state = ");
11398  const char* name = NULL;
11399  switch (kind) {
11400    case STORE_IC:
11401    case KEYED_STORE_IC:
11402      if (extra == STRICT) name = "STRICT";
11403      break;
11404    default:
11405      break;
11406  }
11407  if (name != NULL) {
11408    PrintF(out, "%s\n", name);
11409  } else {
11410    PrintF(out, "%d\n", extra);
11411  }
11412}
11413
11414
11415void Code::Disassemble(const char* name, FILE* out) {
11416  PrintF(out, "kind = %s\n", Kind2String(kind()));
11417  if (has_major_key()) {
11418    PrintF(out, "major_key = %s\n",
11419           CodeStub::MajorName(CodeStub::GetMajorKey(this), true));
11420  }
11421  if (is_inline_cache_stub()) {
11422    PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
11423    PrintExtraICState(out, kind(), extra_ic_state());
11424    if (ic_state() == MONOMORPHIC) {
11425      PrintF(out, "type = %s\n", StubType2String(type()));
11426    }
11427    if (is_compare_ic_stub()) {
11428      ASSERT(major_key() == CodeStub::CompareIC);
11429      CompareIC::State left_state, right_state, handler_state;
11430      Token::Value op;
11431      ICCompareStub::DecodeMinorKey(stub_info(), &left_state, &right_state,
11432                                    &handler_state, &op);
11433      PrintF(out, "compare_state = %s*%s -> %s\n",
11434             CompareIC::GetStateName(left_state),
11435             CompareIC::GetStateName(right_state),
11436             CompareIC::GetStateName(handler_state));
11437      PrintF(out, "compare_operation = %s\n", Token::Name(op));
11438    }
11439  }
11440  if ((name != NULL) && (name[0] != '\0')) {
11441    PrintF(out, "name = %s\n", name);
11442  }
11443  if (kind() == OPTIMIZED_FUNCTION) {
11444    PrintF(out, "stack_slots = %d\n", stack_slots());
11445  }
11446
11447  PrintF(out, "Instructions (size = %d)\n", instruction_size());
11448  Disassembler::Decode(out, this);
11449  PrintF(out, "\n");
11450
11451  if (kind() == FUNCTION) {
11452    DeoptimizationOutputData* data =
11453        DeoptimizationOutputData::cast(this->deoptimization_data());
11454    data->DeoptimizationOutputDataPrint(out);
11455  } else if (kind() == OPTIMIZED_FUNCTION) {
11456    DeoptimizationInputData* data =
11457        DeoptimizationInputData::cast(this->deoptimization_data());
11458    data->DeoptimizationInputDataPrint(out);
11459  }
11460  PrintF(out, "\n");
11461
11462  if (is_crankshafted()) {
11463    SafepointTable table(this);
11464    PrintF(out, "Safepoints (size = %u)\n", table.size());
11465    for (unsigned i = 0; i < table.length(); i++) {
11466      unsigned pc_offset = table.GetPcOffset(i);
11467      PrintF(out, "%p  %4d  ", (instruction_start() + pc_offset), pc_offset);
11468      table.PrintEntry(i, out);
11469      PrintF(out, " (sp -> fp)");
11470      SafepointEntry entry = table.GetEntry(i);
11471      if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
11472        PrintF(out, "  %6d", entry.deoptimization_index());
11473      } else {
11474        PrintF(out, "  <none>");
11475      }
11476      if (entry.argument_count() > 0) {
11477        PrintF(out, " argc: %d", entry.argument_count());
11478      }
11479      PrintF(out, "\n");
11480    }
11481    PrintF(out, "\n");
11482  } else if (kind() == FUNCTION) {
11483    unsigned offset = back_edge_table_offset();
11484    // If there is no back edge table, the "table start" will be at or after
11485    // (due to alignment) the end of the instruction stream.
11486    if (static_cast<int>(offset) < instruction_size()) {
11487      DisallowHeapAllocation no_gc;
11488      BackEdgeTable back_edges(this, &no_gc);
11489
11490      PrintF(out, "Back edges (size = %u)\n", back_edges.length());
11491      PrintF(out, "ast_id  pc_offset  loop_depth\n");
11492
11493      for (uint32_t i = 0; i < back_edges.length(); i++) {
11494        PrintF(out, "%6d  %9u  %10u\n", back_edges.ast_id(i).ToInt(),
11495                                        back_edges.pc_offset(i),
11496                                        back_edges.loop_depth(i));
11497      }
11498
11499      PrintF(out, "\n");
11500    }
11501#ifdef OBJECT_PRINT
11502    if (!type_feedback_info()->IsUndefined()) {
11503      TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(out);
11504      PrintF(out, "\n");
11505    }
11506#endif
11507  }
11508
11509  PrintF(out, "RelocInfo (size = %d)\n", relocation_size());
11510  for (RelocIterator it(this); !it.done(); it.next()) {
11511    it.rinfo()->Print(GetIsolate(), out);
11512  }
11513  PrintF(out, "\n");
11514}
11515#endif  // ENABLE_DISASSEMBLER
11516
11517
11518Handle<FixedArray> JSObject::SetFastElementsCapacityAndLength(
11519    Handle<JSObject> object,
11520    int capacity,
11521    int length,
11522    SetFastElementsCapacitySmiMode smi_mode) {
11523  // We should never end in here with a pixel or external array.
11524  ASSERT(!object->HasExternalArrayElements());
11525
11526  // Allocate a new fast elements backing store.
11527  Handle<FixedArray> new_elements =
11528      object->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
11529
11530  ElementsKind elements_kind = object->GetElementsKind();
11531  ElementsKind new_elements_kind;
11532  // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
11533  // or if it's allowed and the old elements array contained only SMIs.
11534  bool has_fast_smi_elements =
11535      (smi_mode == kForceSmiElements) ||
11536      ((smi_mode == kAllowSmiElements) && object->HasFastSmiElements());
11537  if (has_fast_smi_elements) {
11538    if (IsHoleyElementsKind(elements_kind)) {
11539      new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
11540    } else {
11541      new_elements_kind = FAST_SMI_ELEMENTS;
11542    }
11543  } else {
11544    if (IsHoleyElementsKind(elements_kind)) {
11545      new_elements_kind = FAST_HOLEY_ELEMENTS;
11546    } else {
11547      new_elements_kind = FAST_ELEMENTS;
11548    }
11549  }
11550  Handle<FixedArrayBase> old_elements(object->elements());
11551  ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
11552  accessor->CopyElements(object, new_elements, elements_kind);
11553
11554  if (elements_kind != SLOPPY_ARGUMENTS_ELEMENTS) {
11555    Handle<Map> new_map = (new_elements_kind != elements_kind)
11556        ? GetElementsTransitionMap(object, new_elements_kind)
11557        : handle(object->map());
11558    JSObject::ValidateElements(object);
11559    JSObject::SetMapAndElements(object, new_map, new_elements);
11560
11561    // Transition through the allocation site as well if present.
11562    JSObject::UpdateAllocationSite(object, new_elements_kind);
11563  } else {
11564    Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements);
11565    parameter_map->set(1, *new_elements);
11566  }
11567
11568  if (FLAG_trace_elements_transitions) {
11569    PrintElementsTransition(stdout, object, elements_kind, old_elements,
11570                            object->GetElementsKind(), new_elements);
11571  }
11572
11573  if (object->IsJSArray()) {
11574    Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
11575  }
11576  return new_elements;
11577}
11578
11579
11580void JSObject::SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object,
11581                                                      int capacity,
11582                                                      int length) {
11583  // We should never end in here with a pixel or external array.
11584  ASSERT(!object->HasExternalArrayElements());
11585
11586  Handle<FixedArrayBase> elems =
11587      object->GetIsolate()->factory()->NewFixedDoubleArray(capacity);
11588
11589  ElementsKind elements_kind = object->GetElementsKind();
11590  CHECK(elements_kind != SLOPPY_ARGUMENTS_ELEMENTS);
11591  ElementsKind new_elements_kind = elements_kind;
11592  if (IsHoleyElementsKind(elements_kind)) {
11593    new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
11594  } else {
11595    new_elements_kind = FAST_DOUBLE_ELEMENTS;
11596  }
11597
11598  Handle<Map> new_map = GetElementsTransitionMap(object, new_elements_kind);
11599
11600  Handle<FixedArrayBase> old_elements(object->elements());
11601  ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS);
11602  accessor->CopyElements(object, elems, elements_kind);
11603
11604  JSObject::ValidateElements(object);
11605  JSObject::SetMapAndElements(object, new_map, elems);
11606
11607  if (FLAG_trace_elements_transitions) {
11608    PrintElementsTransition(stdout, object, elements_kind, old_elements,
11609                            object->GetElementsKind(), elems);
11610  }
11611
11612  if (object->IsJSArray()) {
11613    Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
11614  }
11615}
11616
11617
11618// static
11619void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
11620  ASSERT(capacity >= 0);
11621  array->GetIsolate()->factory()->NewJSArrayStorage(
11622      array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
11623}
11624
11625
11626void JSArray::Expand(Handle<JSArray> array, int required_size) {
11627  ElementsAccessor* accessor = array->GetElementsAccessor();
11628  accessor->SetCapacityAndLength(array, required_size, required_size);
11629}
11630
11631
11632// Returns false if the passed-in index is marked non-configurable,
11633// which will cause the ES5 truncation operation to halt, and thus
11634// no further old values need be collected.
11635static bool GetOldValue(Isolate* isolate,
11636                        Handle<JSObject> object,
11637                        uint32_t index,
11638                        List<Handle<Object> >* old_values,
11639                        List<uint32_t>* indices) {
11640  PropertyAttributes attributes =
11641      JSReceiver::GetOwnElementAttribute(object, index);
11642  ASSERT(attributes != ABSENT);
11643  if (attributes == DONT_DELETE) return false;
11644  Handle<Object> value;
11645  if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) {
11646    value = Handle<Object>::cast(isolate->factory()->the_hole_value());
11647  } else {
11648    value = Object::GetElement(isolate, object, index).ToHandleChecked();
11649  }
11650  old_values->Add(value);
11651  indices->Add(index);
11652  return true;
11653}
11654
11655static void EnqueueSpliceRecord(Handle<JSArray> object,
11656                                uint32_t index,
11657                                Handle<JSArray> deleted,
11658                                uint32_t add_count) {
11659  Isolate* isolate = object->GetIsolate();
11660  HandleScope scope(isolate);
11661  Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
11662  Handle<Object> add_count_object =
11663      isolate->factory()->NewNumberFromUint(add_count);
11664
11665  Handle<Object> args[] =
11666      { object, index_object, deleted, add_count_object };
11667
11668  Execution::Call(isolate,
11669                  Handle<JSFunction>(isolate->observers_enqueue_splice()),
11670                  isolate->factory()->undefined_value(),
11671                  ARRAY_SIZE(args),
11672                  args).Assert();
11673}
11674
11675
11676static void BeginPerformSplice(Handle<JSArray> object) {
11677  Isolate* isolate = object->GetIsolate();
11678  HandleScope scope(isolate);
11679  Handle<Object> args[] = { object };
11680
11681  Execution::Call(isolate,
11682                  Handle<JSFunction>(isolate->observers_begin_perform_splice()),
11683                  isolate->factory()->undefined_value(),
11684                  ARRAY_SIZE(args),
11685                  args).Assert();
11686}
11687
11688
11689static void EndPerformSplice(Handle<JSArray> object) {
11690  Isolate* isolate = object->GetIsolate();
11691  HandleScope scope(isolate);
11692  Handle<Object> args[] = { object };
11693
11694  Execution::Call(isolate,
11695                  Handle<JSFunction>(isolate->observers_end_perform_splice()),
11696                  isolate->factory()->undefined_value(),
11697                  ARRAY_SIZE(args),
11698                  args).Assert();
11699}
11700
11701
11702MaybeHandle<Object> JSArray::SetElementsLength(
11703    Handle<JSArray> array,
11704    Handle<Object> new_length_handle) {
11705  // We should never end in here with a pixel or external array.
11706  ASSERT(array->AllowsSetElementsLength());
11707  if (!array->map()->is_observed()) {
11708    return array->GetElementsAccessor()->SetLength(array, new_length_handle);
11709  }
11710
11711  Isolate* isolate = array->GetIsolate();
11712  List<uint32_t> indices;
11713  List<Handle<Object> > old_values;
11714  Handle<Object> old_length_handle(array->length(), isolate);
11715  uint32_t old_length = 0;
11716  CHECK(old_length_handle->ToArrayIndex(&old_length));
11717  uint32_t new_length = 0;
11718  CHECK(new_length_handle->ToArrayIndex(&new_length));
11719
11720  static const PropertyAttributes kNoAttrFilter = NONE;
11721  int num_elements = array->NumberOfOwnElements(kNoAttrFilter);
11722  if (num_elements > 0) {
11723    if (old_length == static_cast<uint32_t>(num_elements)) {
11724      // Simple case for arrays without holes.
11725      for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
11726        if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
11727      }
11728    } else {
11729      // For sparse arrays, only iterate over existing elements.
11730      // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
11731      // the to-be-removed indices twice.
11732      Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
11733      array->GetOwnElementKeys(*keys, kNoAttrFilter);
11734      while (num_elements-- > 0) {
11735        uint32_t index = NumberToUint32(keys->get(num_elements));
11736        if (index < new_length) break;
11737        if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
11738      }
11739    }
11740  }
11741
11742  Handle<Object> hresult;
11743  ASSIGN_RETURN_ON_EXCEPTION(
11744      isolate, hresult,
11745      array->GetElementsAccessor()->SetLength(array, new_length_handle),
11746      Object);
11747
11748  CHECK(array->length()->ToArrayIndex(&new_length));
11749  if (old_length == new_length) return hresult;
11750
11751  BeginPerformSplice(array);
11752
11753  for (int i = 0; i < indices.length(); ++i) {
11754    // For deletions where the property was an accessor, old_values[i]
11755    // will be the hole, which instructs EnqueueChangeRecord to elide
11756    // the "oldValue" property.
11757    JSObject::EnqueueChangeRecord(
11758        array, "delete", isolate->factory()->Uint32ToString(indices[i]),
11759        old_values[i]);
11760  }
11761  JSObject::EnqueueChangeRecord(
11762      array, "update", isolate->factory()->length_string(),
11763      old_length_handle);
11764
11765  EndPerformSplice(array);
11766
11767  uint32_t index = Min(old_length, new_length);
11768  uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
11769  uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
11770  Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
11771  if (delete_count > 0) {
11772    for (int i = indices.length() - 1; i >= 0; i--) {
11773      // Skip deletions where the property was an accessor, leaving holes
11774      // in the array of old values.
11775      if (old_values[i]->IsTheHole()) continue;
11776      JSObject::SetElement(
11777          deleted, indices[i] - index, old_values[i], NONE, SLOPPY).Assert();
11778    }
11779
11780    SetProperty(deleted, isolate->factory()->length_string(),
11781                isolate->factory()->NewNumberFromUint(delete_count),
11782                NONE, SLOPPY).Assert();
11783  }
11784
11785  EnqueueSpliceRecord(array, index, deleted, add_count);
11786
11787  return hresult;
11788}
11789
11790
11791Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
11792                                        Handle<Object> prototype) {
11793  FixedArray* cache = map->GetPrototypeTransitions();
11794  int number_of_transitions = map->NumberOfProtoTransitions();
11795  const int proto_offset =
11796      kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
11797  const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
11798  const int step = kProtoTransitionElementsPerEntry;
11799  for (int i = 0; i < number_of_transitions; i++) {
11800    if (cache->get(proto_offset + i * step) == *prototype) {
11801      Object* result = cache->get(map_offset + i * step);
11802      return Handle<Map>(Map::cast(result));
11803    }
11804  }
11805  return Handle<Map>();
11806}
11807
11808
11809Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
11810                                        Handle<Object> prototype,
11811                                        Handle<Map> target_map) {
11812  ASSERT(target_map->IsMap());
11813  ASSERT(HeapObject::cast(*prototype)->map()->IsMap());
11814  // Don't cache prototype transition if this map is shared.
11815  if (map->is_shared() || !FLAG_cache_prototype_transitions) return map;
11816
11817  const int step = kProtoTransitionElementsPerEntry;
11818  const int header = kProtoTransitionHeaderSize;
11819
11820  Handle<FixedArray> cache(map->GetPrototypeTransitions());
11821  int capacity = (cache->length() - header) / step;
11822  int transitions = map->NumberOfProtoTransitions() + 1;
11823
11824  if (transitions > capacity) {
11825    if (capacity > kMaxCachedPrototypeTransitions) return map;
11826
11827    // Grow array by factor 2 over and above what we need.
11828    cache = FixedArray::CopySize(cache, transitions * 2 * step + header);
11829
11830    SetPrototypeTransitions(map, cache);
11831  }
11832
11833  // Reload number of transitions as GC might shrink them.
11834  int last = map->NumberOfProtoTransitions();
11835  int entry = header + last * step;
11836
11837  cache->set(entry + kProtoTransitionPrototypeOffset, *prototype);
11838  cache->set(entry + kProtoTransitionMapOffset, *target_map);
11839  map->SetNumberOfProtoTransitions(last + 1);
11840
11841  return map;
11842}
11843
11844
11845void Map::ZapTransitions() {
11846  TransitionArray* transition_array = transitions();
11847  // TODO(mstarzinger): Temporarily use a slower version instead of the faster
11848  // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
11849  Object** data = transition_array->data_start();
11850  Object* the_hole = GetHeap()->the_hole_value();
11851  int length = transition_array->length();
11852  for (int i = 0; i < length; i++) {
11853    data[i] = the_hole;
11854  }
11855}
11856
11857
11858void Map::ZapPrototypeTransitions() {
11859  FixedArray* proto_transitions = GetPrototypeTransitions();
11860  MemsetPointer(proto_transitions->data_start(),
11861                GetHeap()->the_hole_value(),
11862                proto_transitions->length());
11863}
11864
11865
11866// static
11867void Map::AddDependentCompilationInfo(Handle<Map> map,
11868                                      DependentCode::DependencyGroup group,
11869                                      CompilationInfo* info) {
11870  Handle<DependentCode> codes =
11871      DependentCode::Insert(handle(map->dependent_code(), info->isolate()),
11872                            group, info->object_wrapper());
11873  if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
11874  info->dependencies(group)->Add(map, info->zone());
11875}
11876
11877
11878// static
11879void Map::AddDependentCode(Handle<Map> map,
11880                           DependentCode::DependencyGroup group,
11881                           Handle<Code> code) {
11882  Handle<DependentCode> codes = DependentCode::Insert(
11883      Handle<DependentCode>(map->dependent_code()), group, code);
11884  if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
11885}
11886
11887
11888// static
11889void Map::AddDependentIC(Handle<Map> map,
11890                         Handle<Code> stub) {
11891  ASSERT(stub->next_code_link()->IsUndefined());
11892  int n = map->dependent_code()->number_of_entries(DependentCode::kWeakICGroup);
11893  if (n == 0) {
11894    // Slow path: insert the head of the list with possible heap allocation.
11895    Map::AddDependentCode(map, DependentCode::kWeakICGroup, stub);
11896  } else {
11897    // Fast path: link the stub to the existing head of the list without any
11898    // heap allocation.
11899    ASSERT(n == 1);
11900    map->dependent_code()->AddToDependentICList(stub);
11901  }
11902}
11903
11904
11905DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
11906  Recompute(entries);
11907}
11908
11909
11910void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
11911  start_indexes_[0] = 0;
11912  for (int g = 1; g <= kGroupCount; g++) {
11913    int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
11914    start_indexes_[g] = start_indexes_[g - 1] + count;
11915  }
11916}
11917
11918
11919DependentCode* DependentCode::ForObject(Handle<HeapObject> object,
11920                                        DependencyGroup group) {
11921  AllowDeferredHandleDereference dependencies_are_safe;
11922  if (group == DependentCode::kPropertyCellChangedGroup) {
11923    return Handle<PropertyCell>::cast(object)->dependent_code();
11924  } else if (group == DependentCode::kAllocationSiteTenuringChangedGroup ||
11925      group == DependentCode::kAllocationSiteTransitionChangedGroup) {
11926    return Handle<AllocationSite>::cast(object)->dependent_code();
11927  }
11928  return Handle<Map>::cast(object)->dependent_code();
11929}
11930
11931
11932Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
11933                                            DependencyGroup group,
11934                                            Handle<Object> object) {
11935  GroupStartIndexes starts(*entries);
11936  int start = starts.at(group);
11937  int end = starts.at(group + 1);
11938  int number_of_entries = starts.number_of_entries();
11939  // Check for existing entry to avoid duplicates.
11940  for (int i = start; i < end; i++) {
11941    if (entries->object_at(i) == *object) return entries;
11942  }
11943  if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
11944    int capacity = kCodesStartIndex + number_of_entries + 1;
11945    if (capacity > 5) capacity = capacity * 5 / 4;
11946    Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
11947        FixedArray::CopySize(entries, capacity, TENURED));
11948    // The number of codes can change after GC.
11949    starts.Recompute(*entries);
11950    start = starts.at(group);
11951    end = starts.at(group + 1);
11952    number_of_entries = starts.number_of_entries();
11953    for (int i = 0; i < number_of_entries; i++) {
11954      entries->clear_at(i);
11955    }
11956    // If the old fixed array was empty, we need to reset counters of the
11957    // new array.
11958    if (number_of_entries == 0) {
11959      for (int g = 0; g < kGroupCount; g++) {
11960        new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
11961      }
11962    }
11963    entries = new_entries;
11964  }
11965  entries->ExtendGroup(group);
11966  entries->set_object_at(end, *object);
11967  entries->set_number_of_entries(group, end + 1 - start);
11968  return entries;
11969}
11970
11971
11972void DependentCode::UpdateToFinishedCode(DependencyGroup group,
11973                                         CompilationInfo* info,
11974                                         Code* code) {
11975  DisallowHeapAllocation no_gc;
11976  AllowDeferredHandleDereference get_object_wrapper;
11977  Foreign* info_wrapper = *info->object_wrapper();
11978  GroupStartIndexes starts(this);
11979  int start = starts.at(group);
11980  int end = starts.at(group + 1);
11981  for (int i = start; i < end; i++) {
11982    if (object_at(i) == info_wrapper) {
11983      set_object_at(i, code);
11984      break;
11985    }
11986  }
11987
11988#ifdef DEBUG
11989  for (int i = start; i < end; i++) {
11990    ASSERT(is_code_at(i) || compilation_info_at(i) != info);
11991  }
11992#endif
11993}
11994
11995
11996void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
11997                                          CompilationInfo* info) {
11998  DisallowHeapAllocation no_allocation;
11999  AllowDeferredHandleDereference get_object_wrapper;
12000  Foreign* info_wrapper = *info->object_wrapper();
12001  GroupStartIndexes starts(this);
12002  int start = starts.at(group);
12003  int end = starts.at(group + 1);
12004  // Find compilation info wrapper.
12005  int info_pos = -1;
12006  for (int i = start; i < end; i++) {
12007    if (object_at(i) == info_wrapper) {
12008      info_pos = i;
12009      break;
12010    }
12011  }
12012  if (info_pos == -1) return;  // Not found.
12013  int gap = info_pos;
12014  // Use the last of each group to fill the gap in the previous group.
12015  for (int i = group; i < kGroupCount; i++) {
12016    int last_of_group = starts.at(i + 1) - 1;
12017    ASSERT(last_of_group >= gap);
12018    if (last_of_group == gap) continue;
12019    copy(last_of_group, gap);
12020    gap = last_of_group;
12021  }
12022  ASSERT(gap == starts.number_of_entries() - 1);
12023  clear_at(gap);  // Clear last gap.
12024  set_number_of_entries(group, end - start - 1);
12025
12026#ifdef DEBUG
12027  for (int i = start; i < end - 1; i++) {
12028    ASSERT(is_code_at(i) || compilation_info_at(i) != info);
12029  }
12030#endif
12031}
12032
12033
12034static bool CodeListContains(Object* head, Code* code) {
12035  while (!head->IsUndefined()) {
12036    if (head == code) return true;
12037    head = Code::cast(head)->next_code_link();
12038  }
12039  return false;
12040}
12041
12042
12043bool DependentCode::Contains(DependencyGroup group, Code* code) {
12044  GroupStartIndexes starts(this);
12045  int start = starts.at(group);
12046  int end = starts.at(group + 1);
12047  if (group == kWeakICGroup) {
12048    return CodeListContains(object_at(start), code);
12049  }
12050  for (int i = start; i < end; i++) {
12051    if (object_at(i) == code) return true;
12052  }
12053  return false;
12054}
12055
12056
12057bool DependentCode::MarkCodeForDeoptimization(
12058    Isolate* isolate,
12059    DependentCode::DependencyGroup group) {
12060  DisallowHeapAllocation no_allocation_scope;
12061  DependentCode::GroupStartIndexes starts(this);
12062  int start = starts.at(group);
12063  int end = starts.at(group + 1);
12064  int code_entries = starts.number_of_entries();
12065  if (start == end) return false;
12066
12067  // Mark all the code that needs to be deoptimized.
12068  bool marked = false;
12069  for (int i = start; i < end; i++) {
12070    if (is_code_at(i)) {
12071      Code* code = code_at(i);
12072      if (!code->marked_for_deoptimization()) {
12073        code->set_marked_for_deoptimization(true);
12074        marked = true;
12075      }
12076    } else {
12077      CompilationInfo* info = compilation_info_at(i);
12078      info->AbortDueToDependencyChange();
12079    }
12080  }
12081  // Compact the array by moving all subsequent groups to fill in the new holes.
12082  for (int src = end, dst = start; src < code_entries; src++, dst++) {
12083    copy(src, dst);
12084  }
12085  // Now the holes are at the end of the array, zap them for heap-verifier.
12086  int removed = end - start;
12087  for (int i = code_entries - removed; i < code_entries; i++) {
12088    clear_at(i);
12089  }
12090  set_number_of_entries(group, 0);
12091  return marked;
12092}
12093
12094
12095void DependentCode::DeoptimizeDependentCodeGroup(
12096    Isolate* isolate,
12097    DependentCode::DependencyGroup group) {
12098  ASSERT(AllowCodeDependencyChange::IsAllowed());
12099  DisallowHeapAllocation no_allocation_scope;
12100  bool marked = MarkCodeForDeoptimization(isolate, group);
12101
12102  if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
12103}
12104
12105
12106void DependentCode::AddToDependentICList(Handle<Code> stub) {
12107  DisallowHeapAllocation no_heap_allocation;
12108  GroupStartIndexes starts(this);
12109  int i = starts.at(kWeakICGroup);
12110  Object* head = object_at(i);
12111  // Try to insert the stub after the head of the list to minimize number of
12112  // writes to the DependentCode array, since a write to the array can make it
12113  // strong if it was alread marked by incremental marker.
12114  if (head->IsCode()) {
12115    stub->set_next_code_link(Code::cast(head)->next_code_link());
12116    Code::cast(head)->set_next_code_link(*stub);
12117  } else {
12118    stub->set_next_code_link(head);
12119    set_object_at(i, *stub);
12120  }
12121}
12122
12123
12124Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
12125                                       Handle<Object> prototype) {
12126  Handle<Map> new_map = GetPrototypeTransition(map, prototype);
12127  if (new_map.is_null()) {
12128    new_map = Copy(map);
12129    PutPrototypeTransition(map, prototype, new_map);
12130    new_map->set_prototype(*prototype);
12131  }
12132  return new_map;
12133}
12134
12135
12136MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
12137                                           Handle<Object> value,
12138                                           bool skip_hidden_prototypes) {
12139#ifdef DEBUG
12140  int size = object->Size();
12141#endif
12142
12143  Isolate* isolate = object->GetIsolate();
12144  Heap* heap = isolate->heap();
12145  // Silently ignore the change if value is not a JSObject or null.
12146  // SpiderMonkey behaves this way.
12147  if (!value->IsJSReceiver() && !value->IsNull()) return value;
12148
12149  // From 8.6.2 Object Internal Methods
12150  // ...
12151  // In addition, if [[Extensible]] is false the value of the [[Class]] and
12152  // [[Prototype]] internal properties of the object may not be modified.
12153  // ...
12154  // Implementation specific extensions that modify [[Class]], [[Prototype]]
12155  // or [[Extensible]] must not violate the invariants defined in the preceding
12156  // paragraph.
12157  if (!object->map()->is_extensible()) {
12158    Handle<Object> args[] = { object };
12159    Handle<Object> error = isolate->factory()->NewTypeError(
12160        "non_extensible_proto", HandleVector(args, ARRAY_SIZE(args)));
12161    return isolate->Throw<Object>(error);
12162  }
12163
12164  // Before we can set the prototype we need to be sure
12165  // prototype cycles are prevented.
12166  // It is sufficient to validate that the receiver is not in the new prototype
12167  // chain.
12168  for (Object* pt = *value;
12169       pt != heap->null_value();
12170       pt = pt->GetPrototype(isolate)) {
12171    if (JSReceiver::cast(pt) == *object) {
12172      // Cycle detected.
12173      Handle<Object> error = isolate->factory()->NewError(
12174          "cyclic_proto", HandleVector<Object>(NULL, 0));
12175      return isolate->Throw<Object>(error);
12176    }
12177  }
12178
12179  bool dictionary_elements_in_chain =
12180      object->map()->DictionaryElementsInPrototypeChainOnly();
12181  Handle<JSObject> real_receiver = object;
12182
12183  if (skip_hidden_prototypes) {
12184    // Find the first object in the chain whose prototype object is not
12185    // hidden and set the new prototype on that object.
12186    Object* current_proto = real_receiver->GetPrototype();
12187    while (current_proto->IsJSObject() &&
12188          JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
12189      real_receiver = handle(JSObject::cast(current_proto), isolate);
12190      current_proto = current_proto->GetPrototype(isolate);
12191    }
12192  }
12193
12194  // Set the new prototype of the object.
12195  Handle<Map> map(real_receiver->map());
12196
12197  // Nothing to do if prototype is already set.
12198  if (map->prototype() == *value) return value;
12199
12200  if (value->IsJSObject()) {
12201    JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
12202  }
12203
12204  Handle<Map> new_map = Map::TransitionToPrototype(map, value);
12205  ASSERT(new_map->prototype() == *value);
12206  JSObject::MigrateToMap(real_receiver, new_map);
12207
12208  if (!dictionary_elements_in_chain &&
12209      new_map->DictionaryElementsInPrototypeChainOnly()) {
12210    // If the prototype chain didn't previously have element callbacks, then
12211    // KeyedStoreICs need to be cleared to ensure any that involve this
12212    // map go generic.
12213    object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
12214  }
12215
12216  heap->ClearInstanceofCache();
12217  ASSERT(size == object->Size());
12218  return value;
12219}
12220
12221
12222void JSObject::EnsureCanContainElements(Handle<JSObject> object,
12223                                        Arguments* args,
12224                                        uint32_t first_arg,
12225                                        uint32_t arg_count,
12226                                        EnsureElementsMode mode) {
12227  // Elements in |Arguments| are ordered backwards (because they're on the
12228  // stack), but the method that's called here iterates over them in forward
12229  // direction.
12230  return EnsureCanContainElements(
12231      object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
12232}
12233
12234
12235MaybeHandle<AccessorPair> JSObject::GetOwnPropertyAccessorPair(
12236    Handle<JSObject> object,
12237    Handle<Name> name) {
12238  uint32_t index = 0;
12239  if (name->AsArrayIndex(&index)) {
12240    return GetOwnElementAccessorPair(object, index);
12241  }
12242
12243  Isolate* isolate = object->GetIsolate();
12244  LookupResult lookup(isolate);
12245  object->LookupOwnRealNamedProperty(name, &lookup);
12246
12247  if (lookup.IsPropertyCallbacks() &&
12248      lookup.GetCallbackObject()->IsAccessorPair()) {
12249    return handle(AccessorPair::cast(lookup.GetCallbackObject()), isolate);
12250  }
12251  return MaybeHandle<AccessorPair>();
12252}
12253
12254
12255MaybeHandle<AccessorPair> JSObject::GetOwnElementAccessorPair(
12256    Handle<JSObject> object,
12257    uint32_t index) {
12258  if (object->IsJSGlobalProxy()) {
12259    Handle<Object> proto(object->GetPrototype(), object->GetIsolate());
12260    if (proto->IsNull()) return MaybeHandle<AccessorPair>();
12261    ASSERT(proto->IsJSGlobalObject());
12262    return GetOwnElementAccessorPair(Handle<JSObject>::cast(proto), index);
12263  }
12264
12265  // Check for lookup interceptor.
12266  if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>();
12267
12268  return object->GetElementsAccessor()->GetAccessorPair(object, object, index);
12269}
12270
12271
12272MaybeHandle<Object> JSObject::SetElementWithInterceptor(
12273    Handle<JSObject> object,
12274    uint32_t index,
12275    Handle<Object> value,
12276    PropertyAttributes attributes,
12277    StrictMode strict_mode,
12278    bool check_prototype,
12279    SetPropertyMode set_mode) {
12280  Isolate* isolate = object->GetIsolate();
12281
12282  // Make sure that the top context does not change when doing
12283  // callbacks or interceptor calls.
12284  AssertNoContextChange ncc(isolate);
12285
12286  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
12287  if (!interceptor->setter()->IsUndefined()) {
12288    v8::IndexedPropertySetterCallback setter =
12289        v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
12290    LOG(isolate,
12291        ApiIndexedPropertyAccess("interceptor-indexed-set", *object, index));
12292    PropertyCallbackArguments args(isolate, interceptor->data(), *object,
12293                                   *object);
12294    v8::Handle<v8::Value> result =
12295        args.Call(setter, index, v8::Utils::ToLocal(value));
12296    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12297    if (!result.IsEmpty()) return value;
12298  }
12299
12300  return SetElementWithoutInterceptor(object, index, value, attributes,
12301                                      strict_mode,
12302                                      check_prototype,
12303                                      set_mode);
12304}
12305
12306
12307MaybeHandle<Object> JSObject::GetElementWithCallback(
12308    Handle<JSObject> object,
12309    Handle<Object> receiver,
12310    Handle<Object> structure,
12311    uint32_t index,
12312    Handle<Object> holder) {
12313  Isolate* isolate = object->GetIsolate();
12314  ASSERT(!structure->IsForeign());
12315  // api style callbacks.
12316  if (structure->IsExecutableAccessorInfo()) {
12317    Handle<ExecutableAccessorInfo> data =
12318        Handle<ExecutableAccessorInfo>::cast(structure);
12319    Object* fun_obj = data->getter();
12320    v8::AccessorGetterCallback call_fun =
12321        v8::ToCData<v8::AccessorGetterCallback>(fun_obj);
12322    if (call_fun == NULL) return isolate->factory()->undefined_value();
12323    Handle<JSObject> holder_handle = Handle<JSObject>::cast(holder);
12324    Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12325    Handle<String> key = isolate->factory()->NumberToString(number);
12326    LOG(isolate, ApiNamedPropertyAccess("load", *holder_handle, *key));
12327    PropertyCallbackArguments
12328        args(isolate, data->data(), *receiver, *holder_handle);
12329    v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key));
12330    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12331    if (result.IsEmpty()) return isolate->factory()->undefined_value();
12332    Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
12333    result_internal->VerifyApiCallResultType();
12334    // Rebox handle before return.
12335    return handle(*result_internal, isolate);
12336  }
12337
12338  // __defineGetter__ callback
12339  if (structure->IsAccessorPair()) {
12340    Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
12341                          isolate);
12342    if (getter->IsSpecFunction()) {
12343      // TODO(rossberg): nicer would be to cast to some JSCallable here...
12344      return GetPropertyWithDefinedGetter(
12345          receiver, Handle<JSReceiver>::cast(getter));
12346    }
12347    // Getter is not a function.
12348    return isolate->factory()->undefined_value();
12349  }
12350
12351  if (structure->IsDeclaredAccessorInfo()) {
12352    return GetDeclaredAccessorProperty(
12353        receiver, Handle<DeclaredAccessorInfo>::cast(structure), isolate);
12354  }
12355
12356  UNREACHABLE();
12357  return MaybeHandle<Object>();
12358}
12359
12360
12361MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object,
12362                                                     Handle<Object> structure,
12363                                                     uint32_t index,
12364                                                     Handle<Object> value,
12365                                                     Handle<JSObject> holder,
12366                                                     StrictMode strict_mode) {
12367  Isolate* isolate = object->GetIsolate();
12368
12369  // We should never get here to initialize a const with the hole
12370  // value since a const declaration would conflict with the setter.
12371  ASSERT(!value->IsTheHole());
12372  ASSERT(!structure->IsForeign());
12373  if (structure->IsExecutableAccessorInfo()) {
12374    // api style callbacks
12375    Handle<ExecutableAccessorInfo> data =
12376        Handle<ExecutableAccessorInfo>::cast(structure);
12377    Object* call_obj = data->setter();
12378    v8::AccessorSetterCallback call_fun =
12379        v8::ToCData<v8::AccessorSetterCallback>(call_obj);
12380    if (call_fun == NULL) return value;
12381    Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12382    Handle<String> key(isolate->factory()->NumberToString(number));
12383    LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
12384    PropertyCallbackArguments
12385        args(isolate, data->data(), *object, *holder);
12386    args.Call(call_fun,
12387              v8::Utils::ToLocal(key),
12388              v8::Utils::ToLocal(value));
12389    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12390    return value;
12391  }
12392
12393  if (structure->IsAccessorPair()) {
12394    Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
12395    if (setter->IsSpecFunction()) {
12396      // TODO(rossberg): nicer would be to cast to some JSCallable here...
12397      return SetPropertyWithDefinedSetter(
12398          object, Handle<JSReceiver>::cast(setter), value);
12399    } else {
12400      if (strict_mode == SLOPPY) return value;
12401      Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
12402      Handle<Object> args[2] = { key, holder };
12403      Handle<Object> error = isolate->factory()->NewTypeError(
12404          "no_setter_in_callback", HandleVector(args, 2));
12405      return isolate->Throw<Object>(error);
12406    }
12407  }
12408
12409  // TODO(dcarney): Handle correctly.
12410  if (structure->IsDeclaredAccessorInfo()) return value;
12411
12412  UNREACHABLE();
12413  return MaybeHandle<Object>();
12414}
12415
12416
12417bool JSObject::HasFastArgumentsElements() {
12418  Heap* heap = GetHeap();
12419  if (!elements()->IsFixedArray()) return false;
12420  FixedArray* elements = FixedArray::cast(this->elements());
12421  if (elements->map() != heap->sloppy_arguments_elements_map()) {
12422    return false;
12423  }
12424  FixedArray* arguments = FixedArray::cast(elements->get(1));
12425  return !arguments->IsDictionary();
12426}
12427
12428
12429bool JSObject::HasDictionaryArgumentsElements() {
12430  Heap* heap = GetHeap();
12431  if (!elements()->IsFixedArray()) return false;
12432  FixedArray* elements = FixedArray::cast(this->elements());
12433  if (elements->map() != heap->sloppy_arguments_elements_map()) {
12434    return false;
12435  }
12436  FixedArray* arguments = FixedArray::cast(elements->get(1));
12437  return arguments->IsDictionary();
12438}
12439
12440
12441// Adding n elements in fast case is O(n*n).
12442// Note: revisit design to have dual undefined values to capture absent
12443// elements.
12444MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
12445                                             uint32_t index,
12446                                             Handle<Object> value,
12447                                             StrictMode strict_mode,
12448                                             bool check_prototype) {
12449  ASSERT(object->HasFastSmiOrObjectElements() ||
12450         object->HasFastArgumentsElements());
12451
12452  Isolate* isolate = object->GetIsolate();
12453
12454  // Array optimizations rely on the prototype lookups of Array objects always
12455  // returning undefined. If there is a store to the initial prototype object,
12456  // make sure all of these optimizations are invalidated.
12457  if (isolate->is_initial_object_prototype(*object) ||
12458      isolate->is_initial_array_prototype(*object)) {
12459    object->map()->dependent_code()->DeoptimizeDependentCodeGroup(isolate,
12460        DependentCode::kElementsCantBeAddedGroup);
12461  }
12462
12463  Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
12464  if (backing_store->map() ==
12465      isolate->heap()->sloppy_arguments_elements_map()) {
12466    backing_store = handle(FixedArray::cast(backing_store->get(1)));
12467  } else {
12468    backing_store = EnsureWritableFastElements(object);
12469  }
12470  uint32_t capacity = static_cast<uint32_t>(backing_store->length());
12471
12472  if (check_prototype &&
12473      (index >= capacity || backing_store->get(index)->IsTheHole())) {
12474    bool found;
12475    MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12476        object, index, value, &found, strict_mode);
12477    if (found) return result;
12478  }
12479
12480  uint32_t new_capacity = capacity;
12481  // Check if the length property of this object needs to be updated.
12482  uint32_t array_length = 0;
12483  bool must_update_array_length = false;
12484  bool introduces_holes = true;
12485  if (object->IsJSArray()) {
12486    CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
12487    introduces_holes = index > array_length;
12488    if (index >= array_length) {
12489      must_update_array_length = true;
12490      array_length = index + 1;
12491    }
12492  } else {
12493    introduces_holes = index >= capacity;
12494  }
12495
12496  // If the array is growing, and it's not growth by a single element at the
12497  // end, make sure that the ElementsKind is HOLEY.
12498  ElementsKind elements_kind = object->GetElementsKind();
12499  if (introduces_holes &&
12500      IsFastElementsKind(elements_kind) &&
12501      !IsFastHoleyElementsKind(elements_kind)) {
12502    ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12503    TransitionElementsKind(object, transitioned_kind);
12504  }
12505
12506  // Check if the capacity of the backing store needs to be increased, or if
12507  // a transition to slow elements is necessary.
12508  if (index >= capacity) {
12509    bool convert_to_slow = true;
12510    if ((index - capacity) < kMaxGap) {
12511      new_capacity = NewElementsCapacity(index + 1);
12512      ASSERT(new_capacity > index);
12513      if (!object->ShouldConvertToSlowElements(new_capacity)) {
12514        convert_to_slow = false;
12515      }
12516    }
12517    if (convert_to_slow) {
12518      NormalizeElements(object);
12519      return SetDictionaryElement(object, index, value, NONE, strict_mode,
12520                                  check_prototype);
12521    }
12522  }
12523  // Convert to fast double elements if appropriate.
12524  if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
12525    // Consider fixing the boilerplate as well if we have one.
12526    ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
12527        ? FAST_HOLEY_DOUBLE_ELEMENTS
12528        : FAST_DOUBLE_ELEMENTS;
12529
12530    UpdateAllocationSite(object, to_kind);
12531
12532    SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length);
12533    FixedDoubleArray::cast(object->elements())->set(index, value->Number());
12534    JSObject::ValidateElements(object);
12535    return value;
12536  }
12537  // Change elements kind from Smi-only to generic FAST if necessary.
12538  if (object->HasFastSmiElements() && !value->IsSmi()) {
12539    ElementsKind kind = object->HasFastHoleyElements()
12540        ? FAST_HOLEY_ELEMENTS
12541        : FAST_ELEMENTS;
12542
12543    UpdateAllocationSite(object, kind);
12544    Handle<Map> new_map = GetElementsTransitionMap(object, kind);
12545    JSObject::MigrateToMap(object, new_map);
12546    ASSERT(IsFastObjectElementsKind(object->GetElementsKind()));
12547  }
12548  // Increase backing store capacity if that's been decided previously.
12549  if (new_capacity != capacity) {
12550    SetFastElementsCapacitySmiMode smi_mode =
12551        value->IsSmi() && object->HasFastSmiElements()
12552            ? kAllowSmiElements
12553            : kDontAllowSmiElements;
12554    Handle<FixedArray> new_elements =
12555        SetFastElementsCapacityAndLength(object, new_capacity, array_length,
12556                                         smi_mode);
12557    new_elements->set(index, *value);
12558    JSObject::ValidateElements(object);
12559    return value;
12560  }
12561
12562  // Finally, set the new element and length.
12563  ASSERT(object->elements()->IsFixedArray());
12564  backing_store->set(index, *value);
12565  if (must_update_array_length) {
12566    Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
12567  }
12568  return value;
12569}
12570
12571
12572MaybeHandle<Object> JSObject::SetDictionaryElement(
12573    Handle<JSObject> object,
12574    uint32_t index,
12575    Handle<Object> value,
12576    PropertyAttributes attributes,
12577    StrictMode strict_mode,
12578    bool check_prototype,
12579    SetPropertyMode set_mode) {
12580  ASSERT(object->HasDictionaryElements() ||
12581         object->HasDictionaryArgumentsElements());
12582  Isolate* isolate = object->GetIsolate();
12583
12584  // Insert element in the dictionary.
12585  Handle<FixedArray> elements(FixedArray::cast(object->elements()));
12586  bool is_arguments =
12587      (elements->map() == isolate->heap()->sloppy_arguments_elements_map());
12588  Handle<SeededNumberDictionary> dictionary(is_arguments
12589    ? SeededNumberDictionary::cast(elements->get(1))
12590    : SeededNumberDictionary::cast(*elements));
12591
12592  int entry = dictionary->FindEntry(index);
12593  if (entry != SeededNumberDictionary::kNotFound) {
12594    Handle<Object> element(dictionary->ValueAt(entry), isolate);
12595    PropertyDetails details = dictionary->DetailsAt(entry);
12596    if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
12597      return SetElementWithCallback(object, element, index, value, object,
12598                                    strict_mode);
12599    } else {
12600      dictionary->UpdateMaxNumberKey(index);
12601      // If a value has not been initialized we allow writing to it even if it
12602      // is read-only (a declared const that has not been initialized).  If a
12603      // value is being defined we skip attribute checks completely.
12604      if (set_mode == DEFINE_PROPERTY) {
12605        details = PropertyDetails(
12606            attributes, NORMAL, details.dictionary_index());
12607        dictionary->DetailsAtPut(entry, details);
12608      } else if (details.IsReadOnly() && !element->IsTheHole()) {
12609        if (strict_mode == SLOPPY) {
12610          return isolate->factory()->undefined_value();
12611        } else {
12612          Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12613          Handle<Object> args[2] = { number, object };
12614          Handle<Object> error =
12615              isolate->factory()->NewTypeError("strict_read_only_property",
12616                                               HandleVector(args, 2));
12617          return isolate->Throw<Object>(error);
12618        }
12619      }
12620      // Elements of the arguments object in slow mode might be slow aliases.
12621      if (is_arguments && element->IsAliasedArgumentsEntry()) {
12622        Handle<AliasedArgumentsEntry> entry =
12623            Handle<AliasedArgumentsEntry>::cast(element);
12624        Handle<Context> context(Context::cast(elements->get(0)));
12625        int context_index = entry->aliased_context_slot();
12626        ASSERT(!context->get(context_index)->IsTheHole());
12627        context->set(context_index, *value);
12628        // For elements that are still writable we keep slow aliasing.
12629        if (!details.IsReadOnly()) value = element;
12630      }
12631      dictionary->ValueAtPut(entry, *value);
12632    }
12633  } else {
12634    // Index not already used. Look for an accessor in the prototype chain.
12635    // Can cause GC!
12636    if (check_prototype) {
12637      bool found;
12638      MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12639          object, index, value, &found, strict_mode);
12640      if (found) return result;
12641    }
12642
12643    // When we set the is_extensible flag to false we always force the
12644    // element into dictionary mode (and force them to stay there).
12645    if (!object->map()->is_extensible()) {
12646      if (strict_mode == SLOPPY) {
12647        return isolate->factory()->undefined_value();
12648      } else {
12649        Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12650        Handle<String> name = isolate->factory()->NumberToString(number);
12651        Handle<Object> args[1] = { name };
12652        Handle<Object> error =
12653            isolate->factory()->NewTypeError("object_not_extensible",
12654                                             HandleVector(args, 1));
12655        return isolate->Throw<Object>(error);
12656      }
12657    }
12658
12659    PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
12660    Handle<SeededNumberDictionary> new_dictionary =
12661        SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
12662                                               details);
12663    if (*dictionary != *new_dictionary) {
12664      if (is_arguments) {
12665        elements->set(1, *new_dictionary);
12666      } else {
12667        object->set_elements(*new_dictionary);
12668      }
12669      dictionary = new_dictionary;
12670    }
12671  }
12672
12673  // Update the array length if this JSObject is an array.
12674  if (object->IsJSArray()) {
12675    JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index,
12676                                          value);
12677  }
12678
12679  // Attempt to put this object back in fast case.
12680  if (object->ShouldConvertToFastElements()) {
12681    uint32_t new_length = 0;
12682    if (object->IsJSArray()) {
12683      CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&new_length));
12684    } else {
12685      new_length = dictionary->max_number_key() + 1;
12686    }
12687    SetFastElementsCapacitySmiMode smi_mode = FLAG_smi_only_arrays
12688        ? kAllowSmiElements
12689        : kDontAllowSmiElements;
12690    bool has_smi_only_elements = false;
12691    bool should_convert_to_fast_double_elements =
12692        object->ShouldConvertToFastDoubleElements(&has_smi_only_elements);
12693    if (has_smi_only_elements) {
12694      smi_mode = kForceSmiElements;
12695    }
12696
12697    if (should_convert_to_fast_double_elements) {
12698      SetFastDoubleElementsCapacityAndLength(object, new_length, new_length);
12699    } else {
12700      SetFastElementsCapacityAndLength(object, new_length, new_length,
12701                                       smi_mode);
12702    }
12703    JSObject::ValidateElements(object);
12704#ifdef DEBUG
12705    if (FLAG_trace_normalization) {
12706      PrintF("Object elements are fast case again:\n");
12707      object->Print();
12708    }
12709#endif
12710  }
12711  return value;
12712}
12713
12714MaybeHandle<Object> JSObject::SetFastDoubleElement(
12715    Handle<JSObject> object,
12716    uint32_t index,
12717    Handle<Object> value,
12718    StrictMode strict_mode,
12719    bool check_prototype) {
12720  ASSERT(object->HasFastDoubleElements());
12721
12722  Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
12723  uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
12724
12725  // If storing to an element that isn't in the array, pass the store request
12726  // up the prototype chain before storing in the receiver's elements.
12727  if (check_prototype &&
12728      (index >= elms_length ||
12729       Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) {
12730    bool found;
12731    MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12732        object, index, value, &found, strict_mode);
12733    if (found) return result;
12734  }
12735
12736  // If the value object is not a heap number, switch to fast elements and try
12737  // again.
12738  bool value_is_smi = value->IsSmi();
12739  bool introduces_holes = true;
12740  uint32_t length = elms_length;
12741  if (object->IsJSArray()) {
12742    CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&length));
12743    introduces_holes = index > length;
12744  } else {
12745    introduces_holes = index >= elms_length;
12746  }
12747
12748  if (!value->IsNumber()) {
12749    SetFastElementsCapacityAndLength(object, elms_length, length,
12750                                     kDontAllowSmiElements);
12751    Handle<Object> result;
12752    ASSIGN_RETURN_ON_EXCEPTION(
12753        object->GetIsolate(), result,
12754        SetFastElement(object, index, value, strict_mode, check_prototype),
12755        Object);
12756    JSObject::ValidateElements(object);
12757    return result;
12758  }
12759
12760  double double_value = value_is_smi
12761      ? static_cast<double>(Handle<Smi>::cast(value)->value())
12762      : Handle<HeapNumber>::cast(value)->value();
12763
12764  // If the array is growing, and it's not growth by a single element at the
12765  // end, make sure that the ElementsKind is HOLEY.
12766  ElementsKind elements_kind = object->GetElementsKind();
12767  if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
12768    ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12769    TransitionElementsKind(object, transitioned_kind);
12770  }
12771
12772  // Check whether there is extra space in the fixed array.
12773  if (index < elms_length) {
12774    Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements()));
12775    elms->set(index, double_value);
12776    if (object->IsJSArray()) {
12777      // Update the length of the array if needed.
12778      uint32_t array_length = 0;
12779      CHECK(
12780          Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
12781      if (index >= array_length) {
12782        Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1));
12783      }
12784    }
12785    return value;
12786  }
12787
12788  // Allow gap in fast case.
12789  if ((index - elms_length) < kMaxGap) {
12790    // Try allocating extra space.
12791    int new_capacity = NewElementsCapacity(index+1);
12792    if (!object->ShouldConvertToSlowElements(new_capacity)) {
12793      ASSERT(static_cast<uint32_t>(new_capacity) > index);
12794      SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1);
12795      FixedDoubleArray::cast(object->elements())->set(index, double_value);
12796      JSObject::ValidateElements(object);
12797      return value;
12798    }
12799  }
12800
12801  // Otherwise default to slow case.
12802  ASSERT(object->HasFastDoubleElements());
12803  ASSERT(object->map()->has_fast_double_elements());
12804  ASSERT(object->elements()->IsFixedDoubleArray() ||
12805         object->elements()->length() == 0);
12806
12807  NormalizeElements(object);
12808  ASSERT(object->HasDictionaryElements());
12809  return SetElement(object, index, value, NONE, strict_mode, check_prototype);
12810}
12811
12812
12813MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
12814                                           uint32_t index,
12815                                           Handle<Object> value,
12816                                           PropertyAttributes attributes,
12817                                           StrictMode strict_mode) {
12818  if (object->IsJSProxy()) {
12819    return JSProxy::SetElementWithHandler(
12820        Handle<JSProxy>::cast(object), object, index, value, strict_mode);
12821  }
12822  return JSObject::SetElement(
12823      Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
12824}
12825
12826
12827MaybeHandle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
12828                                            uint32_t index,
12829                                            Handle<Object> value,
12830                                            StrictMode strict_mode) {
12831  ASSERT(!object->HasExternalArrayElements());
12832  return JSObject::SetElement(object, index, value, NONE, strict_mode, false);
12833}
12834
12835
12836MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
12837                                         uint32_t index,
12838                                         Handle<Object> value,
12839                                         PropertyAttributes attributes,
12840                                         StrictMode strict_mode,
12841                                         bool check_prototype,
12842                                         SetPropertyMode set_mode) {
12843  Isolate* isolate = object->GetIsolate();
12844
12845  if (object->HasExternalArrayElements() ||
12846      object->HasFixedTypedArrayElements()) {
12847    if (!value->IsNumber() && !value->IsUndefined()) {
12848      ASSIGN_RETURN_ON_EXCEPTION(
12849          isolate, value,
12850          Execution::ToNumber(isolate, value), Object);
12851    }
12852  }
12853
12854  // Check access rights if needed.
12855  if (object->IsAccessCheckNeeded()) {
12856    if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_SET)) {
12857      isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
12858      RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12859      return value;
12860    }
12861  }
12862
12863  if (object->IsJSGlobalProxy()) {
12864    Handle<Object> proto(object->GetPrototype(), isolate);
12865    if (proto->IsNull()) return value;
12866    ASSERT(proto->IsJSGlobalObject());
12867    return SetElement(Handle<JSObject>::cast(proto), index, value, attributes,
12868                      strict_mode,
12869                      check_prototype,
12870                      set_mode);
12871  }
12872
12873  // Don't allow element properties to be redefined for external arrays.
12874  if ((object->HasExternalArrayElements() ||
12875          object->HasFixedTypedArrayElements()) &&
12876      set_mode == DEFINE_PROPERTY) {
12877    Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12878    Handle<Object> args[] = { object, number };
12879    Handle<Object> error = isolate->factory()->NewTypeError(
12880        "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
12881    return isolate->Throw<Object>(error);
12882  }
12883
12884  // Normalize the elements to enable attributes on the property.
12885  if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
12886    Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
12887    // Make sure that we never go back to fast case.
12888    dictionary->set_requires_slow_elements();
12889  }
12890
12891  if (!object->map()->is_observed()) {
12892    return object->HasIndexedInterceptor()
12893      ? SetElementWithInterceptor(object, index, value, attributes,
12894                                  strict_mode, check_prototype, set_mode)
12895      : SetElementWithoutInterceptor(object, index, value, attributes,
12896                                     strict_mode, check_prototype, set_mode);
12897  }
12898
12899  PropertyAttributes old_attributes =
12900      JSReceiver::GetOwnElementAttribute(object, index);
12901  Handle<Object> old_value = isolate->factory()->the_hole_value();
12902  Handle<Object> old_length_handle;
12903  Handle<Object> new_length_handle;
12904
12905  if (old_attributes != ABSENT) {
12906    if (GetOwnElementAccessorPair(object, index).is_null()) {
12907      old_value = Object::GetElement(isolate, object, index).ToHandleChecked();
12908    }
12909  } else if (object->IsJSArray()) {
12910    // Store old array length in case adding an element grows the array.
12911    old_length_handle = handle(Handle<JSArray>::cast(object)->length(),
12912                               isolate);
12913  }
12914
12915  // Check for lookup interceptor
12916  Handle<Object> result;
12917  ASSIGN_RETURN_ON_EXCEPTION(
12918      isolate, result,
12919      object->HasIndexedInterceptor()
12920          ? SetElementWithInterceptor(
12921              object, index, value, attributes,
12922              strict_mode, check_prototype, set_mode)
12923          : SetElementWithoutInterceptor(
12924              object, index, value, attributes,
12925              strict_mode, check_prototype, set_mode),
12926      Object);
12927
12928  Handle<String> name = isolate->factory()->Uint32ToString(index);
12929  PropertyAttributes new_attributes = GetOwnElementAttribute(object, index);
12930  if (old_attributes == ABSENT) {
12931    if (object->IsJSArray() &&
12932        !old_length_handle->SameValue(
12933            Handle<JSArray>::cast(object)->length())) {
12934      new_length_handle = handle(Handle<JSArray>::cast(object)->length(),
12935                                 isolate);
12936      uint32_t old_length = 0;
12937      uint32_t new_length = 0;
12938      CHECK(old_length_handle->ToArrayIndex(&old_length));
12939      CHECK(new_length_handle->ToArrayIndex(&new_length));
12940
12941      BeginPerformSplice(Handle<JSArray>::cast(object));
12942      EnqueueChangeRecord(object, "add", name, old_value);
12943      EnqueueChangeRecord(object, "update", isolate->factory()->length_string(),
12944                          old_length_handle);
12945      EndPerformSplice(Handle<JSArray>::cast(object));
12946      Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
12947      EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, deleted,
12948                          new_length - old_length);
12949    } else {
12950      EnqueueChangeRecord(object, "add", name, old_value);
12951    }
12952  } else if (old_value->IsTheHole()) {
12953    EnqueueChangeRecord(object, "reconfigure", name, old_value);
12954  } else {
12955    Handle<Object> new_value =
12956        Object::GetElement(isolate, object, index).ToHandleChecked();
12957    bool value_changed = !old_value->SameValue(*new_value);
12958    if (old_attributes != new_attributes) {
12959      if (!value_changed) old_value = isolate->factory()->the_hole_value();
12960      EnqueueChangeRecord(object, "reconfigure", name, old_value);
12961    } else if (value_changed) {
12962      EnqueueChangeRecord(object, "update", name, old_value);
12963    }
12964  }
12965
12966  return result;
12967}
12968
12969
12970MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
12971    Handle<JSObject> object,
12972    uint32_t index,
12973    Handle<Object> value,
12974    PropertyAttributes attributes,
12975    StrictMode strict_mode,
12976    bool check_prototype,
12977    SetPropertyMode set_mode) {
12978  ASSERT(object->HasDictionaryElements() ||
12979         object->HasDictionaryArgumentsElements() ||
12980         (attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
12981  Isolate* isolate = object->GetIsolate();
12982  if (FLAG_trace_external_array_abuse &&
12983      IsExternalArrayElementsKind(object->GetElementsKind())) {
12984    CheckArrayAbuse(object, "external elements write", index);
12985  }
12986  if (FLAG_trace_js_array_abuse &&
12987      !IsExternalArrayElementsKind(object->GetElementsKind())) {
12988    if (object->IsJSArray()) {
12989      CheckArrayAbuse(object, "elements write", index, true);
12990    }
12991  }
12992  if (object->IsJSArray() && JSArray::WouldChangeReadOnlyLength(
12993      Handle<JSArray>::cast(object), index)) {
12994    if (strict_mode == SLOPPY) {
12995      return value;
12996    } else {
12997      return JSArray::ReadOnlyLengthError(Handle<JSArray>::cast(object));
12998    }
12999  }
13000  switch (object->GetElementsKind()) {
13001    case FAST_SMI_ELEMENTS:
13002    case FAST_ELEMENTS:
13003    case FAST_HOLEY_SMI_ELEMENTS:
13004    case FAST_HOLEY_ELEMENTS:
13005      return SetFastElement(object, index, value, strict_mode, check_prototype);
13006    case FAST_DOUBLE_ELEMENTS:
13007    case FAST_HOLEY_DOUBLE_ELEMENTS:
13008      return SetFastDoubleElement(object, index, value, strict_mode,
13009                                  check_prototype);
13010
13011#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
13012    case EXTERNAL_##TYPE##_ELEMENTS: {                                        \
13013      Handle<External##Type##Array> array(                                    \
13014          External##Type##Array::cast(object->elements()));                   \
13015      return External##Type##Array::SetValue(array, index, value);            \
13016    }                                                                         \
13017    case TYPE##_ELEMENTS: {                                                   \
13018      Handle<Fixed##Type##Array> array(                                       \
13019          Fixed##Type##Array::cast(object->elements()));                      \
13020      return Fixed##Type##Array::SetValue(array, index, value);               \
13021    }
13022
13023    TYPED_ARRAYS(TYPED_ARRAY_CASE)
13024
13025#undef TYPED_ARRAY_CASE
13026
13027    case DICTIONARY_ELEMENTS:
13028      return SetDictionaryElement(object, index, value, attributes, strict_mode,
13029                                  check_prototype,
13030                                  set_mode);
13031    case SLOPPY_ARGUMENTS_ELEMENTS: {
13032      Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
13033      uint32_t length = parameter_map->length();
13034      Handle<Object> probe = index < length - 2 ?
13035          Handle<Object>(parameter_map->get(index + 2), isolate) :
13036          Handle<Object>();
13037      if (!probe.is_null() && !probe->IsTheHole()) {
13038        Handle<Context> context(Context::cast(parameter_map->get(0)));
13039        int context_index = Handle<Smi>::cast(probe)->value();
13040        ASSERT(!context->get(context_index)->IsTheHole());
13041        context->set(context_index, *value);
13042        // Redefining attributes of an aliased element destroys fast aliasing.
13043        if (set_mode == SET_PROPERTY || attributes == NONE) return value;
13044        parameter_map->set_the_hole(index + 2);
13045        // For elements that are still writable we re-establish slow aliasing.
13046        if ((attributes & READ_ONLY) == 0) {
13047          value = Handle<Object>::cast(
13048              isolate->factory()->NewAliasedArgumentsEntry(context_index));
13049        }
13050      }
13051      Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
13052      if (arguments->IsDictionary()) {
13053        return SetDictionaryElement(object, index, value, attributes,
13054                                    strict_mode,
13055                                    check_prototype,
13056                                    set_mode);
13057      } else {
13058        return SetFastElement(object, index, value, strict_mode,
13059                              check_prototype);
13060      }
13061    }
13062  }
13063  // All possible cases have been handled above. Add a return to avoid the
13064  // complaints from the compiler.
13065  UNREACHABLE();
13066  return isolate->factory()->null_value();
13067}
13068
13069
13070const double AllocationSite::kPretenureRatio = 0.85;
13071
13072
13073void AllocationSite::ResetPretenureDecision() {
13074  set_pretenure_decision(kUndecided);
13075  set_memento_found_count(0);
13076  set_memento_create_count(0);
13077}
13078
13079
13080PretenureFlag AllocationSite::GetPretenureMode() {
13081  PretenureDecision mode = pretenure_decision();
13082  // Zombie objects "decide" to be untenured.
13083  return mode == kTenure ? TENURED : NOT_TENURED;
13084}
13085
13086
13087bool AllocationSite::IsNestedSite() {
13088  ASSERT(FLAG_trace_track_allocation_sites);
13089  Object* current = GetHeap()->allocation_sites_list();
13090  while (current->IsAllocationSite()) {
13091    AllocationSite* current_site = AllocationSite::cast(current);
13092    if (current_site->nested_site() == this) {
13093      return true;
13094    }
13095    current = current_site->weak_next();
13096  }
13097  return false;
13098}
13099
13100
13101void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
13102                                              ElementsKind to_kind) {
13103  Isolate* isolate = site->GetIsolate();
13104
13105  if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
13106    Handle<JSArray> transition_info =
13107        handle(JSArray::cast(site->transition_info()));
13108    ElementsKind kind = transition_info->GetElementsKind();
13109    // if kind is holey ensure that to_kind is as well.
13110    if (IsHoleyElementsKind(kind)) {
13111      to_kind = GetHoleyElementsKind(to_kind);
13112    }
13113    if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
13114      // If the array is huge, it's not likely to be defined in a local
13115      // function, so we shouldn't make new instances of it very often.
13116      uint32_t length = 0;
13117      CHECK(transition_info->length()->ToArrayIndex(&length));
13118      if (length <= kMaximumArrayBytesToPretransition) {
13119        if (FLAG_trace_track_allocation_sites) {
13120          bool is_nested = site->IsNestedSite();
13121          PrintF(
13122              "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
13123              reinterpret_cast<void*>(*site),
13124              is_nested ? "(nested)" : "",
13125              ElementsKindToString(kind),
13126              ElementsKindToString(to_kind));
13127        }
13128        JSObject::TransitionElementsKind(transition_info, to_kind);
13129        site->dependent_code()->DeoptimizeDependentCodeGroup(
13130            isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
13131      }
13132    }
13133  } else {
13134    ElementsKind kind = site->GetElementsKind();
13135    // if kind is holey ensure that to_kind is as well.
13136    if (IsHoleyElementsKind(kind)) {
13137      to_kind = GetHoleyElementsKind(to_kind);
13138    }
13139    if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
13140      if (FLAG_trace_track_allocation_sites) {
13141        PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
13142               reinterpret_cast<void*>(*site),
13143               ElementsKindToString(kind),
13144               ElementsKindToString(to_kind));
13145      }
13146      site->SetElementsKind(to_kind);
13147      site->dependent_code()->DeoptimizeDependentCodeGroup(
13148          isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
13149    }
13150  }
13151}
13152
13153
13154// static
13155void AllocationSite::AddDependentCompilationInfo(Handle<AllocationSite> site,
13156                                                 Reason reason,
13157                                                 CompilationInfo* info) {
13158  DependentCode::DependencyGroup group = site->ToDependencyGroup(reason);
13159  Handle<DependentCode> dep(site->dependent_code());
13160  Handle<DependentCode> codes =
13161      DependentCode::Insert(dep, group, info->object_wrapper());
13162  if (*codes != site->dependent_code()) site->set_dependent_code(*codes);
13163  info->dependencies(group)->Add(Handle<HeapObject>(*site), info->zone());
13164}
13165
13166
13167const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
13168  switch (decision) {
13169    case kUndecided: return "undecided";
13170    case kDontTenure: return "don't tenure";
13171    case kMaybeTenure: return "maybe tenure";
13172    case kTenure: return "tenure";
13173    case kZombie: return "zombie";
13174    default: UNREACHABLE();
13175  }
13176  return NULL;
13177}
13178
13179
13180void JSObject::UpdateAllocationSite(Handle<JSObject> object,
13181                                    ElementsKind to_kind) {
13182  if (!object->IsJSArray()) return;
13183
13184  Heap* heap = object->GetHeap();
13185  if (!heap->InNewSpace(*object)) return;
13186
13187  Handle<AllocationSite> site;
13188  {
13189    DisallowHeapAllocation no_allocation;
13190
13191    AllocationMemento* memento = heap->FindAllocationMemento(*object);
13192    if (memento == NULL) return;
13193
13194    // Walk through to the Allocation Site
13195    site = handle(memento->GetAllocationSite());
13196  }
13197  AllocationSite::DigestTransitionFeedback(site, to_kind);
13198}
13199
13200
13201void JSObject::TransitionElementsKind(Handle<JSObject> object,
13202                                      ElementsKind to_kind) {
13203  ElementsKind from_kind = object->map()->elements_kind();
13204
13205  if (IsFastHoleyElementsKind(from_kind)) {
13206    to_kind = GetHoleyElementsKind(to_kind);
13207  }
13208
13209  if (from_kind == to_kind) return;
13210  // Don't update the site if to_kind isn't fast
13211  if (IsFastElementsKind(to_kind)) {
13212    UpdateAllocationSite(object, to_kind);
13213  }
13214
13215  Isolate* isolate = object->GetIsolate();
13216  if (object->elements() == isolate->heap()->empty_fixed_array() ||
13217      (IsFastSmiOrObjectElementsKind(from_kind) &&
13218       IsFastSmiOrObjectElementsKind(to_kind)) ||
13219      (from_kind == FAST_DOUBLE_ELEMENTS &&
13220       to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
13221    ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
13222    // No change is needed to the elements() buffer, the transition
13223    // only requires a map change.
13224    Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
13225    MigrateToMap(object, new_map);
13226    if (FLAG_trace_elements_transitions) {
13227      Handle<FixedArrayBase> elms(object->elements());
13228      PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
13229    }
13230    return;
13231  }
13232
13233  Handle<FixedArrayBase> elms(object->elements());
13234  uint32_t capacity = static_cast<uint32_t>(elms->length());
13235  uint32_t length = capacity;
13236
13237  if (object->IsJSArray()) {
13238    Object* raw_length = Handle<JSArray>::cast(object)->length();
13239    if (raw_length->IsUndefined()) {
13240      // If length is undefined, then JSArray is being initialized and has no
13241      // elements, assume a length of zero.
13242      length = 0;
13243    } else {
13244      CHECK(raw_length->ToArrayIndex(&length));
13245    }
13246  }
13247
13248  if (IsFastSmiElementsKind(from_kind) &&
13249      IsFastDoubleElementsKind(to_kind)) {
13250    SetFastDoubleElementsCapacityAndLength(object, capacity, length);
13251    JSObject::ValidateElements(object);
13252    return;
13253  }
13254
13255  if (IsFastDoubleElementsKind(from_kind) &&
13256      IsFastObjectElementsKind(to_kind)) {
13257    SetFastElementsCapacityAndLength(object, capacity, length,
13258                                     kDontAllowSmiElements);
13259    JSObject::ValidateElements(object);
13260    return;
13261  }
13262
13263  // This method should never be called for any other case than the ones
13264  // handled above.
13265  UNREACHABLE();
13266}
13267
13268
13269// static
13270bool Map::IsValidElementsTransition(ElementsKind from_kind,
13271                                    ElementsKind to_kind) {
13272  // Transitions can't go backwards.
13273  if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
13274    return false;
13275  }
13276
13277  // Transitions from HOLEY -> PACKED are not allowed.
13278  return !IsFastHoleyElementsKind(from_kind) ||
13279      IsFastHoleyElementsKind(to_kind);
13280}
13281
13282
13283void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
13284                                           uint32_t index,
13285                                           Handle<Object> value) {
13286  uint32_t old_len = 0;
13287  CHECK(array->length()->ToArrayIndex(&old_len));
13288  // Check to see if we need to update the length. For now, we make
13289  // sure that the length stays within 32-bits (unsigned).
13290  if (index >= old_len && index != 0xffffffff) {
13291    Handle<Object> len = array->GetIsolate()->factory()->NewNumber(
13292        static_cast<double>(index) + 1);
13293    array->set_length(*len);
13294  }
13295}
13296
13297
13298bool JSArray::IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
13299    Isolate* isolate = jsarray_map->GetIsolate();
13300    ASSERT(!jsarray_map->is_dictionary_map());
13301    LookupResult lookup(isolate);
13302    Handle<Name> length_string = isolate->factory()->length_string();
13303    jsarray_map->LookupDescriptor(NULL, *length_string, &lookup);
13304    return lookup.IsReadOnly();
13305}
13306
13307
13308bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
13309                                        uint32_t index) {
13310  uint32_t length = 0;
13311  CHECK(array->length()->ToArrayIndex(&length));
13312  if (length <= index) {
13313    Isolate* isolate = array->GetIsolate();
13314    LookupResult lookup(isolate);
13315    Handle<Name> length_string = isolate->factory()->length_string();
13316    array->LookupOwnRealNamedProperty(length_string, &lookup);
13317    return lookup.IsReadOnly();
13318  }
13319  return false;
13320}
13321
13322
13323MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) {
13324  Isolate* isolate = array->GetIsolate();
13325  Handle<Name> length = isolate->factory()->length_string();
13326  Handle<Object> args[2] = { length, array };
13327  Handle<Object> error = isolate->factory()->NewTypeError(
13328      "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
13329  return isolate->Throw<Object>(error);
13330}
13331
13332
13333MaybeHandle<Object> JSObject::GetElementWithInterceptor(
13334    Handle<JSObject> object,
13335    Handle<Object> receiver,
13336    uint32_t index) {
13337  Isolate* isolate = object->GetIsolate();
13338
13339  // Make sure that the top context does not change when doing
13340  // callbacks or interceptor calls.
13341  AssertNoContextChange ncc(isolate);
13342
13343  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate);
13344  if (!interceptor->getter()->IsUndefined()) {
13345    v8::IndexedPropertyGetterCallback getter =
13346        v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
13347    LOG(isolate,
13348        ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index));
13349    PropertyCallbackArguments
13350        args(isolate, interceptor->data(), *receiver, *object);
13351    v8::Handle<v8::Value> result = args.Call(getter, index);
13352    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
13353    if (!result.IsEmpty()) {
13354      Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13355      result_internal->VerifyApiCallResultType();
13356      // Rebox handle before return.
13357      return handle(*result_internal, isolate);
13358    }
13359  }
13360
13361  ElementsAccessor* handler = object->GetElementsAccessor();
13362  Handle<Object> result;
13363  ASSIGN_RETURN_ON_EXCEPTION(
13364      isolate, result, handler->Get(receiver,  object, index),
13365      Object);
13366  if (!result->IsTheHole()) return result;
13367
13368  Handle<Object> proto(object->GetPrototype(), isolate);
13369  if (proto->IsNull()) return isolate->factory()->undefined_value();
13370  return Object::GetElementWithReceiver(isolate, proto, receiver, index);
13371}
13372
13373
13374bool JSObject::HasDenseElements() {
13375  int capacity = 0;
13376  int used = 0;
13377  GetElementsCapacityAndUsage(&capacity, &used);
13378  return (capacity == 0) || (used > (capacity / 2));
13379}
13380
13381
13382void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
13383  *capacity = 0;
13384  *used = 0;
13385
13386  FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
13387  FixedArray* backing_store = NULL;
13388  switch (GetElementsKind()) {
13389    case SLOPPY_ARGUMENTS_ELEMENTS:
13390      backing_store_base =
13391          FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
13392      backing_store = FixedArray::cast(backing_store_base);
13393      if (backing_store->IsDictionary()) {
13394        SeededNumberDictionary* dictionary =
13395            SeededNumberDictionary::cast(backing_store);
13396        *capacity = dictionary->Capacity();
13397        *used = dictionary->NumberOfElements();
13398        break;
13399      }
13400      // Fall through.
13401    case FAST_SMI_ELEMENTS:
13402    case FAST_ELEMENTS:
13403      if (IsJSArray()) {
13404        *capacity = backing_store_base->length();
13405        *used = Smi::cast(JSArray::cast(this)->length())->value();
13406        break;
13407      }
13408      // Fall through if packing is not guaranteed.
13409    case FAST_HOLEY_SMI_ELEMENTS:
13410    case FAST_HOLEY_ELEMENTS:
13411      backing_store = FixedArray::cast(backing_store_base);
13412      *capacity = backing_store->length();
13413      for (int i = 0; i < *capacity; ++i) {
13414        if (!backing_store->get(i)->IsTheHole()) ++(*used);
13415      }
13416      break;
13417    case DICTIONARY_ELEMENTS: {
13418      SeededNumberDictionary* dictionary = element_dictionary();
13419      *capacity = dictionary->Capacity();
13420      *used = dictionary->NumberOfElements();
13421      break;
13422    }
13423    case FAST_DOUBLE_ELEMENTS:
13424      if (IsJSArray()) {
13425        *capacity = backing_store_base->length();
13426        *used = Smi::cast(JSArray::cast(this)->length())->value();
13427        break;
13428      }
13429      // Fall through if packing is not guaranteed.
13430    case FAST_HOLEY_DOUBLE_ELEMENTS: {
13431      *capacity = elements()->length();
13432      if (*capacity == 0) break;
13433      FixedDoubleArray * elms = FixedDoubleArray::cast(elements());
13434      for (int i = 0; i < *capacity; i++) {
13435        if (!elms->is_the_hole(i)) ++(*used);
13436      }
13437      break;
13438    }
13439
13440#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
13441    case EXTERNAL_##TYPE##_ELEMENTS:                                         \
13442    case TYPE##_ELEMENTS:                                                    \
13443
13444    TYPED_ARRAYS(TYPED_ARRAY_CASE)
13445#undef TYPED_ARRAY_CASE
13446    {
13447      // External arrays are considered 100% used.
13448      FixedArrayBase* external_array = FixedArrayBase::cast(elements());
13449      *capacity = external_array->length();
13450      *used = external_array->length();
13451      break;
13452    }
13453  }
13454}
13455
13456
13457bool JSObject::WouldConvertToSlowElements(Handle<Object> key) {
13458  uint32_t index;
13459  if (HasFastElements() && key->ToArrayIndex(&index)) {
13460    Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
13461    uint32_t capacity = static_cast<uint32_t>(backing_store->length());
13462    if (index >= capacity) {
13463      if ((index - capacity) >= kMaxGap) return true;
13464      uint32_t new_capacity = NewElementsCapacity(index + 1);
13465      return ShouldConvertToSlowElements(new_capacity);
13466    }
13467  }
13468  return false;
13469}
13470
13471
13472bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
13473  STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
13474                kMaxUncheckedFastElementsLength);
13475  if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
13476      (new_capacity <= kMaxUncheckedFastElementsLength &&
13477       GetHeap()->InNewSpace(this))) {
13478    return false;
13479  }
13480  // If the fast-case backing storage takes up roughly three times as
13481  // much space (in machine words) as a dictionary backing storage
13482  // would, the object should have slow elements.
13483  int old_capacity = 0;
13484  int used_elements = 0;
13485  GetElementsCapacityAndUsage(&old_capacity, &used_elements);
13486  int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
13487      SeededNumberDictionary::kEntrySize;
13488  return 3 * dictionary_size <= new_capacity;
13489}
13490
13491
13492bool JSObject::ShouldConvertToFastElements() {
13493  ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
13494  // If the elements are sparse, we should not go back to fast case.
13495  if (!HasDenseElements()) return false;
13496  // An object requiring access checks is never allowed to have fast
13497  // elements.  If it had fast elements we would skip security checks.
13498  if (IsAccessCheckNeeded()) return false;
13499  // Observed objects may not go to fast mode because they rely on map checks,
13500  // and for fast element accesses we sometimes check element kinds only.
13501  if (map()->is_observed()) return false;
13502
13503  FixedArray* elements = FixedArray::cast(this->elements());
13504  SeededNumberDictionary* dictionary = NULL;
13505  if (elements->map() == GetHeap()->sloppy_arguments_elements_map()) {
13506    dictionary = SeededNumberDictionary::cast(elements->get(1));
13507  } else {
13508    dictionary = SeededNumberDictionary::cast(elements);
13509  }
13510  // If an element has been added at a very high index in the elements
13511  // dictionary, we cannot go back to fast case.
13512  if (dictionary->requires_slow_elements()) return false;
13513  // If the dictionary backing storage takes up roughly half as much
13514  // space (in machine words) as a fast-case backing storage would,
13515  // the object should have fast elements.
13516  uint32_t array_size = 0;
13517  if (IsJSArray()) {
13518    CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
13519  } else {
13520    array_size = dictionary->max_number_key();
13521  }
13522  uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
13523      SeededNumberDictionary::kEntrySize;
13524  return 2 * dictionary_size >= array_size;
13525}
13526
13527
13528bool JSObject::ShouldConvertToFastDoubleElements(
13529    bool* has_smi_only_elements) {
13530  *has_smi_only_elements = false;
13531  if (HasSloppyArgumentsElements()) return false;
13532  if (FLAG_unbox_double_arrays) {
13533    ASSERT(HasDictionaryElements());
13534    SeededNumberDictionary* dictionary = element_dictionary();
13535    bool found_double = false;
13536    for (int i = 0; i < dictionary->Capacity(); i++) {
13537      Object* key = dictionary->KeyAt(i);
13538      if (key->IsNumber()) {
13539        Object* value = dictionary->ValueAt(i);
13540        if (!value->IsNumber()) return false;
13541        if (!value->IsSmi()) {
13542          found_double = true;
13543        }
13544      }
13545    }
13546    *has_smi_only_elements = !found_double;
13547    return found_double;
13548  } else {
13549    return false;
13550  }
13551}
13552
13553
13554// Certain compilers request function template instantiation when they
13555// see the definition of the other template functions in the
13556// class. This requires us to have the template functions put
13557// together, so even though this function belongs in objects-debug.cc,
13558// we keep it here instead to satisfy certain compilers.
13559#ifdef OBJECT_PRINT
13560template<typename Derived, typename Shape, typename Key>
13561void Dictionary<Derived, Shape, Key>::Print(FILE* out) {
13562  int capacity = DerivedHashTable::Capacity();
13563  for (int i = 0; i < capacity; i++) {
13564    Object* k = DerivedHashTable::KeyAt(i);
13565    if (DerivedHashTable::IsKey(k)) {
13566      PrintF(out, " ");
13567      if (k->IsString()) {
13568        String::cast(k)->StringPrint(out);
13569      } else {
13570        k->ShortPrint(out);
13571      }
13572      PrintF(out, ": ");
13573      ValueAt(i)->ShortPrint(out);
13574      PrintF(out, "\n");
13575    }
13576  }
13577}
13578#endif
13579
13580
13581template<typename Derived, typename Shape, typename Key>
13582void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
13583  int pos = 0;
13584  int capacity = DerivedHashTable::Capacity();
13585  DisallowHeapAllocation no_gc;
13586  WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
13587  for (int i = 0; i < capacity; i++) {
13588    Object* k =  Dictionary::KeyAt(i);
13589    if (Dictionary::IsKey(k)) {
13590      elements->set(pos++, ValueAt(i), mode);
13591    }
13592  }
13593  ASSERT(pos == elements->length());
13594}
13595
13596
13597InterceptorInfo* JSObject::GetNamedInterceptor() {
13598  ASSERT(map()->has_named_interceptor());
13599  JSFunction* constructor = JSFunction::cast(map()->constructor());
13600  ASSERT(constructor->shared()->IsApiFunction());
13601  Object* result =
13602      constructor->shared()->get_api_func_data()->named_property_handler();
13603  return InterceptorInfo::cast(result);
13604}
13605
13606
13607InterceptorInfo* JSObject::GetIndexedInterceptor() {
13608  ASSERT(map()->has_indexed_interceptor());
13609  JSFunction* constructor = JSFunction::cast(map()->constructor());
13610  ASSERT(constructor->shared()->IsApiFunction());
13611  Object* result =
13612      constructor->shared()->get_api_func_data()->indexed_property_handler();
13613  return InterceptorInfo::cast(result);
13614}
13615
13616
13617MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(
13618    Handle<JSObject> holder,
13619    Handle<Object> receiver,
13620    Handle<Name> name) {
13621  Isolate* isolate = holder->GetIsolate();
13622
13623  // TODO(rossberg): Support symbols in the API.
13624  if (name->IsSymbol()) return isolate->factory()->undefined_value();
13625
13626  Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
13627  Handle<String> name_string = Handle<String>::cast(name);
13628
13629  if (interceptor->getter()->IsUndefined()) return MaybeHandle<Object>();
13630
13631  v8::NamedPropertyGetterCallback getter =
13632      v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
13633  LOG(isolate,
13634      ApiNamedPropertyAccess("interceptor-named-get", *holder, *name));
13635  PropertyCallbackArguments
13636      args(isolate, interceptor->data(), *receiver, *holder);
13637  v8::Handle<v8::Value> result =
13638      args.Call(getter, v8::Utils::ToLocal(name_string));
13639  RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
13640  if (result.IsEmpty()) return MaybeHandle<Object>();
13641
13642  Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13643  result_internal->VerifyApiCallResultType();
13644  // Rebox handle before return
13645  return handle(*result_internal, isolate);
13646}
13647
13648
13649// Compute the property keys from the interceptor.
13650// TODO(rossberg): support symbols in API, and filter here if needed.
13651MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor(
13652    Handle<JSObject> object, Handle<JSReceiver> receiver) {
13653  Isolate* isolate = receiver->GetIsolate();
13654  Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
13655  PropertyCallbackArguments
13656      args(isolate, interceptor->data(), *receiver, *object);
13657  v8::Handle<v8::Object> result;
13658  if (!interceptor->enumerator()->IsUndefined()) {
13659    v8::NamedPropertyEnumeratorCallback enum_fun =
13660        v8::ToCData<v8::NamedPropertyEnumeratorCallback>(
13661            interceptor->enumerator());
13662    LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
13663    result = args.Call(enum_fun);
13664  }
13665  if (result.IsEmpty()) return MaybeHandle<JSObject>();
13666#if ENABLE_EXTRA_CHECKS
13667  CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13668        v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13669#endif
13670  // Rebox before returning.
13671  return handle(*v8::Utils::OpenHandle(*result), isolate);
13672}
13673
13674
13675// Compute the element keys from the interceptor.
13676MaybeHandle<JSObject> JSObject::GetKeysForIndexedInterceptor(
13677    Handle<JSObject> object, Handle<JSReceiver> receiver) {
13678  Isolate* isolate = receiver->GetIsolate();
13679  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
13680  PropertyCallbackArguments
13681      args(isolate, interceptor->data(), *receiver, *object);
13682  v8::Handle<v8::Object> result;
13683  if (!interceptor->enumerator()->IsUndefined()) {
13684    v8::IndexedPropertyEnumeratorCallback enum_fun =
13685        v8::ToCData<v8::IndexedPropertyEnumeratorCallback>(
13686            interceptor->enumerator());
13687    LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
13688    result = args.Call(enum_fun);
13689  }
13690  if (result.IsEmpty()) return MaybeHandle<JSObject>();
13691#if ENABLE_EXTRA_CHECKS
13692  CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13693        v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13694#endif
13695  // Rebox before returning.
13696  return handle(*v8::Utils::OpenHandle(*result), isolate);
13697}
13698
13699
13700bool JSObject::HasRealNamedProperty(Handle<JSObject> object,
13701                                    Handle<Name> key) {
13702  Isolate* isolate = object->GetIsolate();
13703  SealHandleScope shs(isolate);
13704  // Check access rights if needed.
13705  if (object->IsAccessCheckNeeded()) {
13706    if (!isolate->MayNamedAccess(object, key, v8::ACCESS_HAS)) {
13707      isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
13708      // TODO(yangguo): Issue 3269, check for scheduled exception missing?
13709      return false;
13710    }
13711  }
13712
13713  LookupResult result(isolate);
13714  object->LookupOwnRealNamedProperty(key, &result);
13715  return result.IsFound() && !result.IsInterceptor();
13716}
13717
13718
13719bool JSObject::HasRealElementProperty(Handle<JSObject> object, uint32_t index) {
13720  Isolate* isolate = object->GetIsolate();
13721  HandleScope scope(isolate);
13722  // Check access rights if needed.
13723  if (object->IsAccessCheckNeeded()) {
13724    if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
13725      isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
13726      // TODO(yangguo): Issue 3269, check for scheduled exception missing?
13727      return false;
13728    }
13729  }
13730
13731  if (object->IsJSGlobalProxy()) {
13732    HandleScope scope(isolate);
13733    Handle<Object> proto(object->GetPrototype(), isolate);
13734    if (proto->IsNull()) return false;
13735    ASSERT(proto->IsJSGlobalObject());
13736    return HasRealElementProperty(Handle<JSObject>::cast(proto), index);
13737  }
13738
13739  return GetElementAttributeWithoutInterceptor(
13740             object, object, index, false) != ABSENT;
13741}
13742
13743
13744bool JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
13745                                            Handle<Name> key) {
13746  Isolate* isolate = object->GetIsolate();
13747  SealHandleScope shs(isolate);
13748  // Check access rights if needed.
13749  if (object->IsAccessCheckNeeded()) {
13750    if (!isolate->MayNamedAccess(object, key, v8::ACCESS_HAS)) {
13751      isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
13752      // TODO(yangguo): Issue 3269, check for scheduled exception missing?
13753      return false;
13754    }
13755  }
13756
13757  LookupResult result(isolate);
13758  object->LookupOwnRealNamedProperty(key, &result);
13759  return result.IsPropertyCallbacks();
13760}
13761
13762
13763int JSObject::NumberOfOwnProperties(PropertyAttributes filter) {
13764  if (HasFastProperties()) {
13765    Map* map = this->map();
13766    if (filter == NONE) return map->NumberOfOwnDescriptors();
13767    if (filter & DONT_ENUM) {
13768      int result = map->EnumLength();
13769      if (result != kInvalidEnumCacheSentinel) return result;
13770    }
13771    return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
13772  }
13773  return property_dictionary()->NumberOfElementsFilterAttributes(filter);
13774}
13775
13776
13777void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
13778  Object* temp = get(i);
13779  set(i, get(j));
13780  set(j, temp);
13781  if (this != numbers) {
13782    temp = numbers->get(i);
13783    numbers->set(i, Smi::cast(numbers->get(j)));
13784    numbers->set(j, Smi::cast(temp));
13785  }
13786}
13787
13788
13789static void InsertionSortPairs(FixedArray* content,
13790                               FixedArray* numbers,
13791                               int len) {
13792  for (int i = 1; i < len; i++) {
13793    int j = i;
13794    while (j > 0 &&
13795           (NumberToUint32(numbers->get(j - 1)) >
13796            NumberToUint32(numbers->get(j)))) {
13797      content->SwapPairs(numbers, j - 1, j);
13798      j--;
13799    }
13800  }
13801}
13802
13803
13804void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
13805  // In-place heap sort.
13806  ASSERT(content->length() == numbers->length());
13807
13808  // Bottom-up max-heap construction.
13809  for (int i = 1; i < len; ++i) {
13810    int child_index = i;
13811    while (child_index > 0) {
13812      int parent_index = ((child_index + 1) >> 1) - 1;
13813      uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13814      uint32_t child_value = NumberToUint32(numbers->get(child_index));
13815      if (parent_value < child_value) {
13816        content->SwapPairs(numbers, parent_index, child_index);
13817      } else {
13818        break;
13819      }
13820      child_index = parent_index;
13821    }
13822  }
13823
13824  // Extract elements and create sorted array.
13825  for (int i = len - 1; i > 0; --i) {
13826    // Put max element at the back of the array.
13827    content->SwapPairs(numbers, 0, i);
13828    // Sift down the new top element.
13829    int parent_index = 0;
13830    while (true) {
13831      int child_index = ((parent_index + 1) << 1) - 1;
13832      if (child_index >= i) break;
13833      uint32_t child1_value = NumberToUint32(numbers->get(child_index));
13834      uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
13835      uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13836      if (child_index + 1 >= i || child1_value > child2_value) {
13837        if (parent_value > child1_value) break;
13838        content->SwapPairs(numbers, parent_index, child_index);
13839        parent_index = child_index;
13840      } else {
13841        if (parent_value > child2_value) break;
13842        content->SwapPairs(numbers, parent_index, child_index + 1);
13843        parent_index = child_index + 1;
13844      }
13845    }
13846  }
13847}
13848
13849
13850// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
13851void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
13852  ASSERT(this->length() == numbers->length());
13853  // For small arrays, simply use insertion sort.
13854  if (len <= 10) {
13855    InsertionSortPairs(this, numbers, len);
13856    return;
13857  }
13858  // Check the range of indices.
13859  uint32_t min_index = NumberToUint32(numbers->get(0));
13860  uint32_t max_index = min_index;
13861  uint32_t i;
13862  for (i = 1; i < len; i++) {
13863    if (NumberToUint32(numbers->get(i)) < min_index) {
13864      min_index = NumberToUint32(numbers->get(i));
13865    } else if (NumberToUint32(numbers->get(i)) > max_index) {
13866      max_index = NumberToUint32(numbers->get(i));
13867    }
13868  }
13869  if (max_index - min_index + 1 == len) {
13870    // Indices form a contiguous range, unless there are duplicates.
13871    // Do an in-place linear time sort assuming distinct numbers, but
13872    // avoid hanging in case they are not.
13873    for (i = 0; i < len; i++) {
13874      uint32_t p;
13875      uint32_t j = 0;
13876      // While the current element at i is not at its correct position p,
13877      // swap the elements at these two positions.
13878      while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
13879             j++ < len) {
13880        SwapPairs(numbers, i, p);
13881      }
13882    }
13883  } else {
13884    HeapSortPairs(this, numbers, len);
13885    return;
13886  }
13887}
13888
13889
13890// Fill in the names of own properties into the supplied storage. The main
13891// purpose of this function is to provide reflection information for the object
13892// mirrors.
13893void JSObject::GetOwnPropertyNames(
13894    FixedArray* storage, int index, PropertyAttributes filter) {
13895  ASSERT(storage->length() >= (NumberOfOwnProperties(filter) - index));
13896  if (HasFastProperties()) {
13897    int real_size = map()->NumberOfOwnDescriptors();
13898    DescriptorArray* descs = map()->instance_descriptors();
13899    for (int i = 0; i < real_size; i++) {
13900      if ((descs->GetDetails(i).attributes() & filter) == 0 &&
13901          !FilterKey(descs->GetKey(i), filter)) {
13902        storage->set(index++, descs->GetKey(i));
13903      }
13904    }
13905  } else {
13906    property_dictionary()->CopyKeysTo(storage,
13907                                      index,
13908                                      filter,
13909                                      NameDictionary::UNSORTED);
13910  }
13911}
13912
13913
13914int JSObject::NumberOfOwnElements(PropertyAttributes filter) {
13915  return GetOwnElementKeys(NULL, filter);
13916}
13917
13918
13919int JSObject::NumberOfEnumElements() {
13920  // Fast case for objects with no elements.
13921  if (!IsJSValue() && HasFastObjectElements()) {
13922    uint32_t length = IsJSArray() ?
13923        static_cast<uint32_t>(
13924            Smi::cast(JSArray::cast(this)->length())->value()) :
13925        static_cast<uint32_t>(FixedArray::cast(elements())->length());
13926    if (length == 0) return 0;
13927  }
13928  // Compute the number of enumerable elements.
13929  return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM));
13930}
13931
13932
13933int JSObject::GetOwnElementKeys(FixedArray* storage,
13934                                PropertyAttributes filter) {
13935  int counter = 0;
13936  switch (GetElementsKind()) {
13937    case FAST_SMI_ELEMENTS:
13938    case FAST_ELEMENTS:
13939    case FAST_HOLEY_SMI_ELEMENTS:
13940    case FAST_HOLEY_ELEMENTS: {
13941      int length = IsJSArray() ?
13942          Smi::cast(JSArray::cast(this)->length())->value() :
13943          FixedArray::cast(elements())->length();
13944      for (int i = 0; i < length; i++) {
13945        if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
13946          if (storage != NULL) {
13947            storage->set(counter, Smi::FromInt(i));
13948          }
13949          counter++;
13950        }
13951      }
13952      ASSERT(!storage || storage->length() >= counter);
13953      break;
13954    }
13955    case FAST_DOUBLE_ELEMENTS:
13956    case FAST_HOLEY_DOUBLE_ELEMENTS: {
13957      int length = IsJSArray() ?
13958          Smi::cast(JSArray::cast(this)->length())->value() :
13959          FixedArrayBase::cast(elements())->length();
13960      for (int i = 0; i < length; i++) {
13961        if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
13962          if (storage != NULL) {
13963            storage->set(counter, Smi::FromInt(i));
13964          }
13965          counter++;
13966        }
13967      }
13968      ASSERT(!storage || storage->length() >= counter);
13969      break;
13970    }
13971
13972#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
13973    case EXTERNAL_##TYPE##_ELEMENTS:                                         \
13974    case TYPE##_ELEMENTS:                                                    \
13975
13976    TYPED_ARRAYS(TYPED_ARRAY_CASE)
13977#undef TYPED_ARRAY_CASE
13978    {
13979      int length = FixedArrayBase::cast(elements())->length();
13980      while (counter < length) {
13981        if (storage != NULL) {
13982          storage->set(counter, Smi::FromInt(counter));
13983        }
13984        counter++;
13985      }
13986      ASSERT(!storage || storage->length() >= counter);
13987      break;
13988    }
13989
13990    case DICTIONARY_ELEMENTS: {
13991      if (storage != NULL) {
13992        element_dictionary()->CopyKeysTo(storage,
13993                                         filter,
13994                                         SeededNumberDictionary::SORTED);
13995      }
13996      counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
13997      break;
13998    }
13999    case SLOPPY_ARGUMENTS_ELEMENTS: {
14000      FixedArray* parameter_map = FixedArray::cast(elements());
14001      int mapped_length = parameter_map->length() - 2;
14002      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
14003      if (arguments->IsDictionary()) {
14004        // Copy the keys from arguments first, because Dictionary::CopyKeysTo
14005        // will insert in storage starting at index 0.
14006        SeededNumberDictionary* dictionary =
14007            SeededNumberDictionary::cast(arguments);
14008        if (storage != NULL) {
14009          dictionary->CopyKeysTo(
14010              storage, filter, SeededNumberDictionary::UNSORTED);
14011        }
14012        counter += dictionary->NumberOfElementsFilterAttributes(filter);
14013        for (int i = 0; i < mapped_length; ++i) {
14014          if (!parameter_map->get(i + 2)->IsTheHole()) {
14015            if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14016            ++counter;
14017          }
14018        }
14019        if (storage != NULL) storage->SortPairs(storage, counter);
14020
14021      } else {
14022        int backing_length = arguments->length();
14023        int i = 0;
14024        for (; i < mapped_length; ++i) {
14025          if (!parameter_map->get(i + 2)->IsTheHole()) {
14026            if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14027            ++counter;
14028          } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
14029            if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14030            ++counter;
14031          }
14032        }
14033        for (; i < backing_length; ++i) {
14034          if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14035          ++counter;
14036        }
14037      }
14038      break;
14039    }
14040  }
14041
14042  if (this->IsJSValue()) {
14043    Object* val = JSValue::cast(this)->value();
14044    if (val->IsString()) {
14045      String* str = String::cast(val);
14046      if (storage) {
14047        for (int i = 0; i < str->length(); i++) {
14048          storage->set(counter + i, Smi::FromInt(i));
14049        }
14050      }
14051      counter += str->length();
14052    }
14053  }
14054  ASSERT(!storage || storage->length() == counter);
14055  return counter;
14056}
14057
14058
14059int JSObject::GetEnumElementKeys(FixedArray* storage) {
14060  return GetOwnElementKeys(storage, static_cast<PropertyAttributes>(DONT_ENUM));
14061}
14062
14063
14064// StringKey simply carries a string object as key.
14065class StringKey : public HashTableKey {
14066 public:
14067  explicit StringKey(String* string) :
14068      string_(string),
14069      hash_(HashForObject(string)) { }
14070
14071  bool IsMatch(Object* string) {
14072    // We know that all entries in a hash table had their hash keys created.
14073    // Use that knowledge to have fast failure.
14074    if (hash_ != HashForObject(string)) {
14075      return false;
14076    }
14077    return string_->Equals(String::cast(string));
14078  }
14079
14080  uint32_t Hash() { return hash_; }
14081
14082  uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
14083
14084  Object* AsObject(Heap* heap) { return string_; }
14085
14086  String* string_;
14087  uint32_t hash_;
14088};
14089
14090
14091// StringSharedKeys are used as keys in the eval cache.
14092class StringSharedKey : public HashTableKey {
14093 public:
14094  StringSharedKey(Handle<String> source,
14095                  Handle<SharedFunctionInfo> shared,
14096                  StrictMode strict_mode,
14097                  int scope_position)
14098      : source_(source),
14099        shared_(shared),
14100        strict_mode_(strict_mode),
14101        scope_position_(scope_position) { }
14102
14103  bool IsMatch(Object* other) V8_OVERRIDE {
14104    DisallowHeapAllocation no_allocation;
14105    if (!other->IsFixedArray()) return false;
14106    FixedArray* other_array = FixedArray::cast(other);
14107    SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
14108    if (shared != *shared_) return false;
14109    int strict_unchecked = Smi::cast(other_array->get(2))->value();
14110    ASSERT(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
14111    StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
14112    if (strict_mode != strict_mode_) return false;
14113    int scope_position = Smi::cast(other_array->get(3))->value();
14114    if (scope_position != scope_position_) return false;
14115    String* source = String::cast(other_array->get(1));
14116    return source->Equals(*source_);
14117  }
14118
14119  static uint32_t StringSharedHashHelper(String* source,
14120                                         SharedFunctionInfo* shared,
14121                                         StrictMode strict_mode,
14122                                         int scope_position) {
14123    uint32_t hash = source->Hash();
14124    if (shared->HasSourceCode()) {
14125      // Instead of using the SharedFunctionInfo pointer in the hash
14126      // code computation, we use a combination of the hash of the
14127      // script source code and the start position of the calling scope.
14128      // We do this to ensure that the cache entries can survive garbage
14129      // collection.
14130      Script* script(Script::cast(shared->script()));
14131      hash ^= String::cast(script->source())->Hash();
14132      if (strict_mode == STRICT) hash ^= 0x8000;
14133      hash += scope_position;
14134    }
14135    return hash;
14136  }
14137
14138  uint32_t Hash() V8_OVERRIDE {
14139    return StringSharedHashHelper(*source_, *shared_, strict_mode_,
14140                                  scope_position_);
14141  }
14142
14143  uint32_t HashForObject(Object* obj) V8_OVERRIDE {
14144    DisallowHeapAllocation no_allocation;
14145    FixedArray* other_array = FixedArray::cast(obj);
14146    SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
14147    String* source = String::cast(other_array->get(1));
14148    int strict_unchecked = Smi::cast(other_array->get(2))->value();
14149    ASSERT(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
14150    StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
14151    int scope_position = Smi::cast(other_array->get(3))->value();
14152    return StringSharedHashHelper(
14153        source, shared, strict_mode, scope_position);
14154  }
14155
14156
14157  Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE {
14158    Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
14159    array->set(0, *shared_);
14160    array->set(1, *source_);
14161    array->set(2, Smi::FromInt(strict_mode_));
14162    array->set(3, Smi::FromInt(scope_position_));
14163    return array;
14164  }
14165
14166 private:
14167  Handle<String> source_;
14168  Handle<SharedFunctionInfo> shared_;
14169  StrictMode strict_mode_;
14170  int scope_position_;
14171};
14172
14173
14174// RegExpKey carries the source and flags of a regular expression as key.
14175class RegExpKey : public HashTableKey {
14176 public:
14177  RegExpKey(Handle<String> string, JSRegExp::Flags flags)
14178      : string_(string),
14179        flags_(Smi::FromInt(flags.value())) { }
14180
14181  // Rather than storing the key in the hash table, a pointer to the
14182  // stored value is stored where the key should be.  IsMatch then
14183  // compares the search key to the found object, rather than comparing
14184  // a key to a key.
14185  bool IsMatch(Object* obj) V8_OVERRIDE {
14186    FixedArray* val = FixedArray::cast(obj);
14187    return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
14188        && (flags_ == val->get(JSRegExp::kFlagsIndex));
14189  }
14190
14191  uint32_t Hash() V8_OVERRIDE { return RegExpHash(*string_, flags_); }
14192
14193  Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE {
14194    // Plain hash maps, which is where regexp keys are used, don't
14195    // use this function.
14196    UNREACHABLE();
14197    return MaybeHandle<Object>().ToHandleChecked();
14198  }
14199
14200  uint32_t HashForObject(Object* obj) V8_OVERRIDE {
14201    FixedArray* val = FixedArray::cast(obj);
14202    return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
14203                      Smi::cast(val->get(JSRegExp::kFlagsIndex)));
14204  }
14205
14206  static uint32_t RegExpHash(String* string, Smi* flags) {
14207    return string->Hash() + flags->value();
14208  }
14209
14210  Handle<String> string_;
14211  Smi* flags_;
14212};
14213
14214
14215Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
14216  if (hash_field_ == 0) Hash();
14217  return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
14218}
14219
14220
14221Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
14222  if (hash_field_ == 0) Hash();
14223  return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
14224}
14225
14226
14227template<>
14228const uint8_t* SubStringKey<uint8_t>::GetChars() {
14229  return string_->IsSeqOneByteString()
14230      ? SeqOneByteString::cast(*string_)->GetChars()
14231      : ExternalAsciiString::cast(*string_)->GetChars();
14232}
14233
14234
14235template<>
14236const uint16_t* SubStringKey<uint16_t>::GetChars() {
14237  return string_->IsSeqTwoByteString()
14238      ? SeqTwoByteString::cast(*string_)->GetChars()
14239      : ExternalTwoByteString::cast(*string_)->GetChars();
14240}
14241
14242
14243template<>
14244Handle<Object> SubStringKey<uint8_t>::AsHandle(Isolate* isolate) {
14245  if (hash_field_ == 0) Hash();
14246  Vector<const uint8_t> chars(GetChars() + from_, length_);
14247  return isolate->factory()->NewOneByteInternalizedString(chars, hash_field_);
14248}
14249
14250
14251template<>
14252Handle<Object> SubStringKey<uint16_t>::AsHandle(Isolate* isolate) {
14253  if (hash_field_ == 0) Hash();
14254  Vector<const uint16_t> chars(GetChars() + from_, length_);
14255  return isolate->factory()->NewTwoByteInternalizedString(chars, hash_field_);
14256}
14257
14258
14259template<>
14260bool SubStringKey<uint8_t>::IsMatch(Object* string) {
14261  Vector<const uint8_t> chars(GetChars() + from_, length_);
14262  return String::cast(string)->IsOneByteEqualTo(chars);
14263}
14264
14265
14266template<>
14267bool SubStringKey<uint16_t>::IsMatch(Object* string) {
14268  Vector<const uint16_t> chars(GetChars() + from_, length_);
14269  return String::cast(string)->IsTwoByteEqualTo(chars);
14270}
14271
14272
14273template class SubStringKey<uint8_t>;
14274template class SubStringKey<uint16_t>;
14275
14276
14277// InternalizedStringKey carries a string/internalized-string object as key.
14278class InternalizedStringKey : public HashTableKey {
14279 public:
14280  explicit InternalizedStringKey(Handle<String> string)
14281      : string_(string) { }
14282
14283  virtual bool IsMatch(Object* string) V8_OVERRIDE {
14284    return String::cast(string)->Equals(*string_);
14285  }
14286
14287  virtual uint32_t Hash() V8_OVERRIDE { return string_->Hash(); }
14288
14289  virtual uint32_t HashForObject(Object* other) V8_OVERRIDE {
14290    return String::cast(other)->Hash();
14291  }
14292
14293  virtual Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE {
14294    // Internalize the string if possible.
14295    MaybeHandle<Map> maybe_map =
14296        isolate->factory()->InternalizedStringMapForString(string_);
14297    Handle<Map> map;
14298    if (maybe_map.ToHandle(&map)) {
14299      string_->set_map_no_write_barrier(*map);
14300      ASSERT(string_->IsInternalizedString());
14301      return string_;
14302    }
14303    // Otherwise allocate a new internalized string.
14304    return isolate->factory()->NewInternalizedStringImpl(
14305        string_, string_->length(), string_->hash_field());
14306  }
14307
14308  static uint32_t StringHash(Object* obj) {
14309    return String::cast(obj)->Hash();
14310  }
14311
14312  Handle<String> string_;
14313};
14314
14315
14316template<typename Derived, typename Shape, typename Key>
14317void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
14318  IteratePointers(v, 0, kElementsStartOffset);
14319}
14320
14321
14322template<typename Derived, typename Shape, typename Key>
14323void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
14324  IteratePointers(v,
14325                  kElementsStartOffset,
14326                  kHeaderSize + length() * kPointerSize);
14327}
14328
14329
14330template<typename Derived, typename Shape, typename Key>
14331Handle<Derived> HashTable<Derived, Shape, Key>::New(
14332    Isolate* isolate,
14333    int at_least_space_for,
14334    MinimumCapacity capacity_option,
14335    PretenureFlag pretenure) {
14336  ASSERT(0 <= at_least_space_for);
14337  ASSERT(!capacity_option || IsPowerOf2(at_least_space_for));
14338  int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
14339                     ? at_least_space_for
14340                     : ComputeCapacity(at_least_space_for);
14341  if (capacity > HashTable::kMaxCapacity) {
14342    v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
14343  }
14344
14345  Factory* factory = isolate->factory();
14346  int length = EntryToIndex(capacity);
14347  Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
14348  array->set_map_no_write_barrier(*factory->hash_table_map());
14349  Handle<Derived> table = Handle<Derived>::cast(array);
14350
14351  table->SetNumberOfElements(0);
14352  table->SetNumberOfDeletedElements(0);
14353  table->SetCapacity(capacity);
14354  return table;
14355}
14356
14357
14358// Find entry for key otherwise return kNotFound.
14359int NameDictionary::FindEntry(Handle<Name> key) {
14360  if (!key->IsUniqueName()) {
14361    return DerivedHashTable::FindEntry(key);
14362  }
14363
14364  // Optimized for unique names. Knowledge of the key type allows:
14365  // 1. Move the check if the key is unique out of the loop.
14366  // 2. Avoid comparing hash codes in unique-to-unique comparison.
14367  // 3. Detect a case when a dictionary key is not unique but the key is.
14368  //    In case of positive result the dictionary key may be replaced by the
14369  //    internalized string with minimal performance penalty. It gives a chance
14370  //    to perform further lookups in code stubs (and significant performance
14371  //    boost a certain style of code).
14372
14373  // EnsureCapacity will guarantee the hash table is never full.
14374  uint32_t capacity = Capacity();
14375  uint32_t entry = FirstProbe(key->Hash(), capacity);
14376  uint32_t count = 1;
14377
14378  while (true) {
14379    int index = EntryToIndex(entry);
14380    Object* element = get(index);
14381    if (element->IsUndefined()) break;  // Empty entry.
14382    if (*key == element) return entry;
14383    if (!element->IsUniqueName() &&
14384        !element->IsTheHole() &&
14385        Name::cast(element)->Equals(*key)) {
14386      // Replace a key that is a non-internalized string by the equivalent
14387      // internalized string for faster further lookups.
14388      set(index, *key);
14389      return entry;
14390    }
14391    ASSERT(element->IsTheHole() || !Name::cast(element)->Equals(*key));
14392    entry = NextProbe(entry, count++, capacity);
14393  }
14394  return kNotFound;
14395}
14396
14397
14398template<typename Derived, typename Shape, typename Key>
14399void HashTable<Derived, Shape, Key>::Rehash(
14400    Handle<Derived> new_table,
14401    Key key) {
14402  ASSERT(NumberOfElements() < new_table->Capacity());
14403
14404  DisallowHeapAllocation no_gc;
14405  WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
14406
14407  // Copy prefix to new array.
14408  for (int i = kPrefixStartIndex;
14409       i < kPrefixStartIndex + Shape::kPrefixSize;
14410       i++) {
14411    new_table->set(i, get(i), mode);
14412  }
14413
14414  // Rehash the elements.
14415  int capacity = Capacity();
14416  for (int i = 0; i < capacity; i++) {
14417    uint32_t from_index = EntryToIndex(i);
14418    Object* k = get(from_index);
14419    if (IsKey(k)) {
14420      uint32_t hash = HashTable::HashForObject(key, k);
14421      uint32_t insertion_index =
14422          EntryToIndex(new_table->FindInsertionEntry(hash));
14423      for (int j = 0; j < Shape::kEntrySize; j++) {
14424        new_table->set(insertion_index + j, get(from_index + j), mode);
14425      }
14426    }
14427  }
14428  new_table->SetNumberOfElements(NumberOfElements());
14429  new_table->SetNumberOfDeletedElements(0);
14430}
14431
14432
14433template<typename Derived, typename Shape, typename Key>
14434uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
14435    Key key,
14436    Object* k,
14437    int probe,
14438    uint32_t expected) {
14439  uint32_t hash = HashTable::HashForObject(key, k);
14440  uint32_t capacity = Capacity();
14441  uint32_t entry = FirstProbe(hash, capacity);
14442  for (int i = 1; i < probe; i++) {
14443    if (entry == expected) return expected;
14444    entry = NextProbe(entry, i, capacity);
14445  }
14446  return entry;
14447}
14448
14449
14450template<typename Derived, typename Shape, typename Key>
14451void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
14452                                          uint32_t entry2,
14453                                          WriteBarrierMode mode) {
14454  int index1 = EntryToIndex(entry1);
14455  int index2 = EntryToIndex(entry2);
14456  Object* temp[Shape::kEntrySize];
14457  for (int j = 0; j < Shape::kEntrySize; j++) {
14458    temp[j] = get(index1 + j);
14459  }
14460  for (int j = 0; j < Shape::kEntrySize; j++) {
14461    set(index1 + j, get(index2 + j), mode);
14462  }
14463  for (int j = 0; j < Shape::kEntrySize; j++) {
14464    set(index2 + j, temp[j], mode);
14465  }
14466}
14467
14468
14469template<typename Derived, typename Shape, typename Key>
14470void HashTable<Derived, Shape, Key>::Rehash(Key key) {
14471  DisallowHeapAllocation no_gc;
14472  WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
14473  uint32_t capacity = Capacity();
14474  bool done = false;
14475  for (int probe = 1; !done; probe++) {
14476    // All elements at entries given by one of the first _probe_ probes
14477    // are placed correctly. Other elements might need to be moved.
14478    done = true;
14479    for (uint32_t current = 0; current < capacity; current++) {
14480      Object* current_key = get(EntryToIndex(current));
14481      if (IsKey(current_key)) {
14482        uint32_t target = EntryForProbe(key, current_key, probe, current);
14483        if (current == target) continue;
14484        Object* target_key = get(EntryToIndex(target));
14485        if (!IsKey(target_key) ||
14486            EntryForProbe(key, target_key, probe, target) != target) {
14487          // Put the current element into the correct position.
14488          Swap(current, target, mode);
14489          // The other element will be processed on the next iteration.
14490          current--;
14491        } else {
14492          // The place for the current element is occupied. Leave the element
14493          // for the next probe.
14494          done = false;
14495        }
14496      }
14497    }
14498  }
14499}
14500
14501
14502template<typename Derived, typename Shape, typename Key>
14503Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
14504    Handle<Derived> table,
14505    int n,
14506    Key key,
14507    PretenureFlag pretenure) {
14508  Isolate* isolate = table->GetIsolate();
14509  int capacity = table->Capacity();
14510  int nof = table->NumberOfElements() + n;
14511  int nod = table->NumberOfDeletedElements();
14512  // Return if:
14513  //   50% is still free after adding n elements and
14514  //   at most 50% of the free elements are deleted elements.
14515  if (nod <= (capacity - nof) >> 1) {
14516    int needed_free = nof >> 1;
14517    if (nof + needed_free <= capacity) return table;
14518  }
14519
14520  const int kMinCapacityForPretenure = 256;
14521  bool should_pretenure = pretenure == TENURED ||
14522      ((capacity > kMinCapacityForPretenure) &&
14523          !isolate->heap()->InNewSpace(*table));
14524  Handle<Derived> new_table = HashTable::New(
14525      isolate,
14526      nof * 2,
14527      USE_DEFAULT_MINIMUM_CAPACITY,
14528      should_pretenure ? TENURED : NOT_TENURED);
14529
14530  table->Rehash(new_table, key);
14531  return new_table;
14532}
14533
14534
14535template<typename Derived, typename Shape, typename Key>
14536Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
14537                                                       Key key) {
14538  int capacity = table->Capacity();
14539  int nof = table->NumberOfElements();
14540
14541  // Shrink to fit the number of elements if only a quarter of the
14542  // capacity is filled with elements.
14543  if (nof > (capacity >> 2)) return table;
14544  // Allocate a new dictionary with room for at least the current
14545  // number of elements. The allocation method will make sure that
14546  // there is extra room in the dictionary for additions. Don't go
14547  // lower than room for 16 elements.
14548  int at_least_room_for = nof;
14549  if (at_least_room_for < 16) return table;
14550
14551  Isolate* isolate = table->GetIsolate();
14552  const int kMinCapacityForPretenure = 256;
14553  bool pretenure =
14554      (at_least_room_for > kMinCapacityForPretenure) &&
14555      !isolate->heap()->InNewSpace(*table);
14556  Handle<Derived> new_table = HashTable::New(
14557      isolate,
14558      at_least_room_for,
14559      USE_DEFAULT_MINIMUM_CAPACITY,
14560      pretenure ? TENURED : NOT_TENURED);
14561
14562  table->Rehash(new_table, key);
14563  return new_table;
14564}
14565
14566
14567template<typename Derived, typename Shape, typename Key>
14568uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
14569  uint32_t capacity = Capacity();
14570  uint32_t entry = FirstProbe(hash, capacity);
14571  uint32_t count = 1;
14572  // EnsureCapacity will guarantee the hash table is never full.
14573  while (true) {
14574    Object* element = KeyAt(entry);
14575    if (element->IsUndefined() || element->IsTheHole()) break;
14576    entry = NextProbe(entry, count++, capacity);
14577  }
14578  return entry;
14579}
14580
14581
14582// Force instantiation of template instances class.
14583// Please note this list is compiler dependent.
14584
14585template class HashTable<StringTable, StringTableShape, HashTableKey*>;
14586
14587template class HashTable<CompilationCacheTable,
14588                         CompilationCacheShape,
14589                         HashTableKey*>;
14590
14591template class HashTable<MapCache, MapCacheShape, HashTableKey*>;
14592
14593template class HashTable<ObjectHashTable,
14594                         ObjectHashTableShape,
14595                         Handle<Object> >;
14596
14597template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
14598
14599template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
14600
14601template class Dictionary<SeededNumberDictionary,
14602                          SeededNumberDictionaryShape,
14603                          uint32_t>;
14604
14605template class Dictionary<UnseededNumberDictionary,
14606                          UnseededNumberDictionaryShape,
14607                          uint32_t>;
14608
14609template Handle<SeededNumberDictionary>
14610Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14611    New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
14612
14613template Handle<UnseededNumberDictionary>
14614Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14615    New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
14616
14617template Handle<NameDictionary>
14618Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14619    New(Isolate*, int n, PretenureFlag pretenure);
14620
14621template Handle<SeededNumberDictionary>
14622Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14623    AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
14624
14625template Handle<UnseededNumberDictionary>
14626Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14627    AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
14628
14629template Object*
14630Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14631    SlowReverseLookup(Object* value);
14632
14633template Object*
14634Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14635    SlowReverseLookup(Object* value);
14636
14637template Object*
14638Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14639    SlowReverseLookup(Object* value);
14640
14641template void
14642Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14643    CopyKeysTo(
14644        FixedArray*,
14645        PropertyAttributes,
14646        Dictionary<SeededNumberDictionary,
14647                   SeededNumberDictionaryShape,
14648                   uint32_t>::SortMode);
14649
14650template Handle<Object>
14651Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
14652    Handle<NameDictionary>, int, JSObject::DeleteMode);
14653
14654template Handle<Object>
14655Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14656    DeleteProperty(Handle<SeededNumberDictionary>, int, JSObject::DeleteMode);
14657
14658template Handle<NameDictionary>
14659HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14660    New(Isolate*, int, MinimumCapacity, PretenureFlag);
14661
14662template Handle<NameDictionary>
14663HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14664    Shrink(Handle<NameDictionary>, Handle<Name>);
14665
14666template Handle<SeededNumberDictionary>
14667HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14668    Shrink(Handle<SeededNumberDictionary>, uint32_t);
14669
14670template void Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14671    CopyKeysTo(
14672        FixedArray*,
14673        int,
14674        PropertyAttributes,
14675        Dictionary<
14676            NameDictionary, NameDictionaryShape, Handle<Name> >::SortMode);
14677
14678template int
14679Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14680    NumberOfElementsFilterAttributes(PropertyAttributes);
14681
14682template Handle<NameDictionary>
14683Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
14684    Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
14685
14686template void
14687Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14688    GenerateNewEnumerationIndices(Handle<NameDictionary>);
14689
14690template int
14691Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14692    NumberOfElementsFilterAttributes(PropertyAttributes);
14693
14694template Handle<SeededNumberDictionary>
14695Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14696    Add(Handle<SeededNumberDictionary>,
14697        uint32_t,
14698        Handle<Object>,
14699        PropertyDetails);
14700
14701template Handle<UnseededNumberDictionary>
14702Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14703    Add(Handle<UnseededNumberDictionary>,
14704        uint32_t,
14705        Handle<Object>,
14706        PropertyDetails);
14707
14708template Handle<SeededNumberDictionary>
14709Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14710    EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
14711
14712template Handle<UnseededNumberDictionary>
14713Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14714    EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
14715
14716template Handle<NameDictionary>
14717Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14718    EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
14719
14720template
14721int Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14722    NumberOfEnumElements();
14723
14724template
14725int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14726    NumberOfEnumElements();
14727
14728template
14729int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14730    FindEntry(uint32_t);
14731
14732
14733Handle<Object> JSObject::PrepareSlowElementsForSort(
14734    Handle<JSObject> object, uint32_t limit) {
14735  ASSERT(object->HasDictionaryElements());
14736  Isolate* isolate = object->GetIsolate();
14737  // Must stay in dictionary mode, either because of requires_slow_elements,
14738  // or because we are not going to sort (and therefore compact) all of the
14739  // elements.
14740  Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
14741  Handle<SeededNumberDictionary> new_dict =
14742      SeededNumberDictionary::New(isolate, dict->NumberOfElements());
14743
14744  uint32_t pos = 0;
14745  uint32_t undefs = 0;
14746  int capacity = dict->Capacity();
14747  Handle<Smi> bailout(Smi::FromInt(-1), isolate);
14748  // Entry to the new dictionary does not cause it to grow, as we have
14749  // allocated one that is large enough for all entries.
14750  DisallowHeapAllocation no_gc;
14751  for (int i = 0; i < capacity; i++) {
14752    Object* k = dict->KeyAt(i);
14753    if (!dict->IsKey(k)) continue;
14754
14755    ASSERT(k->IsNumber());
14756    ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
14757    ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
14758    ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
14759
14760    HandleScope scope(isolate);
14761    Handle<Object> value(dict->ValueAt(i), isolate);
14762    PropertyDetails details = dict->DetailsAt(i);
14763    if (details.type() == CALLBACKS || details.IsReadOnly()) {
14764      // Bail out and do the sorting of undefineds and array holes in JS.
14765      // Also bail out if the element is not supposed to be moved.
14766      return bailout;
14767    }
14768
14769    uint32_t key = NumberToUint32(k);
14770    if (key < limit) {
14771      if (value->IsUndefined()) {
14772        undefs++;
14773      } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14774        // Adding an entry with the key beyond smi-range requires
14775        // allocation. Bailout.
14776        return bailout;
14777      } else {
14778        Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14779            new_dict, pos, value, details);
14780        ASSERT(result.is_identical_to(new_dict));
14781        USE(result);
14782        pos++;
14783      }
14784    } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
14785      // Adding an entry with the key beyond smi-range requires
14786      // allocation. Bailout.
14787      return bailout;
14788    } else {
14789      Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14790          new_dict, key, value, details);
14791      ASSERT(result.is_identical_to(new_dict));
14792      USE(result);
14793    }
14794  }
14795
14796  uint32_t result = pos;
14797  PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
14798  while (undefs > 0) {
14799    if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14800      // Adding an entry with the key beyond smi-range requires
14801      // allocation. Bailout.
14802      return bailout;
14803    }
14804    HandleScope scope(isolate);
14805    Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14806        new_dict, pos, isolate->factory()->undefined_value(), no_details);
14807    ASSERT(result.is_identical_to(new_dict));
14808    USE(result);
14809    pos++;
14810    undefs--;
14811  }
14812
14813  object->set_elements(*new_dict);
14814
14815  AllowHeapAllocation allocate_return_value;
14816  return isolate->factory()->NewNumberFromUint(result);
14817}
14818
14819
14820// Collects all defined (non-hole) and non-undefined (array) elements at
14821// the start of the elements array.
14822// If the object is in dictionary mode, it is converted to fast elements
14823// mode.
14824Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
14825                                                uint32_t limit) {
14826  Isolate* isolate = object->GetIsolate();
14827  if (object->HasSloppyArgumentsElements() ||
14828      object->map()->is_observed()) {
14829    return handle(Smi::FromInt(-1), isolate);
14830  }
14831
14832  if (object->HasDictionaryElements()) {
14833    // Convert to fast elements containing only the existing properties.
14834    // Ordering is irrelevant, since we are going to sort anyway.
14835    Handle<SeededNumberDictionary> dict(object->element_dictionary());
14836    if (object->IsJSArray() || dict->requires_slow_elements() ||
14837        dict->max_number_key() >= limit) {
14838      return JSObject::PrepareSlowElementsForSort(object, limit);
14839    }
14840    // Convert to fast elements.
14841
14842    Handle<Map> new_map =
14843        JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
14844
14845    PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
14846        NOT_TENURED: TENURED;
14847    Handle<FixedArray> fast_elements =
14848        isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
14849    dict->CopyValuesTo(*fast_elements);
14850    JSObject::ValidateElements(object);
14851
14852    JSObject::SetMapAndElements(object, new_map, fast_elements);
14853  } else if (object->HasExternalArrayElements() ||
14854             object->HasFixedTypedArrayElements()) {
14855    // Typed arrays cannot have holes or undefined elements.
14856    return handle(Smi::FromInt(
14857        FixedArrayBase::cast(object->elements())->length()), isolate);
14858  } else if (!object->HasFastDoubleElements()) {
14859    EnsureWritableFastElements(object);
14860  }
14861  ASSERT(object->HasFastSmiOrObjectElements() ||
14862         object->HasFastDoubleElements());
14863
14864  // Collect holes at the end, undefined before that and the rest at the
14865  // start, and return the number of non-hole, non-undefined values.
14866
14867  Handle<FixedArrayBase> elements_base(object->elements());
14868  uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
14869  if (limit > elements_length) {
14870    limit = elements_length ;
14871  }
14872  if (limit == 0) {
14873    return handle(Smi::FromInt(0), isolate);
14874  }
14875
14876  uint32_t result = 0;
14877  if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
14878    FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
14879    // Split elements into defined and the_hole, in that order.
14880    unsigned int holes = limit;
14881    // Assume most arrays contain no holes and undefined values, so minimize the
14882    // number of stores of non-undefined, non-the-hole values.
14883    for (unsigned int i = 0; i < holes; i++) {
14884      if (elements->is_the_hole(i)) {
14885        holes--;
14886      } else {
14887        continue;
14888      }
14889      // Position i needs to be filled.
14890      while (holes > i) {
14891        if (elements->is_the_hole(holes)) {
14892          holes--;
14893        } else {
14894          elements->set(i, elements->get_scalar(holes));
14895          break;
14896        }
14897      }
14898    }
14899    result = holes;
14900    while (holes < limit) {
14901      elements->set_the_hole(holes);
14902      holes++;
14903    }
14904  } else {
14905    FixedArray* elements = FixedArray::cast(*elements_base);
14906    DisallowHeapAllocation no_gc;
14907
14908    // Split elements into defined, undefined and the_hole, in that order.  Only
14909    // count locations for undefined and the hole, and fill them afterwards.
14910    WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
14911    unsigned int undefs = limit;
14912    unsigned int holes = limit;
14913    // Assume most arrays contain no holes and undefined values, so minimize the
14914    // number of stores of non-undefined, non-the-hole values.
14915    for (unsigned int i = 0; i < undefs; i++) {
14916      Object* current = elements->get(i);
14917      if (current->IsTheHole()) {
14918        holes--;
14919        undefs--;
14920      } else if (current->IsUndefined()) {
14921        undefs--;
14922      } else {
14923        continue;
14924      }
14925      // Position i needs to be filled.
14926      while (undefs > i) {
14927        current = elements->get(undefs);
14928        if (current->IsTheHole()) {
14929          holes--;
14930          undefs--;
14931        } else if (current->IsUndefined()) {
14932          undefs--;
14933        } else {
14934          elements->set(i, current, write_barrier);
14935          break;
14936        }
14937      }
14938    }
14939    result = undefs;
14940    while (undefs < holes) {
14941      elements->set_undefined(undefs);
14942      undefs++;
14943    }
14944    while (holes < limit) {
14945      elements->set_the_hole(holes);
14946      holes++;
14947    }
14948  }
14949
14950  return isolate->factory()->NewNumberFromUint(result);
14951}
14952
14953
14954ExternalArrayType JSTypedArray::type() {
14955  switch (elements()->map()->instance_type()) {
14956#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size)            \
14957    case EXTERNAL_##TYPE##_ARRAY_TYPE:                                        \
14958    case FIXED_##TYPE##_ARRAY_TYPE:                                           \
14959      return kExternal##Type##Array;
14960
14961    TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
14962#undef INSTANCE_TYPE_TO_ARRAY_TYPE
14963
14964    default:
14965      UNREACHABLE();
14966      return static_cast<ExternalArrayType>(-1);
14967  }
14968}
14969
14970
14971size_t JSTypedArray::element_size() {
14972  switch (elements()->map()->instance_type()) {
14973#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size)          \
14974    case EXTERNAL_##TYPE##_ARRAY_TYPE:                                        \
14975      return size;
14976
14977    TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
14978#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
14979
14980    default:
14981      UNREACHABLE();
14982      return 0;
14983  }
14984}
14985
14986
14987Handle<Object> ExternalUint8ClampedArray::SetValue(
14988    Handle<ExternalUint8ClampedArray> array,
14989    uint32_t index,
14990    Handle<Object> value) {
14991  uint8_t clamped_value = 0;
14992  if (index < static_cast<uint32_t>(array->length())) {
14993    if (value->IsSmi()) {
14994      int int_value = Handle<Smi>::cast(value)->value();
14995      if (int_value < 0) {
14996        clamped_value = 0;
14997      } else if (int_value > 255) {
14998        clamped_value = 255;
14999      } else {
15000        clamped_value = static_cast<uint8_t>(int_value);
15001      }
15002    } else if (value->IsHeapNumber()) {
15003      double double_value = Handle<HeapNumber>::cast(value)->value();
15004      if (!(double_value > 0)) {
15005        // NaN and less than zero clamp to zero.
15006        clamped_value = 0;
15007      } else if (double_value > 255) {
15008        // Greater than 255 clamp to 255.
15009        clamped_value = 255;
15010      } else {
15011        // Other doubles are rounded to the nearest integer.
15012        clamped_value = static_cast<uint8_t>(lrint(double_value));
15013      }
15014    } else {
15015      // Clamp undefined to zero (default). All other types have been
15016      // converted to a number type further up in the call chain.
15017      ASSERT(value->IsUndefined());
15018    }
15019    array->set(index, clamped_value);
15020  }
15021  return handle(Smi::FromInt(clamped_value), array->GetIsolate());
15022}
15023
15024
15025template<typename ExternalArrayClass, typename ValueType>
15026static Handle<Object> ExternalArrayIntSetter(
15027    Isolate* isolate,
15028    Handle<ExternalArrayClass> receiver,
15029    uint32_t index,
15030    Handle<Object> value) {
15031  ValueType cast_value = 0;
15032  if (index < static_cast<uint32_t>(receiver->length())) {
15033    if (value->IsSmi()) {
15034      int int_value = Handle<Smi>::cast(value)->value();
15035      cast_value = static_cast<ValueType>(int_value);
15036    } else if (value->IsHeapNumber()) {
15037      double double_value = Handle<HeapNumber>::cast(value)->value();
15038      cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
15039    } else {
15040      // Clamp undefined to zero (default). All other types have been
15041      // converted to a number type further up in the call chain.
15042      ASSERT(value->IsUndefined());
15043    }
15044    receiver->set(index, cast_value);
15045  }
15046  return isolate->factory()->NewNumberFromInt(cast_value);
15047}
15048
15049
15050Handle<Object> ExternalInt8Array::SetValue(Handle<ExternalInt8Array> array,
15051                                           uint32_t index,
15052                                           Handle<Object> value) {
15053  return ExternalArrayIntSetter<ExternalInt8Array, int8_t>(
15054      array->GetIsolate(), array, index, value);
15055}
15056
15057
15058Handle<Object> ExternalUint8Array::SetValue(Handle<ExternalUint8Array> array,
15059                                            uint32_t index,
15060                                            Handle<Object> value) {
15061  return ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(
15062      array->GetIsolate(), array, index, value);
15063}
15064
15065
15066Handle<Object> ExternalInt16Array::SetValue(Handle<ExternalInt16Array> array,
15067                                            uint32_t index,
15068                                            Handle<Object> value) {
15069  return ExternalArrayIntSetter<ExternalInt16Array, int16_t>(
15070      array->GetIsolate(), array, index, value);
15071}
15072
15073
15074Handle<Object> ExternalUint16Array::SetValue(Handle<ExternalUint16Array> array,
15075                                             uint32_t index,
15076                                             Handle<Object> value) {
15077  return ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(
15078      array->GetIsolate(), array, index, value);
15079}
15080
15081
15082Handle<Object> ExternalInt32Array::SetValue(Handle<ExternalInt32Array> array,
15083                                            uint32_t index,
15084                                            Handle<Object> value) {
15085  return ExternalArrayIntSetter<ExternalInt32Array, int32_t>(
15086      array->GetIsolate(), array, index, value);
15087}
15088
15089
15090Handle<Object> ExternalUint32Array::SetValue(
15091    Handle<ExternalUint32Array> array,
15092    uint32_t index,
15093    Handle<Object> value) {
15094  uint32_t cast_value = 0;
15095  if (index < static_cast<uint32_t>(array->length())) {
15096    if (value->IsSmi()) {
15097      int int_value = Handle<Smi>::cast(value)->value();
15098      cast_value = static_cast<uint32_t>(int_value);
15099    } else if (value->IsHeapNumber()) {
15100      double double_value = Handle<HeapNumber>::cast(value)->value();
15101      cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
15102    } else {
15103      // Clamp undefined to zero (default). All other types have been
15104      // converted to a number type further up in the call chain.
15105      ASSERT(value->IsUndefined());
15106    }
15107    array->set(index, cast_value);
15108  }
15109  return array->GetIsolate()->factory()->NewNumberFromUint(cast_value);
15110}
15111
15112
15113Handle<Object> ExternalFloat32Array::SetValue(
15114    Handle<ExternalFloat32Array> array,
15115    uint32_t index,
15116    Handle<Object> value) {
15117  float cast_value = static_cast<float>(OS::nan_value());
15118  if (index < static_cast<uint32_t>(array->length())) {
15119    if (value->IsSmi()) {
15120      int int_value = Handle<Smi>::cast(value)->value();
15121      cast_value = static_cast<float>(int_value);
15122    } else if (value->IsHeapNumber()) {
15123      double double_value = Handle<HeapNumber>::cast(value)->value();
15124      cast_value = static_cast<float>(double_value);
15125    } else {
15126      // Clamp undefined to NaN (default). All other types have been
15127      // converted to a number type further up in the call chain.
15128      ASSERT(value->IsUndefined());
15129    }
15130    array->set(index, cast_value);
15131  }
15132  return array->GetIsolate()->factory()->NewNumber(cast_value);
15133}
15134
15135
15136Handle<Object> ExternalFloat64Array::SetValue(
15137    Handle<ExternalFloat64Array> array,
15138    uint32_t index,
15139    Handle<Object> value) {
15140  double double_value = OS::nan_value();
15141  if (index < static_cast<uint32_t>(array->length())) {
15142    if (value->IsNumber()) {
15143      double_value = value->Number();
15144    } else {
15145      // Clamp undefined to NaN (default). All other types have been
15146      // converted to a number type further up in the call chain.
15147      ASSERT(value->IsUndefined());
15148    }
15149    array->set(index, double_value);
15150  }
15151  return array->GetIsolate()->factory()->NewNumber(double_value);
15152}
15153
15154
15155PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
15156  ASSERT(!HasFastProperties());
15157  Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
15158  return PropertyCell::cast(value);
15159}
15160
15161
15162Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
15163    Handle<JSGlobalObject> global,
15164    Handle<Name> name) {
15165  ASSERT(!global->HasFastProperties());
15166  int entry = global->property_dictionary()->FindEntry(name);
15167  if (entry == NameDictionary::kNotFound) {
15168    Isolate* isolate = global->GetIsolate();
15169    Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
15170        isolate->factory()->the_hole_value());
15171    PropertyDetails details(NONE, NORMAL, 0);
15172    details = details.AsDeleted();
15173    Handle<NameDictionary> dictionary = NameDictionary::Add(
15174        handle(global->property_dictionary()), name, cell, details);
15175    global->set_properties(*dictionary);
15176    return cell;
15177  } else {
15178    Object* value = global->property_dictionary()->ValueAt(entry);
15179    ASSERT(value->IsPropertyCell());
15180    return handle(PropertyCell::cast(value));
15181  }
15182}
15183
15184
15185// This class is used for looking up two character strings in the string table.
15186// If we don't have a hit we don't want to waste much time so we unroll the
15187// string hash calculation loop here for speed.  Doesn't work if the two
15188// characters form a decimal integer, since such strings have a different hash
15189// algorithm.
15190class TwoCharHashTableKey : public HashTableKey {
15191 public:
15192  TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
15193    : c1_(c1), c2_(c2) {
15194    // Char 1.
15195    uint32_t hash = seed;
15196    hash += c1;
15197    hash += hash << 10;
15198    hash ^= hash >> 6;
15199    // Char 2.
15200    hash += c2;
15201    hash += hash << 10;
15202    hash ^= hash >> 6;
15203    // GetHash.
15204    hash += hash << 3;
15205    hash ^= hash >> 11;
15206    hash += hash << 15;
15207    if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
15208    hash_ = hash;
15209#ifdef DEBUG
15210    // If this assert fails then we failed to reproduce the two-character
15211    // version of the string hashing algorithm above.  One reason could be
15212    // that we were passed two digits as characters, since the hash
15213    // algorithm is different in that case.
15214    uint16_t chars[2] = {c1, c2};
15215    uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
15216    hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
15217    ASSERT_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
15218#endif
15219  }
15220
15221  bool IsMatch(Object* o) V8_OVERRIDE {
15222    if (!o->IsString()) return false;
15223    String* other = String::cast(o);
15224    if (other->length() != 2) return false;
15225    if (other->Get(0) != c1_) return false;
15226    return other->Get(1) == c2_;
15227  }
15228
15229  uint32_t Hash() V8_OVERRIDE { return hash_; }
15230  uint32_t HashForObject(Object* key) V8_OVERRIDE {
15231    if (!key->IsString()) return 0;
15232    return String::cast(key)->Hash();
15233  }
15234
15235  Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE {
15236    // The TwoCharHashTableKey is only used for looking in the string
15237    // table, not for adding to it.
15238    UNREACHABLE();
15239    return MaybeHandle<Object>().ToHandleChecked();
15240  }
15241
15242 private:
15243  uint16_t c1_;
15244  uint16_t c2_;
15245  uint32_t hash_;
15246};
15247
15248
15249MaybeHandle<String> StringTable::InternalizeStringIfExists(
15250    Isolate* isolate,
15251    Handle<String> string) {
15252  if (string->IsInternalizedString()) {
15253    return string;
15254  }
15255  return LookupStringIfExists(isolate, string);
15256}
15257
15258
15259MaybeHandle<String> StringTable::LookupStringIfExists(
15260    Isolate* isolate,
15261    Handle<String> string) {
15262  Handle<StringTable> string_table = isolate->factory()->string_table();
15263  InternalizedStringKey key(string);
15264  int entry = string_table->FindEntry(&key);
15265  if (entry == kNotFound) {
15266    return MaybeHandle<String>();
15267  } else {
15268    Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
15269    ASSERT(StringShape(*result).IsInternalized());
15270    return result;
15271  }
15272}
15273
15274
15275MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
15276    Isolate* isolate,
15277    uint16_t c1,
15278    uint16_t c2) {
15279  Handle<StringTable> string_table = isolate->factory()->string_table();
15280  TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
15281  int entry = string_table->FindEntry(&key);
15282  if (entry == kNotFound) {
15283    return MaybeHandle<String>();
15284  } else {
15285    Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
15286    ASSERT(StringShape(*result).IsInternalized());
15287    return result;
15288  }
15289}
15290
15291
15292Handle<String> StringTable::LookupString(Isolate* isolate,
15293                                         Handle<String> string) {
15294  InternalizedStringKey key(string);
15295  return LookupKey(isolate, &key);
15296}
15297
15298
15299Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
15300  Handle<StringTable> table = isolate->factory()->string_table();
15301  int entry = table->FindEntry(key);
15302
15303  // String already in table.
15304  if (entry != kNotFound) {
15305    return handle(String::cast(table->KeyAt(entry)), isolate);
15306  }
15307
15308  // Adding new string. Grow table if needed.
15309  table = StringTable::EnsureCapacity(table, 1, key);
15310
15311  // Create string object.
15312  Handle<Object> string = key->AsHandle(isolate);
15313  // There must be no attempts to internalize strings that could throw
15314  // InvalidStringLength error.
15315  CHECK(!string.is_null());
15316
15317  // Add the new string and return it along with the string table.
15318  entry = table->FindInsertionEntry(key->Hash());
15319  table->set(EntryToIndex(entry), *string);
15320  table->ElementAdded();
15321
15322  isolate->factory()->set_string_table(table);
15323  return Handle<String>::cast(string);
15324}
15325
15326
15327Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
15328                                             Handle<Context> context) {
15329  Isolate* isolate = GetIsolate();
15330  Handle<SharedFunctionInfo> shared(context->closure()->shared());
15331  StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
15332                      RelocInfo::kNoPosition);
15333  int entry = FindEntry(&key);
15334  if (entry == kNotFound) return isolate->factory()->undefined_value();
15335  return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
15336}
15337
15338
15339Handle<Object> CompilationCacheTable::LookupEval(Handle<String> src,
15340                                                 Handle<Context> context,
15341                                                 StrictMode strict_mode,
15342                                                 int scope_position) {
15343  Isolate* isolate = GetIsolate();
15344  Handle<SharedFunctionInfo> shared(context->closure()->shared());
15345  StringSharedKey key(src, shared, strict_mode, scope_position);
15346  int entry = FindEntry(&key);
15347  if (entry == kNotFound) return isolate->factory()->undefined_value();
15348  return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
15349}
15350
15351
15352Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
15353                                                   JSRegExp::Flags flags) {
15354  Isolate* isolate = GetIsolate();
15355  DisallowHeapAllocation no_allocation;
15356  RegExpKey key(src, flags);
15357  int entry = FindEntry(&key);
15358  if (entry == kNotFound) return isolate->factory()->undefined_value();
15359  return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
15360}
15361
15362
15363Handle<CompilationCacheTable> CompilationCacheTable::Put(
15364    Handle<CompilationCacheTable> cache, Handle<String> src,
15365    Handle<Context> context, Handle<Object> value) {
15366  Isolate* isolate = cache->GetIsolate();
15367  Handle<SharedFunctionInfo> shared(context->closure()->shared());
15368  StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
15369                      RelocInfo::kNoPosition);
15370  cache = EnsureCapacity(cache, 1, &key);
15371  Handle<Object> k = key.AsHandle(isolate);
15372  int entry = cache->FindInsertionEntry(key.Hash());
15373  cache->set(EntryToIndex(entry), *k);
15374  cache->set(EntryToIndex(entry) + 1, *value);
15375  cache->ElementAdded();
15376  return cache;
15377}
15378
15379
15380Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
15381    Handle<CompilationCacheTable> cache, Handle<String> src,
15382    Handle<Context> context, Handle<SharedFunctionInfo> value,
15383    int scope_position) {
15384  Isolate* isolate = cache->GetIsolate();
15385  Handle<SharedFunctionInfo> shared(context->closure()->shared());
15386  StringSharedKey key(src, shared, value->strict_mode(), scope_position);
15387  cache = EnsureCapacity(cache, 1, &key);
15388  Handle<Object> k = key.AsHandle(isolate);
15389  int entry = cache->FindInsertionEntry(key.Hash());
15390  cache->set(EntryToIndex(entry), *k);
15391  cache->set(EntryToIndex(entry) + 1, *value);
15392  cache->ElementAdded();
15393  return cache;
15394}
15395
15396
15397Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
15398      Handle<CompilationCacheTable> cache, Handle<String> src,
15399      JSRegExp::Flags flags, Handle<FixedArray> value) {
15400  RegExpKey key(src, flags);
15401  cache = EnsureCapacity(cache, 1, &key);
15402  int entry = cache->FindInsertionEntry(key.Hash());
15403  // We store the value in the key slot, and compare the search key
15404  // to the stored value with a custon IsMatch function during lookups.
15405  cache->set(EntryToIndex(entry), *value);
15406  cache->set(EntryToIndex(entry) + 1, *value);
15407  cache->ElementAdded();
15408  return cache;
15409}
15410
15411
15412void CompilationCacheTable::Remove(Object* value) {
15413  DisallowHeapAllocation no_allocation;
15414  Object* the_hole_value = GetHeap()->the_hole_value();
15415  for (int entry = 0, size = Capacity(); entry < size; entry++) {
15416    int entry_index = EntryToIndex(entry);
15417    int value_index = entry_index + 1;
15418    if (get(value_index) == value) {
15419      NoWriteBarrierSet(this, entry_index, the_hole_value);
15420      NoWriteBarrierSet(this, value_index, the_hole_value);
15421      ElementRemoved();
15422    }
15423  }
15424  return;
15425}
15426
15427
15428// StringsKey used for HashTable where key is array of internalized strings.
15429class StringsKey : public HashTableKey {
15430 public:
15431  explicit StringsKey(Handle<FixedArray> strings) : strings_(strings) { }
15432
15433  bool IsMatch(Object* strings) V8_OVERRIDE {
15434    FixedArray* o = FixedArray::cast(strings);
15435    int len = strings_->length();
15436    if (o->length() != len) return false;
15437    for (int i = 0; i < len; i++) {
15438      if (o->get(i) != strings_->get(i)) return false;
15439    }
15440    return true;
15441  }
15442
15443  uint32_t Hash() V8_OVERRIDE { return HashForObject(*strings_); }
15444
15445  uint32_t HashForObject(Object* obj) V8_OVERRIDE {
15446    FixedArray* strings = FixedArray::cast(obj);
15447    int len = strings->length();
15448    uint32_t hash = 0;
15449    for (int i = 0; i < len; i++) {
15450      hash ^= String::cast(strings->get(i))->Hash();
15451    }
15452    return hash;
15453  }
15454
15455  Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE { return strings_; }
15456
15457 private:
15458  Handle<FixedArray> strings_;
15459};
15460
15461
15462Object* MapCache::Lookup(FixedArray* array) {
15463  DisallowHeapAllocation no_alloc;
15464  StringsKey key(handle(array));
15465  int entry = FindEntry(&key);
15466  if (entry == kNotFound) return GetHeap()->undefined_value();
15467  return get(EntryToIndex(entry) + 1);
15468}
15469
15470
15471Handle<MapCache> MapCache::Put(
15472    Handle<MapCache> map_cache, Handle<FixedArray> array, Handle<Map> value) {
15473  StringsKey key(array);
15474
15475  Handle<MapCache> new_cache = EnsureCapacity(map_cache, 1, &key);
15476  int entry = new_cache->FindInsertionEntry(key.Hash());
15477  new_cache->set(EntryToIndex(entry), *array);
15478  new_cache->set(EntryToIndex(entry) + 1, *value);
15479  new_cache->ElementAdded();
15480  return new_cache;
15481}
15482
15483
15484template<typename Derived, typename Shape, typename Key>
15485Handle<Derived> Dictionary<Derived, Shape, Key>::New(
15486    Isolate* isolate,
15487    int at_least_space_for,
15488    PretenureFlag pretenure) {
15489  ASSERT(0 <= at_least_space_for);
15490  Handle<Derived> dict = DerivedHashTable::New(isolate,
15491                                               at_least_space_for,
15492                                               USE_DEFAULT_MINIMUM_CAPACITY,
15493                                               pretenure);
15494
15495  // Initialize the next enumeration index.
15496  dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
15497  return dict;
15498}
15499
15500
15501template<typename Derived, typename Shape, typename Key>
15502void Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
15503    Handle<Derived> dictionary) {
15504  Factory* factory = dictionary->GetIsolate()->factory();
15505  int length = dictionary->NumberOfElements();
15506
15507  // Allocate and initialize iteration order array.
15508  Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
15509  for (int i = 0; i < length; i++) {
15510    iteration_order->set(i, Smi::FromInt(i));
15511  }
15512
15513  // Allocate array with enumeration order.
15514  Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
15515
15516  // Fill the enumeration order array with property details.
15517  int capacity = dictionary->Capacity();
15518  int pos = 0;
15519  for (int i = 0; i < capacity; i++) {
15520    if (dictionary->IsKey(dictionary->KeyAt(i))) {
15521      int index = dictionary->DetailsAt(i).dictionary_index();
15522      enumeration_order->set(pos++, Smi::FromInt(index));
15523    }
15524  }
15525
15526  // Sort the arrays wrt. enumeration order.
15527  iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
15528
15529  // Overwrite the enumeration_order with the enumeration indices.
15530  for (int i = 0; i < length; i++) {
15531    int index = Smi::cast(iteration_order->get(i))->value();
15532    int enum_index = PropertyDetails::kInitialIndex + i;
15533    enumeration_order->set(index, Smi::FromInt(enum_index));
15534  }
15535
15536  // Update the dictionary with new indices.
15537  capacity = dictionary->Capacity();
15538  pos = 0;
15539  for (int i = 0; i < capacity; i++) {
15540    if (dictionary->IsKey(dictionary->KeyAt(i))) {
15541      int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
15542      PropertyDetails details = dictionary->DetailsAt(i);
15543      PropertyDetails new_details = PropertyDetails(
15544          details.attributes(), details.type(), enum_index);
15545      dictionary->DetailsAtPut(i, new_details);
15546    }
15547  }
15548
15549  // Set the next enumeration index.
15550  dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
15551}
15552
15553
15554template<typename Derived, typename Shape, typename Key>
15555Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
15556    Handle<Derived> dictionary, int n, Key key) {
15557  // Check whether there are enough enumeration indices to add n elements.
15558  if (Shape::kIsEnumerable &&
15559      !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
15560    // If not, we generate new indices for the properties.
15561    GenerateNewEnumerationIndices(dictionary);
15562  }
15563  return DerivedHashTable::EnsureCapacity(dictionary, n, key);
15564}
15565
15566
15567template<typename Derived, typename Shape, typename Key>
15568Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
15569    Handle<Derived> dictionary,
15570    int entry,
15571    JSObject::DeleteMode mode) {
15572  Factory* factory = dictionary->GetIsolate()->factory();
15573  PropertyDetails details = dictionary->DetailsAt(entry);
15574  // Ignore attributes if forcing a deletion.
15575  if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
15576    return factory->false_value();
15577  }
15578
15579  dictionary->SetEntry(
15580      entry, factory->the_hole_value(), factory->the_hole_value());
15581  dictionary->ElementRemoved();
15582  return factory->true_value();
15583}
15584
15585
15586template<typename Derived, typename Shape, typename Key>
15587Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
15588    Handle<Derived> dictionary, Key key, Handle<Object> value) {
15589  int entry = dictionary->FindEntry(key);
15590
15591  // If the entry is present set the value;
15592  if (entry != Dictionary::kNotFound) {
15593    dictionary->ValueAtPut(entry, *value);
15594    return dictionary;
15595  }
15596
15597  // Check whether the dictionary should be extended.
15598  dictionary = EnsureCapacity(dictionary, 1, key);
15599#ifdef DEBUG
15600  USE(Shape::AsHandle(dictionary->GetIsolate(), key));
15601#endif
15602  PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
15603
15604  AddEntry(dictionary, key, value, details, dictionary->Hash(key));
15605  return dictionary;
15606}
15607
15608
15609template<typename Derived, typename Shape, typename Key>
15610Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
15611    Handle<Derived> dictionary,
15612    Key key,
15613    Handle<Object> value,
15614    PropertyDetails details) {
15615  // Valdate key is absent.
15616  SLOW_ASSERT((dictionary->FindEntry(key) == Dictionary::kNotFound));
15617  // Check whether the dictionary should be extended.
15618  dictionary = EnsureCapacity(dictionary, 1, key);
15619
15620  AddEntry(dictionary, key, value, details, dictionary->Hash(key));
15621  return dictionary;
15622}
15623
15624
15625// Add a key, value pair to the dictionary.
15626template<typename Derived, typename Shape, typename Key>
15627void Dictionary<Derived, Shape, Key>::AddEntry(
15628    Handle<Derived> dictionary,
15629    Key key,
15630    Handle<Object> value,
15631    PropertyDetails details,
15632    uint32_t hash) {
15633  // Compute the key object.
15634  Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
15635
15636  uint32_t entry = dictionary->FindInsertionEntry(hash);
15637  // Insert element at empty or deleted entry
15638  if (!details.IsDeleted() &&
15639      details.dictionary_index() == 0 &&
15640      Shape::kIsEnumerable) {
15641    // Assign an enumeration index to the property and update
15642    // SetNextEnumerationIndex.
15643    int index = dictionary->NextEnumerationIndex();
15644    details = PropertyDetails(details.attributes(), details.type(), index);
15645    dictionary->SetNextEnumerationIndex(index + 1);
15646  }
15647  dictionary->SetEntry(entry, k, value, details);
15648  ASSERT((dictionary->KeyAt(entry)->IsNumber() ||
15649          dictionary->KeyAt(entry)->IsName()));
15650  dictionary->ElementAdded();
15651}
15652
15653
15654void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
15655  DisallowHeapAllocation no_allocation;
15656  // If the dictionary requires slow elements an element has already
15657  // been added at a high index.
15658  if (requires_slow_elements()) return;
15659  // Check if this index is high enough that we should require slow
15660  // elements.
15661  if (key > kRequiresSlowElementsLimit) {
15662    set_requires_slow_elements();
15663    return;
15664  }
15665  // Update max key value.
15666  Object* max_index_object = get(kMaxNumberKeyIndex);
15667  if (!max_index_object->IsSmi() || max_number_key() < key) {
15668    FixedArray::set(kMaxNumberKeyIndex,
15669                    Smi::FromInt(key << kRequiresSlowElementsTagSize));
15670  }
15671}
15672
15673
15674Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
15675    Handle<SeededNumberDictionary> dictionary,
15676    uint32_t key,
15677    Handle<Object> value,
15678    PropertyDetails details) {
15679  dictionary->UpdateMaxNumberKey(key);
15680  SLOW_ASSERT(dictionary->FindEntry(key) == kNotFound);
15681  return Add(dictionary, key, value, details);
15682}
15683
15684
15685Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
15686    Handle<UnseededNumberDictionary> dictionary,
15687    uint32_t key,
15688    Handle<Object> value) {
15689  SLOW_ASSERT(dictionary->FindEntry(key) == kNotFound);
15690  return Add(dictionary, key, value, PropertyDetails(NONE, NORMAL, 0));
15691}
15692
15693
15694Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
15695    Handle<SeededNumberDictionary> dictionary,
15696    uint32_t key,
15697    Handle<Object> value) {
15698  dictionary->UpdateMaxNumberKey(key);
15699  return AtPut(dictionary, key, value);
15700}
15701
15702
15703Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
15704    Handle<UnseededNumberDictionary> dictionary,
15705    uint32_t key,
15706    Handle<Object> value) {
15707  return AtPut(dictionary, key, value);
15708}
15709
15710
15711Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
15712    Handle<SeededNumberDictionary> dictionary,
15713    uint32_t key,
15714    Handle<Object> value,
15715    PropertyDetails details) {
15716  int entry = dictionary->FindEntry(key);
15717  if (entry == kNotFound) {
15718    return AddNumberEntry(dictionary, key, value, details);
15719  }
15720  // Preserve enumeration index.
15721  details = PropertyDetails(details.attributes(),
15722                            details.type(),
15723                            dictionary->DetailsAt(entry).dictionary_index());
15724  Handle<Object> object_key =
15725      SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15726  dictionary->SetEntry(entry, object_key, value, details);
15727  return dictionary;
15728}
15729
15730
15731Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
15732    Handle<UnseededNumberDictionary> dictionary,
15733    uint32_t key,
15734    Handle<Object> value) {
15735  int entry = dictionary->FindEntry(key);
15736  if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
15737  Handle<Object> object_key =
15738      UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15739  dictionary->SetEntry(entry, object_key, value);
15740  return dictionary;
15741}
15742
15743
15744
15745template<typename Derived, typename Shape, typename Key>
15746int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
15747    PropertyAttributes filter) {
15748  int capacity = DerivedHashTable::Capacity();
15749  int result = 0;
15750  for (int i = 0; i < capacity; i++) {
15751    Object* k = DerivedHashTable::KeyAt(i);
15752    if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
15753      PropertyDetails details = DetailsAt(i);
15754      if (details.IsDeleted()) continue;
15755      PropertyAttributes attr = details.attributes();
15756      if ((attr & filter) == 0) result++;
15757    }
15758  }
15759  return result;
15760}
15761
15762
15763template<typename Derived, typename Shape, typename Key>
15764int Dictionary<Derived, Shape, Key>::NumberOfEnumElements() {
15765  return NumberOfElementsFilterAttributes(
15766      static_cast<PropertyAttributes>(DONT_ENUM | SYMBOLIC));
15767}
15768
15769
15770template<typename Derived, typename Shape, typename Key>
15771void Dictionary<Derived, Shape, Key>::CopyKeysTo(
15772    FixedArray* storage,
15773    PropertyAttributes filter,
15774    typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15775  ASSERT(storage->length() >= NumberOfElementsFilterAttributes(filter));
15776  int capacity = DerivedHashTable::Capacity();
15777  int index = 0;
15778  for (int i = 0; i < capacity; i++) {
15779     Object* k = DerivedHashTable::KeyAt(i);
15780     if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
15781       PropertyDetails details = DetailsAt(i);
15782       if (details.IsDeleted()) continue;
15783       PropertyAttributes attr = details.attributes();
15784       if ((attr & filter) == 0) storage->set(index++, k);
15785     }
15786  }
15787  if (sort_mode == Dictionary::SORTED) {
15788    storage->SortPairs(storage, index);
15789  }
15790  ASSERT(storage->length() >= index);
15791}
15792
15793
15794struct EnumIndexComparator {
15795  explicit EnumIndexComparator(NameDictionary* dict) : dict(dict) { }
15796  bool operator() (Smi* a, Smi* b) {
15797    PropertyDetails da(dict->DetailsAt(a->value()));
15798    PropertyDetails db(dict->DetailsAt(b->value()));
15799    return da.dictionary_index() < db.dictionary_index();
15800  }
15801  NameDictionary* dict;
15802};
15803
15804
15805void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
15806  int length = storage->length();
15807  int capacity = Capacity();
15808  int properties = 0;
15809  for (int i = 0; i < capacity; i++) {
15810     Object* k = KeyAt(i);
15811     if (IsKey(k) && !k->IsSymbol()) {
15812       PropertyDetails details = DetailsAt(i);
15813       if (details.IsDeleted() || details.IsDontEnum()) continue;
15814       storage->set(properties, Smi::FromInt(i));
15815       properties++;
15816       if (properties == length) break;
15817     }
15818  }
15819  CHECK_EQ(length, properties);
15820  EnumIndexComparator cmp(this);
15821  Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
15822  std::sort(start, start + length, cmp);
15823  for (int i = 0; i < length; i++) {
15824    int index = Smi::cast(storage->get(i))->value();
15825    storage->set(i, KeyAt(index));
15826  }
15827}
15828
15829
15830template<typename Derived, typename Shape, typename Key>
15831void Dictionary<Derived, Shape, Key>::CopyKeysTo(
15832    FixedArray* storage,
15833    int index,
15834    PropertyAttributes filter,
15835    typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15836  ASSERT(storage->length() >= NumberOfElementsFilterAttributes(filter));
15837  int capacity = DerivedHashTable::Capacity();
15838  for (int i = 0; i < capacity; i++) {
15839    Object* k = DerivedHashTable::KeyAt(i);
15840    if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
15841      PropertyDetails details = DetailsAt(i);
15842      if (details.IsDeleted()) continue;
15843      PropertyAttributes attr = details.attributes();
15844      if ((attr & filter) == 0) storage->set(index++, k);
15845    }
15846  }
15847  if (sort_mode == Dictionary::SORTED) {
15848    storage->SortPairs(storage, index);
15849  }
15850  ASSERT(storage->length() >= index);
15851}
15852
15853
15854// Backwards lookup (slow).
15855template<typename Derived, typename Shape, typename Key>
15856Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
15857  int capacity = DerivedHashTable::Capacity();
15858  for (int i = 0; i < capacity; i++) {
15859    Object* k =  DerivedHashTable::KeyAt(i);
15860    if (Dictionary::IsKey(k)) {
15861      Object* e = ValueAt(i);
15862      if (e->IsPropertyCell()) {
15863        e = PropertyCell::cast(e)->value();
15864      }
15865      if (e == value) return k;
15866    }
15867  }
15868  Heap* heap = Dictionary::GetHeap();
15869  return heap->undefined_value();
15870}
15871
15872
15873Object* ObjectHashTable::Lookup(Handle<Object> key) {
15874  DisallowHeapAllocation no_gc;
15875  ASSERT(IsKey(*key));
15876
15877  // If the object does not have an identity hash, it was never used as a key.
15878  Object* hash = key->GetHash();
15879  if (hash->IsUndefined()) {
15880    return GetHeap()->the_hole_value();
15881  }
15882  int entry = FindEntry(key);
15883  if (entry == kNotFound) return GetHeap()->the_hole_value();
15884  return get(EntryToIndex(entry) + 1);
15885}
15886
15887
15888Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
15889                                             Handle<Object> key,
15890                                             Handle<Object> value) {
15891  ASSERT(table->IsKey(*key));
15892  ASSERT(!value->IsTheHole());
15893
15894  Isolate* isolate = table->GetIsolate();
15895
15896  // Make sure the key object has an identity hash code.
15897  Handle<Smi> hash = Object::GetOrCreateHash(isolate, key);
15898
15899  int entry = table->FindEntry(key);
15900
15901  // Key is already in table, just overwrite value.
15902  if (entry != kNotFound) {
15903    table->set(EntryToIndex(entry) + 1, *value);
15904    return table;
15905  }
15906
15907  // Check whether the hash table should be extended.
15908  table = EnsureCapacity(table, 1, key);
15909  table->AddEntry(table->FindInsertionEntry(hash->value()),
15910                  *key,
15911                  *value);
15912  return table;
15913}
15914
15915
15916Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
15917                                                Handle<Object> key,
15918                                                bool* was_present) {
15919  ASSERT(table->IsKey(*key));
15920
15921  Object* hash = key->GetHash();
15922  if (hash->IsUndefined()) {
15923    *was_present = false;
15924    return table;
15925  }
15926
15927  int entry = table->FindEntry(key);
15928  if (entry == kNotFound) {
15929    *was_present = false;
15930    return table;
15931  }
15932
15933  *was_present = true;
15934  table->RemoveEntry(entry);
15935  return Shrink(table, key);
15936}
15937
15938
15939void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
15940  set(EntryToIndex(entry), key);
15941  set(EntryToIndex(entry) + 1, value);
15942  ElementAdded();
15943}
15944
15945
15946void ObjectHashTable::RemoveEntry(int entry) {
15947  set_the_hole(EntryToIndex(entry));
15948  set_the_hole(EntryToIndex(entry) + 1);
15949  ElementRemoved();
15950}
15951
15952
15953Object* WeakHashTable::Lookup(Handle<Object> key) {
15954  DisallowHeapAllocation no_gc;
15955  ASSERT(IsKey(*key));
15956  int entry = FindEntry(key);
15957  if (entry == kNotFound) return GetHeap()->the_hole_value();
15958  return get(EntryToValueIndex(entry));
15959}
15960
15961
15962Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
15963                                         Handle<Object> key,
15964                                         Handle<Object> value) {
15965  ASSERT(table->IsKey(*key));
15966  int entry = table->FindEntry(key);
15967  // Key is already in table, just overwrite value.
15968  if (entry != kNotFound) {
15969    // TODO(ulan): Skipping write barrier is a temporary solution to avoid
15970    // memory leaks. Remove this once we have special visitor for weak fixed
15971    // arrays.
15972    table->set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
15973    return table;
15974  }
15975
15976  // Check whether the hash table should be extended.
15977  table = EnsureCapacity(table, 1, key, TENURED);
15978
15979  table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key, value);
15980  return table;
15981}
15982
15983
15984void WeakHashTable::AddEntry(int entry,
15985                             Handle<Object> key,
15986                             Handle<Object> value) {
15987  DisallowHeapAllocation no_allocation;
15988  // TODO(ulan): Skipping write barrier is a temporary solution to avoid
15989  // memory leaks. Remove this once we have special visitor for weak fixed
15990  // arrays.
15991  set(EntryToIndex(entry), *key, SKIP_WRITE_BARRIER);
15992  set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
15993  ElementAdded();
15994}
15995
15996
15997template<class Derived, class Iterator, int entrysize>
15998Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
15999    Isolate* isolate, int capacity, PretenureFlag pretenure) {
16000  // Capacity must be a power of two, since we depend on being able
16001  // to divide and multiple by 2 (kLoadFactor) to derive capacity
16002  // from number of buckets. If we decide to change kLoadFactor
16003  // to something other than 2, capacity should be stored as another
16004  // field of this object.
16005  capacity = RoundUpToPowerOf2(Max(kMinCapacity, capacity));
16006  if (capacity > kMaxCapacity) {
16007    v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16008  }
16009  int num_buckets = capacity / kLoadFactor;
16010  Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
16011      kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
16012  backing_store->set_map_no_write_barrier(
16013      isolate->heap()->ordered_hash_table_map());
16014  Handle<Derived> table = Handle<Derived>::cast(backing_store);
16015  for (int i = 0; i < num_buckets; ++i) {
16016    table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
16017  }
16018  table->SetNumberOfBuckets(num_buckets);
16019  table->SetNumberOfElements(0);
16020  table->SetNumberOfDeletedElements(0);
16021  return table;
16022}
16023
16024
16025template<class Derived, class Iterator, int entrysize>
16026Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
16027    Handle<Derived> table) {
16028  ASSERT(!table->IsObsolete());
16029
16030  int nof = table->NumberOfElements();
16031  int nod = table->NumberOfDeletedElements();
16032  int capacity = table->Capacity();
16033  if ((nof + nod) < capacity) return table;
16034  // Don't need to grow if we can simply clear out deleted entries instead.
16035  // Note that we can't compact in place, though, so we always allocate
16036  // a new table.
16037  return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
16038}
16039
16040
16041template<class Derived, class Iterator, int entrysize>
16042Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
16043    Handle<Derived> table) {
16044  ASSERT(!table->IsObsolete());
16045
16046  int nof = table->NumberOfElements();
16047  int capacity = table->Capacity();
16048  if (nof >= (capacity >> 2)) return table;
16049  return Rehash(table, capacity / 2);
16050}
16051
16052
16053template<class Derived, class Iterator, int entrysize>
16054Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
16055    Handle<Derived> table) {
16056  ASSERT(!table->IsObsolete());
16057
16058  Handle<Derived> new_table =
16059      Allocate(table->GetIsolate(),
16060               kMinCapacity,
16061               table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
16062
16063  table->SetNextTable(*new_table);
16064  table->SetNumberOfDeletedElements(-1);
16065
16066  return new_table;
16067}
16068
16069
16070template<class Derived, class Iterator, int entrysize>
16071Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Remove(
16072    Handle<Derived> table, Handle<Object> key, bool* was_present) {
16073  int entry = table->FindEntry(key);
16074  if (entry == kNotFound) {
16075    *was_present = false;
16076    return table;
16077  }
16078  *was_present = true;
16079  table->RemoveEntry(entry);
16080  return Shrink(table);
16081}
16082
16083
16084template<class Derived, class Iterator, int entrysize>
16085Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
16086    Handle<Derived> table, int new_capacity) {
16087  ASSERT(!table->IsObsolete());
16088
16089  Handle<Derived> new_table =
16090      Allocate(table->GetIsolate(),
16091               new_capacity,
16092               table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
16093  int nof = table->NumberOfElements();
16094  int nod = table->NumberOfDeletedElements();
16095  int new_buckets = new_table->NumberOfBuckets();
16096  int new_entry = 0;
16097  int removed_holes_index = 0;
16098
16099  for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
16100    Object* key = table->KeyAt(old_entry);
16101    if (key->IsTheHole()) {
16102      table->SetRemovedIndexAt(removed_holes_index++, old_entry);
16103      continue;
16104    }
16105
16106    Object* hash = key->GetHash();
16107    int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
16108    Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
16109    new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
16110    int new_index = new_table->EntryToIndex(new_entry);
16111    int old_index = table->EntryToIndex(old_entry);
16112    for (int i = 0; i < entrysize; ++i) {
16113      Object* value = table->get(old_index + i);
16114      new_table->set(new_index + i, value);
16115    }
16116    new_table->set(new_index + kChainOffset, chain_entry);
16117    ++new_entry;
16118  }
16119
16120  ASSERT_EQ(nod, removed_holes_index);
16121
16122  new_table->SetNumberOfElements(nof);
16123  table->SetNextTable(*new_table);
16124
16125  return new_table;
16126}
16127
16128
16129template<class Derived, class Iterator, int entrysize>
16130int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
16131    Handle<Object> key) {
16132  ASSERT(!IsObsolete());
16133
16134  DisallowHeapAllocation no_gc;
16135  ASSERT(!key->IsTheHole());
16136  Object* hash = key->GetHash();
16137  if (hash->IsUndefined()) return kNotFound;
16138  for (int entry = HashToEntry(Smi::cast(hash)->value());
16139       entry != kNotFound;
16140       entry = ChainAt(entry)) {
16141    Object* candidate = KeyAt(entry);
16142    if (candidate->SameValueZero(*key))
16143      return entry;
16144  }
16145  return kNotFound;
16146}
16147
16148
16149template<class Derived, class Iterator, int entrysize>
16150int OrderedHashTable<Derived, Iterator, entrysize>::AddEntry(int hash) {
16151  ASSERT(!IsObsolete());
16152
16153  int entry = UsedCapacity();
16154  int bucket = HashToBucket(hash);
16155  int index = EntryToIndex(entry);
16156  Object* chain_entry = get(kHashTableStartIndex + bucket);
16157  set(kHashTableStartIndex + bucket, Smi::FromInt(entry));
16158  set(index + kChainOffset, chain_entry);
16159  SetNumberOfElements(NumberOfElements() + 1);
16160  return index;
16161}
16162
16163
16164template<class Derived, class Iterator, int entrysize>
16165void OrderedHashTable<Derived, Iterator, entrysize>::RemoveEntry(int entry) {
16166  ASSERT(!IsObsolete());
16167
16168  int index = EntryToIndex(entry);
16169  for (int i = 0; i < entrysize; ++i) {
16170    set_the_hole(index + i);
16171  }
16172  SetNumberOfElements(NumberOfElements() - 1);
16173  SetNumberOfDeletedElements(NumberOfDeletedElements() + 1);
16174}
16175
16176
16177template Handle<OrderedHashSet>
16178OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
16179    Isolate* isolate, int capacity, PretenureFlag pretenure);
16180
16181template Handle<OrderedHashSet>
16182OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
16183    Handle<OrderedHashSet> table);
16184
16185template Handle<OrderedHashSet>
16186OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
16187    Handle<OrderedHashSet> table);
16188
16189template Handle<OrderedHashSet>
16190OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
16191    Handle<OrderedHashSet> table);
16192
16193template Handle<OrderedHashSet>
16194OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Remove(
16195    Handle<OrderedHashSet> table, Handle<Object> key, bool* was_present);
16196
16197template int
16198OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::FindEntry(
16199    Handle<Object> key);
16200
16201template int
16202OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::AddEntry(int hash);
16203
16204template void
16205OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::RemoveEntry(int entry);
16206
16207
16208template Handle<OrderedHashMap>
16209OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
16210    Isolate* isolate, int capacity, PretenureFlag pretenure);
16211
16212template Handle<OrderedHashMap>
16213OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
16214    Handle<OrderedHashMap> table);
16215
16216template Handle<OrderedHashMap>
16217OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
16218    Handle<OrderedHashMap> table);
16219
16220template Handle<OrderedHashMap>
16221OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
16222    Handle<OrderedHashMap> table);
16223
16224template Handle<OrderedHashMap>
16225OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Remove(
16226    Handle<OrderedHashMap> table, Handle<Object> key, bool* was_present);
16227
16228template int
16229OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::FindEntry(
16230    Handle<Object> key);
16231
16232template int
16233OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::AddEntry(int hash);
16234
16235template void
16236OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::RemoveEntry(int entry);
16237
16238
16239bool OrderedHashSet::Contains(Handle<Object> key) {
16240  return FindEntry(key) != kNotFound;
16241}
16242
16243
16244Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
16245                                           Handle<Object> key) {
16246  if (table->FindEntry(key) != kNotFound) return table;
16247
16248  table = EnsureGrowable(table);
16249
16250  Handle<Smi> hash = GetOrCreateHash(table->GetIsolate(), key);
16251  int index = table->AddEntry(hash->value());
16252  table->set(index, *key);
16253  return table;
16254}
16255
16256
16257Object* OrderedHashMap::Lookup(Handle<Object> key) {
16258  DisallowHeapAllocation no_gc;
16259  int entry = FindEntry(key);
16260  if (entry == kNotFound) return GetHeap()->the_hole_value();
16261  return ValueAt(entry);
16262}
16263
16264
16265Handle<OrderedHashMap> OrderedHashMap::Put(Handle<OrderedHashMap> table,
16266                                           Handle<Object> key,
16267                                           Handle<Object> value) {
16268  ASSERT(!key->IsTheHole());
16269
16270  int entry = table->FindEntry(key);
16271
16272  if (entry != kNotFound) {
16273    table->set(table->EntryToIndex(entry) + kValueOffset, *value);
16274    return table;
16275  }
16276
16277  table = EnsureGrowable(table);
16278
16279  Handle<Smi> hash = GetOrCreateHash(table->GetIsolate(), key);
16280  int index = table->AddEntry(hash->value());
16281  table->set(index, *key);
16282  table->set(index + kValueOffset, *value);
16283  return table;
16284}
16285
16286
16287template<class Derived, class TableType>
16288Handle<JSObject> OrderedHashTableIterator<Derived, TableType>::Next(
16289    Handle<Derived> iterator) {
16290  Isolate* isolate = iterator->GetIsolate();
16291  Factory* factory = isolate->factory();
16292
16293  Handle<Object> maybe_table(iterator->table(), isolate);
16294  if (!maybe_table->IsUndefined()) {
16295    iterator->Transition();
16296
16297    Handle<TableType> table(TableType::cast(iterator->table()), isolate);
16298    int index = Smi::cast(iterator->index())->value();
16299    int used_capacity = table->UsedCapacity();
16300
16301    while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
16302      index++;
16303    }
16304
16305    if (index < used_capacity) {
16306      int entry_index = table->EntryToIndex(index);
16307      Handle<Object> value =
16308          Derived::ValueForKind(iterator, entry_index);
16309      iterator->set_index(Smi::FromInt(index + 1));
16310      return factory->NewIteratorResultObject(value, false);
16311    }
16312
16313    iterator->set_table(iterator->GetHeap()->undefined_value());
16314  }
16315
16316  return factory->NewIteratorResultObject(factory->undefined_value(), true);
16317}
16318
16319
16320template<class Derived, class TableType>
16321void OrderedHashTableIterator<Derived, TableType>::Transition() {
16322  Isolate* isolate = GetIsolate();
16323  Handle<TableType> table(TableType::cast(this->table()), isolate);
16324  if (!table->IsObsolete()) return;
16325
16326  int index = Smi::cast(this->index())->value();
16327  while (table->IsObsolete()) {
16328    Handle<TableType> next_table(table->NextTable(), isolate);
16329
16330    if (index > 0) {
16331      int nod = table->NumberOfDeletedElements();
16332
16333      // When we clear the table we set the number of deleted elements to -1.
16334      if (nod == -1) {
16335        index = 0;
16336      } else {
16337        int old_index = index;
16338        for (int i = 0; i < nod; ++i) {
16339          int removed_index = table->RemovedIndexAt(i);
16340          if (removed_index >= old_index) break;
16341          --index;
16342        }
16343      }
16344    }
16345
16346    table = next_table;
16347  }
16348
16349  set_table(*table);
16350  set_index(Smi::FromInt(index));
16351}
16352
16353
16354template Handle<JSObject>
16355OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
16356    Handle<JSSetIterator> iterator);
16357
16358template void
16359OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
16360
16361
16362template Handle<JSObject>
16363OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
16364    Handle<JSMapIterator> iterator);
16365
16366template void
16367OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
16368
16369
16370Handle<Object> JSSetIterator::ValueForKind(
16371    Handle<JSSetIterator> iterator, int entry_index) {
16372  int kind = iterator->kind()->value();
16373  // Set.prototype only has values and entries.
16374  ASSERT(kind == kKindValues || kind == kKindEntries);
16375
16376  Isolate* isolate = iterator->GetIsolate();
16377  Factory* factory = isolate->factory();
16378
16379  Handle<OrderedHashSet> table(
16380      OrderedHashSet::cast(iterator->table()), isolate);
16381  Handle<Object> value = Handle<Object>(table->get(entry_index), isolate);
16382
16383  if (kind == kKindEntries) {
16384    Handle<FixedArray> array = factory->NewFixedArray(2);
16385    array->set(0, *value);
16386    array->set(1, *value);
16387    return factory->NewJSArrayWithElements(array);
16388  }
16389
16390  return value;
16391}
16392
16393
16394Handle<Object> JSMapIterator::ValueForKind(
16395    Handle<JSMapIterator> iterator, int entry_index) {
16396  int kind = iterator->kind()->value();
16397  ASSERT(kind == kKindKeys || kind == kKindValues || kind == kKindEntries);
16398
16399  Isolate* isolate = iterator->GetIsolate();
16400  Factory* factory = isolate->factory();
16401
16402  Handle<OrderedHashMap> table(
16403      OrderedHashMap::cast(iterator->table()), isolate);
16404
16405  switch (kind) {
16406    case kKindKeys:
16407      return Handle<Object>(table->get(entry_index), isolate);
16408
16409    case kKindValues:
16410      return Handle<Object>(table->get(entry_index + 1), isolate);
16411
16412    case kKindEntries: {
16413      Handle<Object> key(table->get(entry_index), isolate);
16414      Handle<Object> value(table->get(entry_index + 1), isolate);
16415      Handle<FixedArray> array = factory->NewFixedArray(2);
16416      array->set(0, *key);
16417      array->set(1, *value);
16418      return factory->NewJSArrayWithElements(array);
16419    }
16420  }
16421
16422  UNREACHABLE();
16423  return factory->undefined_value();
16424}
16425
16426
16427DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
16428    DeclaredAccessorDescriptor* descriptor)
16429    : array_(descriptor->serialized_data()->GetDataStartAddress()),
16430      length_(descriptor->serialized_data()->length()),
16431      offset_(0) {
16432}
16433
16434
16435const DeclaredAccessorDescriptorData*
16436  DeclaredAccessorDescriptorIterator::Next() {
16437  ASSERT(offset_ < length_);
16438  uint8_t* ptr = &array_[offset_];
16439  ASSERT(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
16440  const DeclaredAccessorDescriptorData* data =
16441      reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
16442  offset_ += sizeof(*data);
16443  ASSERT(offset_ <= length_);
16444  return data;
16445}
16446
16447
16448Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
16449    Isolate* isolate,
16450    const DeclaredAccessorDescriptorData& descriptor,
16451    Handle<DeclaredAccessorDescriptor> previous) {
16452  int previous_length =
16453      previous.is_null() ? 0 : previous->serialized_data()->length();
16454  int length = sizeof(descriptor) + previous_length;
16455  Handle<ByteArray> serialized_descriptor =
16456      isolate->factory()->NewByteArray(length);
16457  Handle<DeclaredAccessorDescriptor> value =
16458      isolate->factory()->NewDeclaredAccessorDescriptor();
16459  value->set_serialized_data(*serialized_descriptor);
16460  // Copy in the data.
16461  {
16462    DisallowHeapAllocation no_allocation;
16463    uint8_t* array = serialized_descriptor->GetDataStartAddress();
16464    if (previous_length != 0) {
16465      uint8_t* previous_array =
16466          previous->serialized_data()->GetDataStartAddress();
16467      MemCopy(array, previous_array, previous_length);
16468      array += previous_length;
16469    }
16470    ASSERT(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
16471    DeclaredAccessorDescriptorData* data =
16472        reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
16473    *data = descriptor;
16474  }
16475  return value;
16476}
16477
16478
16479// Check if there is a break point at this code position.
16480bool DebugInfo::HasBreakPoint(int code_position) {
16481  // Get the break point info object for this code position.
16482  Object* break_point_info = GetBreakPointInfo(code_position);
16483
16484  // If there is no break point info object or no break points in the break
16485  // point info object there is no break point at this code position.
16486  if (break_point_info->IsUndefined()) return false;
16487  return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
16488}
16489
16490
16491// Get the break point info object for this code position.
16492Object* DebugInfo::GetBreakPointInfo(int code_position) {
16493  // Find the index of the break point info object for this code position.
16494  int index = GetBreakPointInfoIndex(code_position);
16495
16496  // Return the break point info object if any.
16497  if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
16498  return BreakPointInfo::cast(break_points()->get(index));
16499}
16500
16501
16502// Clear a break point at the specified code position.
16503void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
16504                                int code_position,
16505                                Handle<Object> break_point_object) {
16506  Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
16507                                  debug_info->GetIsolate());
16508  if (break_point_info->IsUndefined()) return;
16509  BreakPointInfo::ClearBreakPoint(
16510      Handle<BreakPointInfo>::cast(break_point_info),
16511      break_point_object);
16512}
16513
16514
16515void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
16516                              int code_position,
16517                              int source_position,
16518                              int statement_position,
16519                              Handle<Object> break_point_object) {
16520  Isolate* isolate = debug_info->GetIsolate();
16521  Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
16522                                  isolate);
16523  if (!break_point_info->IsUndefined()) {
16524    BreakPointInfo::SetBreakPoint(
16525        Handle<BreakPointInfo>::cast(break_point_info),
16526        break_point_object);
16527    return;
16528  }
16529
16530  // Adding a new break point for a code position which did not have any
16531  // break points before. Try to find a free slot.
16532  int index = kNoBreakPointInfo;
16533  for (int i = 0; i < debug_info->break_points()->length(); i++) {
16534    if (debug_info->break_points()->get(i)->IsUndefined()) {
16535      index = i;
16536      break;
16537    }
16538  }
16539  if (index == kNoBreakPointInfo) {
16540    // No free slot - extend break point info array.
16541    Handle<FixedArray> old_break_points =
16542        Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
16543    Handle<FixedArray> new_break_points =
16544        isolate->factory()->NewFixedArray(
16545            old_break_points->length() +
16546            DebugInfo::kEstimatedNofBreakPointsInFunction);
16547
16548    debug_info->set_break_points(*new_break_points);
16549    for (int i = 0; i < old_break_points->length(); i++) {
16550      new_break_points->set(i, old_break_points->get(i));
16551    }
16552    index = old_break_points->length();
16553  }
16554  ASSERT(index != kNoBreakPointInfo);
16555
16556  // Allocate new BreakPointInfo object and set the break point.
16557  Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
16558      isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
16559  new_break_point_info->set_code_position(Smi::FromInt(code_position));
16560  new_break_point_info->set_source_position(Smi::FromInt(source_position));
16561  new_break_point_info->
16562      set_statement_position(Smi::FromInt(statement_position));
16563  new_break_point_info->set_break_point_objects(
16564      isolate->heap()->undefined_value());
16565  BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
16566  debug_info->break_points()->set(index, *new_break_point_info);
16567}
16568
16569
16570// Get the break point objects for a code position.
16571Object* DebugInfo::GetBreakPointObjects(int code_position) {
16572  Object* break_point_info = GetBreakPointInfo(code_position);
16573  if (break_point_info->IsUndefined()) {
16574    return GetHeap()->undefined_value();
16575  }
16576  return BreakPointInfo::cast(break_point_info)->break_point_objects();
16577}
16578
16579
16580// Get the total number of break points.
16581int DebugInfo::GetBreakPointCount() {
16582  if (break_points()->IsUndefined()) return 0;
16583  int count = 0;
16584  for (int i = 0; i < break_points()->length(); i++) {
16585    if (!break_points()->get(i)->IsUndefined()) {
16586      BreakPointInfo* break_point_info =
16587          BreakPointInfo::cast(break_points()->get(i));
16588      count += break_point_info->GetBreakPointCount();
16589    }
16590  }
16591  return count;
16592}
16593
16594
16595Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
16596                                      Handle<Object> break_point_object) {
16597  Heap* heap = debug_info->GetHeap();
16598  if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
16599  for (int i = 0; i < debug_info->break_points()->length(); i++) {
16600    if (!debug_info->break_points()->get(i)->IsUndefined()) {
16601      Handle<BreakPointInfo> break_point_info =
16602          Handle<BreakPointInfo>(BreakPointInfo::cast(
16603              debug_info->break_points()->get(i)));
16604      if (BreakPointInfo::HasBreakPointObject(break_point_info,
16605                                              break_point_object)) {
16606        return *break_point_info;
16607      }
16608    }
16609  }
16610  return heap->undefined_value();
16611}
16612
16613
16614// Find the index of the break point info object for the specified code
16615// position.
16616int DebugInfo::GetBreakPointInfoIndex(int code_position) {
16617  if (break_points()->IsUndefined()) return kNoBreakPointInfo;
16618  for (int i = 0; i < break_points()->length(); i++) {
16619    if (!break_points()->get(i)->IsUndefined()) {
16620      BreakPointInfo* break_point_info =
16621          BreakPointInfo::cast(break_points()->get(i));
16622      if (break_point_info->code_position()->value() == code_position) {
16623        return i;
16624      }
16625    }
16626  }
16627  return kNoBreakPointInfo;
16628}
16629
16630
16631// Remove the specified break point object.
16632void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
16633                                     Handle<Object> break_point_object) {
16634  Isolate* isolate = break_point_info->GetIsolate();
16635  // If there are no break points just ignore.
16636  if (break_point_info->break_point_objects()->IsUndefined()) return;
16637  // If there is a single break point clear it if it is the same.
16638  if (!break_point_info->break_point_objects()->IsFixedArray()) {
16639    if (break_point_info->break_point_objects() == *break_point_object) {
16640      break_point_info->set_break_point_objects(
16641          isolate->heap()->undefined_value());
16642    }
16643    return;
16644  }
16645  // If there are multiple break points shrink the array
16646  ASSERT(break_point_info->break_point_objects()->IsFixedArray());
16647  Handle<FixedArray> old_array =
16648      Handle<FixedArray>(
16649          FixedArray::cast(break_point_info->break_point_objects()));
16650  Handle<FixedArray> new_array =
16651      isolate->factory()->NewFixedArray(old_array->length() - 1);
16652  int found_count = 0;
16653  for (int i = 0; i < old_array->length(); i++) {
16654    if (old_array->get(i) == *break_point_object) {
16655      ASSERT(found_count == 0);
16656      found_count++;
16657    } else {
16658      new_array->set(i - found_count, old_array->get(i));
16659    }
16660  }
16661  // If the break point was found in the list change it.
16662  if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
16663}
16664
16665
16666// Add the specified break point object.
16667void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
16668                                   Handle<Object> break_point_object) {
16669  Isolate* isolate = break_point_info->GetIsolate();
16670
16671  // If there was no break point objects before just set it.
16672  if (break_point_info->break_point_objects()->IsUndefined()) {
16673    break_point_info->set_break_point_objects(*break_point_object);
16674    return;
16675  }
16676  // If the break point object is the same as before just ignore.
16677  if (break_point_info->break_point_objects() == *break_point_object) return;
16678  // If there was one break point object before replace with array.
16679  if (!break_point_info->break_point_objects()->IsFixedArray()) {
16680    Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
16681    array->set(0, break_point_info->break_point_objects());
16682    array->set(1, *break_point_object);
16683    break_point_info->set_break_point_objects(*array);
16684    return;
16685  }
16686  // If there was more than one break point before extend array.
16687  Handle<FixedArray> old_array =
16688      Handle<FixedArray>(
16689          FixedArray::cast(break_point_info->break_point_objects()));
16690  Handle<FixedArray> new_array =
16691      isolate->factory()->NewFixedArray(old_array->length() + 1);
16692  for (int i = 0; i < old_array->length(); i++) {
16693    // If the break point was there before just ignore.
16694    if (old_array->get(i) == *break_point_object) return;
16695    new_array->set(i, old_array->get(i));
16696  }
16697  // Add the new break point.
16698  new_array->set(old_array->length(), *break_point_object);
16699  break_point_info->set_break_point_objects(*new_array);
16700}
16701
16702
16703bool BreakPointInfo::HasBreakPointObject(
16704    Handle<BreakPointInfo> break_point_info,
16705    Handle<Object> break_point_object) {
16706  // No break point.
16707  if (break_point_info->break_point_objects()->IsUndefined()) return false;
16708  // Single break point.
16709  if (!break_point_info->break_point_objects()->IsFixedArray()) {
16710    return break_point_info->break_point_objects() == *break_point_object;
16711  }
16712  // Multiple break points.
16713  FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
16714  for (int i = 0; i < array->length(); i++) {
16715    if (array->get(i) == *break_point_object) {
16716      return true;
16717    }
16718  }
16719  return false;
16720}
16721
16722
16723// Get the number of break points.
16724int BreakPointInfo::GetBreakPointCount() {
16725  // No break point.
16726  if (break_point_objects()->IsUndefined()) return 0;
16727  // Single break point.
16728  if (!break_point_objects()->IsFixedArray()) return 1;
16729  // Multiple break points.
16730  return FixedArray::cast(break_point_objects())->length();
16731}
16732
16733
16734Object* JSDate::GetField(Object* object, Smi* index) {
16735  return JSDate::cast(object)->DoGetField(
16736      static_cast<FieldIndex>(index->value()));
16737}
16738
16739
16740Object* JSDate::DoGetField(FieldIndex index) {
16741  ASSERT(index != kDateValue);
16742
16743  DateCache* date_cache = GetIsolate()->date_cache();
16744
16745  if (index < kFirstUncachedField) {
16746    Object* stamp = cache_stamp();
16747    if (stamp != date_cache->stamp() && stamp->IsSmi()) {
16748      // Since the stamp is not NaN, the value is also not NaN.
16749      int64_t local_time_ms =
16750          date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
16751      SetCachedFields(local_time_ms, date_cache);
16752    }
16753    switch (index) {
16754      case kYear: return year();
16755      case kMonth: return month();
16756      case kDay: return day();
16757      case kWeekday: return weekday();
16758      case kHour: return hour();
16759      case kMinute: return min();
16760      case kSecond: return sec();
16761      default: UNREACHABLE();
16762    }
16763  }
16764
16765  if (index >= kFirstUTCField) {
16766    return GetUTCField(index, value()->Number(), date_cache);
16767  }
16768
16769  double time = value()->Number();
16770  if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
16771
16772  int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
16773  int days = DateCache::DaysFromTime(local_time_ms);
16774
16775  if (index == kDays) return Smi::FromInt(days);
16776
16777  int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16778  if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
16779  ASSERT(index == kTimeInDay);
16780  return Smi::FromInt(time_in_day_ms);
16781}
16782
16783
16784Object* JSDate::GetUTCField(FieldIndex index,
16785                            double value,
16786                            DateCache* date_cache) {
16787  ASSERT(index >= kFirstUTCField);
16788
16789  if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
16790
16791  int64_t time_ms = static_cast<int64_t>(value);
16792
16793  if (index == kTimezoneOffset) {
16794    return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
16795  }
16796
16797  int days = DateCache::DaysFromTime(time_ms);
16798
16799  if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
16800
16801  if (index <= kDayUTC) {
16802    int year, month, day;
16803    date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16804    if (index == kYearUTC) return Smi::FromInt(year);
16805    if (index == kMonthUTC) return Smi::FromInt(month);
16806    ASSERT(index == kDayUTC);
16807    return Smi::FromInt(day);
16808  }
16809
16810  int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
16811  switch (index) {
16812    case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
16813    case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
16814    case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
16815    case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
16816    case kDaysUTC: return Smi::FromInt(days);
16817    case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
16818    default: UNREACHABLE();
16819  }
16820
16821  UNREACHABLE();
16822  return NULL;
16823}
16824
16825
16826void JSDate::SetValue(Object* value, bool is_value_nan) {
16827  set_value(value);
16828  if (is_value_nan) {
16829    HeapNumber* nan = GetIsolate()->heap()->nan_value();
16830    set_cache_stamp(nan, SKIP_WRITE_BARRIER);
16831    set_year(nan, SKIP_WRITE_BARRIER);
16832    set_month(nan, SKIP_WRITE_BARRIER);
16833    set_day(nan, SKIP_WRITE_BARRIER);
16834    set_hour(nan, SKIP_WRITE_BARRIER);
16835    set_min(nan, SKIP_WRITE_BARRIER);
16836    set_sec(nan, SKIP_WRITE_BARRIER);
16837    set_weekday(nan, SKIP_WRITE_BARRIER);
16838  } else {
16839    set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
16840  }
16841}
16842
16843
16844void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
16845  int days = DateCache::DaysFromTime(local_time_ms);
16846  int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16847  int year, month, day;
16848  date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16849  int weekday = date_cache->Weekday(days);
16850  int hour = time_in_day_ms / (60 * 60 * 1000);
16851  int min = (time_in_day_ms / (60 * 1000)) % 60;
16852  int sec = (time_in_day_ms / 1000) % 60;
16853  set_cache_stamp(date_cache->stamp());
16854  set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
16855  set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
16856  set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
16857  set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
16858  set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
16859  set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
16860  set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
16861}
16862
16863
16864void JSArrayBuffer::Neuter() {
16865  ASSERT(is_external());
16866  set_backing_store(NULL);
16867  set_byte_length(Smi::FromInt(0));
16868}
16869
16870
16871void JSArrayBufferView::NeuterView() {
16872  set_byte_offset(Smi::FromInt(0));
16873  set_byte_length(Smi::FromInt(0));
16874}
16875
16876
16877void JSDataView::Neuter() {
16878  NeuterView();
16879}
16880
16881
16882void JSTypedArray::Neuter() {
16883  NeuterView();
16884  set_length(Smi::FromInt(0));
16885  set_elements(GetHeap()->EmptyExternalArrayForMap(map()));
16886}
16887
16888
16889static ElementsKind FixedToExternalElementsKind(ElementsKind elements_kind) {
16890  switch (elements_kind) {
16891#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
16892    case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS;
16893
16894    TYPED_ARRAYS(TYPED_ARRAY_CASE)
16895#undef TYPED_ARRAY_CASE
16896
16897    default:
16898      UNREACHABLE();
16899      return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
16900  }
16901}
16902
16903
16904Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
16905    Handle<JSTypedArray> typed_array) {
16906
16907  Handle<Map> map(typed_array->map());
16908  Isolate* isolate = typed_array->GetIsolate();
16909
16910  ASSERT(IsFixedTypedArrayElementsKind(map->elements_kind()));
16911
16912  Handle<Map> new_map = Map::TransitionElementsTo(
16913          map,
16914          FixedToExternalElementsKind(map->elements_kind()));
16915
16916  Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
16917  Handle<FixedTypedArrayBase> fixed_typed_array(
16918      FixedTypedArrayBase::cast(typed_array->elements()));
16919  Runtime::SetupArrayBufferAllocatingData(isolate, buffer,
16920      fixed_typed_array->DataSize(), false);
16921  memcpy(buffer->backing_store(),
16922         fixed_typed_array->DataPtr(),
16923         fixed_typed_array->DataSize());
16924  Handle<ExternalArray> new_elements =
16925      isolate->factory()->NewExternalArray(
16926          fixed_typed_array->length(), typed_array->type(),
16927          static_cast<uint8_t*>(buffer->backing_store()));
16928
16929  buffer->set_weak_first_view(*typed_array);
16930  ASSERT(typed_array->weak_next() == isolate->heap()->undefined_value());
16931  typed_array->set_buffer(*buffer);
16932  JSObject::SetMapAndElements(typed_array, new_map, new_elements);
16933
16934  return buffer;
16935}
16936
16937
16938Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
16939  Handle<Object> result(buffer(), GetIsolate());
16940  if (*result != Smi::FromInt(0)) {
16941    ASSERT(IsExternalArrayElementsKind(map()->elements_kind()));
16942    return Handle<JSArrayBuffer>::cast(result);
16943  }
16944  Handle<JSTypedArray> self(this);
16945  return MaterializeArrayBuffer(self);
16946}
16947
16948
16949HeapType* PropertyCell::type() {
16950  return static_cast<HeapType*>(type_raw());
16951}
16952
16953
16954void PropertyCell::set_type(HeapType* type, WriteBarrierMode ignored) {
16955  ASSERT(IsPropertyCell());
16956  set_type_raw(type, ignored);
16957}
16958
16959
16960Handle<HeapType> PropertyCell::UpdatedType(Handle<PropertyCell> cell,
16961                                           Handle<Object> value) {
16962  Isolate* isolate = cell->GetIsolate();
16963  Handle<HeapType> old_type(cell->type(), isolate);
16964  // TODO(2803): Do not track ConsString as constant because they cannot be
16965  // embedded into code.
16966  Handle<HeapType> new_type = value->IsConsString() || value->IsTheHole()
16967      ? HeapType::Any(isolate) : HeapType::Constant(value, isolate);
16968
16969  if (new_type->Is(old_type)) {
16970    return old_type;
16971  }
16972
16973  cell->dependent_code()->DeoptimizeDependentCodeGroup(
16974      isolate, DependentCode::kPropertyCellChangedGroup);
16975
16976  if (old_type->Is(HeapType::None()) || old_type->Is(HeapType::Undefined())) {
16977    return new_type;
16978  }
16979
16980  return HeapType::Any(isolate);
16981}
16982
16983
16984void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
16985                                     Handle<Object> value) {
16986  cell->set_value(*value);
16987  if (!HeapType::Any()->Is(cell->type())) {
16988    Handle<HeapType> new_type = UpdatedType(cell, value);
16989    cell->set_type(*new_type);
16990  }
16991}
16992
16993
16994// static
16995void PropertyCell::AddDependentCompilationInfo(Handle<PropertyCell> cell,
16996                                               CompilationInfo* info) {
16997  Handle<DependentCode> codes =
16998      DependentCode::Insert(handle(cell->dependent_code(), info->isolate()),
16999                            DependentCode::kPropertyCellChangedGroup,
17000                            info->object_wrapper());
17001  if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes);
17002  info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add(
17003      cell, info->zone());
17004}
17005
17006
17007const char* GetBailoutReason(BailoutReason reason) {
17008  ASSERT(reason < kLastErrorMessage);
17009#define ERROR_MESSAGES_TEXTS(C, T) T,
17010  static const char* error_messages_[] = {
17011      ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS)
17012  };
17013#undef ERROR_MESSAGES_TEXTS
17014  return error_messages_[reason];
17015}
17016
17017
17018} }  // namespace v8::internal
17019