• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "api.h"
31 #include "arguments.h"
32 #include "bootstrapper.h"
33 #include "codegen.h"
34 #include "debug.h"
35 #include "deoptimizer.h"
36 #include "date.h"
37 #include "elements.h"
38 #include "execution.h"
39 #include "full-codegen.h"
40 #include "hydrogen.h"
41 #include "objects-inl.h"
42 #include "objects-visiting.h"
43 #include "objects-visiting-inl.h"
44 #include "macro-assembler.h"
45 #include "mark-compact.h"
46 #include "safepoint-table.h"
47 #include "string-stream.h"
48 #include "utils.h"
49 #include "vm-state-inl.h"
50 
51 #ifdef ENABLE_DISASSEMBLER
52 #include "disasm.h"
53 #include "disassembler.h"
54 #endif
55 
56 namespace v8 {
57 namespace internal {
58 
PrintElementsKind(FILE * out,ElementsKind kind)59 void PrintElementsKind(FILE* out, ElementsKind kind) {
60   ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
61   PrintF(out, "%s", accessor->name());
62 }
63 
64 
CreateJSValue(JSFunction * constructor,Object * value)65 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
66                                                   Object* value) {
67   Object* result;
68   { MaybeObject* maybe_result =
69         constructor->GetHeap()->AllocateJSObject(constructor);
70     if (!maybe_result->ToObject(&result)) return maybe_result;
71   }
72   JSValue::cast(result)->set_value(value);
73   return result;
74 }
75 
76 
ToObject(Context * global_context)77 MaybeObject* Object::ToObject(Context* global_context) {
78   if (IsNumber()) {
79     return CreateJSValue(global_context->number_function(), this);
80   } else if (IsBoolean()) {
81     return CreateJSValue(global_context->boolean_function(), this);
82   } else if (IsString()) {
83     return CreateJSValue(global_context->string_function(), this);
84   }
85   ASSERT(IsJSObject());
86   return this;
87 }
88 
89 
ToObject()90 MaybeObject* Object::ToObject() {
91   if (IsJSReceiver()) {
92     return this;
93   } else if (IsNumber()) {
94     Isolate* isolate = Isolate::Current();
95     Context* global_context = isolate->context()->global_context();
96     return CreateJSValue(global_context->number_function(), this);
97   } else if (IsBoolean()) {
98     Isolate* isolate = HeapObject::cast(this)->GetIsolate();
99     Context* global_context = isolate->context()->global_context();
100     return CreateJSValue(global_context->boolean_function(), this);
101   } else if (IsString()) {
102     Isolate* isolate = HeapObject::cast(this)->GetIsolate();
103     Context* global_context = isolate->context()->global_context();
104     return CreateJSValue(global_context->string_function(), this);
105   }
106 
107   // Throw a type error.
108   return Failure::InternalError();
109 }
110 
111 
ToBoolean()112 Object* Object::ToBoolean() {
113   if (IsTrue()) return this;
114   if (IsFalse()) return this;
115   if (IsSmi()) {
116     return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
117   }
118   HeapObject* heap_object = HeapObject::cast(this);
119   if (heap_object->IsUndefined() || heap_object->IsNull()) {
120     return heap_object->GetHeap()->false_value();
121   }
122   // Undetectable object is false
123   if (heap_object->IsUndetectableObject()) {
124     return heap_object->GetHeap()->false_value();
125   }
126   if (heap_object->IsString()) {
127     return heap_object->GetHeap()->ToBoolean(
128         String::cast(this)->length() != 0);
129   }
130   if (heap_object->IsHeapNumber()) {
131     return HeapNumber::cast(this)->HeapNumberToBoolean();
132   }
133   return heap_object->GetHeap()->true_value();
134 }
135 
136 
Lookup(String * name,LookupResult * result)137 void Object::Lookup(String* name, LookupResult* result) {
138   Object* holder = NULL;
139   if (IsJSReceiver()) {
140     holder = this;
141   } else {
142     Context* global_context = Isolate::Current()->context()->global_context();
143     if (IsNumber()) {
144       holder = global_context->number_function()->instance_prototype();
145     } else if (IsString()) {
146       holder = global_context->string_function()->instance_prototype();
147     } else if (IsBoolean()) {
148       holder = global_context->boolean_function()->instance_prototype();
149     }
150   }
151   ASSERT(holder != NULL);  // Cannot handle null or undefined.
152   JSReceiver::cast(holder)->Lookup(name, result);
153 }
154 
155 
GetPropertyWithReceiver(Object * receiver,String * name,PropertyAttributes * attributes)156 MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
157                                              String* name,
158                                              PropertyAttributes* attributes) {
159   LookupResult result(name->GetIsolate());
160   Lookup(name, &result);
161   MaybeObject* value = GetProperty(receiver, &result, name, attributes);
162   ASSERT(*attributes <= ABSENT);
163   return value;
164 }
165 
166 
GetPropertyWithCallback(Object * receiver,Object * structure,String * name)167 MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
168                                                Object* structure,
169                                                String* name) {
170   Isolate* isolate = name->GetIsolate();
171   // To accommodate both the old and the new api we switch on the
172   // data structure used to store the callbacks.  Eventually foreign
173   // callbacks should be phased out.
174   if (structure->IsForeign()) {
175     AccessorDescriptor* callback =
176         reinterpret_cast<AccessorDescriptor*>(
177             Foreign::cast(structure)->foreign_address());
178     MaybeObject* value = (callback->getter)(receiver, callback->data);
179     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
180     return value;
181   }
182 
183   // api style callbacks.
184   if (structure->IsAccessorInfo()) {
185     AccessorInfo* data = AccessorInfo::cast(structure);
186     Object* fun_obj = data->getter();
187     v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
188     HandleScope scope(isolate);
189     JSObject* self = JSObject::cast(receiver);
190     Handle<String> key(name);
191     LOG(isolate, ApiNamedPropertyAccess("load", self, name));
192     CustomArguments args(isolate, data->data(), self, this);
193     v8::AccessorInfo info(args.end());
194     v8::Handle<v8::Value> result;
195     {
196       // Leaving JavaScript.
197       VMState state(isolate, EXTERNAL);
198       result = call_fun(v8::Utils::ToLocal(key), info);
199     }
200     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
201     if (result.IsEmpty()) {
202       return isolate->heap()->undefined_value();
203     }
204     return *v8::Utils::OpenHandle(*result);
205   }
206 
207   // __defineGetter__ callback
208   if (structure->IsAccessorPair()) {
209     Object* getter = AccessorPair::cast(structure)->getter();
210     if (getter->IsSpecFunction()) {
211       // TODO(rossberg): nicer would be to cast to some JSCallable here...
212       return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
213     }
214     // Getter is not a function.
215     return isolate->heap()->undefined_value();
216   }
217 
218   UNREACHABLE();
219   return NULL;
220 }
221 
222 
GetPropertyWithHandler(Object * receiver_raw,String * name_raw)223 MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
224                                              String* name_raw) {
225   Isolate* isolate = GetIsolate();
226   HandleScope scope(isolate);
227   Handle<Object> receiver(receiver_raw);
228   Handle<Object> name(name_raw);
229 
230   Handle<Object> args[] = { receiver, name };
231   Handle<Object> result = CallTrap(
232     "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
233   if (isolate->has_pending_exception()) return Failure::Exception();
234 
235   return *result;
236 }
237 
238 
GetElement(Handle<Object> object,uint32_t index)239 Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
240   Isolate* isolate = object->IsHeapObject()
241       ? Handle<HeapObject>::cast(object)->GetIsolate()
242       : Isolate::Current();
243   CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
244 }
245 
246 
GetElementWithHandler(Object * receiver,uint32_t index)247 MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
248                                             uint32_t index) {
249   String* name;
250   MaybeObject* maybe = GetHeap()->Uint32ToString(index);
251   if (!maybe->To<String>(&name)) return maybe;
252   return GetPropertyWithHandler(receiver, name);
253 }
254 
255 
SetElementWithHandler(uint32_t index,Object * value,StrictModeFlag strict_mode)256 MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
257                                             Object* value,
258                                             StrictModeFlag strict_mode) {
259   String* name;
260   MaybeObject* maybe = GetHeap()->Uint32ToString(index);
261   if (!maybe->To<String>(&name)) return maybe;
262   return SetPropertyWithHandler(name, value, NONE, strict_mode);
263 }
264 
265 
HasElementWithHandler(uint32_t index)266 bool JSProxy::HasElementWithHandler(uint32_t index) {
267   String* name;
268   MaybeObject* maybe = GetHeap()->Uint32ToString(index);
269   if (!maybe->To<String>(&name)) return maybe;
270   return HasPropertyWithHandler(name);
271 }
272 
273 
GetPropertyWithDefinedGetter(Object * receiver,JSReceiver * getter)274 MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
275                                                   JSReceiver* getter) {
276   HandleScope scope;
277   Handle<JSReceiver> fun(getter);
278   Handle<Object> self(receiver);
279 #ifdef ENABLE_DEBUGGER_SUPPORT
280   Debug* debug = fun->GetHeap()->isolate()->debug();
281   // Handle stepping into a getter if step into is active.
282   // TODO(rossberg): should this apply to getters that are function proxies?
283   if (debug->StepInActive() && fun->IsJSFunction()) {
284     debug->HandleStepIn(
285         Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
286   }
287 #endif
288 
289   bool has_pending_exception;
290   Handle<Object> result =
291       Execution::Call(fun, self, 0, NULL, &has_pending_exception, true);
292   // Check for pending exception and return the result.
293   if (has_pending_exception) return Failure::Exception();
294   return *result;
295 }
296 
297 
298 // Only deal with CALLBACKS and INTERCEPTOR
GetPropertyWithFailedAccessCheck(Object * receiver,LookupResult * result,String * name,PropertyAttributes * attributes)299 MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
300     Object* receiver,
301     LookupResult* result,
302     String* name,
303     PropertyAttributes* attributes) {
304   if (result->IsProperty()) {
305     switch (result->type()) {
306       case CALLBACKS: {
307         // Only allow API accessors.
308         Object* obj = result->GetCallbackObject();
309         if (obj->IsAccessorInfo()) {
310           AccessorInfo* info = AccessorInfo::cast(obj);
311           if (info->all_can_read()) {
312             *attributes = result->GetAttributes();
313             return result->holder()->GetPropertyWithCallback(
314                 receiver, result->GetCallbackObject(), name);
315           }
316         }
317         break;
318       }
319       case NORMAL:
320       case FIELD:
321       case CONSTANT_FUNCTION: {
322         // Search ALL_CAN_READ accessors in prototype chain.
323         LookupResult r(GetIsolate());
324         result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
325         if (r.IsProperty()) {
326           return GetPropertyWithFailedAccessCheck(receiver,
327                                                   &r,
328                                                   name,
329                                                   attributes);
330         }
331         break;
332       }
333       case INTERCEPTOR: {
334         // If the object has an interceptor, try real named properties.
335         // No access check in GetPropertyAttributeWithInterceptor.
336         LookupResult r(GetIsolate());
337         result->holder()->LookupRealNamedProperty(name, &r);
338         if (r.IsProperty()) {
339           return GetPropertyWithFailedAccessCheck(receiver,
340                                                   &r,
341                                                   name,
342                                                   attributes);
343         }
344         break;
345       }
346       default:
347         UNREACHABLE();
348     }
349   }
350 
351   // No accessible property found.
352   *attributes = ABSENT;
353   Heap* heap = name->GetHeap();
354   heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
355   return heap->undefined_value();
356 }
357 
358 
GetPropertyAttributeWithFailedAccessCheck(Object * receiver,LookupResult * result,String * name,bool continue_search)359 PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
360     Object* receiver,
361     LookupResult* result,
362     String* name,
363     bool continue_search) {
364   if (result->IsProperty()) {
365     switch (result->type()) {
366       case CALLBACKS: {
367         // Only allow API accessors.
368         Object* obj = result->GetCallbackObject();
369         if (obj->IsAccessorInfo()) {
370           AccessorInfo* info = AccessorInfo::cast(obj);
371           if (info->all_can_read()) {
372             return result->GetAttributes();
373           }
374         }
375         break;
376       }
377 
378       case NORMAL:
379       case FIELD:
380       case CONSTANT_FUNCTION: {
381         if (!continue_search) break;
382         // Search ALL_CAN_READ accessors in prototype chain.
383         LookupResult r(GetIsolate());
384         result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
385         if (r.IsProperty()) {
386           return GetPropertyAttributeWithFailedAccessCheck(receiver,
387                                                            &r,
388                                                            name,
389                                                            continue_search);
390         }
391         break;
392       }
393 
394       case INTERCEPTOR: {
395         // If the object has an interceptor, try real named properties.
396         // No access check in GetPropertyAttributeWithInterceptor.
397         LookupResult r(GetIsolate());
398         if (continue_search) {
399           result->holder()->LookupRealNamedProperty(name, &r);
400         } else {
401           result->holder()->LocalLookupRealNamedProperty(name, &r);
402         }
403         if (r.IsProperty()) {
404           return GetPropertyAttributeWithFailedAccessCheck(receiver,
405                                                            &r,
406                                                            name,
407                                                            continue_search);
408         }
409         break;
410       }
411 
412       default:
413         UNREACHABLE();
414     }
415   }
416 
417   GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
418   return ABSENT;
419 }
420 
421 
GetNormalizedProperty(LookupResult * result)422 Object* JSObject::GetNormalizedProperty(LookupResult* result) {
423   ASSERT(!HasFastProperties());
424   Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
425   if (IsGlobalObject()) {
426     value = JSGlobalPropertyCell::cast(value)->value();
427   }
428   ASSERT(!value->IsJSGlobalPropertyCell());
429   return value;
430 }
431 
432 
SetNormalizedProperty(LookupResult * result,Object * value)433 Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
434   ASSERT(!HasFastProperties());
435   if (IsGlobalObject()) {
436     JSGlobalPropertyCell* cell =
437         JSGlobalPropertyCell::cast(
438             property_dictionary()->ValueAt(result->GetDictionaryEntry()));
439     cell->set_value(value);
440   } else {
441     property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
442   }
443   return value;
444 }
445 
446 
SetNormalizedProperty(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyDetails details)447 Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
448                                                Handle<String> key,
449                                                Handle<Object> value,
450                                                PropertyDetails details) {
451   CALL_HEAP_FUNCTION(object->GetIsolate(),
452                      object->SetNormalizedProperty(*key, *value, details),
453                      Object);
454 }
455 
456 
SetNormalizedProperty(String * name,Object * value,PropertyDetails details)457 MaybeObject* JSObject::SetNormalizedProperty(String* name,
458                                              Object* value,
459                                              PropertyDetails details) {
460   ASSERT(!HasFastProperties());
461   int entry = property_dictionary()->FindEntry(name);
462   if (entry == StringDictionary::kNotFound) {
463     Object* store_value = value;
464     if (IsGlobalObject()) {
465       Heap* heap = name->GetHeap();
466       MaybeObject* maybe_store_value =
467           heap->AllocateJSGlobalPropertyCell(value);
468       if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
469     }
470     Object* dict;
471     { MaybeObject* maybe_dict =
472           property_dictionary()->Add(name, store_value, details);
473       if (!maybe_dict->ToObject(&dict)) return maybe_dict;
474     }
475     set_properties(StringDictionary::cast(dict));
476     return value;
477   }
478   // Preserve enumeration index.
479   details = PropertyDetails(details.attributes(),
480                             details.type(),
481                             property_dictionary()->DetailsAt(entry).index());
482   if (IsGlobalObject()) {
483     JSGlobalPropertyCell* cell =
484         JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
485     cell->set_value(value);
486     // Please note we have to update the property details.
487     property_dictionary()->DetailsAtPut(entry, details);
488   } else {
489     property_dictionary()->SetEntry(entry, name, value, details);
490   }
491   return value;
492 }
493 
494 
DeleteNormalizedProperty(String * name,DeleteMode mode)495 MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
496   ASSERT(!HasFastProperties());
497   StringDictionary* dictionary = property_dictionary();
498   int entry = dictionary->FindEntry(name);
499   if (entry != StringDictionary::kNotFound) {
500     // If we have a global object set the cell to the hole.
501     if (IsGlobalObject()) {
502       PropertyDetails details = dictionary->DetailsAt(entry);
503       if (details.IsDontDelete()) {
504         if (mode != FORCE_DELETION) return GetHeap()->false_value();
505         // When forced to delete global properties, we have to make a
506         // map change to invalidate any ICs that think they can load
507         // from the DontDelete cell without checking if it contains
508         // the hole value.
509         Object* new_map;
510         { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
511           if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
512         }
513         set_map(Map::cast(new_map));
514       }
515       JSGlobalPropertyCell* cell =
516           JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
517       cell->set_value(cell->GetHeap()->the_hole_value());
518       dictionary->DetailsAtPut(entry, details.AsDeleted());
519     } else {
520       Object* deleted = dictionary->DeleteProperty(entry, mode);
521       if (deleted == GetHeap()->true_value()) {
522         FixedArray* new_properties = NULL;
523         MaybeObject* maybe_properties = dictionary->Shrink(name);
524         if (!maybe_properties->To(&new_properties)) {
525           return maybe_properties;
526         }
527         set_properties(new_properties);
528       }
529       return deleted;
530     }
531   }
532   return GetHeap()->true_value();
533 }
534 
535 
IsDirty()536 bool JSObject::IsDirty() {
537   Object* cons_obj = map()->constructor();
538   if (!cons_obj->IsJSFunction())
539     return true;
540   JSFunction* fun = JSFunction::cast(cons_obj);
541   if (!fun->shared()->IsApiFunction())
542     return true;
543   // If the object is fully fast case and has the same map it was
544   // created with then no changes can have been made to it.
545   return map() != fun->initial_map()
546       || !HasFastElements()
547       || !HasFastProperties();
548 }
549 
550 
GetProperty(Handle<Object> object,Handle<Object> receiver,LookupResult * result,Handle<String> key,PropertyAttributes * attributes)551 Handle<Object> Object::GetProperty(Handle<Object> object,
552                                    Handle<Object> receiver,
553                                    LookupResult* result,
554                                    Handle<String> key,
555                                    PropertyAttributes* attributes) {
556   Isolate* isolate = object->IsHeapObject()
557       ? Handle<HeapObject>::cast(object)->GetIsolate()
558       : Isolate::Current();
559   CALL_HEAP_FUNCTION(
560       isolate,
561       object->GetProperty(*receiver, result, *key, attributes),
562       Object);
563 }
564 
565 
GetProperty(Object * receiver,LookupResult * result,String * name,PropertyAttributes * attributes)566 MaybeObject* Object::GetProperty(Object* receiver,
567                                  LookupResult* result,
568                                  String* name,
569                                  PropertyAttributes* attributes) {
570   // Make sure that the top context does not change when doing
571   // callbacks or interceptor calls.
572   AssertNoContextChange ncc;
573   Heap* heap = name->GetHeap();
574 
575   // Traverse the prototype chain from the current object (this) to
576   // the holder and check for access rights. This avoids traversing the
577   // objects more than once in case of interceptors, because the
578   // holder will always be the interceptor holder and the search may
579   // only continue with a current object just after the interceptor
580   // holder in the prototype chain.
581   // Proxy handlers do not use the proxy's prototype, so we can skip this.
582   if (!result->IsHandler()) {
583     Object* last = result->IsProperty()
584         ? result->holder()
585         : Object::cast(heap->null_value());
586     ASSERT(this != this->GetPrototype());
587     for (Object* current = this; true; current = current->GetPrototype()) {
588       if (current->IsAccessCheckNeeded()) {
589         // Check if we're allowed to read from the current object. Note
590         // that even though we may not actually end up loading the named
591         // property from the current object, we still check that we have
592         // access to it.
593         JSObject* checked = JSObject::cast(current);
594         if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
595           return checked->GetPropertyWithFailedAccessCheck(receiver,
596                                                            result,
597                                                            name,
598                                                            attributes);
599         }
600       }
601       // Stop traversing the chain once we reach the last object in the
602       // chain; either the holder of the result or null in case of an
603       // absent property.
604       if (current == last) break;
605     }
606   }
607 
608   if (!result->IsProperty()) {
609     *attributes = ABSENT;
610     return heap->undefined_value();
611   }
612   *attributes = result->GetAttributes();
613   Object* value;
614   switch (result->type()) {
615     case NORMAL:
616       value = result->holder()->GetNormalizedProperty(result);
617       ASSERT(!value->IsTheHole() || result->IsReadOnly());
618       return value->IsTheHole() ? heap->undefined_value() : value;
619     case FIELD:
620       value = result->holder()->FastPropertyAt(result->GetFieldIndex());
621       ASSERT(!value->IsTheHole() || result->IsReadOnly());
622       return value->IsTheHole() ? heap->undefined_value() : value;
623     case CONSTANT_FUNCTION:
624       return result->GetConstantFunction();
625     case CALLBACKS:
626       return result->holder()->GetPropertyWithCallback(
627           receiver, result->GetCallbackObject(), name);
628     case HANDLER:
629       return result->proxy()->GetPropertyWithHandler(receiver, name);
630     case INTERCEPTOR: {
631       JSObject* recvr = JSObject::cast(receiver);
632       return result->holder()->GetPropertyWithInterceptor(
633           recvr, name, attributes);
634     }
635     case MAP_TRANSITION:
636     case ELEMENTS_TRANSITION:
637     case CONSTANT_TRANSITION:
638     case NULL_DESCRIPTOR:
639       break;
640   }
641   UNREACHABLE();
642   return NULL;
643 }
644 
645 
GetElementWithReceiver(Object * receiver,uint32_t index)646 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
647   Heap* heap = IsSmi()
648       ? Isolate::Current()->heap()
649       : HeapObject::cast(this)->GetHeap();
650   Object* holder = this;
651 
652   // Iterate up the prototype chain until an element is found or the null
653   // prototype is encountered.
654   for (holder = this;
655        holder != heap->null_value();
656        holder = holder->GetPrototype()) {
657     if (!holder->IsJSObject()) {
658       Isolate* isolate = heap->isolate();
659       Context* global_context = isolate->context()->global_context();
660       if (holder->IsNumber()) {
661         holder = global_context->number_function()->instance_prototype();
662       } else if (holder->IsString()) {
663         holder = global_context->string_function()->instance_prototype();
664       } else if (holder->IsBoolean()) {
665         holder = global_context->boolean_function()->instance_prototype();
666       } else if (holder->IsJSProxy()) {
667         return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
668       } else {
669         // Undefined and null have no indexed properties.
670         ASSERT(holder->IsUndefined() || holder->IsNull());
671         return heap->undefined_value();
672       }
673     }
674 
675     // Inline the case for JSObjects. Doing so significantly improves the
676     // performance of fetching elements where checking the prototype chain is
677     // necessary.
678     JSObject* js_object = JSObject::cast(holder);
679 
680     // Check access rights if needed.
681     if (js_object->IsAccessCheckNeeded()) {
682       Isolate* isolate = heap->isolate();
683       if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
684         isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
685         return heap->undefined_value();
686       }
687     }
688 
689     if (js_object->HasIndexedInterceptor()) {
690       return js_object->GetElementWithInterceptor(receiver, index);
691     }
692 
693     if (js_object->elements() != heap->empty_fixed_array()) {
694       MaybeObject* result = js_object->GetElementsAccessor()->Get(
695           receiver, js_object, index);
696       if (result != heap->the_hole_value()) return result;
697     }
698   }
699 
700   return heap->undefined_value();
701 }
702 
703 
GetPrototype()704 Object* Object::GetPrototype() {
705   if (IsSmi()) {
706     Heap* heap = Isolate::Current()->heap();
707     Context* context = heap->isolate()->context()->global_context();
708     return context->number_function()->instance_prototype();
709   }
710 
711   HeapObject* heap_object = HeapObject::cast(this);
712 
713   // The object is either a number, a string, a boolean,
714   // a real JS object, or a Harmony proxy.
715   if (heap_object->IsJSReceiver()) {
716     return heap_object->map()->prototype();
717   }
718   Heap* heap = heap_object->GetHeap();
719   Context* context = heap->isolate()->context()->global_context();
720 
721   if (heap_object->IsHeapNumber()) {
722     return context->number_function()->instance_prototype();
723   }
724   if (heap_object->IsString()) {
725     return context->string_function()->instance_prototype();
726   }
727   if (heap_object->IsBoolean()) {
728     return context->boolean_function()->instance_prototype();
729   } else {
730     return heap->null_value();
731   }
732 }
733 
734 
GetHash(CreationFlag flag)735 MaybeObject* Object::GetHash(CreationFlag flag) {
736   // The object is either a number, a string, an odd-ball,
737   // a real JS object, or a Harmony proxy.
738   if (IsNumber()) {
739     uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
740     return Smi::FromInt(hash & Smi::kMaxValue);
741   }
742   if (IsString()) {
743     uint32_t hash = String::cast(this)->Hash();
744     return Smi::FromInt(hash);
745   }
746   if (IsOddball()) {
747     uint32_t hash = Oddball::cast(this)->to_string()->Hash();
748     return Smi::FromInt(hash);
749   }
750   if (IsJSReceiver()) {
751     return JSReceiver::cast(this)->GetIdentityHash(flag);
752   }
753 
754   UNREACHABLE();
755   return Smi::FromInt(0);
756 }
757 
758 
SameValue(Object * other)759 bool Object::SameValue(Object* other) {
760   if (other == this) return true;
761   if (!IsHeapObject() || !other->IsHeapObject()) return false;
762 
763   // The object is either a number, a string, an odd-ball,
764   // a real JS object, or a Harmony proxy.
765   if (IsNumber() && other->IsNumber()) {
766     double this_value = Number();
767     double other_value = other->Number();
768     return (this_value == other_value) ||
769         (isnan(this_value) && isnan(other_value));
770   }
771   if (IsString() && other->IsString()) {
772     return String::cast(this)->Equals(String::cast(other));
773   }
774   return false;
775 }
776 
777 
ShortPrint(FILE * out)778 void Object::ShortPrint(FILE* out) {
779   HeapStringAllocator allocator;
780   StringStream accumulator(&allocator);
781   ShortPrint(&accumulator);
782   accumulator.OutputToFile(out);
783 }
784 
785 
ShortPrint(StringStream * accumulator)786 void Object::ShortPrint(StringStream* accumulator) {
787   if (IsSmi()) {
788     Smi::cast(this)->SmiPrint(accumulator);
789   } else if (IsFailure()) {
790     Failure::cast(this)->FailurePrint(accumulator);
791   } else {
792     HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
793   }
794 }
795 
796 
SmiPrint(FILE * out)797 void Smi::SmiPrint(FILE* out) {
798   PrintF(out, "%d", value());
799 }
800 
801 
SmiPrint(StringStream * accumulator)802 void Smi::SmiPrint(StringStream* accumulator) {
803   accumulator->Add("%d", value());
804 }
805 
806 
FailurePrint(StringStream * accumulator)807 void Failure::FailurePrint(StringStream* accumulator) {
808   accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
809 }
810 
811 
FailurePrint(FILE * out)812 void Failure::FailurePrint(FILE* out) {
813   PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
814 }
815 
816 
817 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
818 // English?  Returns false for non-ASCII or words that don't start with
819 // a capital letter.  The a/an rule follows pronunciation in English.
820 // We don't use the BBC's overcorrect "an historic occasion" though if
821 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)822 static bool AnWord(String* str) {
823   if (str->length() == 0) return false;  // A nothing.
824   int c0 = str->Get(0);
825   int c1 = str->length() > 1 ? str->Get(1) : 0;
826   if (c0 == 'U') {
827     if (c1 > 'Z') {
828       return true;  // An Umpire, but a UTF8String, a U.
829     }
830   } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
831     return true;    // An Ape, an ABCBook.
832   } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
833            (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
834             c0 == 'S' || c0 == 'X')) {
835     return true;    // An MP3File, an M.
836   }
837   return false;
838 }
839 
840 
SlowTryFlatten(PretenureFlag pretenure)841 MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
842 #ifdef DEBUG
843   // Do not attempt to flatten in debug mode when allocation is not
844   // allowed.  This is to avoid an assertion failure when allocating.
845   // Flattening strings is the only case where we always allow
846   // allocation because no GC is performed if the allocation fails.
847   if (!HEAP->IsAllocationAllowed()) return this;
848 #endif
849 
850   Heap* heap = GetHeap();
851   switch (StringShape(this).representation_tag()) {
852     case kConsStringTag: {
853       ConsString* cs = ConsString::cast(this);
854       if (cs->second()->length() == 0) {
855         return cs->first();
856       }
857       // There's little point in putting the flat string in new space if the
858       // cons string is in old space.  It can never get GCed until there is
859       // an old space GC.
860       PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
861       int len = length();
862       Object* object;
863       String* result;
864       if (IsAsciiRepresentation()) {
865         { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
866           if (!maybe_object->ToObject(&object)) return maybe_object;
867         }
868         result = String::cast(object);
869         String* first = cs->first();
870         int first_length = first->length();
871         char* dest = SeqAsciiString::cast(result)->GetChars();
872         WriteToFlat(first, dest, 0, first_length);
873         String* second = cs->second();
874         WriteToFlat(second,
875                     dest + first_length,
876                     0,
877                     len - first_length);
878       } else {
879         { MaybeObject* maybe_object =
880               heap->AllocateRawTwoByteString(len, tenure);
881           if (!maybe_object->ToObject(&object)) return maybe_object;
882         }
883         result = String::cast(object);
884         uc16* dest = SeqTwoByteString::cast(result)->GetChars();
885         String* first = cs->first();
886         int first_length = first->length();
887         WriteToFlat(first, dest, 0, first_length);
888         String* second = cs->second();
889         WriteToFlat(second,
890                     dest + first_length,
891                     0,
892                     len - first_length);
893       }
894       cs->set_first(result);
895       cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
896       return result;
897     }
898     default:
899       return this;
900   }
901 }
902 
903 
MakeExternal(v8::String::ExternalStringResource * resource)904 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
905   // Externalizing twice leaks the external resource, so it's
906   // prohibited by the API.
907   ASSERT(!this->IsExternalString());
908 #ifdef DEBUG
909   if (FLAG_enable_slow_asserts) {
910     // Assert that the resource and the string are equivalent.
911     ASSERT(static_cast<size_t>(this->length()) == resource->length());
912     ScopedVector<uc16> smart_chars(this->length());
913     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
914     ASSERT(memcmp(smart_chars.start(),
915                   resource->data(),
916                   resource->length() * sizeof(smart_chars[0])) == 0);
917   }
918 #endif  // DEBUG
919   Heap* heap = GetHeap();
920   int size = this->Size();  // Byte size of the original string.
921   if (size < ExternalString::kShortSize) {
922     return false;
923   }
924   bool is_ascii = this->IsAsciiRepresentation();
925   bool is_symbol = this->IsSymbol();
926 
927   // Morph the object to an external string by adjusting the map and
928   // reinitializing the fields.
929   if (size >= ExternalString::kSize) {
930     this->set_map_no_write_barrier(
931         is_symbol
932             ? (is_ascii ?  heap->external_symbol_with_ascii_data_map()
933                         :  heap->external_symbol_map())
934             : (is_ascii ?  heap->external_string_with_ascii_data_map()
935                         :  heap->external_string_map()));
936   } else {
937     this->set_map_no_write_barrier(
938         is_symbol
939             ? (is_ascii ?  heap->short_external_symbol_with_ascii_data_map()
940                         :  heap->short_external_symbol_map())
941             : (is_ascii ?  heap->short_external_string_with_ascii_data_map()
942                         :  heap->short_external_string_map()));
943   }
944   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
945   self->set_resource(resource);
946   if (is_symbol) self->Hash();  // Force regeneration of the hash value.
947 
948   // Fill the remainder of the string with dead wood.
949   int new_size = this->Size();  // Byte size of the external String object.
950   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
951   if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
952     MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
953                                                new_size - size);
954   }
955   return true;
956 }
957 
958 
MakeExternal(v8::String::ExternalAsciiStringResource * resource)959 bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
960 #ifdef DEBUG
961   if (FLAG_enable_slow_asserts) {
962     // Assert that the resource and the string are equivalent.
963     ASSERT(static_cast<size_t>(this->length()) == resource->length());
964     ScopedVector<char> smart_chars(this->length());
965     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
966     ASSERT(memcmp(smart_chars.start(),
967                   resource->data(),
968                   resource->length() * sizeof(smart_chars[0])) == 0);
969   }
970 #endif  // DEBUG
971   Heap* heap = GetHeap();
972   int size = this->Size();  // Byte size of the original string.
973   if (size < ExternalString::kShortSize) {
974     return false;
975   }
976   bool is_symbol = this->IsSymbol();
977 
978   // Morph the object to an external string by adjusting the map and
979   // reinitializing the fields.  Use short version if space is limited.
980   if (size >= ExternalString::kSize) {
981     this->set_map_no_write_barrier(
982         is_symbol ? heap->external_ascii_symbol_map()
983                   : heap->external_ascii_string_map());
984   } else {
985     this->set_map_no_write_barrier(
986         is_symbol ? heap->short_external_ascii_symbol_map()
987                   : heap->short_external_ascii_string_map());
988   }
989   ExternalAsciiString* self = ExternalAsciiString::cast(this);
990   self->set_resource(resource);
991   if (is_symbol) self->Hash();  // Force regeneration of the hash value.
992 
993   // Fill the remainder of the string with dead wood.
994   int new_size = this->Size();  // Byte size of the external String object.
995   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
996   if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
997     MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
998                                                new_size - size);
999   }
1000   return true;
1001 }
1002 
1003 
StringShortPrint(StringStream * accumulator)1004 void String::StringShortPrint(StringStream* accumulator) {
1005   int len = length();
1006   if (len > kMaxShortPrintLength) {
1007     accumulator->Add("<Very long string[%u]>", len);
1008     return;
1009   }
1010 
1011   if (!LooksValid()) {
1012     accumulator->Add("<Invalid String>");
1013     return;
1014   }
1015 
1016   StringInputBuffer buf(this);
1017 
1018   bool truncated = false;
1019   if (len > kMaxShortPrintLength) {
1020     len = kMaxShortPrintLength;
1021     truncated = true;
1022   }
1023   bool ascii = true;
1024   for (int i = 0; i < len; i++) {
1025     int c = buf.GetNext();
1026 
1027     if (c < 32 || c >= 127) {
1028       ascii = false;
1029     }
1030   }
1031   buf.Reset(this);
1032   if (ascii) {
1033     accumulator->Add("<String[%u]: ", length());
1034     for (int i = 0; i < len; i++) {
1035       accumulator->Put(buf.GetNext());
1036     }
1037     accumulator->Put('>');
1038   } else {
1039     // Backslash indicates that the string contains control
1040     // characters and that backslashes are therefore escaped.
1041     accumulator->Add("<String[%u]\\: ", length());
1042     for (int i = 0; i < len; i++) {
1043       int c = buf.GetNext();
1044       if (c == '\n') {
1045         accumulator->Add("\\n");
1046       } else if (c == '\r') {
1047         accumulator->Add("\\r");
1048       } else if (c == '\\') {
1049         accumulator->Add("\\\\");
1050       } else if (c < 32 || c > 126) {
1051         accumulator->Add("\\x%02x", c);
1052       } else {
1053         accumulator->Put(c);
1054       }
1055     }
1056     if (truncated) {
1057       accumulator->Put('.');
1058       accumulator->Put('.');
1059       accumulator->Put('.');
1060     }
1061     accumulator->Put('>');
1062   }
1063   return;
1064 }
1065 
1066 
JSObjectShortPrint(StringStream * accumulator)1067 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1068   switch (map()->instance_type()) {
1069     case JS_ARRAY_TYPE: {
1070       double length = JSArray::cast(this)->length()->Number();
1071       accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
1072       break;
1073     }
1074     case JS_WEAK_MAP_TYPE: {
1075       accumulator->Add("<JS WeakMap>");
1076       break;
1077     }
1078     case JS_REGEXP_TYPE: {
1079       accumulator->Add("<JS RegExp>");
1080       break;
1081     }
1082     case JS_FUNCTION_TYPE: {
1083       Object* fun_name = JSFunction::cast(this)->shared()->name();
1084       bool printed = false;
1085       if (fun_name->IsString()) {
1086         String* str = String::cast(fun_name);
1087         if (str->length() > 0) {
1088           accumulator->Add("<JS Function ");
1089           accumulator->Put(str);
1090           accumulator->Put('>');
1091           printed = true;
1092         }
1093       }
1094       if (!printed) {
1095         accumulator->Add("<JS Function>");
1096       }
1097       break;
1098     }
1099     // All other JSObjects are rather similar to each other (JSObject,
1100     // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1101     default: {
1102       Map* map_of_this = map();
1103       Heap* heap = GetHeap();
1104       Object* constructor = map_of_this->constructor();
1105       bool printed = false;
1106       if (constructor->IsHeapObject() &&
1107           !heap->Contains(HeapObject::cast(constructor))) {
1108         accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1109       } else {
1110         bool global_object = IsJSGlobalProxy();
1111         if (constructor->IsJSFunction()) {
1112           if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
1113             accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1114           } else {
1115             Object* constructor_name =
1116                 JSFunction::cast(constructor)->shared()->name();
1117             if (constructor_name->IsString()) {
1118               String* str = String::cast(constructor_name);
1119               if (str->length() > 0) {
1120                 bool vowel = AnWord(str);
1121                 accumulator->Add("<%sa%s ",
1122                        global_object ? "Global Object: " : "",
1123                        vowel ? "n" : "");
1124                 accumulator->Put(str);
1125                 printed = true;
1126               }
1127             }
1128           }
1129         }
1130         if (!printed) {
1131           accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1132         }
1133       }
1134       if (IsJSValue()) {
1135         accumulator->Add(" value = ");
1136         JSValue::cast(this)->value()->ShortPrint(accumulator);
1137       }
1138       accumulator->Put('>');
1139       break;
1140     }
1141   }
1142 }
1143 
1144 
PrintElementsTransition(FILE * file,ElementsKind from_kind,FixedArrayBase * from_elements,ElementsKind to_kind,FixedArrayBase * to_elements)1145 void JSObject::PrintElementsTransition(
1146     FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1147     ElementsKind to_kind, FixedArrayBase* to_elements) {
1148   if (from_kind != to_kind) {
1149     PrintF(file, "elements transition [");
1150     PrintElementsKind(file, from_kind);
1151     PrintF(file, " -> ");
1152     PrintElementsKind(file, to_kind);
1153     PrintF(file, "] in ");
1154     JavaScriptFrame::PrintTop(file, false, true);
1155     PrintF(file, " for ");
1156     ShortPrint(file);
1157     PrintF(file, " from ");
1158     from_elements->ShortPrint(file);
1159     PrintF(file, " to ");
1160     to_elements->ShortPrint(file);
1161     PrintF(file, "\n");
1162   }
1163 }
1164 
1165 
HeapObjectShortPrint(StringStream * accumulator)1166 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
1167   Heap* heap = GetHeap();
1168   if (!heap->Contains(this)) {
1169     accumulator->Add("!!!INVALID POINTER!!!");
1170     return;
1171   }
1172   if (!heap->Contains(map())) {
1173     accumulator->Add("!!!INVALID MAP!!!");
1174     return;
1175   }
1176 
1177   accumulator->Add("%p ", this);
1178 
1179   if (IsString()) {
1180     String::cast(this)->StringShortPrint(accumulator);
1181     return;
1182   }
1183   if (IsJSObject()) {
1184     JSObject::cast(this)->JSObjectShortPrint(accumulator);
1185     return;
1186   }
1187   switch (map()->instance_type()) {
1188     case MAP_TYPE:
1189       accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
1190       break;
1191     case FIXED_ARRAY_TYPE:
1192       accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1193       break;
1194     case FIXED_DOUBLE_ARRAY_TYPE:
1195       accumulator->Add("<FixedDoubleArray[%u]>",
1196                        FixedDoubleArray::cast(this)->length());
1197       break;
1198     case BYTE_ARRAY_TYPE:
1199       accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1200       break;
1201     case FREE_SPACE_TYPE:
1202       accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1203       break;
1204     case EXTERNAL_PIXEL_ARRAY_TYPE:
1205       accumulator->Add("<ExternalPixelArray[%u]>",
1206                        ExternalPixelArray::cast(this)->length());
1207       break;
1208     case EXTERNAL_BYTE_ARRAY_TYPE:
1209       accumulator->Add("<ExternalByteArray[%u]>",
1210                        ExternalByteArray::cast(this)->length());
1211       break;
1212     case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1213       accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1214                        ExternalUnsignedByteArray::cast(this)->length());
1215       break;
1216     case EXTERNAL_SHORT_ARRAY_TYPE:
1217       accumulator->Add("<ExternalShortArray[%u]>",
1218                        ExternalShortArray::cast(this)->length());
1219       break;
1220     case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1221       accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1222                        ExternalUnsignedShortArray::cast(this)->length());
1223       break;
1224     case EXTERNAL_INT_ARRAY_TYPE:
1225       accumulator->Add("<ExternalIntArray[%u]>",
1226                        ExternalIntArray::cast(this)->length());
1227       break;
1228     case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1229       accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1230                        ExternalUnsignedIntArray::cast(this)->length());
1231       break;
1232     case EXTERNAL_FLOAT_ARRAY_TYPE:
1233       accumulator->Add("<ExternalFloatArray[%u]>",
1234                        ExternalFloatArray::cast(this)->length());
1235       break;
1236     case EXTERNAL_DOUBLE_ARRAY_TYPE:
1237       accumulator->Add("<ExternalDoubleArray[%u]>",
1238                        ExternalDoubleArray::cast(this)->length());
1239       break;
1240     case SHARED_FUNCTION_INFO_TYPE:
1241       accumulator->Add("<SharedFunctionInfo>");
1242       break;
1243     case JS_MESSAGE_OBJECT_TYPE:
1244       accumulator->Add("<JSMessageObject>");
1245       break;
1246 #define MAKE_STRUCT_CASE(NAME, Name, name) \
1247   case NAME##_TYPE:                        \
1248     accumulator->Put('<');                 \
1249     accumulator->Add(#Name);               \
1250     accumulator->Put('>');                 \
1251     break;
1252   STRUCT_LIST(MAKE_STRUCT_CASE)
1253 #undef MAKE_STRUCT_CASE
1254     case CODE_TYPE:
1255       accumulator->Add("<Code>");
1256       break;
1257     case ODDBALL_TYPE: {
1258       if (IsUndefined())
1259         accumulator->Add("<undefined>");
1260       else if (IsTheHole())
1261         accumulator->Add("<the hole>");
1262       else if (IsNull())
1263         accumulator->Add("<null>");
1264       else if (IsTrue())
1265         accumulator->Add("<true>");
1266       else if (IsFalse())
1267         accumulator->Add("<false>");
1268       else
1269         accumulator->Add("<Odd Oddball>");
1270       break;
1271     }
1272     case HEAP_NUMBER_TYPE:
1273       accumulator->Add("<Number: ");
1274       HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1275       accumulator->Put('>');
1276       break;
1277     case JS_PROXY_TYPE:
1278       accumulator->Add("<JSProxy>");
1279       break;
1280     case JS_FUNCTION_PROXY_TYPE:
1281       accumulator->Add("<JSFunctionProxy>");
1282       break;
1283     case FOREIGN_TYPE:
1284       accumulator->Add("<Foreign>");
1285       break;
1286     case JS_GLOBAL_PROPERTY_CELL_TYPE:
1287       accumulator->Add("Cell for ");
1288       JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1289       break;
1290     default:
1291       accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1292       break;
1293   }
1294 }
1295 
1296 
Iterate(ObjectVisitor * v)1297 void HeapObject::Iterate(ObjectVisitor* v) {
1298   // Handle header
1299   IteratePointer(v, kMapOffset);
1300   // Handle object body
1301   Map* m = map();
1302   IterateBody(m->instance_type(), SizeFromMap(m), v);
1303 }
1304 
1305 
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)1306 void HeapObject::IterateBody(InstanceType type, int object_size,
1307                              ObjectVisitor* v) {
1308   // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1309   // During GC, the map pointer field is encoded.
1310   if (type < FIRST_NONSTRING_TYPE) {
1311     switch (type & kStringRepresentationMask) {
1312       case kSeqStringTag:
1313         break;
1314       case kConsStringTag:
1315         ConsString::BodyDescriptor::IterateBody(this, v);
1316         break;
1317       case kSlicedStringTag:
1318         SlicedString::BodyDescriptor::IterateBody(this, v);
1319         break;
1320       case kExternalStringTag:
1321         if ((type & kStringEncodingMask) == kAsciiStringTag) {
1322           reinterpret_cast<ExternalAsciiString*>(this)->
1323               ExternalAsciiStringIterateBody(v);
1324         } else {
1325           reinterpret_cast<ExternalTwoByteString*>(this)->
1326               ExternalTwoByteStringIterateBody(v);
1327         }
1328         break;
1329     }
1330     return;
1331   }
1332 
1333   switch (type) {
1334     case FIXED_ARRAY_TYPE:
1335       FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
1336       break;
1337     case FIXED_DOUBLE_ARRAY_TYPE:
1338       break;
1339     case JS_OBJECT_TYPE:
1340     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1341     case JS_VALUE_TYPE:
1342     case JS_DATE_TYPE:
1343     case JS_ARRAY_TYPE:
1344     case JS_SET_TYPE:
1345     case JS_MAP_TYPE:
1346     case JS_WEAK_MAP_TYPE:
1347     case JS_REGEXP_TYPE:
1348     case JS_GLOBAL_PROXY_TYPE:
1349     case JS_GLOBAL_OBJECT_TYPE:
1350     case JS_BUILTINS_OBJECT_TYPE:
1351     case JS_MESSAGE_OBJECT_TYPE:
1352       JSObject::BodyDescriptor::IterateBody(this, object_size, v);
1353       break;
1354     case JS_FUNCTION_TYPE:
1355       reinterpret_cast<JSFunction*>(this)
1356           ->JSFunctionIterateBody(object_size, v);
1357       break;
1358     case ODDBALL_TYPE:
1359       Oddball::BodyDescriptor::IterateBody(this, v);
1360       break;
1361     case JS_PROXY_TYPE:
1362       JSProxy::BodyDescriptor::IterateBody(this, v);
1363       break;
1364     case JS_FUNCTION_PROXY_TYPE:
1365       JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1366       break;
1367     case FOREIGN_TYPE:
1368       reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
1369       break;
1370     case MAP_TYPE:
1371       Map::BodyDescriptor::IterateBody(this, v);
1372       break;
1373     case CODE_TYPE:
1374       reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1375       break;
1376     case JS_GLOBAL_PROPERTY_CELL_TYPE:
1377       JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
1378       break;
1379     case HEAP_NUMBER_TYPE:
1380     case FILLER_TYPE:
1381     case BYTE_ARRAY_TYPE:
1382     case FREE_SPACE_TYPE:
1383     case EXTERNAL_PIXEL_ARRAY_TYPE:
1384     case EXTERNAL_BYTE_ARRAY_TYPE:
1385     case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1386     case EXTERNAL_SHORT_ARRAY_TYPE:
1387     case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1388     case EXTERNAL_INT_ARRAY_TYPE:
1389     case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1390     case EXTERNAL_FLOAT_ARRAY_TYPE:
1391     case EXTERNAL_DOUBLE_ARRAY_TYPE:
1392       break;
1393     case SHARED_FUNCTION_INFO_TYPE: {
1394       SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
1395       shared->SharedFunctionInfoIterateBody(v);
1396       break;
1397     }
1398 
1399 #define MAKE_STRUCT_CASE(NAME, Name, name) \
1400         case NAME##_TYPE:
1401       STRUCT_LIST(MAKE_STRUCT_CASE)
1402 #undef MAKE_STRUCT_CASE
1403       StructBodyDescriptor::IterateBody(this, object_size, v);
1404       break;
1405     default:
1406       PrintF("Unknown type: %d\n", type);
1407       UNREACHABLE();
1408   }
1409 }
1410 
1411 
HeapNumberToBoolean()1412 Object* HeapNumber::HeapNumberToBoolean() {
1413   // NaN, +0, and -0 should return the false object
1414 #if __BYTE_ORDER == __LITTLE_ENDIAN
1415   union IeeeDoubleLittleEndianArchType u;
1416 #elif __BYTE_ORDER == __BIG_ENDIAN
1417   union IeeeDoubleBigEndianArchType u;
1418 #endif
1419   u.d = value();
1420   if (u.bits.exp == 2047) {
1421     // Detect NaN for IEEE double precision floating point.
1422     if ((u.bits.man_low | u.bits.man_high) != 0)
1423       return GetHeap()->false_value();
1424   }
1425   if (u.bits.exp == 0) {
1426     // Detect +0, and -0 for IEEE double precision floating point.
1427     if ((u.bits.man_low | u.bits.man_high) == 0)
1428       return GetHeap()->false_value();
1429   }
1430   return GetHeap()->true_value();
1431 }
1432 
1433 
HeapNumberPrint(FILE * out)1434 void HeapNumber::HeapNumberPrint(FILE* out) {
1435   PrintF(out, "%.16g", Number());
1436 }
1437 
1438 
HeapNumberPrint(StringStream * accumulator)1439 void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1440   // The Windows version of vsnprintf can allocate when printing a %g string
1441   // into a buffer that may not be big enough.  We don't want random memory
1442   // allocation when producing post-crash stack traces, so we print into a
1443   // buffer that is plenty big enough for any floating point number, then
1444   // print that using vsnprintf (which may truncate but never allocate if
1445   // there is no more space in the buffer).
1446   EmbeddedVector<char, 100> buffer;
1447   OS::SNPrintF(buffer, "%.16g", Number());
1448   accumulator->Add("%s", buffer.start());
1449 }
1450 
1451 
class_name()1452 String* JSReceiver::class_name() {
1453   if (IsJSFunction() && IsJSFunctionProxy()) {
1454     return GetHeap()->function_class_symbol();
1455   }
1456   if (map()->constructor()->IsJSFunction()) {
1457     JSFunction* constructor = JSFunction::cast(map()->constructor());
1458     return String::cast(constructor->shared()->instance_class_name());
1459   }
1460   // If the constructor is not present, return "Object".
1461   return GetHeap()->Object_symbol();
1462 }
1463 
1464 
constructor_name()1465 String* JSReceiver::constructor_name() {
1466   if (map()->constructor()->IsJSFunction()) {
1467     JSFunction* constructor = JSFunction::cast(map()->constructor());
1468     String* name = String::cast(constructor->shared()->name());
1469     if (name->length() > 0) return name;
1470     String* inferred_name = constructor->shared()->inferred_name();
1471     if (inferred_name->length() > 0) return inferred_name;
1472     Object* proto = GetPrototype();
1473     if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
1474   }
1475   // TODO(rossberg): what about proxies?
1476   // If the constructor is not present, return "Object".
1477   return GetHeap()->Object_symbol();
1478 }
1479 
1480 
AddFastPropertyUsingMap(Map * new_map,String * name,Object * value)1481 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1482                                                String* name,
1483                                                Object* value) {
1484   int index = new_map->PropertyIndexFor(name);
1485   if (map()->unused_property_fields() == 0) {
1486     ASSERT(map()->unused_property_fields() == 0);
1487     int new_unused = new_map->unused_property_fields();
1488     Object* values;
1489     { MaybeObject* maybe_values =
1490           properties()->CopySize(properties()->length() + new_unused + 1);
1491       if (!maybe_values->ToObject(&values)) return maybe_values;
1492     }
1493     set_properties(FixedArray::cast(values));
1494   }
1495   set_map(new_map);
1496   return FastPropertyAtPut(index, value);
1497 }
1498 
1499 
IsIdentifier(UnicodeCache * cache,unibrow::CharacterStream * buffer)1500 static bool IsIdentifier(UnicodeCache* cache,
1501                          unibrow::CharacterStream* buffer) {
1502   // Checks whether the buffer contains an identifier (no escape).
1503   if (!buffer->has_more()) return false;
1504   if (!cache->IsIdentifierStart(buffer->GetNext())) {
1505     return false;
1506   }
1507   while (buffer->has_more()) {
1508     if (!cache->IsIdentifierPart(buffer->GetNext())) {
1509       return false;
1510     }
1511   }
1512   return true;
1513 }
1514 
1515 
AddFastProperty(String * name,Object * value,PropertyAttributes attributes)1516 MaybeObject* JSObject::AddFastProperty(String* name,
1517                                        Object* value,
1518                                        PropertyAttributes attributes) {
1519   ASSERT(!IsJSGlobalProxy());
1520 
1521   // Normalize the object if the name is an actual string (not the
1522   // hidden symbols) and is not a real identifier.
1523   Isolate* isolate = GetHeap()->isolate();
1524   StringInputBuffer buffer(name);
1525   if (!IsIdentifier(isolate->unicode_cache(), &buffer)
1526       && name != isolate->heap()->hidden_symbol()) {
1527     Object* obj;
1528     { MaybeObject* maybe_obj =
1529           NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1530       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1531     }
1532     return AddSlowProperty(name, value, attributes);
1533   }
1534 
1535   DescriptorArray* old_descriptors = map()->instance_descriptors();
1536   // Compute the new index for new field.
1537   int index = map()->NextFreePropertyIndex();
1538 
1539   // Allocate new instance descriptors with (name, index) added
1540   FieldDescriptor new_field(name, index, attributes);
1541   Object* new_descriptors;
1542   { MaybeObject* maybe_new_descriptors =
1543         old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1544     if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1545       return maybe_new_descriptors;
1546     }
1547   }
1548 
1549   // Only allow map transition if the object isn't the global object and there
1550   // is not a transition for the name, or there's a transition for the name but
1551   // it's unrelated to properties.
1552   int descriptor_index = old_descriptors->Search(name);
1553 
1554   // Element transitions are stored in the descriptor for property "", which is
1555   // not a identifier and should have forced a switch to slow properties above.
1556   ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1557       old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
1558   bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1559       old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
1560   bool allow_map_transition =
1561       can_insert_transition &&
1562       (isolate->context()->global_context()->object_function()->map() != map());
1563 
1564   ASSERT(index < map()->inobject_properties() ||
1565          (index - map()->inobject_properties()) < properties()->length() ||
1566          map()->unused_property_fields() == 0);
1567   // Allocate a new map for the object.
1568   Object* r;
1569   { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1570     if (!maybe_r->ToObject(&r)) return maybe_r;
1571   }
1572   Map* new_map = Map::cast(r);
1573   if (allow_map_transition) {
1574     // Allocate new instance descriptors for the old map with map transition.
1575     MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
1576     Object* r;
1577     { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1578       if (!maybe_r->ToObject(&r)) return maybe_r;
1579     }
1580     old_descriptors = DescriptorArray::cast(r);
1581   }
1582 
1583   if (map()->unused_property_fields() == 0) {
1584     if (properties()->length() > MaxFastProperties()) {
1585       Object* obj;
1586       { MaybeObject* maybe_obj =
1587             NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1588         if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1589       }
1590       return AddSlowProperty(name, value, attributes);
1591     }
1592     // Make room for the new value
1593     Object* values;
1594     { MaybeObject* maybe_values =
1595           properties()->CopySize(properties()->length() + kFieldsAdded);
1596       if (!maybe_values->ToObject(&values)) return maybe_values;
1597     }
1598     set_properties(FixedArray::cast(values));
1599     new_map->set_unused_property_fields(kFieldsAdded - 1);
1600   } else {
1601     new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1602   }
1603   // We have now allocated all the necessary objects.
1604   // All the changes can be applied at once, so they are atomic.
1605   map()->set_instance_descriptors(old_descriptors);
1606   new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1607   set_map(new_map);
1608   return FastPropertyAtPut(index, value);
1609 }
1610 
1611 
AddConstantFunctionProperty(String * name,JSFunction * function,PropertyAttributes attributes)1612 MaybeObject* JSObject::AddConstantFunctionProperty(
1613     String* name,
1614     JSFunction* function,
1615     PropertyAttributes attributes) {
1616   // Allocate new instance descriptors with (name, function) added
1617   ConstantFunctionDescriptor d(name, function, attributes);
1618   Object* new_descriptors;
1619   { MaybeObject* maybe_new_descriptors =
1620         map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1621     if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1622       return maybe_new_descriptors;
1623     }
1624   }
1625 
1626   // Allocate a new map for the object.
1627   Object* new_map;
1628   { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1629     if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1630   }
1631 
1632   DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1633   Map::cast(new_map)->set_instance_descriptors(descriptors);
1634   Map* old_map = map();
1635   set_map(Map::cast(new_map));
1636 
1637   // If the old map is the global object map (from new Object()),
1638   // then transitions are not added to it, so we are done.
1639   Heap* heap = GetHeap();
1640   if (old_map == heap->isolate()->context()->global_context()->
1641       object_function()->map()) {
1642     return function;
1643   }
1644 
1645   // Do not add CONSTANT_TRANSITIONS to global objects
1646   if (IsGlobalObject()) {
1647     return function;
1648   }
1649 
1650   // Add a CONSTANT_TRANSITION descriptor to the old map,
1651   // so future assignments to this property on other objects
1652   // of the same type will create a normal field, not a constant function.
1653   // Don't do this for special properties, with non-trival attributes.
1654   if (attributes != NONE) {
1655     return function;
1656   }
1657   ConstTransitionDescriptor mark(name, Map::cast(new_map));
1658   { MaybeObject* maybe_new_descriptors =
1659         old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1660     if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1661       // We have accomplished the main goal, so return success.
1662       return function;
1663     }
1664   }
1665   old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1666 
1667   return function;
1668 }
1669 
1670 
1671 // Add property in slow mode
AddSlowProperty(String * name,Object * value,PropertyAttributes attributes)1672 MaybeObject* JSObject::AddSlowProperty(String* name,
1673                                        Object* value,
1674                                        PropertyAttributes attributes) {
1675   ASSERT(!HasFastProperties());
1676   StringDictionary* dict = property_dictionary();
1677   Object* store_value = value;
1678   if (IsGlobalObject()) {
1679     // In case name is an orphaned property reuse the cell.
1680     int entry = dict->FindEntry(name);
1681     if (entry != StringDictionary::kNotFound) {
1682       store_value = dict->ValueAt(entry);
1683       JSGlobalPropertyCell::cast(store_value)->set_value(value);
1684       // Assign an enumeration index to the property and update
1685       // SetNextEnumerationIndex.
1686       int index = dict->NextEnumerationIndex();
1687       PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1688       dict->SetNextEnumerationIndex(index + 1);
1689       dict->SetEntry(entry, name, store_value, details);
1690       return value;
1691     }
1692     Heap* heap = GetHeap();
1693     { MaybeObject* maybe_store_value =
1694           heap->AllocateJSGlobalPropertyCell(value);
1695       if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1696     }
1697     JSGlobalPropertyCell::cast(store_value)->set_value(value);
1698   }
1699   PropertyDetails details = PropertyDetails(attributes, NORMAL);
1700   Object* result;
1701   { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1702     if (!maybe_result->ToObject(&result)) return maybe_result;
1703   }
1704   if (dict != result) set_properties(StringDictionary::cast(result));
1705   return value;
1706 }
1707 
1708 
AddProperty(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1709 MaybeObject* JSObject::AddProperty(String* name,
1710                                    Object* value,
1711                                    PropertyAttributes attributes,
1712                                    StrictModeFlag strict_mode) {
1713   ASSERT(!IsJSGlobalProxy());
1714   Map* map_of_this = map();
1715   Heap* heap = GetHeap();
1716   if (!map_of_this->is_extensible()) {
1717     if (strict_mode == kNonStrictMode) {
1718       return value;
1719     } else {
1720       Handle<Object> args[1] = {Handle<String>(name)};
1721       return heap->isolate()->Throw(
1722           *FACTORY->NewTypeError("object_not_extensible",
1723                                  HandleVector(args, 1)));
1724     }
1725   }
1726   if (HasFastProperties()) {
1727     // Ensure the descriptor array does not get too big.
1728     if (map_of_this->instance_descriptors()->number_of_descriptors() <
1729         DescriptorArray::kMaxNumberOfDescriptors) {
1730       if (value->IsJSFunction()) {
1731         return AddConstantFunctionProperty(name,
1732                                            JSFunction::cast(value),
1733                                            attributes);
1734       } else {
1735         return AddFastProperty(name, value, attributes);
1736       }
1737     } else {
1738       // Normalize the object to prevent very large instance descriptors.
1739       // This eliminates unwanted N^2 allocation and lookup behavior.
1740       Object* obj;
1741       { MaybeObject* maybe_obj =
1742             NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1743         if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1744       }
1745     }
1746   }
1747   return AddSlowProperty(name, value, attributes);
1748 }
1749 
1750 
SetPropertyPostInterceptor(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1751 MaybeObject* JSObject::SetPropertyPostInterceptor(
1752     String* name,
1753     Object* value,
1754     PropertyAttributes attributes,
1755     StrictModeFlag strict_mode) {
1756   // Check local property, ignore interceptor.
1757   LookupResult result(GetIsolate());
1758   LocalLookupRealNamedProperty(name, &result);
1759   if (result.IsFound()) {
1760     // An existing property, a map transition or a null descriptor was
1761     // found.  Use set property to handle all these cases.
1762     return SetProperty(&result, name, value, attributes, strict_mode);
1763   }
1764   bool found = false;
1765   MaybeObject* result_object;
1766   result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1767                                                             value,
1768                                                             attributes,
1769                                                             &found,
1770                                                             strict_mode);
1771   if (found) return result_object;
1772   // Add a new real property.
1773   return AddProperty(name, value, attributes, strict_mode);
1774 }
1775 
1776 
ReplaceSlowProperty(String * name,Object * value,PropertyAttributes attributes)1777 MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1778                                            Object* value,
1779                                            PropertyAttributes attributes) {
1780   StringDictionary* dictionary = property_dictionary();
1781   int old_index = dictionary->FindEntry(name);
1782   int new_enumeration_index = 0;  // 0 means "Use the next available index."
1783   if (old_index != -1) {
1784     // All calls to ReplaceSlowProperty have had all transitions removed.
1785     ASSERT(!dictionary->ContainsTransition(old_index));
1786     new_enumeration_index = dictionary->DetailsAt(old_index).index();
1787   }
1788 
1789   PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1790   return SetNormalizedProperty(name, value, new_details);
1791 }
1792 
1793 
ConvertDescriptorToFieldAndMapTransition(String * name,Object * new_value,PropertyAttributes attributes)1794 MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
1795     String* name,
1796     Object* new_value,
1797     PropertyAttributes attributes) {
1798   Map* old_map = map();
1799   Object* result;
1800   { MaybeObject* maybe_result =
1801         ConvertDescriptorToField(name, new_value, attributes);
1802     if (!maybe_result->ToObject(&result)) return maybe_result;
1803   }
1804   // If we get to this point we have succeeded - do not return failure
1805   // after this point.  Later stuff is optional.
1806   if (!HasFastProperties()) {
1807     return result;
1808   }
1809   // Do not add transitions to the map of "new Object()".
1810   if (map() == GetIsolate()->context()->global_context()->
1811       object_function()->map()) {
1812     return result;
1813   }
1814 
1815   MapTransitionDescriptor transition(name,
1816                                      map(),
1817                                      attributes);
1818   Object* new_descriptors;
1819   { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1820         CopyInsert(&transition, KEEP_TRANSITIONS);
1821     if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1822       return result;  // Yes, return _result_.
1823     }
1824   }
1825   old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1826   return result;
1827 }
1828 
1829 
ConvertDescriptorToField(String * name,Object * new_value,PropertyAttributes attributes)1830 MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1831                                                 Object* new_value,
1832                                                 PropertyAttributes attributes) {
1833   if (map()->unused_property_fields() == 0 &&
1834       properties()->length() > MaxFastProperties()) {
1835     Object* obj;
1836     { MaybeObject* maybe_obj =
1837           NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1838       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1839     }
1840     return ReplaceSlowProperty(name, new_value, attributes);
1841   }
1842 
1843   int index = map()->NextFreePropertyIndex();
1844   FieldDescriptor new_field(name, index, attributes);
1845   // Make a new DescriptorArray replacing an entry with FieldDescriptor.
1846   Object* descriptors_unchecked;
1847   { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1848                                   CopyInsert(&new_field, REMOVE_TRANSITIONS);
1849     if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1850       return maybe_descriptors_unchecked;
1851     }
1852   }
1853   DescriptorArray* new_descriptors =
1854       DescriptorArray::cast(descriptors_unchecked);
1855 
1856   // Make a new map for the object.
1857   Object* new_map_unchecked;
1858   { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1859     if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1860       return maybe_new_map_unchecked;
1861     }
1862   }
1863   Map* new_map = Map::cast(new_map_unchecked);
1864   new_map->set_instance_descriptors(new_descriptors);
1865 
1866   // Make new properties array if necessary.
1867   FixedArray* new_properties = 0;  // Will always be NULL or a valid pointer.
1868   int new_unused_property_fields = map()->unused_property_fields() - 1;
1869   if (map()->unused_property_fields() == 0) {
1870     new_unused_property_fields = kFieldsAdded - 1;
1871     Object* new_properties_object;
1872     { MaybeObject* maybe_new_properties_object =
1873           properties()->CopySize(properties()->length() + kFieldsAdded);
1874       if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1875         return maybe_new_properties_object;
1876       }
1877     }
1878     new_properties = FixedArray::cast(new_properties_object);
1879   }
1880 
1881   // Update pointers to commit changes.
1882   // Object points to the new map.
1883   new_map->set_unused_property_fields(new_unused_property_fields);
1884   set_map(new_map);
1885   if (new_properties) {
1886     set_properties(FixedArray::cast(new_properties));
1887   }
1888   return FastPropertyAtPut(index, new_value);
1889 }
1890 
1891 
1892 
SetPropertyWithInterceptor(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1893 MaybeObject* JSObject::SetPropertyWithInterceptor(
1894     String* name,
1895     Object* value,
1896     PropertyAttributes attributes,
1897     StrictModeFlag strict_mode) {
1898   Isolate* isolate = GetIsolate();
1899   HandleScope scope(isolate);
1900   Handle<JSObject> this_handle(this);
1901   Handle<String> name_handle(name);
1902   Handle<Object> value_handle(value, isolate);
1903   Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1904   if (!interceptor->setter()->IsUndefined()) {
1905     LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1906     CustomArguments args(isolate, interceptor->data(), this, this);
1907     v8::AccessorInfo info(args.end());
1908     v8::NamedPropertySetter setter =
1909         v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1910     v8::Handle<v8::Value> result;
1911     {
1912       // Leaving JavaScript.
1913       VMState state(isolate, EXTERNAL);
1914       Handle<Object> value_unhole(value->IsTheHole() ?
1915                                   isolate->heap()->undefined_value() :
1916                                   value,
1917                                   isolate);
1918       result = setter(v8::Utils::ToLocal(name_handle),
1919                       v8::Utils::ToLocal(value_unhole),
1920                       info);
1921     }
1922     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1923     if (!result.IsEmpty()) return *value_handle;
1924   }
1925   MaybeObject* raw_result =
1926       this_handle->SetPropertyPostInterceptor(*name_handle,
1927                                               *value_handle,
1928                                               attributes,
1929                                               strict_mode);
1930   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1931   return raw_result;
1932 }
1933 
1934 
SetProperty(Handle<JSReceiver> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes,StrictModeFlag strict_mode)1935 Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1936                                        Handle<String> key,
1937                                        Handle<Object> value,
1938                                        PropertyAttributes attributes,
1939                                        StrictModeFlag strict_mode) {
1940   CALL_HEAP_FUNCTION(object->GetIsolate(),
1941                      object->SetProperty(*key, *value, attributes, strict_mode),
1942                      Object);
1943 }
1944 
1945 
SetProperty(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1946 MaybeObject* JSReceiver::SetProperty(String* name,
1947                                      Object* value,
1948                                      PropertyAttributes attributes,
1949                                      StrictModeFlag strict_mode) {
1950   LookupResult result(GetIsolate());
1951   LocalLookup(name, &result);
1952   return SetProperty(&result, name, value, attributes, strict_mode);
1953 }
1954 
1955 
SetPropertyWithCallback(Object * structure,String * name,Object * value,JSObject * holder,StrictModeFlag strict_mode)1956 MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1957                                                String* name,
1958                                                Object* value,
1959                                                JSObject* holder,
1960                                                StrictModeFlag strict_mode) {
1961   Isolate* isolate = GetIsolate();
1962   HandleScope scope(isolate);
1963 
1964   // We should never get here to initialize a const with the hole
1965   // value since a const declaration would conflict with the setter.
1966   ASSERT(!value->IsTheHole());
1967   Handle<Object> value_handle(value, isolate);
1968 
1969   // To accommodate both the old and the new api we switch on the
1970   // data structure used to store the callbacks.  Eventually foreign
1971   // callbacks should be phased out.
1972   if (structure->IsForeign()) {
1973     AccessorDescriptor* callback =
1974         reinterpret_cast<AccessorDescriptor*>(
1975             Foreign::cast(structure)->foreign_address());
1976     MaybeObject* obj = (callback->setter)(this,  value, callback->data);
1977     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1978     if (obj->IsFailure()) return obj;
1979     return *value_handle;
1980   }
1981 
1982   if (structure->IsAccessorInfo()) {
1983     // api style callbacks
1984     AccessorInfo* data = AccessorInfo::cast(structure);
1985     Object* call_obj = data->setter();
1986     v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1987     if (call_fun == NULL) return value;
1988     Handle<String> key(name);
1989     LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1990     CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
1991     v8::AccessorInfo info(args.end());
1992     {
1993       // Leaving JavaScript.
1994       VMState state(isolate, EXTERNAL);
1995       call_fun(v8::Utils::ToLocal(key),
1996                v8::Utils::ToLocal(value_handle),
1997                info);
1998     }
1999     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
2000     return *value_handle;
2001   }
2002 
2003   if (structure->IsAccessorPair()) {
2004     Object* setter = AccessorPair::cast(structure)->setter();
2005     if (setter->IsSpecFunction()) {
2006       // TODO(rossberg): nicer would be to cast to some JSCallable here...
2007      return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
2008     } else {
2009       if (strict_mode == kNonStrictMode) {
2010         return value;
2011       }
2012       Handle<String> key(name);
2013       Handle<Object> holder_handle(holder, isolate);
2014       Handle<Object> args[2] = { key, holder_handle };
2015       return isolate->Throw(
2016           *isolate->factory()->NewTypeError("no_setter_in_callback",
2017                                             HandleVector(args, 2)));
2018     }
2019   }
2020 
2021   UNREACHABLE();
2022   return NULL;
2023 }
2024 
2025 
SetPropertyWithDefinedSetter(JSReceiver * setter,Object * value)2026 MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2027                                                       Object* value) {
2028   Isolate* isolate = GetIsolate();
2029   Handle<Object> value_handle(value, isolate);
2030   Handle<JSReceiver> fun(setter, isolate);
2031   Handle<JSReceiver> self(this, isolate);
2032 #ifdef ENABLE_DEBUGGER_SUPPORT
2033   Debug* debug = isolate->debug();
2034   // Handle stepping into a setter if step into is active.
2035   // TODO(rossberg): should this apply to getters that are function proxies?
2036   if (debug->StepInActive() && fun->IsJSFunction()) {
2037     debug->HandleStepIn(
2038         Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
2039   }
2040 #endif
2041   bool has_pending_exception;
2042   Handle<Object> argv[] = { value_handle };
2043   Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
2044   // Check for pending exception and return the result.
2045   if (has_pending_exception) return Failure::Exception();
2046   return *value_handle;
2047 }
2048 
2049 
LookupCallbackSetterInPrototypes(String * name,LookupResult * result)2050 void JSObject::LookupCallbackSetterInPrototypes(String* name,
2051                                                 LookupResult* result) {
2052   Heap* heap = GetHeap();
2053   for (Object* pt = GetPrototype();
2054        pt != heap->null_value();
2055        pt = pt->GetPrototype()) {
2056     if (pt->IsJSProxy()) {
2057       return result->HandlerResult(JSProxy::cast(pt));
2058     }
2059     JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
2060     if (result->IsProperty()) {
2061       if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2062       // Found non-callback or read-only callback, stop looking.
2063       break;
2064     }
2065   }
2066   result->NotFound();
2067 }
2068 
2069 
SetElementWithCallbackSetterInPrototypes(uint32_t index,Object * value,bool * found,StrictModeFlag strict_mode)2070 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2071     uint32_t index,
2072     Object* value,
2073     bool* found,
2074     StrictModeFlag strict_mode) {
2075   Heap* heap = GetHeap();
2076   for (Object* pt = GetPrototype();
2077        pt != heap->null_value();
2078        pt = pt->GetPrototype()) {
2079     if (pt->IsJSProxy()) {
2080       String* name;
2081       MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2082       if (!maybe->To<String>(&name)) {
2083         *found = true;  // Force abort
2084         return maybe;
2085       }
2086       return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2087           name, value, NONE, strict_mode, found);
2088     }
2089     if (!JSObject::cast(pt)->HasDictionaryElements()) {
2090       continue;
2091     }
2092     SeededNumberDictionary* dictionary =
2093         JSObject::cast(pt)->element_dictionary();
2094     int entry = dictionary->FindEntry(index);
2095     if (entry != SeededNumberDictionary::kNotFound) {
2096       PropertyDetails details = dictionary->DetailsAt(entry);
2097       if (details.type() == CALLBACKS) {
2098         *found = true;
2099         return SetElementWithCallback(dictionary->ValueAt(entry),
2100                                       index,
2101                                       value,
2102                                       JSObject::cast(pt),
2103                                       strict_mode);
2104       }
2105     }
2106   }
2107   *found = false;
2108   return heap->the_hole_value();
2109 }
2110 
SetPropertyWithCallbackSetterInPrototypes(String * name,Object * value,PropertyAttributes attributes,bool * found,StrictModeFlag strict_mode)2111 MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2112     String* name,
2113     Object* value,
2114     PropertyAttributes attributes,
2115     bool* found,
2116     StrictModeFlag strict_mode) {
2117   Heap* heap = GetHeap();
2118   // We could not find a local property so let's check whether there is an
2119   // accessor that wants to handle the property.
2120   LookupResult accessor_result(heap->isolate());
2121   LookupCallbackSetterInPrototypes(name, &accessor_result);
2122   if (accessor_result.IsFound()) {
2123     *found = true;
2124     if (accessor_result.type() == CALLBACKS) {
2125       return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2126                                      name,
2127                                      value,
2128                                      accessor_result.holder(),
2129                                      strict_mode);
2130     } else if (accessor_result.type() == HANDLER) {
2131       // There is a proxy in the prototype chain. Invoke its
2132       // getPropertyDescriptor trap.
2133       bool found = false;
2134       // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2135       // make sure to use the handlified references after calling
2136       // the function.
2137       Handle<JSObject> self(this);
2138       Handle<String> hname(name);
2139       Handle<Object> hvalue(value);
2140       MaybeObject* result =
2141           accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2142               name, value, attributes, strict_mode, &found);
2143       if (found) return result;
2144       // The proxy does not define the property as an accessor.
2145       // Consequently, it has no effect on setting the receiver.
2146       return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
2147     }
2148   }
2149   *found = false;
2150   return heap->the_hole_value();
2151 }
2152 
2153 
LookupInDescriptor(String * name,LookupResult * result)2154 void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2155   DescriptorArray* descriptors = map()->instance_descriptors();
2156   int number = descriptors->SearchWithCache(name);
2157   if (number != DescriptorArray::kNotFound) {
2158     result->DescriptorResult(this, descriptors->GetDetails(number), number);
2159   } else {
2160     result->NotFound();
2161   }
2162 }
2163 
2164 
LookupInDescriptors(JSObject * holder,String * name,LookupResult * result)2165 void Map::LookupInDescriptors(JSObject* holder,
2166                               String* name,
2167                               LookupResult* result) {
2168   DescriptorArray* descriptors = instance_descriptors();
2169   DescriptorLookupCache* cache =
2170       GetHeap()->isolate()->descriptor_lookup_cache();
2171   int number = cache->Lookup(descriptors, name);
2172   if (number == DescriptorLookupCache::kAbsent) {
2173     number = descriptors->Search(name);
2174     cache->Update(descriptors, name, number);
2175   }
2176   if (number != DescriptorArray::kNotFound) {
2177     result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2178   } else {
2179     result->NotFound();
2180   }
2181 }
2182 
2183 
ContainsMap(MapHandleList * maps,Handle<Map> map)2184 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2185   ASSERT(!map.is_null());
2186   for (int i = 0; i < maps->length(); ++i) {
2187     if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2188   }
2189   return false;
2190 }
2191 
2192 
2193 template <class T>
MaybeNull(T * p)2194 static Handle<T> MaybeNull(T* p) {
2195   if (p == NULL) return Handle<T>::null();
2196   return Handle<T>(p);
2197 }
2198 
2199 
FindTransitionedMap(MapHandleList * candidates)2200 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2201   ElementsKind elms_kind = elements_kind();
2202   if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2203     bool dummy = true;
2204     Handle<Map> fast_map =
2205         MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2206     if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2207       return fast_map;
2208     }
2209     return Handle<Map>::null();
2210   }
2211   if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2212     bool dummy = true;
2213     Handle<Map> double_map =
2214         MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2215     // In the current implementation, if the DOUBLE map doesn't exist, the
2216     // FAST map can't exist either.
2217     if (double_map.is_null()) return Handle<Map>::null();
2218     Handle<Map> fast_map =
2219         MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2220                                                           &dummy));
2221     if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2222       return fast_map;
2223     }
2224     if (ContainsMap(candidates, double_map)) return double_map;
2225   }
2226   return Handle<Map>::null();
2227 }
2228 
GetElementsTransitionMapFromDescriptor(Object * descriptor_contents,ElementsKind elements_kind)2229 static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2230                                                    ElementsKind elements_kind) {
2231   if (descriptor_contents->IsMap()) {
2232     Map* map = Map::cast(descriptor_contents);
2233     if (map->elements_kind() == elements_kind) {
2234       return map;
2235     }
2236     return NULL;
2237   }
2238 
2239   FixedArray* map_array = FixedArray::cast(descriptor_contents);
2240   for (int i = 0; i < map_array->length(); ++i) {
2241     Object* current = map_array->get(i);
2242     // Skip undefined slots, they are sentinels for reclaimed maps.
2243     if (!current->IsUndefined()) {
2244       Map* current_map = Map::cast(map_array->get(i));
2245       if (current_map->elements_kind() == elements_kind) {
2246         return current_map;
2247       }
2248     }
2249   }
2250 
2251   return NULL;
2252 }
2253 
2254 
AddElementsTransitionMapToDescriptor(Object * descriptor_contents,Map * new_map)2255 static MaybeObject* AddElementsTransitionMapToDescriptor(
2256     Object* descriptor_contents,
2257     Map* new_map) {
2258   // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2259   // simply add the map.
2260   if (descriptor_contents == NULL) {
2261     return new_map;
2262   }
2263 
2264   // There was already a map in the descriptor, create a 2-element FixedArray
2265   // to contain the existing map plus the new one.
2266   FixedArray* new_array;
2267   Heap* heap = new_map->GetHeap();
2268   if (descriptor_contents->IsMap()) {
2269     // Must tenure, DescriptorArray expects no new-space objects.
2270     MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2271     if (!maybe_new_array->To<FixedArray>(&new_array)) {
2272       return maybe_new_array;
2273     }
2274     new_array->set(0, descriptor_contents);
2275     new_array->set(1, new_map);
2276     return new_array;
2277   }
2278 
2279   // The descriptor already contained a list of maps for different ElementKinds
2280   // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2281   // slot, and if that's not available, create a FixedArray to hold the existing
2282   // maps plus the new one and fill it in.
2283   FixedArray* array = FixedArray::cast(descriptor_contents);
2284   for (int i = 0; i < array->length(); ++i) {
2285     if (array->get(i)->IsUndefined()) {
2286       array->set(i, new_map);
2287       return array;
2288     }
2289   }
2290 
2291   // Must tenure, DescriptorArray expects no new-space objects.
2292   MaybeObject* maybe_new_array =
2293       heap->AllocateFixedArray(array->length() + 1, TENURED);
2294   if (!maybe_new_array->To<FixedArray>(&new_array)) {
2295     return maybe_new_array;
2296   }
2297   int i = 0;
2298   while (i < array->length()) {
2299     new_array->set(i, array->get(i));
2300     ++i;
2301   }
2302   new_array->set(i, new_map);
2303   return new_array;
2304 }
2305 
2306 
elements_transition_sentinel_name()2307 String* Map::elements_transition_sentinel_name() {
2308   return GetHeap()->empty_symbol();
2309 }
2310 
2311 
GetDescriptorContents(String * sentinel_name,bool * safe_to_add_transition)2312 Object* Map::GetDescriptorContents(String* sentinel_name,
2313                                    bool* safe_to_add_transition) {
2314   // Get the cached index for the descriptors lookup, or find and cache it.
2315   DescriptorArray* descriptors = instance_descriptors();
2316   DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2317   int index = cache->Lookup(descriptors, sentinel_name);
2318   if (index == DescriptorLookupCache::kAbsent) {
2319     index = descriptors->Search(sentinel_name);
2320     cache->Update(descriptors, sentinel_name, index);
2321   }
2322   // If the transition already exists, return its descriptor.
2323   if (index != DescriptorArray::kNotFound) {
2324     PropertyDetails details(descriptors->GetDetails(index));
2325     if (details.type() == ELEMENTS_TRANSITION) {
2326       return descriptors->GetValue(index);
2327     } else {
2328       if (safe_to_add_transition != NULL) {
2329         *safe_to_add_transition = false;
2330       }
2331     }
2332   }
2333   return NULL;
2334 }
2335 
2336 
LookupElementsTransitionMap(ElementsKind elements_kind,bool * safe_to_add_transition)2337 Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2338                                       bool* safe_to_add_transition) {
2339   // Special case: indirect SMI->FAST transition (cf. comment in
2340   // AddElementsTransition()).
2341   if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2342       elements_kind == FAST_ELEMENTS) {
2343     Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2344                                                         safe_to_add_transition);
2345     if (double_map == NULL) return double_map;
2346     return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2347                                                    safe_to_add_transition);
2348   }
2349   Object* descriptor_contents = GetDescriptorContents(
2350       elements_transition_sentinel_name(), safe_to_add_transition);
2351   if (descriptor_contents != NULL) {
2352     Map* maybe_transition_map =
2353         GetElementsTransitionMapFromDescriptor(descriptor_contents,
2354                                                elements_kind);
2355     ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2356     return maybe_transition_map;
2357   }
2358   return NULL;
2359 }
2360 
2361 
AddElementsTransition(ElementsKind elements_kind,Map * transitioned_map)2362 MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2363                                         Map* transitioned_map) {
2364   // The map transition graph should be a tree, therefore the transition
2365   // from SMI to FAST elements is not done directly, but by going through
2366   // DOUBLE elements first.
2367   if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2368       elements_kind == FAST_ELEMENTS) {
2369     bool safe_to_add = true;
2370     Map* double_map = this->LookupElementsTransitionMap(
2371         FAST_DOUBLE_ELEMENTS, &safe_to_add);
2372     // This method is only called when safe_to_add_transition has been found
2373     // to be true earlier.
2374     ASSERT(safe_to_add);
2375 
2376     if (double_map == NULL) {
2377       MaybeObject* maybe_map = this->CopyDropTransitions();
2378       if (!maybe_map->To(&double_map)) return maybe_map;
2379       double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2380       MaybeObject* maybe_double_transition = this->AddElementsTransition(
2381           FAST_DOUBLE_ELEMENTS, double_map);
2382       if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2383     }
2384     return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2385   }
2386 
2387   bool safe_to_add_transition = true;
2388   Object* descriptor_contents = GetDescriptorContents(
2389       elements_transition_sentinel_name(), &safe_to_add_transition);
2390   // This method is only called when safe_to_add_transition has been found
2391   // to be true earlier.
2392   ASSERT(safe_to_add_transition);
2393   MaybeObject* maybe_new_contents =
2394       AddElementsTransitionMapToDescriptor(descriptor_contents,
2395                                            transitioned_map);
2396   Object* new_contents;
2397   if (!maybe_new_contents->ToObject(&new_contents)) {
2398     return maybe_new_contents;
2399   }
2400 
2401   ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2402                                     new_contents);
2403   Object* new_descriptors;
2404   MaybeObject* maybe_new_descriptors =
2405       instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2406   if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2407     return maybe_new_descriptors;
2408   }
2409   set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2410   return this;
2411 }
2412 
2413 
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)2414 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2415                                                ElementsKind to_kind) {
2416   Isolate* isolate = object->GetIsolate();
2417   CALL_HEAP_FUNCTION(isolate,
2418                      object->GetElementsTransitionMap(isolate, to_kind),
2419                      Map);
2420 }
2421 
2422 
GetElementsTransitionMapSlow(ElementsKind to_kind)2423 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
2424   Map* current_map = map();
2425   ElementsKind from_kind = current_map->elements_kind();
2426 
2427   if (from_kind == to_kind) return current_map;
2428 
2429   // Only objects with FastProperties can have DescriptorArrays and can track
2430   // element-related maps. Also don't add descriptors to maps that are shared.
2431   bool safe_to_add_transition = HasFastProperties() &&
2432       !current_map->IsUndefined() &&
2433       !current_map->is_shared();
2434 
2435   // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2436   // with elements that switch back and forth between dictionary and fast
2437   // element mode.
2438   if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2439     safe_to_add_transition = false;
2440   }
2441 
2442   if (safe_to_add_transition) {
2443     // It's only safe to manipulate the descriptor array if it would be
2444     // safe to add a transition.
2445     Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2446         to_kind, &safe_to_add_transition);
2447     if (maybe_transition_map != NULL) {
2448       return maybe_transition_map;
2449     }
2450   }
2451 
2452   Map* new_map = NULL;
2453 
2454   // No transition to an existing map for the given ElementsKind. Make a new
2455   // one.
2456   { MaybeObject* maybe_map = current_map->CopyDropTransitions();
2457     if (!maybe_map->To(&new_map)) return maybe_map;
2458   }
2459 
2460   new_map->set_elements_kind(to_kind);
2461 
2462   // Only remember the map transition if the object's map is NOT equal to the
2463   // global object_function's map and there is not an already existing
2464   // non-matching element transition.
2465   Context* global_context = GetIsolate()->context()->global_context();
2466   bool allow_map_transition = safe_to_add_transition &&
2467       (global_context->object_function()->map() != map());
2468   if (allow_map_transition) {
2469     MaybeObject* maybe_transition =
2470         current_map->AddElementsTransition(to_kind, new_map);
2471     if (maybe_transition->IsFailure()) return maybe_transition;
2472   }
2473   return new_map;
2474 }
2475 
2476 
LocalLookupRealNamedProperty(String * name,LookupResult * result)2477 void JSObject::LocalLookupRealNamedProperty(String* name,
2478                                             LookupResult* result) {
2479   if (IsJSGlobalProxy()) {
2480     Object* proto = GetPrototype();
2481     if (proto->IsNull()) return result->NotFound();
2482     ASSERT(proto->IsJSGlobalObject());
2483     // A GlobalProxy's prototype should always be a proper JSObject.
2484     return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2485   }
2486 
2487   if (HasFastProperties()) {
2488     LookupInDescriptor(name, result);
2489     if (result->IsFound()) {
2490       // A property, a map transition or a null descriptor was found.
2491       // We return all of these result types because
2492       // LocalLookupRealNamedProperty is used when setting properties
2493       // where map transitions and null descriptors are handled.
2494       ASSERT(result->holder() == this && result->type() != NORMAL);
2495       // Disallow caching for uninitialized constants. These can only
2496       // occur as fields.
2497       if (result->IsReadOnly() && result->type() == FIELD &&
2498           FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2499         result->DisallowCaching();
2500       }
2501       return;
2502     }
2503   } else {
2504     int entry = property_dictionary()->FindEntry(name);
2505     if (entry != StringDictionary::kNotFound) {
2506       Object* value = property_dictionary()->ValueAt(entry);
2507       if (IsGlobalObject()) {
2508         PropertyDetails d = property_dictionary()->DetailsAt(entry);
2509         if (d.IsDeleted()) {
2510           result->NotFound();
2511           return;
2512         }
2513         value = JSGlobalPropertyCell::cast(value)->value();
2514       }
2515       // Make sure to disallow caching for uninitialized constants
2516       // found in the dictionary-mode objects.
2517       if (value->IsTheHole()) result->DisallowCaching();
2518       result->DictionaryResult(this, entry);
2519       return;
2520     }
2521   }
2522   result->NotFound();
2523 }
2524 
2525 
LookupRealNamedProperty(String * name,LookupResult * result)2526 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2527   LocalLookupRealNamedProperty(name, result);
2528   if (result->IsProperty()) return;
2529 
2530   LookupRealNamedPropertyInPrototypes(name, result);
2531 }
2532 
2533 
LookupRealNamedPropertyInPrototypes(String * name,LookupResult * result)2534 void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2535                                                    LookupResult* result) {
2536   Heap* heap = GetHeap();
2537   for (Object* pt = GetPrototype();
2538        pt != heap->null_value();
2539        pt = JSObject::cast(pt)->GetPrototype()) {
2540     JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
2541     if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
2542   }
2543   result->NotFound();
2544 }
2545 
2546 
2547 // We only need to deal with CALLBACKS and INTERCEPTORS
SetPropertyWithFailedAccessCheck(LookupResult * result,String * name,Object * value,bool check_prototype,StrictModeFlag strict_mode)2548 MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2549     LookupResult* result,
2550     String* name,
2551     Object* value,
2552     bool check_prototype,
2553     StrictModeFlag strict_mode) {
2554   if (check_prototype && !result->IsProperty()) {
2555     LookupCallbackSetterInPrototypes(name, result);
2556   }
2557 
2558   if (result->IsProperty()) {
2559     if (!result->IsReadOnly()) {
2560       switch (result->type()) {
2561         case CALLBACKS: {
2562           Object* obj = result->GetCallbackObject();
2563           if (obj->IsAccessorInfo()) {
2564             AccessorInfo* info = AccessorInfo::cast(obj);
2565             if (info->all_can_write()) {
2566               return SetPropertyWithCallback(result->GetCallbackObject(),
2567                                              name,
2568                                              value,
2569                                              result->holder(),
2570                                              strict_mode);
2571             }
2572           }
2573           break;
2574         }
2575         case INTERCEPTOR: {
2576           // Try lookup real named properties. Note that only property can be
2577           // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2578           LookupResult r(GetIsolate());
2579           LookupRealNamedProperty(name, &r);
2580           if (r.IsProperty()) {
2581             return SetPropertyWithFailedAccessCheck(&r,
2582                                                     name,
2583                                                     value,
2584                                                     check_prototype,
2585                                                     strict_mode);
2586           }
2587           break;
2588         }
2589         default: {
2590           break;
2591         }
2592       }
2593     }
2594   }
2595 
2596   Isolate* isolate = GetIsolate();
2597   HandleScope scope(isolate);
2598   Handle<Object> value_handle(value);
2599   isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
2600   return *value_handle;
2601 }
2602 
2603 
SetProperty(LookupResult * result,String * key,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)2604 MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2605                                      String* key,
2606                                      Object* value,
2607                                      PropertyAttributes attributes,
2608                                      StrictModeFlag strict_mode) {
2609   if (result->IsFound() && result->type() == HANDLER) {
2610     return result->proxy()->SetPropertyWithHandler(
2611         key, value, attributes, strict_mode);
2612   } else {
2613     return JSObject::cast(this)->SetPropertyForResult(
2614         result, key, value, attributes, strict_mode);
2615   }
2616 }
2617 
2618 
HasPropertyWithHandler(String * name_raw)2619 bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2620   Isolate* isolate = GetIsolate();
2621   HandleScope scope(isolate);
2622   Handle<Object> receiver(this);
2623   Handle<Object> name(name_raw);
2624 
2625   Handle<Object> args[] = { name };
2626   Handle<Object> result = CallTrap(
2627     "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
2628   if (isolate->has_pending_exception()) return Failure::Exception();
2629 
2630   return result->ToBoolean()->IsTrue();
2631 }
2632 
2633 
SetPropertyWithHandler(String * name_raw,Object * value_raw,PropertyAttributes attributes,StrictModeFlag strict_mode)2634 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2635     String* name_raw,
2636     Object* value_raw,
2637     PropertyAttributes attributes,
2638     StrictModeFlag strict_mode) {
2639   Isolate* isolate = GetIsolate();
2640   HandleScope scope(isolate);
2641   Handle<Object> receiver(this);
2642   Handle<Object> name(name_raw);
2643   Handle<Object> value(value_raw);
2644 
2645   Handle<Object> args[] = { receiver, name, value };
2646   CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
2647   if (isolate->has_pending_exception()) return Failure::Exception();
2648 
2649   return *value;
2650 }
2651 
2652 
SetPropertyWithHandlerIfDefiningSetter(String * name_raw,Object * value_raw,PropertyAttributes attributes,StrictModeFlag strict_mode,bool * found)2653 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2654     String* name_raw,
2655     Object* value_raw,
2656     PropertyAttributes attributes,
2657     StrictModeFlag strict_mode,
2658     bool* found) {
2659   *found = true;  // except where defined otherwise...
2660   Isolate* isolate = GetHeap()->isolate();
2661   Handle<JSProxy> proxy(this);
2662   Handle<Object> handler(this->handler());  // Trap might morph proxy.
2663   Handle<String> name(name_raw);
2664   Handle<Object> value(value_raw);
2665   Handle<Object> args[] = { name };
2666   Handle<Object> result = proxy->CallTrap(
2667       "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2668   if (isolate->has_pending_exception()) return Failure::Exception();
2669 
2670   if (!result->IsUndefined()) {
2671     // The proxy handler cares about this property.
2672     // Check whether it is virtualized as an accessor.
2673     // Emulate [[GetProperty]] semantics for proxies.
2674     bool has_pending_exception;
2675     Handle<Object> argv[] = { result };
2676     Handle<Object> desc =
2677         Execution::Call(isolate->to_complete_property_descriptor(), result,
2678                         ARRAY_SIZE(argv), argv, &has_pending_exception);
2679     if (has_pending_exception) return Failure::Exception();
2680 
2681     Handle<String> conf_name =
2682         isolate->factory()->LookupAsciiSymbol("configurable_");
2683     Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2684     ASSERT(!isolate->has_pending_exception());
2685     if (configurable->IsFalse()) {
2686       Handle<String> trap =
2687           isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2688       Handle<Object> args[] = { handler, trap, name };
2689       Handle<Object> error = isolate->factory()->NewTypeError(
2690           "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2691       return isolate->Throw(*error);
2692     }
2693     ASSERT(configurable->IsTrue());
2694 
2695     // Check for AccessorDescriptor.
2696     Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2697     Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2698     ASSERT(!isolate->has_pending_exception());
2699     if (!setter->IsUndefined()) {
2700       // We have a setter -- invoke it.
2701       // TODO(rossberg): nicer would be to cast to some JSCallable here...
2702       return proxy->SetPropertyWithDefinedSetter(
2703           JSReceiver::cast(*setter), *value);
2704     } else {
2705       Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2706       Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2707       ASSERT(!isolate->has_pending_exception());
2708       if (!getter->IsUndefined()) {
2709         // We have a getter but no setter -- the property may not be
2710         // written. In strict mode, throw an error.
2711         if (strict_mode == kNonStrictMode) return *value;
2712         Handle<Object> args[] = { name, proxy };
2713         Handle<Object> error = isolate->factory()->NewTypeError(
2714             "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2715         return isolate->Throw(*error);
2716       }
2717     }
2718     // Fall-through.
2719   }
2720 
2721   // The proxy does not define the property as an accessor.
2722   *found = false;
2723   return *value;
2724 }
2725 
2726 
DeletePropertyWithHandler(String * name_raw,DeleteMode mode)2727 MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2728     String* name_raw, DeleteMode mode) {
2729   Isolate* isolate = GetIsolate();
2730   HandleScope scope(isolate);
2731   Handle<Object> receiver(this);
2732   Handle<Object> name(name_raw);
2733 
2734   Handle<Object> args[] = { name };
2735   Handle<Object> result = CallTrap(
2736     "delete", Handle<Object>(), ARRAY_SIZE(args), args);
2737   if (isolate->has_pending_exception()) return Failure::Exception();
2738 
2739   Object* bool_result = result->ToBoolean();
2740   if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2741     Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2742     Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
2743     Handle<Object> error = isolate->factory()->NewTypeError(
2744         "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2745     isolate->Throw(*error);
2746     return Failure::Exception();
2747   }
2748   return bool_result;
2749 }
2750 
2751 
DeleteElementWithHandler(uint32_t index,DeleteMode mode)2752 MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2753     uint32_t index,
2754     DeleteMode mode) {
2755   Isolate* isolate = GetIsolate();
2756   HandleScope scope(isolate);
2757   Handle<String> name = isolate->factory()->Uint32ToString(index);
2758   return JSProxy::DeletePropertyWithHandler(*name, mode);
2759 }
2760 
2761 
GetPropertyAttributeWithHandler(JSReceiver * receiver_raw,String * name_raw)2762 MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2763     JSReceiver* receiver_raw,
2764     String* name_raw) {
2765   Isolate* isolate = GetIsolate();
2766   HandleScope scope(isolate);
2767   Handle<JSProxy> proxy(this);
2768   Handle<Object> handler(this->handler());  // Trap might morph proxy.
2769   Handle<JSReceiver> receiver(receiver_raw);
2770   Handle<Object> name(name_raw);
2771 
2772   Handle<Object> args[] = { name };
2773   Handle<Object> result = CallTrap(
2774     "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2775   if (isolate->has_pending_exception()) return NONE;
2776 
2777   if (result->IsUndefined()) return ABSENT;
2778 
2779   bool has_pending_exception;
2780   Handle<Object> argv[] = { result };
2781   Handle<Object> desc =
2782       Execution::Call(isolate->to_complete_property_descriptor(), result,
2783                       ARRAY_SIZE(argv), argv, &has_pending_exception);
2784   if (has_pending_exception) return NONE;
2785 
2786   // Convert result to PropertyAttributes.
2787   Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2788   Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2789   if (isolate->has_pending_exception()) return NONE;
2790   Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2791   Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2792   if (isolate->has_pending_exception()) return NONE;
2793   Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2794   Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2795   if (isolate->has_pending_exception()) return NONE;
2796 
2797   if (configurable->IsFalse()) {
2798     Handle<String> trap =
2799         isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2800     Handle<Object> args[] = { handler, trap, name };
2801     Handle<Object> error = isolate->factory()->NewTypeError(
2802         "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2803     isolate->Throw(*error);
2804     return NONE;
2805   }
2806 
2807   int attributes = NONE;
2808   if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2809   if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2810   if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2811   return static_cast<PropertyAttributes>(attributes);
2812 }
2813 
2814 
GetElementAttributeWithHandler(JSReceiver * receiver,uint32_t index)2815 MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2816     JSReceiver* receiver,
2817     uint32_t index) {
2818   Isolate* isolate = GetIsolate();
2819   HandleScope scope(isolate);
2820   Handle<String> name = isolate->factory()->Uint32ToString(index);
2821   return GetPropertyAttributeWithHandler(receiver, *name);
2822 }
2823 
2824 
Fix()2825 void JSProxy::Fix() {
2826   Isolate* isolate = GetIsolate();
2827   HandleScope scope(isolate);
2828   Handle<JSProxy> self(this);
2829 
2830   // Save identity hash.
2831   MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2832 
2833   if (IsJSFunctionProxy()) {
2834     isolate->factory()->BecomeJSFunction(self);
2835     // Code will be set on the JavaScript side.
2836   } else {
2837     isolate->factory()->BecomeJSObject(self);
2838   }
2839   ASSERT(self->IsJSObject());
2840 
2841   // Inherit identity, if it was present.
2842   Object* hash;
2843   if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2844     Handle<JSObject> new_self(JSObject::cast(*self));
2845     isolate->factory()->SetIdentityHash(new_self, hash);
2846   }
2847 }
2848 
2849 
CallTrap(const char * name,Handle<Object> derived,int argc,Handle<Object> argv[])2850 MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2851                                                  Handle<Object> derived,
2852                                                  int argc,
2853                                                  Handle<Object> argv[]) {
2854   Isolate* isolate = GetIsolate();
2855   Handle<Object> handler(this->handler());
2856 
2857   Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2858   Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2859   if (isolate->has_pending_exception()) return trap;
2860 
2861   if (trap->IsUndefined()) {
2862     if (derived.is_null()) {
2863       Handle<Object> args[] = { handler, trap_name };
2864       Handle<Object> error = isolate->factory()->NewTypeError(
2865         "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2866       isolate->Throw(*error);
2867       return Handle<Object>();
2868     }
2869     trap = Handle<Object>(derived);
2870   }
2871 
2872   bool threw;
2873   return Execution::Call(trap, handler, argc, argv, &threw);
2874 }
2875 
2876 
SetPropertyForResult(LookupResult * result,String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)2877 MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2878                                             String* name,
2879                                             Object* value,
2880                                             PropertyAttributes attributes,
2881                                             StrictModeFlag strict_mode) {
2882   Heap* heap = GetHeap();
2883   // Make sure that the top context does not change when doing callbacks or
2884   // interceptor calls.
2885   AssertNoContextChange ncc;
2886 
2887   // Optimization for 2-byte strings often used as keys in a decompression
2888   // dictionary.  We make these short keys into symbols to avoid constantly
2889   // reallocating them.
2890   if (!name->IsSymbol() && name->length() <= 2) {
2891     Object* symbol_version;
2892     { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
2893       if (maybe_symbol_version->ToObject(&symbol_version)) {
2894         name = String::cast(symbol_version);
2895       }
2896     }
2897   }
2898 
2899   // Check access rights if needed.
2900   if (IsAccessCheckNeeded()) {
2901     if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2902       return SetPropertyWithFailedAccessCheck(
2903           result, name, value, true, strict_mode);
2904     }
2905   }
2906 
2907   if (IsJSGlobalProxy()) {
2908     Object* proto = GetPrototype();
2909     if (proto->IsNull()) return value;
2910     ASSERT(proto->IsJSGlobalObject());
2911     return JSObject::cast(proto)->SetPropertyForResult(
2912         result, name, value, attributes, strict_mode);
2913   }
2914 
2915   if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2916     bool found = false;
2917     MaybeObject* result_object;
2918     result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2919                                                               value,
2920                                                               attributes,
2921                                                               &found,
2922                                                               strict_mode);
2923     if (found) return result_object;
2924   }
2925 
2926   // At this point, no GC should have happened, as this would invalidate
2927   // 'result', which we cannot handlify!
2928 
2929   if (!result->IsFound()) {
2930     // Neither properties nor transitions found.
2931     return AddProperty(name, value, attributes, strict_mode);
2932   }
2933   if (result->IsReadOnly() && result->IsProperty()) {
2934     if (strict_mode == kStrictMode) {
2935       Handle<JSObject> self(this);
2936       Handle<String> hname(name);
2937       Handle<Object> args[] = { hname, self };
2938       return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2939           "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
2940     } else {
2941       return value;
2942     }
2943   }
2944   // This is a real property that is not read-only, or it is a
2945   // transition or null descriptor and there are no setters in the prototypes.
2946   switch (result->type()) {
2947     case NORMAL:
2948       return SetNormalizedProperty(result, value);
2949     case FIELD:
2950       return FastPropertyAtPut(result->GetFieldIndex(), value);
2951     case MAP_TRANSITION:
2952       if (attributes == result->GetAttributes()) {
2953         // Only use map transition if the attributes match.
2954         return AddFastPropertyUsingMap(result->GetTransitionMap(),
2955                                        name,
2956                                        value);
2957       }
2958       return ConvertDescriptorToField(name, value, attributes);
2959     case CONSTANT_FUNCTION:
2960       // Only replace the function if necessary.
2961       if (value == result->GetConstantFunction()) return value;
2962       // Preserve the attributes of this existing property.
2963       attributes = result->GetAttributes();
2964       return ConvertDescriptorToField(name, value, attributes);
2965     case CALLBACKS:
2966       return SetPropertyWithCallback(result->GetCallbackObject(),
2967                                      name,
2968                                      value,
2969                                      result->holder(),
2970                                      strict_mode);
2971     case INTERCEPTOR:
2972       return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
2973     case CONSTANT_TRANSITION: {
2974       // If the same constant function is being added we can simply
2975       // transition to the target map.
2976       Map* target_map = result->GetTransitionMap();
2977       DescriptorArray* target_descriptors = target_map->instance_descriptors();
2978       int number = target_descriptors->SearchWithCache(name);
2979       ASSERT(number != DescriptorArray::kNotFound);
2980       ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2981       JSFunction* function =
2982           JSFunction::cast(target_descriptors->GetValue(number));
2983       if (value == function) {
2984         set_map(target_map);
2985         return value;
2986       }
2987       // Otherwise, replace with a MAP_TRANSITION to a new map with a
2988       // FIELD, even if the value is a constant function.
2989       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2990     }
2991     case NULL_DESCRIPTOR:
2992     case ELEMENTS_TRANSITION:
2993       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2994     case HANDLER:
2995       UNREACHABLE();
2996       return value;
2997   }
2998   UNREACHABLE();  // keep the compiler happy
2999   return value;
3000 }
3001 
3002 
3003 // Set a real local property, even if it is READ_ONLY.  If the property is not
3004 // present, add it with attributes NONE.  This code is an exact clone of
3005 // SetProperty, with the check for IsReadOnly and the check for a
3006 // callback setter removed.  The two lines looking up the LookupResult
3007 // result are also added.  If one of the functions is changed, the other
3008 // should be.
3009 // Note that this method cannot be used to set the prototype of a function
3010 // because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3011 // doesn't handle function prototypes correctly.
SetLocalPropertyIgnoreAttributes(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes)3012 Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3013     Handle<JSObject> object,
3014     Handle<String> key,
3015     Handle<Object> value,
3016     PropertyAttributes attributes) {
3017   CALL_HEAP_FUNCTION(
3018     object->GetIsolate(),
3019     object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3020     Object);
3021 }
3022 
3023 
SetLocalPropertyIgnoreAttributes(String * name,Object * value,PropertyAttributes attributes)3024 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
3025     String* name,
3026     Object* value,
3027     PropertyAttributes attributes) {
3028 
3029   // Make sure that the top context does not change when doing callbacks or
3030   // interceptor calls.
3031   AssertNoContextChange ncc;
3032   Isolate* isolate = GetIsolate();
3033   LookupResult result(isolate);
3034   LocalLookup(name, &result);
3035   // Check access rights if needed.
3036   if (IsAccessCheckNeeded()) {
3037     if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3038       return SetPropertyWithFailedAccessCheck(&result,
3039                                               name,
3040                                               value,
3041                                               false,
3042                                               kNonStrictMode);
3043     }
3044   }
3045 
3046   if (IsJSGlobalProxy()) {
3047     Object* proto = GetPrototype();
3048     if (proto->IsNull()) return value;
3049     ASSERT(proto->IsJSGlobalObject());
3050     return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
3051         name,
3052         value,
3053         attributes);
3054   }
3055 
3056   // Check for accessor in prototype chain removed here in clone.
3057   if (!result.IsFound()) {
3058     // Neither properties nor transitions found.
3059     return AddProperty(name, value, attributes, kNonStrictMode);
3060   }
3061 
3062   PropertyDetails details = PropertyDetails(attributes, NORMAL);
3063 
3064   // Check of IsReadOnly removed from here in clone.
3065   switch (result.type()) {
3066     case NORMAL:
3067       return SetNormalizedProperty(name, value, details);
3068     case FIELD:
3069       return FastPropertyAtPut(result.GetFieldIndex(), value);
3070     case MAP_TRANSITION:
3071       if (attributes == result.GetAttributes()) {
3072         // Only use map transition if the attributes match.
3073         return AddFastPropertyUsingMap(result.GetTransitionMap(),
3074                                        name,
3075                                        value);
3076       }
3077       return ConvertDescriptorToField(name, value, attributes);
3078     case CONSTANT_FUNCTION:
3079       // Only replace the function if necessary.
3080       if (value == result.GetConstantFunction()) return value;
3081       // Preserve the attributes of this existing property.
3082       attributes = result.GetAttributes();
3083       return ConvertDescriptorToField(name, value, attributes);
3084     case CALLBACKS:
3085     case INTERCEPTOR:
3086       // Override callback in clone
3087       return ConvertDescriptorToField(name, value, attributes);
3088     case CONSTANT_TRANSITION:
3089       // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3090       // if the value is a function.
3091       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3092     case NULL_DESCRIPTOR:
3093     case ELEMENTS_TRANSITION:
3094       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3095     case HANDLER:
3096       UNREACHABLE();
3097       return value;
3098   }
3099   UNREACHABLE();  // keep the compiler happy
3100   return value;
3101 }
3102 
3103 
GetPropertyAttributePostInterceptor(JSObject * receiver,String * name,bool continue_search)3104 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3105       JSObject* receiver,
3106       String* name,
3107       bool continue_search) {
3108   // Check local property, ignore interceptor.
3109   LookupResult result(GetIsolate());
3110   LocalLookupRealNamedProperty(name, &result);
3111   if (result.IsProperty()) return result.GetAttributes();
3112 
3113   if (continue_search) {
3114     // Continue searching via the prototype chain.
3115     Object* pt = GetPrototype();
3116     if (!pt->IsNull()) {
3117       return JSObject::cast(pt)->
3118         GetPropertyAttributeWithReceiver(receiver, name);
3119     }
3120   }
3121   return ABSENT;
3122 }
3123 
3124 
GetPropertyAttributeWithInterceptor(JSObject * receiver,String * name,bool continue_search)3125 PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3126       JSObject* receiver,
3127       String* name,
3128       bool continue_search) {
3129   Isolate* isolate = GetIsolate();
3130 
3131   // Make sure that the top context does not change when doing
3132   // callbacks or interceptor calls.
3133   AssertNoContextChange ncc;
3134 
3135   HandleScope scope(isolate);
3136   Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3137   Handle<JSObject> receiver_handle(receiver);
3138   Handle<JSObject> holder_handle(this);
3139   Handle<String> name_handle(name);
3140   CustomArguments args(isolate, interceptor->data(), receiver, this);
3141   v8::AccessorInfo info(args.end());
3142   if (!interceptor->query()->IsUndefined()) {
3143     v8::NamedPropertyQuery query =
3144         v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
3145     LOG(isolate,
3146         ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
3147     v8::Handle<v8::Integer> result;
3148     {
3149       // Leaving JavaScript.
3150       VMState state(isolate, EXTERNAL);
3151       result = query(v8::Utils::ToLocal(name_handle), info);
3152     }
3153     if (!result.IsEmpty()) {
3154       ASSERT(result->IsInt32());
3155       return static_cast<PropertyAttributes>(result->Int32Value());
3156     }
3157   } else if (!interceptor->getter()->IsUndefined()) {
3158     v8::NamedPropertyGetter getter =
3159         v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
3160     LOG(isolate,
3161         ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
3162     v8::Handle<v8::Value> result;
3163     {
3164       // Leaving JavaScript.
3165       VMState state(isolate, EXTERNAL);
3166       result = getter(v8::Utils::ToLocal(name_handle), info);
3167     }
3168     if (!result.IsEmpty()) return DONT_ENUM;
3169   }
3170   return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3171                                                             *name_handle,
3172                                                             continue_search);
3173 }
3174 
3175 
GetPropertyAttributeWithReceiver(JSReceiver * receiver,String * key)3176 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3177       JSReceiver* receiver,
3178       String* key) {
3179   uint32_t index = 0;
3180   if (IsJSObject() && key->AsArrayIndex(&index)) {
3181     return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3182         ? NONE : ABSENT;
3183   }
3184   // Named property.
3185   LookupResult result(GetIsolate());
3186   Lookup(key, &result);
3187   return GetPropertyAttribute(receiver, &result, key, true);
3188 }
3189 
3190 
GetPropertyAttribute(JSReceiver * receiver,LookupResult * result,String * name,bool continue_search)3191 PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3192                                                     LookupResult* result,
3193                                                     String* name,
3194                                                     bool continue_search) {
3195   // Check access rights if needed.
3196   if (IsAccessCheckNeeded()) {
3197     JSObject* this_obj = JSObject::cast(this);
3198     Heap* heap = GetHeap();
3199     if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3200       return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3201           receiver, result, name, continue_search);
3202     }
3203   }
3204   if (result->IsProperty()) {
3205     switch (result->type()) {
3206       case NORMAL:  // fall through
3207       case FIELD:
3208       case CONSTANT_FUNCTION:
3209       case CALLBACKS:
3210         return result->GetAttributes();
3211       case HANDLER: {
3212         return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3213             receiver, name);
3214       }
3215       case INTERCEPTOR:
3216         return result->holder()->GetPropertyAttributeWithInterceptor(
3217             JSObject::cast(receiver), name, continue_search);
3218       default:
3219         UNREACHABLE();
3220     }
3221   }
3222   return ABSENT;
3223 }
3224 
3225 
GetLocalPropertyAttribute(String * name)3226 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
3227   // Check whether the name is an array index.
3228   uint32_t index = 0;
3229   if (IsJSObject() && name->AsArrayIndex(&index)) {
3230     if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
3231     return ABSENT;
3232   }
3233   // Named property.
3234   LookupResult result(GetIsolate());
3235   LocalLookup(name, &result);
3236   return GetPropertyAttribute(this, &result, name, false);
3237 }
3238 
3239 
Get(JSObject * obj,PropertyNormalizationMode mode)3240 MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3241                                      PropertyNormalizationMode mode) {
3242   Isolate* isolate = obj->GetIsolate();
3243   Map* fast = obj->map();
3244   int index = fast->Hash() % kEntries;
3245   Object* result = get(index);
3246   if (result->IsMap() &&
3247       Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
3248 #ifdef DEBUG
3249     if (FLAG_verify_heap) {
3250       Map::cast(result)->SharedMapVerify();
3251     }
3252     if (FLAG_enable_slow_asserts) {
3253       // The cached map should match newly created normalized map bit-by-bit.
3254       Object* fresh;
3255       { MaybeObject* maybe_fresh =
3256             fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3257         if (maybe_fresh->ToObject(&fresh)) {
3258           ASSERT(memcmp(Map::cast(fresh)->address(),
3259                         Map::cast(result)->address(),
3260                         Map::kSize) == 0);
3261         }
3262       }
3263     }
3264 #endif
3265     return result;
3266   }
3267 
3268   { MaybeObject* maybe_result =
3269         fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3270     if (!maybe_result->ToObject(&result)) return maybe_result;
3271   }
3272   set(index, result);
3273   isolate->counters()->normalized_maps()->Increment();
3274 
3275   return result;
3276 }
3277 
3278 
Clear()3279 void NormalizedMapCache::Clear() {
3280   int entries = length();
3281   for (int i = 0; i != entries; i++) {
3282     set_undefined(i);
3283   }
3284 }
3285 
3286 
UpdateMapCodeCache(Handle<JSObject> object,Handle<String> name,Handle<Code> code)3287 void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3288                                   Handle<String> name,
3289                                   Handle<Code> code) {
3290   Isolate* isolate = object->GetIsolate();
3291   CALL_HEAP_FUNCTION_VOID(isolate,
3292                           object->UpdateMapCodeCache(*name, *code));
3293 }
3294 
3295 
UpdateMapCodeCache(String * name,Code * code)3296 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
3297   if (map()->is_shared()) {
3298     // Fast case maps are never marked as shared.
3299     ASSERT(!HasFastProperties());
3300     // Replace the map with an identical copy that can be safely modified.
3301     Object* obj;
3302     { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3303                                                      UNIQUE_NORMALIZED_MAP);
3304       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3305     }
3306     GetIsolate()->counters()->normalized_maps()->Increment();
3307 
3308     set_map(Map::cast(obj));
3309   }
3310   return map()->UpdateCodeCache(name, code);
3311 }
3312 
3313 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties)3314 void JSObject::NormalizeProperties(Handle<JSObject> object,
3315                                    PropertyNormalizationMode mode,
3316                                    int expected_additional_properties) {
3317   CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3318                           object->NormalizeProperties(
3319                               mode, expected_additional_properties));
3320 }
3321 
3322 
NormalizeProperties(PropertyNormalizationMode mode,int expected_additional_properties)3323 MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3324                                            int expected_additional_properties) {
3325   if (!HasFastProperties()) return this;
3326 
3327   // The global object is always normalized.
3328   ASSERT(!IsGlobalObject());
3329   // JSGlobalProxy must never be normalized
3330   ASSERT(!IsJSGlobalProxy());
3331 
3332   Map* map_of_this = map();
3333 
3334   // Allocate new content.
3335   int property_count = map_of_this->NumberOfDescribedProperties();
3336   if (expected_additional_properties > 0) {
3337     property_count += expected_additional_properties;
3338   } else {
3339     property_count += 2;  // Make space for two more properties.
3340   }
3341   StringDictionary* dictionary;
3342   { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count);
3343     if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3344   }
3345 
3346   DescriptorArray* descs = map_of_this->instance_descriptors();
3347   for (int i = 0; i < descs->number_of_descriptors(); i++) {
3348     PropertyDetails details(descs->GetDetails(i));
3349     switch (details.type()) {
3350       case CONSTANT_FUNCTION: {
3351         PropertyDetails d =
3352             PropertyDetails(details.attributes(), NORMAL, details.index());
3353         Object* value = descs->GetConstantFunction(i);
3354         MaybeObject* maybe_dictionary =
3355             dictionary->Add(descs->GetKey(i), value, d);
3356         if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3357         break;
3358       }
3359       case FIELD: {
3360         PropertyDetails d =
3361             PropertyDetails(details.attributes(), NORMAL, details.index());
3362         Object* value = FastPropertyAt(descs->GetFieldIndex(i));
3363         MaybeObject* maybe_dictionary =
3364             dictionary->Add(descs->GetKey(i), value, d);
3365         if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3366         break;
3367       }
3368       case CALLBACKS: {
3369         if (!descs->IsProperty(i)) break;
3370         Object* value = descs->GetCallbacksObject(i);
3371         if (value->IsAccessorPair()) {
3372           MaybeObject* maybe_copy =
3373               AccessorPair::cast(value)->CopyWithoutTransitions();
3374           if (!maybe_copy->To(&value)) return maybe_copy;
3375         }
3376         MaybeObject* maybe_dictionary =
3377             dictionary->Add(descs->GetKey(i), value, details);
3378         if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3379         break;
3380       }
3381       case MAP_TRANSITION:
3382       case CONSTANT_TRANSITION:
3383       case NULL_DESCRIPTOR:
3384       case INTERCEPTOR:
3385       case ELEMENTS_TRANSITION:
3386         break;
3387       case HANDLER:
3388       case NORMAL:
3389         UNREACHABLE();
3390         break;
3391     }
3392   }
3393 
3394   Heap* current_heap = GetHeap();
3395 
3396   // Copy the next enumeration index from instance descriptor.
3397   int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
3398   dictionary->SetNextEnumerationIndex(index);
3399 
3400   Map* new_map;
3401   { MaybeObject* maybe_map =
3402         current_heap->isolate()->context()->global_context()->
3403         normalized_map_cache()->Get(this, mode);
3404     if (!maybe_map->To(&new_map)) return maybe_map;
3405   }
3406 
3407   // We have now successfully allocated all the necessary objects.
3408   // Changes can now be made with the guarantee that all of them take effect.
3409 
3410   // Resize the object in the heap if necessary.
3411   int new_instance_size = new_map->instance_size();
3412   int instance_size_delta = map_of_this->instance_size() - new_instance_size;
3413   ASSERT(instance_size_delta >= 0);
3414   current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3415                                      instance_size_delta);
3416   if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
3417     MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3418                                                -instance_size_delta);
3419   }
3420 
3421 
3422   set_map(new_map);
3423   new_map->clear_instance_descriptors();
3424 
3425   set_properties(dictionary);
3426 
3427   current_heap->isolate()->counters()->props_to_dictionary()->Increment();
3428 
3429 #ifdef DEBUG
3430   if (FLAG_trace_normalization) {
3431     PrintF("Object properties have been normalized:\n");
3432     Print();
3433   }
3434 #endif
3435   return this;
3436 }
3437 
3438 
TransformToFastProperties(Handle<JSObject> object,int unused_property_fields)3439 void JSObject::TransformToFastProperties(Handle<JSObject> object,
3440                                          int unused_property_fields) {
3441   CALL_HEAP_FUNCTION_VOID(
3442       object->GetIsolate(),
3443       object->TransformToFastProperties(unused_property_fields));
3444 }
3445 
3446 
TransformToFastProperties(int unused_property_fields)3447 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
3448   if (HasFastProperties()) return this;
3449   ASSERT(!IsGlobalObject());
3450   return property_dictionary()->
3451       TransformPropertiesToFastFor(this, unused_property_fields);
3452 }
3453 
3454 
NormalizeElements(Handle<JSObject> object)3455 Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3456     Handle<JSObject> object) {
3457   CALL_HEAP_FUNCTION(object->GetIsolate(),
3458                      object->NormalizeElements(),
3459                      SeededNumberDictionary);
3460 }
3461 
3462 
NormalizeElements()3463 MaybeObject* JSObject::NormalizeElements() {
3464   ASSERT(!HasExternalArrayElements());
3465 
3466   // Find the backing store.
3467   FixedArrayBase* array = FixedArrayBase::cast(elements());
3468   Map* old_map = array->map();
3469   bool is_arguments =
3470       (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
3471   if (is_arguments) {
3472     array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
3473   }
3474   if (array->IsDictionary()) return array;
3475 
3476   ASSERT(HasFastElements() ||
3477          HasFastSmiOnlyElements() ||
3478          HasFastDoubleElements() ||
3479          HasFastArgumentsElements());
3480   // Compute the effective length and allocate a new backing store.
3481   int length = IsJSArray()
3482       ? Smi::cast(JSArray::cast(this)->length())->value()
3483       : array->length();
3484   int old_capacity = 0;
3485   int used_elements = 0;
3486   GetElementsCapacityAndUsage(&old_capacity, &used_elements);
3487   SeededNumberDictionary* dictionary = NULL;
3488   { Object* object;
3489     MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
3490     if (!maybe->ToObject(&object)) return maybe;
3491     dictionary = SeededNumberDictionary::cast(object);
3492   }
3493 
3494   // Copy the elements to the new backing store.
3495   bool has_double_elements = array->IsFixedDoubleArray();
3496   for (int i = 0; i < length; i++) {
3497     Object* value = NULL;
3498     if (has_double_elements) {
3499       FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3500       if (double_array->is_the_hole(i)) {
3501         value = GetIsolate()->heap()->the_hole_value();
3502       } else {
3503         // Objects must be allocated in the old object space, since the
3504         // overall number of HeapNumbers needed for the conversion might
3505         // exceed the capacity of new space, and we would fail repeatedly
3506         // trying to convert the FixedDoubleArray.
3507         MaybeObject* maybe_value_object =
3508             GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
3509         if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
3510       }
3511     } else {
3512       ASSERT(old_map->has_fast_elements() ||
3513              old_map->has_fast_smi_only_elements());
3514       value = FixedArray::cast(array)->get(i);
3515     }
3516     PropertyDetails details = PropertyDetails(NONE, NORMAL);
3517     if (!value->IsTheHole()) {
3518       Object* result;
3519       MaybeObject* maybe_result =
3520           dictionary->AddNumberEntry(i, value, details);
3521       if (!maybe_result->ToObject(&result)) return maybe_result;
3522       dictionary = SeededNumberDictionary::cast(result);
3523     }
3524   }
3525 
3526   // Switch to using the dictionary as the backing storage for elements.
3527   if (is_arguments) {
3528     FixedArray::cast(elements())->set(1, dictionary);
3529   } else {
3530     // Set the new map first to satify the elements type assert in
3531     // set_elements().
3532     Object* new_map;
3533     MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
3534                                                   DICTIONARY_ELEMENTS);
3535     if (!maybe->ToObject(&new_map)) return maybe;
3536     set_map(Map::cast(new_map));
3537     set_elements(dictionary);
3538   }
3539 
3540   old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3541       Increment();
3542 
3543 #ifdef DEBUG
3544   if (FLAG_trace_normalization) {
3545     PrintF("Object elements have been normalized:\n");
3546     Print();
3547   }
3548 #endif
3549 
3550   ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3551   return dictionary;
3552 }
3553 
3554 
GenerateIdentityHash()3555 Smi* JSReceiver::GenerateIdentityHash() {
3556   Isolate* isolate = GetIsolate();
3557 
3558   int hash_value;
3559   int attempts = 0;
3560   do {
3561     // Generate a random 32-bit hash value but limit range to fit
3562     // within a smi.
3563     hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
3564     attempts++;
3565   } while (hash_value == 0 && attempts < 30);
3566   hash_value = hash_value != 0 ? hash_value : 1;  // never return 0
3567 
3568   return Smi::FromInt(hash_value);
3569 }
3570 
3571 
SetIdentityHash(Object * hash,CreationFlag flag)3572 MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3573   MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3574                                          hash);
3575   if (maybe->IsFailure()) return maybe;
3576   return this;
3577 }
3578 
3579 
GetIdentityHash(Handle<JSObject> obj)3580 int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3581   CALL_AND_RETRY(obj->GetIsolate(),
3582                  obj->GetIdentityHash(ALLOW_CREATION),
3583                  return Smi::cast(__object__)->value(),
3584                  return 0);
3585 }
3586 
3587 
GetIdentityHash(CreationFlag flag)3588 MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3589   Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3590   if (stored_value->IsSmi()) return stored_value;
3591 
3592   // Do not generate permanent identity hash code if not requested.
3593   if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3594 
3595   Smi* hash = GenerateIdentityHash();
3596   MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3597                                           hash);
3598   if (result->IsFailure()) return result;
3599   if (result->ToObjectUnchecked()->IsUndefined()) {
3600     // Trying to get hash of detached proxy.
3601     return Smi::FromInt(0);
3602   }
3603   return hash;
3604 }
3605 
3606 
GetIdentityHash(CreationFlag flag)3607 MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3608   Object* hash = this->hash();
3609   if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3610     hash = GenerateIdentityHash();
3611     set_hash(hash);
3612   }
3613   return hash;
3614 }
3615 
3616 
GetHiddenProperty(String * key)3617 Object* JSObject::GetHiddenProperty(String* key) {
3618   if (IsJSGlobalProxy()) {
3619     // For a proxy, use the prototype as target object.
3620     Object* proxy_parent = GetPrototype();
3621     // If the proxy is detached, return undefined.
3622     if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3623     ASSERT(proxy_parent->IsJSGlobalObject());
3624     return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3625   }
3626   ASSERT(!IsJSGlobalProxy());
3627   MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3628   ASSERT(!hidden_lookup->IsFailure());  // No failure when passing false as arg.
3629   if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3630     return GetHeap()->undefined_value();
3631   }
3632   StringDictionary* dictionary =
3633       StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3634   int entry = dictionary->FindEntry(key);
3635   if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3636   return dictionary->ValueAt(entry);
3637 }
3638 
3639 
SetHiddenProperty(Handle<JSObject> obj,Handle<String> key,Handle<Object> value)3640 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3641                                  Handle<String> key,
3642                                  Handle<Object> value) {
3643   CALL_HEAP_FUNCTION(obj->GetIsolate(),
3644                      obj->SetHiddenProperty(*key, *value),
3645                      Object);
3646 }
3647 
3648 
SetHiddenProperty(String * key,Object * value)3649 MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3650   if (IsJSGlobalProxy()) {
3651     // For a proxy, use the prototype as target object.
3652     Object* proxy_parent = GetPrototype();
3653     // If the proxy is detached, return undefined.
3654     if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3655     ASSERT(proxy_parent->IsJSGlobalObject());
3656     return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3657   }
3658   ASSERT(!IsJSGlobalProxy());
3659   MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3660   StringDictionary* dictionary;
3661   if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3662 
3663   // If it was found, check if the key is already in the dictionary.
3664   int entry = dictionary->FindEntry(key);
3665   if (entry != StringDictionary::kNotFound) {
3666     // If key was found, just update the value.
3667     dictionary->ValueAtPut(entry, value);
3668     return this;
3669   }
3670   // Key was not already in the dictionary, so add the entry.
3671   MaybeObject* insert_result = dictionary->Add(key,
3672                                                value,
3673                                                PropertyDetails(NONE, NORMAL));
3674   StringDictionary* new_dict;
3675   if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3676   if (new_dict != dictionary) {
3677     // If adding the key expanded the dictionary (i.e., Add returned a new
3678     // dictionary), store it back to the object.
3679     MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3680     if (store_result->IsFailure()) return store_result;
3681   }
3682   // Return this to mark success.
3683   return this;
3684 }
3685 
3686 
DeleteHiddenProperty(String * key)3687 void JSObject::DeleteHiddenProperty(String* key) {
3688   if (IsJSGlobalProxy()) {
3689     // For a proxy, use the prototype as target object.
3690     Object* proxy_parent = GetPrototype();
3691     // If the proxy is detached, return immediately.
3692     if (proxy_parent->IsNull()) return;
3693     ASSERT(proxy_parent->IsJSGlobalObject());
3694     JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3695     return;
3696   }
3697   MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3698   ASSERT(!hidden_lookup->IsFailure());  // No failure when passing false as arg.
3699   if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3700   StringDictionary* dictionary =
3701       StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3702   int entry = dictionary->FindEntry(key);
3703   if (entry == StringDictionary::kNotFound) {
3704     // Key wasn't in dictionary. Deletion is a success.
3705     return;
3706   }
3707   // Key was in the dictionary. Remove it.
3708   dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3709 }
3710 
3711 
HasHiddenProperties()3712 bool JSObject::HasHiddenProperties() {
3713   return GetPropertyAttributePostInterceptor(this,
3714                                              GetHeap()->hidden_symbol(),
3715                                              false) != ABSENT;
3716 }
3717 
3718 
GetHiddenPropertiesDictionary(bool create_if_absent)3719 MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3720   ASSERT(!IsJSGlobalProxy());
3721   if (HasFastProperties()) {
3722     // If the object has fast properties, check whether the first slot
3723     // in the descriptor array matches the hidden symbol. Since the
3724     // hidden symbols hash code is zero (and no other string has hash
3725     // code zero) it will always occupy the first entry if present.
3726     DescriptorArray* descriptors = this->map()->instance_descriptors();
3727     if ((descriptors->number_of_descriptors() > 0) &&
3728         (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3729       if (descriptors->GetType(0) == FIELD) {
3730         Object* hidden_store =
3731             this->FastPropertyAt(descriptors->GetFieldIndex(0));
3732         return StringDictionary::cast(hidden_store);
3733       } else {
3734         ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3735                descriptors->GetType(0) == MAP_TRANSITION);
3736       }
3737     }
3738   } else {
3739     PropertyAttributes attributes;
3740     // You can't install a getter on a property indexed by the hidden symbol,
3741     // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3742     // object.
3743     Object* lookup =
3744         GetLocalPropertyPostInterceptor(this,
3745                                         GetHeap()->hidden_symbol(),
3746                                         &attributes)->ToObjectUnchecked();
3747     if (!lookup->IsUndefined()) {
3748       return StringDictionary::cast(lookup);
3749     }
3750   }
3751   if (!create_if_absent) return GetHeap()->undefined_value();
3752   const int kInitialSize = 5;
3753   MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3754   StringDictionary* dictionary;
3755   if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3756   MaybeObject* store_result =
3757       SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3758                                  dictionary,
3759                                  DONT_ENUM,
3760                                  kNonStrictMode);
3761   if (store_result->IsFailure()) return store_result;
3762   return dictionary;
3763 }
3764 
3765 
SetHiddenPropertiesDictionary(StringDictionary * dictionary)3766 MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3767     StringDictionary* dictionary) {
3768   ASSERT(!IsJSGlobalProxy());
3769   ASSERT(HasHiddenProperties());
3770   if (HasFastProperties()) {
3771     // If the object has fast properties, check whether the first slot
3772     // in the descriptor array matches the hidden symbol. Since the
3773     // hidden symbols hash code is zero (and no other string has hash
3774     // code zero) it will always occupy the first entry if present.
3775     DescriptorArray* descriptors = this->map()->instance_descriptors();
3776     if ((descriptors->number_of_descriptors() > 0) &&
3777         (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3778       if (descriptors->GetType(0) == FIELD) {
3779         this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3780         return this;
3781       } else {
3782         ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3783                descriptors->GetType(0) == MAP_TRANSITION);
3784       }
3785     }
3786   }
3787   MaybeObject* store_result =
3788       SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3789                                  dictionary,
3790                                  DONT_ENUM,
3791                                  kNonStrictMode);
3792   if (store_result->IsFailure()) return store_result;
3793   return this;
3794 }
3795 
3796 
DeletePropertyPostInterceptor(String * name,DeleteMode mode)3797 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3798                                                      DeleteMode mode) {
3799   // Check local property, ignore interceptor.
3800   LookupResult result(GetIsolate());
3801   LocalLookupRealNamedProperty(name, &result);
3802   if (!result.IsProperty()) return GetHeap()->true_value();
3803 
3804   // Normalize object if needed.
3805   Object* obj;
3806   { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3807     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3808   }
3809 
3810   return DeleteNormalizedProperty(name, mode);
3811 }
3812 
3813 
DeletePropertyWithInterceptor(String * name)3814 MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
3815   Isolate* isolate = GetIsolate();
3816   HandleScope scope(isolate);
3817   Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3818   Handle<String> name_handle(name);
3819   Handle<JSObject> this_handle(this);
3820   if (!interceptor->deleter()->IsUndefined()) {
3821     v8::NamedPropertyDeleter deleter =
3822         v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
3823     LOG(isolate,
3824         ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3825     CustomArguments args(isolate, interceptor->data(), this, this);
3826     v8::AccessorInfo info(args.end());
3827     v8::Handle<v8::Boolean> result;
3828     {
3829       // Leaving JavaScript.
3830       VMState state(isolate, EXTERNAL);
3831       result = deleter(v8::Utils::ToLocal(name_handle), info);
3832     }
3833     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3834     if (!result.IsEmpty()) {
3835       ASSERT(result->IsBoolean());
3836       return *v8::Utils::OpenHandle(*result);
3837     }
3838   }
3839   MaybeObject* raw_result =
3840       this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
3841   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3842   return raw_result;
3843 }
3844 
3845 
DeleteElementWithInterceptor(uint32_t index)3846 MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
3847   Isolate* isolate = GetIsolate();
3848   Heap* heap = isolate->heap();
3849   // Make sure that the top context does not change when doing
3850   // callbacks or interceptor calls.
3851   AssertNoContextChange ncc;
3852   HandleScope scope(isolate);
3853   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
3854   if (interceptor->deleter()->IsUndefined()) return heap->false_value();
3855   v8::IndexedPropertyDeleter deleter =
3856       v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3857   Handle<JSObject> this_handle(this);
3858   LOG(isolate,
3859       ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3860   CustomArguments args(isolate, interceptor->data(), this, this);
3861   v8::AccessorInfo info(args.end());
3862   v8::Handle<v8::Boolean> result;
3863   {
3864     // Leaving JavaScript.
3865     VMState state(isolate, EXTERNAL);
3866     result = deleter(index, info);
3867   }
3868   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3869   if (!result.IsEmpty()) {
3870     ASSERT(result->IsBoolean());
3871     return *v8::Utils::OpenHandle(*result);
3872   }
3873   MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3874       *this_handle,
3875       index,
3876       NORMAL_DELETION);
3877   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3878   return raw_result;
3879 }
3880 
3881 
DeleteElement(Handle<JSObject> obj,uint32_t index)3882 Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3883                                        uint32_t index) {
3884   CALL_HEAP_FUNCTION(obj->GetIsolate(),
3885                      obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3886                      Object);
3887 }
3888 
3889 
DeleteElement(uint32_t index,DeleteMode mode)3890 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
3891   Isolate* isolate = GetIsolate();
3892   // Check access rights if needed.
3893   if (IsAccessCheckNeeded() &&
3894       !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3895     isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3896     return isolate->heap()->false_value();
3897   }
3898 
3899   if (IsJSGlobalProxy()) {
3900     Object* proto = GetPrototype();
3901     if (proto->IsNull()) return isolate->heap()->false_value();
3902     ASSERT(proto->IsJSGlobalObject());
3903     return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3904   }
3905 
3906   if (HasIndexedInterceptor()) {
3907     // Skip interceptor if forcing deletion.
3908     if (mode != FORCE_DELETION) {
3909       return DeleteElementWithInterceptor(index);
3910     }
3911     mode = JSReceiver::FORCE_DELETION;
3912   }
3913 
3914   return GetElementsAccessor()->Delete(this, index, mode);
3915 }
3916 
3917 
DeleteProperty(Handle<JSObject> obj,Handle<String> prop)3918 Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3919                               Handle<String> prop) {
3920   CALL_HEAP_FUNCTION(obj->GetIsolate(),
3921                      obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3922                      Object);
3923 }
3924 
3925 
DeleteProperty(String * name,DeleteMode mode)3926 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
3927   Isolate* isolate = GetIsolate();
3928   // ECMA-262, 3rd, 8.6.2.5
3929   ASSERT(name->IsString());
3930 
3931   // Check access rights if needed.
3932   if (IsAccessCheckNeeded() &&
3933       !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3934     isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3935     return isolate->heap()->false_value();
3936   }
3937 
3938   if (IsJSGlobalProxy()) {
3939     Object* proto = GetPrototype();
3940     if (proto->IsNull()) return isolate->heap()->false_value();
3941     ASSERT(proto->IsJSGlobalObject());
3942     return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3943   }
3944 
3945   uint32_t index = 0;
3946   if (name->AsArrayIndex(&index)) {
3947     return DeleteElement(index, mode);
3948   } else {
3949     LookupResult result(isolate);
3950     LocalLookup(name, &result);
3951     if (!result.IsProperty()) return isolate->heap()->true_value();
3952     // Ignore attributes if forcing a deletion.
3953     if (result.IsDontDelete() && mode != FORCE_DELETION) {
3954       if (mode == STRICT_DELETION) {
3955         // Deleting a non-configurable property in strict mode.
3956         HandleScope scope(isolate);
3957         Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
3958         return isolate->Throw(*isolate->factory()->NewTypeError(
3959             "strict_delete_property", HandleVector(args, 2)));
3960       }
3961       return isolate->heap()->false_value();
3962     }
3963     // Check for interceptor.
3964     if (result.type() == INTERCEPTOR) {
3965       // Skip interceptor if forcing a deletion.
3966       if (mode == FORCE_DELETION) {
3967         return DeletePropertyPostInterceptor(name, mode);
3968       }
3969       return DeletePropertyWithInterceptor(name);
3970     }
3971     // Normalize object if needed.
3972     Object* obj;
3973     { MaybeObject* maybe_obj =
3974           NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3975       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3976     }
3977     // Make sure the properties are normalized before removing the entry.
3978     return DeleteNormalizedProperty(name, mode);
3979   }
3980 }
3981 
3982 
DeleteElement(uint32_t index,DeleteMode mode)3983 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
3984   if (IsJSProxy()) {
3985     return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
3986   }
3987   return JSObject::cast(this)->DeleteElement(index, mode);
3988 }
3989 
3990 
DeleteProperty(String * name,DeleteMode mode)3991 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3992   if (IsJSProxy()) {
3993     return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3994   }
3995   return JSObject::cast(this)->DeleteProperty(name, mode);
3996 }
3997 
3998 
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)3999 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
4000                                             ElementsKind kind,
4001                                             Object* object) {
4002   ASSERT(kind == FAST_ELEMENTS ||
4003          kind == DICTIONARY_ELEMENTS);
4004   if (kind == FAST_ELEMENTS) {
4005     int length = IsJSArray()
4006         ? Smi::cast(JSArray::cast(this)->length())->value()
4007         : elements->length();
4008     for (int i = 0; i < length; ++i) {
4009       Object* element = elements->get(i);
4010       if (!element->IsTheHole() && element == object) return true;
4011     }
4012   } else {
4013     Object* key =
4014         SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
4015     if (!key->IsUndefined()) return true;
4016   }
4017   return false;
4018 }
4019 
4020 
4021 // Check whether this object references another object.
ReferencesObject(Object * obj)4022 bool JSObject::ReferencesObject(Object* obj) {
4023   Map* map_of_this = map();
4024   Heap* heap = GetHeap();
4025   AssertNoAllocation no_alloc;
4026 
4027   // Is the object the constructor for this object?
4028   if (map_of_this->constructor() == obj) {
4029     return true;
4030   }
4031 
4032   // Is the object the prototype for this object?
4033   if (map_of_this->prototype() == obj) {
4034     return true;
4035   }
4036 
4037   // Check if the object is among the named properties.
4038   Object* key = SlowReverseLookup(obj);
4039   if (!key->IsUndefined()) {
4040     return true;
4041   }
4042 
4043   // Check if the object is among the indexed properties.
4044   ElementsKind kind = GetElementsKind();
4045   switch (kind) {
4046     case EXTERNAL_PIXEL_ELEMENTS:
4047     case EXTERNAL_BYTE_ELEMENTS:
4048     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4049     case EXTERNAL_SHORT_ELEMENTS:
4050     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4051     case EXTERNAL_INT_ELEMENTS:
4052     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4053     case EXTERNAL_FLOAT_ELEMENTS:
4054     case EXTERNAL_DOUBLE_ELEMENTS:
4055     case FAST_DOUBLE_ELEMENTS:
4056       // Raw pixels and external arrays do not reference other
4057       // objects.
4058       break;
4059     case FAST_SMI_ONLY_ELEMENTS:
4060       break;
4061     case FAST_ELEMENTS:
4062     case DICTIONARY_ELEMENTS: {
4063       FixedArray* elements = FixedArray::cast(this->elements());
4064       if (ReferencesObjectFromElements(elements, kind, obj)) return true;
4065       break;
4066     }
4067     case NON_STRICT_ARGUMENTS_ELEMENTS: {
4068       FixedArray* parameter_map = FixedArray::cast(elements());
4069       // Check the mapped parameters.
4070       int length = parameter_map->length();
4071       for (int i = 2; i < length; ++i) {
4072         Object* value = parameter_map->get(i);
4073         if (!value->IsTheHole() && value == obj) return true;
4074       }
4075       // Check the arguments.
4076       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4077       kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4078       if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
4079       break;
4080     }
4081   }
4082 
4083   // For functions check the context.
4084   if (IsJSFunction()) {
4085     // Get the constructor function for arguments array.
4086     JSObject* arguments_boilerplate =
4087         heap->isolate()->context()->global_context()->
4088             arguments_boilerplate();
4089     JSFunction* arguments_function =
4090         JSFunction::cast(arguments_boilerplate->map()->constructor());
4091 
4092     // Get the context and don't check if it is the global context.
4093     JSFunction* f = JSFunction::cast(this);
4094     Context* context = f->context();
4095     if (context->IsGlobalContext()) {
4096       return false;
4097     }
4098 
4099     // Check the non-special context slots.
4100     for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4101       // Only check JS objects.
4102       if (context->get(i)->IsJSObject()) {
4103         JSObject* ctxobj = JSObject::cast(context->get(i));
4104         // If it is an arguments array check the content.
4105         if (ctxobj->map()->constructor() == arguments_function) {
4106           if (ctxobj->ReferencesObject(obj)) {
4107             return true;
4108           }
4109         } else if (ctxobj == obj) {
4110           return true;
4111         }
4112       }
4113     }
4114 
4115     // Check the context extension (if any) if it can have references.
4116     if (context->has_extension() && !context->IsCatchContext()) {
4117       return JSObject::cast(context->extension())->ReferencesObject(obj);
4118     }
4119   }
4120 
4121   // No references to object.
4122   return false;
4123 }
4124 
4125 
PreventExtensions(Handle<JSObject> object)4126 Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
4127   CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
4128 }
4129 
4130 
PreventExtensions()4131 MaybeObject* JSObject::PreventExtensions() {
4132   Isolate* isolate = GetIsolate();
4133   if (IsAccessCheckNeeded() &&
4134       !isolate->MayNamedAccess(this,
4135                                isolate->heap()->undefined_value(),
4136                                v8::ACCESS_KEYS)) {
4137     isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4138     return isolate->heap()->false_value();
4139   }
4140 
4141   if (IsJSGlobalProxy()) {
4142     Object* proto = GetPrototype();
4143     if (proto->IsNull()) return this;
4144     ASSERT(proto->IsJSGlobalObject());
4145     return JSObject::cast(proto)->PreventExtensions();
4146   }
4147 
4148   // It's not possible to seal objects with external array elements
4149   if (HasExternalArrayElements()) {
4150     HandleScope scope(isolate);
4151     Handle<Object> object(this);
4152     Handle<Object> error  =
4153         isolate->factory()->NewTypeError(
4154             "cant_prevent_ext_external_array_elements",
4155             HandleVector(&object, 1));
4156     return isolate->Throw(*error);
4157   }
4158 
4159   // If there are fast elements we normalize.
4160   SeededNumberDictionary* dictionary = NULL;
4161   { MaybeObject* maybe = NormalizeElements();
4162     if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
4163   }
4164   ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4165   // Make sure that we never go back to fast case.
4166   dictionary->set_requires_slow_elements();
4167 
4168   // Do a map transition, other objects with this map may still
4169   // be extensible.
4170   Map* new_map;
4171   { MaybeObject* maybe = map()->CopyDropTransitions();
4172     if (!maybe->To<Map>(&new_map)) return maybe;
4173   }
4174   new_map->set_is_extensible(false);
4175   set_map(new_map);
4176   ASSERT(!map()->is_extensible());
4177   return new_map;
4178 }
4179 
4180 
4181 // Tests for the fast common case for property enumeration:
4182 // - This object and all prototypes has an enum cache (which means that
4183 //   it is no proxy, has no interceptors and needs no access checks).
4184 // - This object has no elements.
4185 // - No prototype has enumerable properties/elements.
IsSimpleEnum()4186 bool JSReceiver::IsSimpleEnum() {
4187   Heap* heap = GetHeap();
4188   for (Object* o = this;
4189        o != heap->null_value();
4190        o = JSObject::cast(o)->GetPrototype()) {
4191     if (!o->IsJSObject()) return false;
4192     JSObject* curr = JSObject::cast(o);
4193     if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
4194     ASSERT(!curr->HasNamedInterceptor());
4195     ASSERT(!curr->HasIndexedInterceptor());
4196     ASSERT(!curr->IsAccessCheckNeeded());
4197     if (curr->NumberOfEnumElements() > 0) return false;
4198     if (curr != this) {
4199       FixedArray* curr_fixed_array =
4200           FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
4201       if (curr_fixed_array->length() > 0) return false;
4202     }
4203   }
4204   return true;
4205 }
4206 
4207 
NumberOfDescribedProperties(PropertyAttributes filter)4208 int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
4209   int result = 0;
4210   DescriptorArray* descs = instance_descriptors();
4211   for (int i = 0; i < descs->number_of_descriptors(); i++) {
4212     PropertyDetails details(descs->GetDetails(i));
4213     if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
4214       result++;
4215     }
4216   }
4217   return result;
4218 }
4219 
4220 
PropertyIndexFor(String * name)4221 int Map::PropertyIndexFor(String* name) {
4222   DescriptorArray* descs = instance_descriptors();
4223   for (int i = 0; i < descs->number_of_descriptors(); i++) {
4224     if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4225       return descs->GetFieldIndex(i);
4226     }
4227   }
4228   return -1;
4229 }
4230 
4231 
NextFreePropertyIndex()4232 int Map::NextFreePropertyIndex() {
4233   int max_index = -1;
4234   DescriptorArray* descs = instance_descriptors();
4235   for (int i = 0; i < descs->number_of_descriptors(); i++) {
4236     if (descs->GetType(i) == FIELD) {
4237       int current_index = descs->GetFieldIndex(i);
4238       if (current_index > max_index) max_index = current_index;
4239     }
4240   }
4241   return max_index + 1;
4242 }
4243 
4244 
FindAccessor(String * name)4245 AccessorDescriptor* Map::FindAccessor(String* name) {
4246   DescriptorArray* descs = instance_descriptors();
4247   for (int i = 0; i < descs->number_of_descriptors(); i++) {
4248     if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4249       return descs->GetCallbacks(i);
4250     }
4251   }
4252   return NULL;
4253 }
4254 
4255 
LocalLookup(String * name,LookupResult * result)4256 void JSReceiver::LocalLookup(String* name, LookupResult* result) {
4257   ASSERT(name->IsString());
4258 
4259   Heap* heap = GetHeap();
4260 
4261   if (IsJSGlobalProxy()) {
4262     Object* proto = GetPrototype();
4263     if (proto->IsNull()) return result->NotFound();
4264     ASSERT(proto->IsJSGlobalObject());
4265     return JSReceiver::cast(proto)->LocalLookup(name, result);
4266   }
4267 
4268   if (IsJSProxy()) {
4269     result->HandlerResult(JSProxy::cast(this));
4270     return;
4271   }
4272 
4273   // Do not use inline caching if the object is a non-global object
4274   // that requires access checks.
4275   if (IsAccessCheckNeeded()) {
4276     result->DisallowCaching();
4277   }
4278 
4279   JSObject* js_object = JSObject::cast(this);
4280 
4281   // Check __proto__ before interceptor.
4282   if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
4283     result->ConstantResult(js_object);
4284     return;
4285   }
4286 
4287   // Check for lookup interceptor except when bootstrapping.
4288   if (js_object->HasNamedInterceptor() &&
4289       !heap->isolate()->bootstrapper()->IsActive()) {
4290     result->InterceptorResult(js_object);
4291     return;
4292   }
4293 
4294   js_object->LocalLookupRealNamedProperty(name, result);
4295 }
4296 
4297 
Lookup(String * name,LookupResult * result)4298 void JSReceiver::Lookup(String* name, LookupResult* result) {
4299   // Ecma-262 3rd 8.6.2.4
4300   Heap* heap = GetHeap();
4301   for (Object* current = this;
4302        current != heap->null_value();
4303        current = JSObject::cast(current)->GetPrototype()) {
4304     JSReceiver::cast(current)->LocalLookup(name, result);
4305     if (result->IsProperty()) return;
4306   }
4307   result->NotFound();
4308 }
4309 
4310 
4311 // Search object and it's prototype chain for callback properties.
LookupCallback(String * name,LookupResult * result)4312 void JSObject::LookupCallback(String* name, LookupResult* result) {
4313   Heap* heap = GetHeap();
4314   for (Object* current = this;
4315        current != heap->null_value() && current->IsJSObject();
4316        current = JSObject::cast(current)->GetPrototype()) {
4317     JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
4318     if (result->IsFound() && result->type() == CALLBACKS) return;
4319   }
4320   result->NotFound();
4321 }
4322 
4323 
4324 // Try to update an accessor in an elements dictionary. Return true if the
4325 // update succeeded, and false otherwise.
UpdateGetterSetterInDictionary(SeededNumberDictionary * dictionary,uint32_t index,Object * getter,Object * setter,PropertyAttributes attributes)4326 static bool UpdateGetterSetterInDictionary(
4327     SeededNumberDictionary* dictionary,
4328     uint32_t index,
4329     Object* getter,
4330     Object* setter,
4331     PropertyAttributes attributes) {
4332   int entry = dictionary->FindEntry(index);
4333   if (entry != SeededNumberDictionary::kNotFound) {
4334     Object* result = dictionary->ValueAt(entry);
4335     PropertyDetails details = dictionary->DetailsAt(entry);
4336     if (details.type() == CALLBACKS && result->IsAccessorPair()) {
4337       ASSERT(!details.IsDontDelete());
4338       if (details.attributes() != attributes) {
4339         dictionary->DetailsAtPut(entry,
4340                                  PropertyDetails(attributes, CALLBACKS, index));
4341       }
4342       AccessorPair::cast(result)->SetComponents(getter, setter);
4343       return true;
4344     }
4345   }
4346   return false;
4347 }
4348 
4349 
DefineElementAccessor(uint32_t index,Object * getter,Object * setter,PropertyAttributes attributes)4350 MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
4351                                              Object* getter,
4352                                              Object* setter,
4353                                              PropertyAttributes attributes) {
4354   switch (GetElementsKind()) {
4355     case FAST_SMI_ONLY_ELEMENTS:
4356     case FAST_ELEMENTS:
4357     case FAST_DOUBLE_ELEMENTS:
4358       break;
4359     case EXTERNAL_PIXEL_ELEMENTS:
4360     case EXTERNAL_BYTE_ELEMENTS:
4361     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4362     case EXTERNAL_SHORT_ELEMENTS:
4363     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4364     case EXTERNAL_INT_ELEMENTS:
4365     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4366     case EXTERNAL_FLOAT_ELEMENTS:
4367     case EXTERNAL_DOUBLE_ELEMENTS:
4368       // Ignore getters and setters on pixel and external array elements.
4369       return GetHeap()->undefined_value();
4370     case DICTIONARY_ELEMENTS:
4371       if (UpdateGetterSetterInDictionary(element_dictionary(),
4372                                          index,
4373                                          getter,
4374                                          setter,
4375                                          attributes)) {
4376         return GetHeap()->undefined_value();
4377       }
4378       break;
4379     case NON_STRICT_ARGUMENTS_ELEMENTS: {
4380       // Ascertain whether we have read-only properties or an existing
4381       // getter/setter pair in an arguments elements dictionary backing
4382       // store.
4383       FixedArray* parameter_map = FixedArray::cast(elements());
4384       uint32_t length = parameter_map->length();
4385       Object* probe =
4386           index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4387       if (probe == NULL || probe->IsTheHole()) {
4388         FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4389         if (arguments->IsDictionary()) {
4390           SeededNumberDictionary* dictionary =
4391               SeededNumberDictionary::cast(arguments);
4392           if (UpdateGetterSetterInDictionary(dictionary,
4393                                              index,
4394                                              getter,
4395                                              setter,
4396                                              attributes)) {
4397             return GetHeap()->undefined_value();
4398           }
4399         }
4400       }
4401       break;
4402     }
4403   }
4404 
4405   AccessorPair* accessors;
4406   { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4407     if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4408   }
4409   accessors->SetComponents(getter, setter);
4410 
4411   return SetElementCallback(index, accessors, attributes);
4412 }
4413 
4414 
DefinePropertyAccessor(String * name,Object * getter,Object * setter,PropertyAttributes attributes)4415 MaybeObject* JSObject::DefinePropertyAccessor(String* name,
4416                                               Object* getter,
4417                                               Object* setter,
4418                                               PropertyAttributes attributes) {
4419   // Lookup the name.
4420   LookupResult result(GetHeap()->isolate());
4421   LocalLookupRealNamedProperty(name, &result);
4422   if (result.IsFound()) {
4423     if (result.type() == CALLBACKS) {
4424       ASSERT(!result.IsDontDelete());
4425       Object* obj = result.GetCallbackObject();
4426       // Need to preserve old getters/setters.
4427       if (obj->IsAccessorPair()) {
4428         AccessorPair* copy;
4429         { MaybeObject* maybe_copy =
4430               AccessorPair::cast(obj)->CopyWithoutTransitions();
4431           if (!maybe_copy->To(&copy)) return maybe_copy;
4432         }
4433         copy->SetComponents(getter, setter);
4434         // Use set to update attributes.
4435         return SetPropertyCallback(name, copy, attributes);
4436       }
4437     }
4438   }
4439 
4440   AccessorPair* accessors;
4441   { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4442     if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4443   }
4444   accessors->SetComponents(getter, setter);
4445 
4446   return SetPropertyCallback(name, accessors, attributes);
4447 }
4448 
4449 
CanSetCallback(String * name)4450 bool JSObject::CanSetCallback(String* name) {
4451   ASSERT(!IsAccessCheckNeeded() ||
4452          GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
4453 
4454   // Check if there is an API defined callback object which prohibits
4455   // callback overwriting in this object or it's prototype chain.
4456   // This mechanism is needed for instance in a browser setting, where
4457   // certain accessors such as window.location should not be allowed
4458   // to be overwritten because allowing overwriting could potentially
4459   // cause security problems.
4460   LookupResult callback_result(GetIsolate());
4461   LookupCallback(name, &callback_result);
4462   if (callback_result.IsProperty()) {
4463     Object* obj = callback_result.GetCallbackObject();
4464     if (obj->IsAccessorInfo() &&
4465         AccessorInfo::cast(obj)->prohibits_overwriting()) {
4466       return false;
4467     }
4468   }
4469 
4470   return true;
4471 }
4472 
4473 
SetElementCallback(uint32_t index,Object * structure,PropertyAttributes attributes)4474 MaybeObject* JSObject::SetElementCallback(uint32_t index,
4475                                           Object* structure,
4476                                           PropertyAttributes attributes) {
4477   PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4478 
4479   // Normalize elements to make this operation simple.
4480   SeededNumberDictionary* dictionary;
4481   { MaybeObject* maybe_dictionary = NormalizeElements();
4482     if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
4483   }
4484   ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4485 
4486   // Update the dictionary with the new CALLBACKS property.
4487   { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
4488     if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
4489   }
4490 
4491   dictionary->set_requires_slow_elements();
4492   // Update the dictionary backing store on the object.
4493   if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4494     // Also delete any parameter alias.
4495     //
4496     // TODO(kmillikin): when deleting the last parameter alias we could
4497     // switch to a direct backing store without the parameter map.  This
4498     // would allow GC of the context.
4499     FixedArray* parameter_map = FixedArray::cast(elements());
4500     if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
4501       parameter_map->set(index + 2, GetHeap()->the_hole_value());
4502     }
4503     parameter_map->set(1, dictionary);
4504   } else {
4505     set_elements(dictionary);
4506   }
4507 
4508   return GetHeap()->undefined_value();
4509 }
4510 
4511 
SetPropertyCallback(String * name,Object * structure,PropertyAttributes attributes)4512 MaybeObject* JSObject::SetPropertyCallback(String* name,
4513                                            Object* structure,
4514                                            PropertyAttributes attributes) {
4515   // Normalize object to make this operation simple.
4516   { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4517     if (maybe_ok->IsFailure()) return maybe_ok;
4518   }
4519 
4520   // For the global object allocate a new map to invalidate the global inline
4521   // caches which have a global property cell reference directly in the code.
4522   if (IsGlobalObject()) {
4523     Map* new_map;
4524     { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
4525       if (!maybe_new_map->To(&new_map)) return maybe_new_map;
4526     }
4527     set_map(new_map);
4528     // When running crankshaft, changing the map is not enough. We
4529     // need to deoptimize all functions that rely on this global
4530     // object.
4531     Deoptimizer::DeoptimizeGlobalObject(this);
4532   }
4533 
4534   // Update the dictionary with the new CALLBACKS property.
4535   PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4536   { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details);
4537     if (maybe_ok->IsFailure()) return maybe_ok;
4538   }
4539 
4540   return GetHeap()->undefined_value();
4541 }
4542 
4543 
DefineAccessor(Handle<JSObject> object,Handle<String> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)4544 void JSObject::DefineAccessor(Handle<JSObject> object,
4545                               Handle<String> name,
4546                               Handle<Object> getter,
4547                               Handle<Object> setter,
4548                               PropertyAttributes attributes) {
4549   CALL_HEAP_FUNCTION_VOID(
4550       object->GetIsolate(),
4551       object->DefineAccessor(*name, *getter, *setter, attributes));
4552 }
4553 
DefineAccessor(String * name,Object * getter,Object * setter,PropertyAttributes attributes)4554 MaybeObject* JSObject::DefineAccessor(String* name,
4555                                       Object* getter,
4556                                       Object* setter,
4557                                       PropertyAttributes attributes) {
4558   Isolate* isolate = GetIsolate();
4559   // Check access rights if needed.
4560   if (IsAccessCheckNeeded() &&
4561       !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4562     isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4563     return isolate->heap()->undefined_value();
4564   }
4565 
4566   if (IsJSGlobalProxy()) {
4567     Object* proto = GetPrototype();
4568     if (proto->IsNull()) return this;
4569     ASSERT(proto->IsJSGlobalObject());
4570     return JSObject::cast(proto)->DefineAccessor(
4571         name, getter, setter, attributes);
4572   }
4573 
4574   // Make sure that the top context does not change when doing callbacks or
4575   // interceptor calls.
4576   AssertNoContextChange ncc;
4577 
4578   // Try to flatten before operating on the string.
4579   name->TryFlatten();
4580 
4581   if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4582 
4583   uint32_t index = 0;
4584   return name->AsArrayIndex(&index) ?
4585       DefineElementAccessor(index, getter, setter, attributes) :
4586       DefinePropertyAccessor(name, getter, setter, attributes);
4587 }
4588 
4589 
DefineAccessor(AccessorInfo * info)4590 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
4591   Isolate* isolate = GetIsolate();
4592   String* name = String::cast(info->name());
4593   // Check access rights if needed.
4594   if (IsAccessCheckNeeded() &&
4595       !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4596     isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4597     return isolate->heap()->undefined_value();
4598   }
4599 
4600   if (IsJSGlobalProxy()) {
4601     Object* proto = GetPrototype();
4602     if (proto->IsNull()) return this;
4603     ASSERT(proto->IsJSGlobalObject());
4604     return JSObject::cast(proto)->DefineAccessor(info);
4605   }
4606 
4607   // Make sure that the top context does not change when doing callbacks or
4608   // interceptor calls.
4609   AssertNoContextChange ncc;
4610 
4611   // Try to flatten before operating on the string.
4612   name->TryFlatten();
4613 
4614   if (!CanSetCallback(name)) {
4615     return isolate->heap()->undefined_value();
4616   }
4617 
4618   uint32_t index = 0;
4619   bool is_element = name->AsArrayIndex(&index);
4620 
4621   if (is_element) {
4622     if (IsJSArray()) return isolate->heap()->undefined_value();
4623 
4624     // Accessors overwrite previous callbacks (cf. with getters/setters).
4625     switch (GetElementsKind()) {
4626       case FAST_SMI_ONLY_ELEMENTS:
4627       case FAST_ELEMENTS:
4628       case FAST_DOUBLE_ELEMENTS:
4629         break;
4630       case EXTERNAL_PIXEL_ELEMENTS:
4631       case EXTERNAL_BYTE_ELEMENTS:
4632       case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4633       case EXTERNAL_SHORT_ELEMENTS:
4634       case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4635       case EXTERNAL_INT_ELEMENTS:
4636       case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4637       case EXTERNAL_FLOAT_ELEMENTS:
4638       case EXTERNAL_DOUBLE_ELEMENTS:
4639         // Ignore getters and setters on pixel and external array
4640         // elements.
4641         return isolate->heap()->undefined_value();
4642       case DICTIONARY_ELEMENTS:
4643         break;
4644       case NON_STRICT_ARGUMENTS_ELEMENTS:
4645         UNIMPLEMENTED();
4646         break;
4647     }
4648 
4649     { MaybeObject* maybe_ok =
4650           SetElementCallback(index, info, info->property_attributes());
4651       if (maybe_ok->IsFailure()) return maybe_ok;
4652     }
4653   } else {
4654     // Lookup the name.
4655     LookupResult result(isolate);
4656     LocalLookup(name, &result);
4657     // ES5 forbids turning a property into an accessor if it's not
4658     // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4659     if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
4660       return isolate->heap()->undefined_value();
4661     }
4662     { MaybeObject* maybe_ok =
4663           SetPropertyCallback(name, info, info->property_attributes());
4664       if (maybe_ok->IsFailure()) return maybe_ok;
4665     }
4666   }
4667 
4668   return this;
4669 }
4670 
4671 
LookupAccessor(String * name,AccessorComponent component)4672 Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
4673   Heap* heap = GetHeap();
4674 
4675   // Make sure that the top context does not change when doing callbacks or
4676   // interceptor calls.
4677   AssertNoContextChange ncc;
4678 
4679   // Check access rights if needed.
4680   if (IsAccessCheckNeeded() &&
4681       !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4682     heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4683     return heap->undefined_value();
4684   }
4685 
4686   // Make the lookup and include prototypes.
4687   uint32_t index = 0;
4688   if (name->AsArrayIndex(&index)) {
4689     for (Object* obj = this;
4690          obj != heap->null_value();
4691          obj = JSObject::cast(obj)->GetPrototype()) {
4692       JSObject* js_object = JSObject::cast(obj);
4693       if (js_object->HasDictionaryElements()) {
4694         SeededNumberDictionary* dictionary = js_object->element_dictionary();
4695         int entry = dictionary->FindEntry(index);
4696         if (entry != SeededNumberDictionary::kNotFound) {
4697           Object* element = dictionary->ValueAt(entry);
4698           if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
4699               element->IsAccessorPair()) {
4700             return AccessorPair::cast(element)->GetComponent(component);
4701           }
4702         }
4703       }
4704     }
4705   } else {
4706     for (Object* obj = this;
4707          obj != heap->null_value();
4708          obj = JSObject::cast(obj)->GetPrototype()) {
4709       LookupResult result(heap->isolate());
4710       JSObject::cast(obj)->LocalLookup(name, &result);
4711       if (result.IsProperty()) {
4712         if (result.IsReadOnly()) return heap->undefined_value();
4713         if (result.type() == CALLBACKS) {
4714           Object* obj = result.GetCallbackObject();
4715           if (obj->IsAccessorPair()) {
4716             return AccessorPair::cast(obj)->GetComponent(component);
4717           }
4718         }
4719       }
4720     }
4721   }
4722   return heap->undefined_value();
4723 }
4724 
4725 
SlowReverseLookup(Object * value)4726 Object* JSObject::SlowReverseLookup(Object* value) {
4727   if (HasFastProperties()) {
4728     DescriptorArray* descs = map()->instance_descriptors();
4729     for (int i = 0; i < descs->number_of_descriptors(); i++) {
4730       if (descs->GetType(i) == FIELD) {
4731         if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4732           return descs->GetKey(i);
4733         }
4734       } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4735         if (descs->GetConstantFunction(i) == value) {
4736           return descs->GetKey(i);
4737         }
4738       }
4739     }
4740     return GetHeap()->undefined_value();
4741   } else {
4742     return property_dictionary()->SlowReverseLookup(value);
4743   }
4744 }
4745 
4746 
CopyDropDescriptors()4747 MaybeObject* Map::CopyDropDescriptors() {
4748   Heap* heap = GetHeap();
4749   Object* result;
4750   { MaybeObject* maybe_result =
4751         heap->AllocateMap(instance_type(), instance_size());
4752     if (!maybe_result->ToObject(&result)) return maybe_result;
4753   }
4754   Map::cast(result)->set_prototype(prototype());
4755   Map::cast(result)->set_constructor(constructor());
4756   // Don't copy descriptors, so map transitions always remain a forest.
4757   // If we retained the same descriptors we would have two maps
4758   // pointing to the same transition which is bad because the garbage
4759   // collector relies on being able to reverse pointers from transitions
4760   // to maps.  If properties need to be retained use CopyDropTransitions.
4761   Map::cast(result)->clear_instance_descriptors();
4762   // Please note instance_type and instance_size are set when allocated.
4763   Map::cast(result)->set_inobject_properties(inobject_properties());
4764   Map::cast(result)->set_unused_property_fields(unused_property_fields());
4765 
4766   // If the map has pre-allocated properties always start out with a descriptor
4767   // array describing these properties.
4768   if (pre_allocated_property_fields() > 0) {
4769     ASSERT(constructor()->IsJSFunction());
4770     JSFunction* ctor = JSFunction::cast(constructor());
4771     Object* descriptors;
4772     { MaybeObject* maybe_descriptors =
4773           ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4774       if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4775     }
4776     Map::cast(result)->set_instance_descriptors(
4777         DescriptorArray::cast(descriptors));
4778     Map::cast(result)->set_pre_allocated_property_fields(
4779         pre_allocated_property_fields());
4780   }
4781   Map::cast(result)->set_bit_field(bit_field());
4782   Map::cast(result)->set_bit_field2(bit_field2());
4783   Map::cast(result)->set_bit_field3(bit_field3());
4784   Map::cast(result)->set_is_shared(false);
4785   Map::cast(result)->ClearCodeCache(heap);
4786   return result;
4787 }
4788 
4789 
CopyNormalized(PropertyNormalizationMode mode,NormalizedMapSharingMode sharing)4790 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4791                                  NormalizedMapSharingMode sharing) {
4792   int new_instance_size = instance_size();
4793   if (mode == CLEAR_INOBJECT_PROPERTIES) {
4794     new_instance_size -= inobject_properties() * kPointerSize;
4795   }
4796 
4797   Object* result;
4798   { MaybeObject* maybe_result =
4799         GetHeap()->AllocateMap(instance_type(), new_instance_size);
4800     if (!maybe_result->ToObject(&result)) return maybe_result;
4801   }
4802 
4803   if (mode != CLEAR_INOBJECT_PROPERTIES) {
4804     Map::cast(result)->set_inobject_properties(inobject_properties());
4805   }
4806 
4807   Map::cast(result)->set_prototype(prototype());
4808   Map::cast(result)->set_constructor(constructor());
4809 
4810   Map::cast(result)->set_bit_field(bit_field());
4811   Map::cast(result)->set_bit_field2(bit_field2());
4812   Map::cast(result)->set_bit_field3(bit_field3());
4813 
4814   Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4815 
4816 #ifdef DEBUG
4817   if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
4818     Map::cast(result)->SharedMapVerify();
4819   }
4820 #endif
4821 
4822   return result;
4823 }
4824 
4825 
CopyDropTransitions()4826 MaybeObject* Map::CopyDropTransitions() {
4827   Object* new_map;
4828   { MaybeObject* maybe_new_map = CopyDropDescriptors();
4829     if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4830   }
4831   Object* descriptors;
4832   { MaybeObject* maybe_descriptors =
4833         instance_descriptors()->RemoveTransitions();
4834     if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4835   }
4836   cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
4837   return new_map;
4838 }
4839 
UpdateCodeCache(Handle<Map> map,Handle<String> name,Handle<Code> code)4840 void Map::UpdateCodeCache(Handle<Map> map,
4841                           Handle<String> name,
4842                           Handle<Code> code) {
4843   Isolate* isolate = map->GetIsolate();
4844   CALL_HEAP_FUNCTION_VOID(isolate,
4845                           map->UpdateCodeCache(*name, *code));
4846 }
4847 
UpdateCodeCache(String * name,Code * code)4848 MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
4849   // Allocate the code cache if not present.
4850   if (code_cache()->IsFixedArray()) {
4851     Object* result;
4852     { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
4853       if (!maybe_result->ToObject(&result)) return maybe_result;
4854     }
4855     set_code_cache(result);
4856   }
4857 
4858   // Update the code cache.
4859   return CodeCache::cast(code_cache())->Update(name, code);
4860 }
4861 
4862 
FindInCodeCache(String * name,Code::Flags flags)4863 Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4864   // Do a lookup if a code cache exists.
4865   if (!code_cache()->IsFixedArray()) {
4866     return CodeCache::cast(code_cache())->Lookup(name, flags);
4867   } else {
4868     return GetHeap()->undefined_value();
4869   }
4870 }
4871 
4872 
IndexInCodeCache(Object * name,Code * code)4873 int Map::IndexInCodeCache(Object* name, Code* code) {
4874   // Get the internal index if a code cache exists.
4875   if (!code_cache()->IsFixedArray()) {
4876     return CodeCache::cast(code_cache())->GetIndex(name, code);
4877   }
4878   return -1;
4879 }
4880 
4881 
RemoveFromCodeCache(String * name,Code * code,int index)4882 void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4883   // No GC is supposed to happen between a call to IndexInCodeCache and
4884   // RemoveFromCodeCache so the code cache must be there.
4885   ASSERT(!code_cache()->IsFixedArray());
4886   CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4887 }
4888 
4889 
4890 // An iterator over all map transitions in an descriptor array, reusing the map
4891 // field of the contens array while it is running.
4892 class IntrusiveMapTransitionIterator {
4893  public:
IntrusiveMapTransitionIterator(DescriptorArray * descriptor_array)4894   explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
4895       : descriptor_array_(descriptor_array) { }
4896 
Start()4897   void Start() {
4898     ASSERT(!IsIterating());
4899     if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
4900   }
4901 
IsIterating()4902   bool IsIterating() {
4903     return HasContentArray() && (*ContentHeader())->IsSmi();
4904   }
4905 
Next()4906   Map* Next() {
4907     ASSERT(IsIterating());
4908     FixedArray* contents = ContentArray();
4909     // Attention, tricky index manipulation ahead: Every entry in the contents
4910     // array consists of a value/details pair, so the index is typically even.
4911     // An exception is made for CALLBACKS entries: An even index means we look
4912     // at its getter, and an odd index means we look at its setter.
4913     int index = Smi::cast(*ContentHeader())->value();
4914     while (index < contents->length()) {
4915       PropertyDetails details(Smi::cast(contents->get(index | 1)));
4916       switch (details.type()) {
4917         case MAP_TRANSITION:
4918         case CONSTANT_TRANSITION:
4919         case ELEMENTS_TRANSITION:
4920           // We definitely have a map transition.
4921           *ContentHeader() = Smi::FromInt(index + 2);
4922           return static_cast<Map*>(contents->get(index));
4923         case CALLBACKS: {
4924           // We might have a map transition in a getter or in a setter.
4925           AccessorPair* accessors =
4926               static_cast<AccessorPair*>(contents->get(index & ~1));
4927           Object* accessor =
4928               ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4929           index++;
4930           if (accessor->IsMap()) {
4931             *ContentHeader() = Smi::FromInt(index);
4932             return static_cast<Map*>(accessor);
4933           }
4934           break;
4935         }
4936         case NORMAL:
4937         case FIELD:
4938         case CONSTANT_FUNCTION:
4939         case HANDLER:
4940         case INTERCEPTOR:
4941         case NULL_DESCRIPTOR:
4942           // We definitely have no map transition.
4943           index += 2;
4944           break;
4945       }
4946     }
4947     *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4948     return NULL;
4949   }
4950 
4951  private:
HasContentArray()4952   bool HasContentArray() {
4953     return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
4954   }
4955 
ContentArray()4956   FixedArray* ContentArray() {
4957     Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
4958     return static_cast<FixedArray*>(array);
4959   }
4960 
ContentHeader()4961   Object** ContentHeader() {
4962     return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
4963   }
4964 
4965   DescriptorArray* descriptor_array_;
4966 };
4967 
4968 
4969 // An iterator over all prototype transitions, reusing the map field of the
4970 // underlying array while it is running.
4971 class IntrusivePrototypeTransitionIterator {
4972  public:
IntrusivePrototypeTransitionIterator(FixedArray * proto_trans)4973   explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
4974       : proto_trans_(proto_trans) { }
4975 
Start()4976   void Start() {
4977     ASSERT(!IsIterating());
4978     if (HasTransitions()) *Header() = Smi::FromInt(0);
4979   }
4980 
IsIterating()4981   bool IsIterating() {
4982     return HasTransitions() && (*Header())->IsSmi();
4983   }
4984 
Next()4985   Map* Next() {
4986     ASSERT(IsIterating());
4987     int transitionNumber = Smi::cast(*Header())->value();
4988     if (transitionNumber < NumberOfTransitions()) {
4989       *Header() = Smi::FromInt(transitionNumber + 1);
4990       return GetTransition(transitionNumber);
4991     }
4992     *Header() = proto_trans_->GetHeap()->fixed_array_map();
4993     return NULL;
4994   }
4995 
4996  private:
HasTransitions()4997   bool HasTransitions() {
4998     return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
4999   }
5000 
Header()5001   Object** Header() {
5002     return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
5003   }
5004 
NumberOfTransitions()5005   int NumberOfTransitions() {
5006     Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5007     return Smi::cast(num)->value();
5008   }
5009 
GetTransition(int transitionNumber)5010   Map* GetTransition(int transitionNumber) {
5011     return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5012   }
5013 
IndexFor(int transitionNumber)5014   int IndexFor(int transitionNumber) {
5015     return Map::kProtoTransitionHeaderSize +
5016         Map::kProtoTransitionMapOffset +
5017         transitionNumber * Map::kProtoTransitionElementsPerEntry;
5018   }
5019 
5020   FixedArray* proto_trans_;
5021 };
5022 
5023 
5024 // To traverse the transition tree iteratively, we have to store two kinds of
5025 // information in a map: The parent map in the traversal and which children of a
5026 // node have already been visited. To do this without additional memory, we
5027 // temporarily reuse two maps with known values:
5028 //
5029 //  (1) The map of the map temporarily holds the parent, and is restored to the
5030 //      meta map afterwards.
5031 //
5032 //  (2) The info which children have already been visited depends on which part
5033 //      of the map we currently iterate:
5034 //
5035 //    (a) If we currently follow normal map transitions, we temporarily store
5036 //        the current index in the map of the FixedArray of the desciptor
5037 //        array's contents, and restore it to the fixed array map afterwards.
5038 //        Note that a single descriptor can have 0, 1, or 2 transitions.
5039 //
5040 //    (b) If we currently follow prototype transitions, we temporarily store
5041 //        the current index in the map of the FixedArray holding the prototype
5042 //        transitions, and restore it to the fixed array map afterwards.
5043 //
5044 // Note that the child iterator is just a concatenation of two iterators: One
5045 // iterating over map transitions and one iterating over prototype transisitons.
5046 class TraversableMap : public Map {
5047  public:
5048   // Record the parent in the traversal within this map. Note that this destroys
5049   // this map's map!
SetParent(TraversableMap * parent)5050   void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5051 
5052   // Reset the current map's map, returning the parent previously stored in it.
GetAndResetParent()5053   TraversableMap* GetAndResetParent() {
5054     TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5055     set_map_no_write_barrier(GetHeap()->meta_map());
5056     return old_parent;
5057   }
5058 
5059   // Start iterating over this map's children, possibly destroying a FixedArray
5060   // map (see explanation above).
ChildIteratorStart()5061   void ChildIteratorStart() {
5062     IntrusiveMapTransitionIterator(instance_descriptors()).Start();
5063     IntrusivePrototypeTransitionIterator(
5064         unchecked_prototype_transitions()).Start();
5065   }
5066 
5067   // If we have an unvisited child map, return that one and advance. If we have
5068   // none, return NULL and reset any destroyed FixedArray maps.
ChildIteratorNext()5069   TraversableMap* ChildIteratorNext() {
5070     IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5071     if (descriptor_iterator.IsIterating()) {
5072       Map* next = descriptor_iterator.Next();
5073       if (next != NULL) return static_cast<TraversableMap*>(next);
5074     }
5075     IntrusivePrototypeTransitionIterator
5076         proto_iterator(unchecked_prototype_transitions());
5077     if (proto_iterator.IsIterating()) {
5078       Map* next = proto_iterator.Next();
5079       if (next != NULL) return static_cast<TraversableMap*>(next);
5080     }
5081     return NULL;
5082   }
5083 };
5084 
5085 
5086 // Traverse the transition tree in postorder without using the C++ stack by
5087 // doing pointer reversal.
TraverseTransitionTree(TraverseCallback callback,void * data)5088 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
5089   TraversableMap* current = static_cast<TraversableMap*>(this);
5090   current->ChildIteratorStart();
5091   while (true) {
5092     TraversableMap* child = current->ChildIteratorNext();
5093     if (child != NULL) {
5094       child->ChildIteratorStart();
5095       child->SetParent(current);
5096       current = child;
5097     } else {
5098       TraversableMap* parent = current->GetAndResetParent();
5099       callback(current, data);
5100       if (current == this) break;
5101       current = parent;
5102     }
5103   }
5104 }
5105 
5106 
Update(String * name,Code * code)5107 MaybeObject* CodeCache::Update(String* name, Code* code) {
5108   // The number of monomorphic stubs for normal load/store/call IC's can grow to
5109   // a large number and therefore they need to go into a hash table. They are
5110   // used to load global properties from cells.
5111   if (code->type() == NORMAL) {
5112     // Make sure that a hash table is allocated for the normal load code cache.
5113     if (normal_type_cache()->IsUndefined()) {
5114       Object* result;
5115       { MaybeObject* maybe_result =
5116             CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
5117         if (!maybe_result->ToObject(&result)) return maybe_result;
5118       }
5119       set_normal_type_cache(result);
5120     }
5121     return UpdateNormalTypeCache(name, code);
5122   } else {
5123     ASSERT(default_cache()->IsFixedArray());
5124     return UpdateDefaultCache(name, code);
5125   }
5126 }
5127 
5128 
UpdateDefaultCache(String * name,Code * code)5129 MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
5130   // When updating the default code cache we disregard the type encoded in the
5131   // flags. This allows call constant stubs to overwrite call field
5132   // stubs, etc.
5133   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
5134 
5135   // First check whether we can update existing code cache without
5136   // extending it.
5137   FixedArray* cache = default_cache();
5138   int length = cache->length();
5139   int deleted_index = -1;
5140   for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5141     Object* key = cache->get(i);
5142     if (key->IsNull()) {
5143       if (deleted_index < 0) deleted_index = i;
5144       continue;
5145     }
5146     if (key->IsUndefined()) {
5147       if (deleted_index >= 0) i = deleted_index;
5148       cache->set(i + kCodeCacheEntryNameOffset, name);
5149       cache->set(i + kCodeCacheEntryCodeOffset, code);
5150       return this;
5151     }
5152     if (name->Equals(String::cast(key))) {
5153       Code::Flags found =
5154           Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
5155       if (Code::RemoveTypeFromFlags(found) == flags) {
5156         cache->set(i + kCodeCacheEntryCodeOffset, code);
5157         return this;
5158       }
5159     }
5160   }
5161 
5162   // Reached the end of the code cache.  If there were deleted
5163   // elements, reuse the space for the first of them.
5164   if (deleted_index >= 0) {
5165     cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
5166     cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
5167     return this;
5168   }
5169 
5170   // Extend the code cache with some new entries (at least one). Must be a
5171   // multiple of the entry size.
5172   int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
5173   new_length = new_length - new_length % kCodeCacheEntrySize;
5174   ASSERT((new_length % kCodeCacheEntrySize) == 0);
5175   Object* result;
5176   { MaybeObject* maybe_result = cache->CopySize(new_length);
5177     if (!maybe_result->ToObject(&result)) return maybe_result;
5178   }
5179 
5180   // Add the (name, code) pair to the new cache.
5181   cache = FixedArray::cast(result);
5182   cache->set(length + kCodeCacheEntryNameOffset, name);
5183   cache->set(length + kCodeCacheEntryCodeOffset, code);
5184   set_default_cache(cache);
5185   return this;
5186 }
5187 
5188 
UpdateNormalTypeCache(String * name,Code * code)5189 MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
5190   // Adding a new entry can cause a new cache to be allocated.
5191   CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5192   Object* new_cache;
5193   { MaybeObject* maybe_new_cache = cache->Put(name, code);
5194     if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5195   }
5196   set_normal_type_cache(new_cache);
5197   return this;
5198 }
5199 
5200 
Lookup(String * name,Code::Flags flags)5201 Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5202   if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5203     return LookupNormalTypeCache(name, flags);
5204   } else {
5205     return LookupDefaultCache(name, flags);
5206   }
5207 }
5208 
5209 
LookupDefaultCache(String * name,Code::Flags flags)5210 Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5211   FixedArray* cache = default_cache();
5212   int length = cache->length();
5213   for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5214     Object* key = cache->get(i + kCodeCacheEntryNameOffset);
5215     // Skip deleted elements.
5216     if (key->IsNull()) continue;
5217     if (key->IsUndefined()) return key;
5218     if (name->Equals(String::cast(key))) {
5219       Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5220       if (code->flags() == flags) {
5221         return code;
5222       }
5223     }
5224   }
5225   return GetHeap()->undefined_value();
5226 }
5227 
5228 
LookupNormalTypeCache(String * name,Code::Flags flags)5229 Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5230   if (!normal_type_cache()->IsUndefined()) {
5231     CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5232     return cache->Lookup(name, flags);
5233   } else {
5234     return GetHeap()->undefined_value();
5235   }
5236 }
5237 
5238 
GetIndex(Object * name,Code * code)5239 int CodeCache::GetIndex(Object* name, Code* code) {
5240   if (code->type() == NORMAL) {
5241     if (normal_type_cache()->IsUndefined()) return -1;
5242     CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5243     return cache->GetIndex(String::cast(name), code->flags());
5244   }
5245 
5246   FixedArray* array = default_cache();
5247   int len = array->length();
5248   for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5249     if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
5250   }
5251   return -1;
5252 }
5253 
5254 
RemoveByIndex(Object * name,Code * code,int index)5255 void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
5256   if (code->type() == NORMAL) {
5257     ASSERT(!normal_type_cache()->IsUndefined());
5258     CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5259     ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
5260     cache->RemoveByIndex(index);
5261   } else {
5262     FixedArray* array = default_cache();
5263     ASSERT(array->length() >= index && array->get(index)->IsCode());
5264     // Use null instead of undefined for deleted elements to distinguish
5265     // deleted elements from unused elements.  This distinction is used
5266     // when looking up in the cache and when updating the cache.
5267     ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5268     array->set_null(index - 1);  // Name.
5269     array->set_null(index);  // Code.
5270   }
5271 }
5272 
5273 
5274 // The key in the code cache hash table consists of the property name and the
5275 // code object. The actual match is on the name and the code flags. If a key
5276 // is created using the flags and not a code object it can only be used for
5277 // lookup not to create a new entry.
5278 class CodeCacheHashTableKey : public HashTableKey {
5279  public:
CodeCacheHashTableKey(String * name,Code::Flags flags)5280   CodeCacheHashTableKey(String* name, Code::Flags flags)
5281       : name_(name), flags_(flags), code_(NULL) { }
5282 
CodeCacheHashTableKey(String * name,Code * code)5283   CodeCacheHashTableKey(String* name, Code* code)
5284       : name_(name),
5285         flags_(code->flags()),
5286         code_(code) { }
5287 
5288 
IsMatch(Object * other)5289   bool IsMatch(Object* other) {
5290     if (!other->IsFixedArray()) return false;
5291     FixedArray* pair = FixedArray::cast(other);
5292     String* name = String::cast(pair->get(0));
5293     Code::Flags flags = Code::cast(pair->get(1))->flags();
5294     if (flags != flags_) {
5295       return false;
5296     }
5297     return name_->Equals(name);
5298   }
5299 
NameFlagsHashHelper(String * name,Code::Flags flags)5300   static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5301     return name->Hash() ^ flags;
5302   }
5303 
Hash()5304   uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5305 
HashForObject(Object * obj)5306   uint32_t HashForObject(Object* obj) {
5307     FixedArray* pair = FixedArray::cast(obj);
5308     String* name = String::cast(pair->get(0));
5309     Code* code = Code::cast(pair->get(1));
5310     return NameFlagsHashHelper(name, code->flags());
5311   }
5312 
AsObject()5313   MUST_USE_RESULT MaybeObject* AsObject() {
5314     ASSERT(code_ != NULL);
5315     Object* obj;
5316     { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
5317       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5318     }
5319     FixedArray* pair = FixedArray::cast(obj);
5320     pair->set(0, name_);
5321     pair->set(1, code_);
5322     return pair;
5323   }
5324 
5325  private:
5326   String* name_;
5327   Code::Flags flags_;
5328   // TODO(jkummerow): We should be able to get by without this.
5329   Code* code_;
5330 };
5331 
5332 
Lookup(String * name,Code::Flags flags)5333 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5334   CodeCacheHashTableKey key(name, flags);
5335   int entry = FindEntry(&key);
5336   if (entry == kNotFound) return GetHeap()->undefined_value();
5337   return get(EntryToIndex(entry) + 1);
5338 }
5339 
5340 
Put(String * name,Code * code)5341 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
5342   CodeCacheHashTableKey key(name, code);
5343   Object* obj;
5344   { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5345     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5346   }
5347 
5348   // Don't use |this|, as the table might have grown.
5349   CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5350 
5351   int entry = cache->FindInsertionEntry(key.Hash());
5352   Object* k;
5353   { MaybeObject* maybe_k = key.AsObject();
5354     if (!maybe_k->ToObject(&k)) return maybe_k;
5355   }
5356 
5357   cache->set(EntryToIndex(entry), k);
5358   cache->set(EntryToIndex(entry) + 1, code);
5359   cache->ElementAdded();
5360   return cache;
5361 }
5362 
5363 
GetIndex(String * name,Code::Flags flags)5364 int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5365   CodeCacheHashTableKey key(name, flags);
5366   int entry = FindEntry(&key);
5367   return (entry == kNotFound) ? -1 : entry;
5368 }
5369 
5370 
RemoveByIndex(int index)5371 void CodeCacheHashTable::RemoveByIndex(int index) {
5372   ASSERT(index >= 0);
5373   Heap* heap = GetHeap();
5374   set(EntryToIndex(index), heap->the_hole_value());
5375   set(EntryToIndex(index) + 1, heap->the_hole_value());
5376   ElementRemoved();
5377 }
5378 
5379 
Update(Handle<PolymorphicCodeCache> cache,MapHandleList * maps,Code::Flags flags,Handle<Code> code)5380 void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5381                                   MapHandleList* maps,
5382                                   Code::Flags flags,
5383                                   Handle<Code> code) {
5384   Isolate* isolate = cache->GetIsolate();
5385   CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5386 }
5387 
5388 
Update(MapHandleList * maps,Code::Flags flags,Code * code)5389 MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
5390                                           Code::Flags flags,
5391                                           Code* code) {
5392   // Initialize cache if necessary.
5393   if (cache()->IsUndefined()) {
5394     Object* result;
5395     { MaybeObject* maybe_result =
5396           PolymorphicCodeCacheHashTable::Allocate(
5397               PolymorphicCodeCacheHashTable::kInitialSize);
5398       if (!maybe_result->ToObject(&result)) return maybe_result;
5399     }
5400     set_cache(result);
5401   } else {
5402     // This entry shouldn't be contained in the cache yet.
5403     ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5404                ->Lookup(maps, flags)->IsUndefined());
5405   }
5406   PolymorphicCodeCacheHashTable* hash_table =
5407       PolymorphicCodeCacheHashTable::cast(cache());
5408   Object* new_cache;
5409   { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5410     if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5411   }
5412   set_cache(new_cache);
5413   return this;
5414 }
5415 
5416 
Lookup(MapHandleList * maps,Code::Flags flags)5417 Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5418                                             Code::Flags flags) {
5419   if (!cache()->IsUndefined()) {
5420     PolymorphicCodeCacheHashTable* hash_table =
5421         PolymorphicCodeCacheHashTable::cast(cache());
5422     return Handle<Object>(hash_table->Lookup(maps, flags));
5423   } else {
5424     return GetIsolate()->factory()->undefined_value();
5425   }
5426 }
5427 
5428 
5429 // Despite their name, object of this class are not stored in the actual
5430 // hash table; instead they're temporarily used for lookups. It is therefore
5431 // safe to have a weak (non-owning) pointer to a MapList as a member field.
5432 class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5433  public:
5434   // Callers must ensure that |maps| outlives the newly constructed object.
PolymorphicCodeCacheHashTableKey(MapHandleList * maps,int code_flags)5435   PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
5436       : maps_(maps),
5437         code_flags_(code_flags) {}
5438 
IsMatch(Object * other)5439   bool IsMatch(Object* other) {
5440     MapHandleList other_maps(kDefaultListAllocationSize);
5441     int other_flags;
5442     FromObject(other, &other_flags, &other_maps);
5443     if (code_flags_ != other_flags) return false;
5444     if (maps_->length() != other_maps.length()) return false;
5445     // Compare just the hashes first because it's faster.
5446     int this_hash = MapsHashHelper(maps_, code_flags_);
5447     int other_hash = MapsHashHelper(&other_maps, other_flags);
5448     if (this_hash != other_hash) return false;
5449 
5450     // Full comparison: for each map in maps_, look for an equivalent map in
5451     // other_maps. This implementation is slow, but probably good enough for
5452     // now because the lists are short (<= 4 elements currently).
5453     for (int i = 0; i < maps_->length(); ++i) {
5454       bool match_found = false;
5455       for (int j = 0; j < other_maps.length(); ++j) {
5456         if (*(maps_->at(i)) == *(other_maps.at(j))) {
5457           match_found = true;
5458           break;
5459         }
5460       }
5461       if (!match_found) return false;
5462     }
5463     return true;
5464   }
5465 
MapsHashHelper(MapHandleList * maps,int code_flags)5466   static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
5467     uint32_t hash = code_flags;
5468     for (int i = 0; i < maps->length(); ++i) {
5469       hash ^= maps->at(i)->Hash();
5470     }
5471     return hash;
5472   }
5473 
Hash()5474   uint32_t Hash() {
5475     return MapsHashHelper(maps_, code_flags_);
5476   }
5477 
HashForObject(Object * obj)5478   uint32_t HashForObject(Object* obj) {
5479     MapHandleList other_maps(kDefaultListAllocationSize);
5480     int other_flags;
5481     FromObject(obj, &other_flags, &other_maps);
5482     return MapsHashHelper(&other_maps, other_flags);
5483   }
5484 
AsObject()5485   MUST_USE_RESULT MaybeObject* AsObject() {
5486     Object* obj;
5487     // The maps in |maps_| must be copied to a newly allocated FixedArray,
5488     // both because the referenced MapList is short-lived, and because C++
5489     // objects can't be stored in the heap anyway.
5490     { MaybeObject* maybe_obj =
5491         HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5492       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5493     }
5494     FixedArray* list = FixedArray::cast(obj);
5495     list->set(0, Smi::FromInt(code_flags_));
5496     for (int i = 0; i < maps_->length(); ++i) {
5497       list->set(i + 1, *maps_->at(i));
5498     }
5499     return list;
5500   }
5501 
5502  private:
FromObject(Object * obj,int * code_flags,MapHandleList * maps)5503   static MapHandleList* FromObject(Object* obj,
5504                                    int* code_flags,
5505                                    MapHandleList* maps) {
5506     FixedArray* list = FixedArray::cast(obj);
5507     maps->Rewind(0);
5508     *code_flags = Smi::cast(list->get(0))->value();
5509     for (int i = 1; i < list->length(); ++i) {
5510       maps->Add(Handle<Map>(Map::cast(list->get(i))));
5511     }
5512     return maps;
5513   }
5514 
5515   MapHandleList* maps_;  // weak.
5516   int code_flags_;
5517   static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
5518 };
5519 
5520 
Lookup(MapHandleList * maps,int code_flags)5521 Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5522                                               int code_flags) {
5523   PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5524   int entry = FindEntry(&key);
5525   if (entry == kNotFound) return GetHeap()->undefined_value();
5526   return get(EntryToIndex(entry) + 1);
5527 }
5528 
5529 
Put(MapHandleList * maps,int code_flags,Code * code)5530 MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
5531                                                 int code_flags,
5532                                                 Code* code) {
5533   PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5534   Object* obj;
5535   { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5536     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5537   }
5538   PolymorphicCodeCacheHashTable* cache =
5539       reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5540   int entry = cache->FindInsertionEntry(key.Hash());
5541   { MaybeObject* maybe_obj = key.AsObject();
5542     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5543   }
5544   cache->set(EntryToIndex(entry), obj);
5545   cache->set(EntryToIndex(entry) + 1, code);
5546   cache->ElementAdded();
5547   return cache;
5548 }
5549 
5550 
AddKeysFromJSArray(JSArray * array)5551 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
5552   ElementsAccessor* accessor = array->GetElementsAccessor();
5553   MaybeObject* maybe_result =
5554       accessor->AddElementsToFixedArray(array, array, this);
5555   FixedArray* result;
5556   if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5557 #ifdef DEBUG
5558   if (FLAG_enable_slow_asserts) {
5559     for (int i = 0; i < result->length(); i++) {
5560       Object* current = result->get(i);
5561       ASSERT(current->IsNumber() || current->IsString());
5562     }
5563   }
5564 #endif
5565   return result;
5566 }
5567 
5568 
UnionOfKeys(FixedArray * other)5569 MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
5570   ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5571   MaybeObject* maybe_result =
5572       accessor->AddElementsToFixedArray(NULL, NULL, this, other);
5573   FixedArray* result;
5574   if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5575 #ifdef DEBUG
5576   if (FLAG_enable_slow_asserts) {
5577     for (int i = 0; i < result->length(); i++) {
5578       Object* current = result->get(i);
5579       ASSERT(current->IsNumber() || current->IsString());
5580     }
5581   }
5582 #endif
5583   return result;
5584 }
5585 
5586 
CopySize(int new_length)5587 MaybeObject* FixedArray::CopySize(int new_length) {
5588   Heap* heap = GetHeap();
5589   if (new_length == 0) return heap->empty_fixed_array();
5590   Object* obj;
5591   { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
5592     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5593   }
5594   FixedArray* result = FixedArray::cast(obj);
5595   // Copy the content
5596   AssertNoAllocation no_gc;
5597   int len = length();
5598   if (new_length < len) len = new_length;
5599   // We are taking the map from the old fixed array so the map is sure to
5600   // be an immortal immutable object.
5601   result->set_map_no_write_barrier(map());
5602   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
5603   for (int i = 0; i < len; i++) {
5604     result->set(i, get(i), mode);
5605   }
5606   return result;
5607 }
5608 
5609 
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)5610 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
5611   AssertNoAllocation no_gc;
5612   WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
5613   for (int index = 0; index < len; index++) {
5614     dest->set(dest_pos+index, get(pos+index), mode);
5615   }
5616 }
5617 
5618 
5619 #ifdef DEBUG
IsEqualTo(FixedArray * other)5620 bool FixedArray::IsEqualTo(FixedArray* other) {
5621   if (length() != other->length()) return false;
5622   for (int i = 0 ; i < length(); ++i) {
5623     if (get(i) != other->get(i)) return false;
5624   }
5625   return true;
5626 }
5627 #endif
5628 
5629 
Allocate(int number_of_descriptors)5630 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
5631   Heap* heap = Isolate::Current()->heap();
5632   if (number_of_descriptors == 0) {
5633     return heap->empty_descriptor_array();
5634   }
5635   // Allocate the array of keys.
5636   Object* array;
5637   { MaybeObject* maybe_array =
5638         heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
5639     if (!maybe_array->ToObject(&array)) return maybe_array;
5640   }
5641   // Do not use DescriptorArray::cast on incomplete object.
5642   FixedArray* result = FixedArray::cast(array);
5643 
5644   // Allocate the content array and set it in the descriptor array.
5645   { MaybeObject* maybe_array =
5646         heap->AllocateFixedArray(number_of_descriptors << 1);
5647     if (!maybe_array->ToObject(&array)) return maybe_array;
5648   }
5649   result->set(kBitField3StorageIndex, Smi::FromInt(0));
5650   result->set(kContentArrayIndex, array);
5651   result->set(kEnumerationIndexIndex,
5652               Smi::FromInt(PropertyDetails::kInitialIndex));
5653   return result;
5654 }
5655 
5656 
SetEnumCache(FixedArray * bridge_storage,FixedArray * new_cache,Object * new_index_cache)5657 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
5658                                    FixedArray* new_cache,
5659                                    Object* new_index_cache) {
5660   ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
5661   ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
5662   if (HasEnumCache()) {
5663     FixedArray::cast(get(kEnumerationIndexIndex))->
5664       set(kEnumCacheBridgeCacheIndex, new_cache);
5665     FixedArray::cast(get(kEnumerationIndexIndex))->
5666       set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
5667   } else {
5668     if (IsEmpty()) return;  // Do nothing for empty descriptor array.
5669     FixedArray::cast(bridge_storage)->
5670       set(kEnumCacheBridgeCacheIndex, new_cache);
5671     FixedArray::cast(bridge_storage)->
5672       set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
5673     NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5674                       kEnumCacheBridgeEnumIndex,
5675                       get(kEnumerationIndexIndex));
5676     set(kEnumerationIndexIndex, bridge_storage);
5677   }
5678 }
5679 
5680 
InsertionPointFound(String * key1,String * key2)5681 static bool InsertionPointFound(String* key1, String* key2) {
5682   return key1->Hash() > key2->Hash() || key1 == key2;
5683 }
5684 
5685 
CopyFrom(Handle<DescriptorArray> dst,int dst_index,Handle<DescriptorArray> src,int src_index,const WhitenessWitness & witness)5686 void DescriptorArray::CopyFrom(Handle<DescriptorArray> dst,
5687                                int dst_index,
5688                                Handle<DescriptorArray> src,
5689                                int src_index,
5690                                const WhitenessWitness& witness) {
5691   CALL_HEAP_FUNCTION_VOID(dst->GetIsolate(),
5692                           dst->CopyFrom(dst_index, *src, src_index, witness));
5693 }
5694 
5695 
CopyFrom(int dst_index,DescriptorArray * src,int src_index,const WhitenessWitness & witness)5696 MaybeObject* DescriptorArray::CopyFrom(int dst_index,
5697                                        DescriptorArray* src,
5698                                        int src_index,
5699                                        const WhitenessWitness& witness) {
5700   Object* value = src->GetValue(src_index);
5701   PropertyDetails details(src->GetDetails(src_index));
5702   if (details.type() == CALLBACKS && value->IsAccessorPair()) {
5703     MaybeObject* maybe_copy =
5704         AccessorPair::cast(value)->CopyWithoutTransitions();
5705     if (!maybe_copy->To(&value)) return maybe_copy;
5706   }
5707   Descriptor desc(src->GetKey(src_index), value, details);
5708   Set(dst_index, &desc, witness);
5709   return this;
5710 }
5711 
5712 
CopyInsert(Descriptor * descriptor,TransitionFlag transition_flag)5713 MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5714                                          TransitionFlag transition_flag) {
5715   // Transitions are only kept when inserting another transition.
5716   // This precondition is not required by this function's implementation, but
5717   // is currently required by the semantics of maps, so we check it.
5718   // Conversely, we filter after replacing, so replacing a transition and
5719   // removing all other transitions is not supported.
5720   bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
5721   ASSERT(remove_transitions == !descriptor->ContainsTransition());
5722   ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
5723 
5724   // Ensure the key is a symbol.
5725   { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5726     if (maybe_result->IsFailure()) return maybe_result;
5727   }
5728 
5729   int new_size = 0;
5730   for (int i = 0; i < number_of_descriptors(); i++) {
5731     if (IsNullDescriptor(i)) continue;
5732     if (remove_transitions && IsTransitionOnly(i)) continue;
5733     new_size++;
5734   }
5735 
5736   // If key is in descriptor, we replace it in-place when filtering.
5737   // Count a null descriptor for key as inserted, not replaced.
5738   int index = Search(descriptor->GetKey());
5739   const bool replacing = (index != kNotFound);
5740   bool keep_enumeration_index = false;
5741   if (replacing) {
5742     // We are replacing an existing descriptor.  We keep the enumeration
5743     // index of a visible property.
5744     PropertyType t = PropertyDetails(GetDetails(index)).type();
5745     if (t == CONSTANT_FUNCTION ||
5746         t == FIELD ||
5747         t == CALLBACKS ||
5748         t == INTERCEPTOR) {
5749       keep_enumeration_index = true;
5750     } else if (remove_transitions) {
5751      // Replaced descriptor has been counted as removed if it is
5752      // a transition that will be replaced.  Adjust count in this case.
5753       ++new_size;
5754     }
5755   } else {
5756     ++new_size;
5757   }
5758 
5759   DescriptorArray* new_descriptors;
5760   { MaybeObject* maybe_result = Allocate(new_size);
5761     if (!maybe_result->To(&new_descriptors)) return maybe_result;
5762   }
5763 
5764   DescriptorArray::WhitenessWitness witness(new_descriptors);
5765 
5766   // Set the enumeration index in the descriptors and set the enumeration index
5767   // in the result.
5768   int enumeration_index = NextEnumerationIndex();
5769   if (!descriptor->ContainsTransition()) {
5770     if (keep_enumeration_index) {
5771       descriptor->SetEnumerationIndex(
5772           PropertyDetails(GetDetails(index)).index());
5773     } else {
5774       descriptor->SetEnumerationIndex(enumeration_index);
5775       ++enumeration_index;
5776     }
5777   }
5778   new_descriptors->SetNextEnumerationIndex(enumeration_index);
5779 
5780   // Copy the descriptors, filtering out transitions and null descriptors,
5781   // and inserting or replacing a descriptor.
5782   int to_index = 0;
5783   int insertion_index = -1;
5784   int from_index = 0;
5785   while (from_index < number_of_descriptors()) {
5786     if (insertion_index < 0 &&
5787         InsertionPointFound(GetKey(from_index), descriptor->GetKey())) {
5788       insertion_index = to_index++;
5789       if (replacing) from_index++;
5790     } else {
5791       if (!(IsNullDescriptor(from_index) ||
5792             (remove_transitions && IsTransitionOnly(from_index)))) {
5793         MaybeObject* copy_result =
5794             new_descriptors->CopyFrom(to_index++, this, from_index, witness);
5795         if (copy_result->IsFailure()) return copy_result;
5796       }
5797       from_index++;
5798     }
5799   }
5800   if (insertion_index < 0) insertion_index = to_index++;
5801   new_descriptors->Set(insertion_index, descriptor, witness);
5802 
5803   ASSERT(to_index == new_descriptors->number_of_descriptors());
5804   SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5805 
5806   return new_descriptors;
5807 }
5808 
5809 
RemoveTransitions()5810 MaybeObject* DescriptorArray::RemoveTransitions() {
5811   // Allocate the new descriptor array.
5812   int new_number_of_descriptors = 0;
5813   for (int i = 0; i < number_of_descriptors(); i++) {
5814     if (IsProperty(i)) new_number_of_descriptors++;
5815   }
5816   DescriptorArray* new_descriptors;
5817   { MaybeObject* maybe_result = Allocate(new_number_of_descriptors);
5818     if (!maybe_result->To(&new_descriptors)) return maybe_result;
5819   }
5820 
5821   // Copy the content.
5822   DescriptorArray::WhitenessWitness witness(new_descriptors);
5823   int next_descriptor = 0;
5824   for (int i = 0; i < number_of_descriptors(); i++) {
5825     if (IsProperty(i)) {
5826       MaybeObject* copy_result =
5827           new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5828       if (copy_result->IsFailure()) return copy_result;
5829     }
5830   }
5831   ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5832 
5833   return new_descriptors;
5834 }
5835 
5836 
SortUnchecked(const WhitenessWitness & witness)5837 void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
5838   // In-place heap sort.
5839   int len = number_of_descriptors();
5840 
5841   // Bottom-up max-heap construction.
5842   // Index of the last node with children
5843   const int max_parent_index = (len / 2) - 1;
5844   for (int i = max_parent_index; i >= 0; --i) {
5845     int parent_index = i;
5846     const uint32_t parent_hash = GetKey(i)->Hash();
5847     while (parent_index <= max_parent_index) {
5848       int child_index = 2 * parent_index + 1;
5849       uint32_t child_hash = GetKey(child_index)->Hash();
5850       if (child_index + 1 < len) {
5851         uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5852         if (right_child_hash > child_hash) {
5853           child_index++;
5854           child_hash = right_child_hash;
5855         }
5856       }
5857       if (child_hash <= parent_hash) break;
5858       NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
5859       // Now element at child_index could be < its children.
5860       parent_index = child_index;  // parent_hash remains correct.
5861     }
5862   }
5863 
5864   // Extract elements and create sorted array.
5865   for (int i = len - 1; i > 0; --i) {
5866     // Put max element at the back of the array.
5867     NoIncrementalWriteBarrierSwapDescriptors(0, i);
5868     // Shift down the new top element.
5869     int parent_index = 0;
5870     const uint32_t parent_hash = GetKey(parent_index)->Hash();
5871     const int max_parent_index = (i / 2) - 1;
5872     while (parent_index <= max_parent_index) {
5873       int child_index = parent_index * 2 + 1;
5874       uint32_t child_hash = GetKey(child_index)->Hash();
5875       if (child_index + 1 < i) {
5876         uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5877         if (right_child_hash > child_hash) {
5878           child_index++;
5879           child_hash = right_child_hash;
5880         }
5881       }
5882       if (child_hash <= parent_hash) break;
5883       NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
5884       parent_index = child_index;
5885     }
5886   }
5887 }
5888 
5889 
Sort(const WhitenessWitness & witness)5890 void DescriptorArray::Sort(const WhitenessWitness& witness) {
5891   SortUnchecked(witness);
5892   SLOW_ASSERT(IsSortedNoDuplicates());
5893 }
5894 
5895 
BinarySearch(String * name,int low,int high)5896 int DescriptorArray::BinarySearch(String* name, int low, int high) {
5897   uint32_t hash = name->Hash();
5898 
5899   while (low <= high) {
5900     int mid = (low + high) / 2;
5901     String* mid_name = GetKey(mid);
5902     uint32_t mid_hash = mid_name->Hash();
5903 
5904     if (mid_hash > hash) {
5905       high = mid - 1;
5906       continue;
5907     }
5908     if (mid_hash < hash) {
5909       low = mid + 1;
5910       continue;
5911     }
5912     // Found an element with the same hash-code.
5913     ASSERT(hash == mid_hash);
5914     // There might be more, so we find the first one and
5915     // check them all to see if we have a match.
5916     if (name == mid_name  && !is_null_descriptor(mid)) return mid;
5917     while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5918     for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
5919       if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
5920     }
5921     break;
5922   }
5923   return kNotFound;
5924 }
5925 
5926 
LinearSearch(String * name,int len)5927 int DescriptorArray::LinearSearch(String* name, int len) {
5928   uint32_t hash = name->Hash();
5929   for (int number = 0; number < len; number++) {
5930     String* entry = GetKey(number);
5931     if ((entry->Hash() == hash) &&
5932         name->Equals(entry) &&
5933         !is_null_descriptor(number)) {
5934       return number;
5935     }
5936   }
5937   return kNotFound;
5938 }
5939 
5940 
CopyWithoutTransitions()5941 MaybeObject* AccessorPair::CopyWithoutTransitions() {
5942   Heap* heap = GetHeap();
5943   AccessorPair* copy;
5944   { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5945     if (!maybe_copy->To(&copy)) return maybe_copy;
5946   }
5947   copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
5948   copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
5949   return copy;
5950 }
5951 
5952 
GetComponent(AccessorComponent component)5953 Object* AccessorPair::GetComponent(AccessorComponent component) {
5954     Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter();
5955     return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
5956 }
5957 
5958 
Allocate(int deopt_entry_count,PretenureFlag pretenure)5959 MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5960                                                PretenureFlag pretenure) {
5961   ASSERT(deopt_entry_count > 0);
5962   return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
5963                                   pretenure);
5964 }
5965 
5966 
Allocate(int number_of_deopt_points,PretenureFlag pretenure)5967 MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5968                                                 PretenureFlag pretenure) {
5969   if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5970   return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
5971                                   pretenure);
5972 }
5973 
5974 
5975 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)5976 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5977   if (IsEmpty()) return other->IsEmpty();
5978   if (other->IsEmpty()) return false;
5979   if (length() != other->length()) return false;
5980   for (int i = 0; i < length(); ++i) {
5981     if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5982   }
5983   return GetContentArray()->IsEqualTo(other->GetContentArray());
5984 }
5985 #endif
5986 
5987 
LooksValid()5988 bool String::LooksValid() {
5989   if (!Isolate::Current()->heap()->Contains(this)) return false;
5990   return true;
5991 }
5992 
5993 
GetFlatContent()5994 String::FlatContent String::GetFlatContent() {
5995   int length = this->length();
5996   StringShape shape(this);
5997   String* string = this;
5998   int offset = 0;
5999   if (shape.representation_tag() == kConsStringTag) {
6000     ConsString* cons = ConsString::cast(string);
6001     if (cons->second()->length() != 0) {
6002       return FlatContent();
6003     }
6004     string = cons->first();
6005     shape = StringShape(string);
6006   }
6007   if (shape.representation_tag() == kSlicedStringTag) {
6008     SlicedString* slice = SlicedString::cast(string);
6009     offset = slice->offset();
6010     string = slice->parent();
6011     shape = StringShape(string);
6012     ASSERT(shape.representation_tag() != kConsStringTag &&
6013            shape.representation_tag() != kSlicedStringTag);
6014   }
6015   if (shape.encoding_tag() == kAsciiStringTag) {
6016     const char* start;
6017     if (shape.representation_tag() == kSeqStringTag) {
6018       start = SeqAsciiString::cast(string)->GetChars();
6019     } else {
6020       start = ExternalAsciiString::cast(string)->GetChars();
6021     }
6022     return FlatContent(Vector<const char>(start + offset, length));
6023   } else {
6024     ASSERT(shape.encoding_tag() == kTwoByteStringTag);
6025     const uc16* start;
6026     if (shape.representation_tag() == kSeqStringTag) {
6027       start = SeqTwoByteString::cast(string)->GetChars();
6028     } else {
6029       start = ExternalTwoByteString::cast(string)->GetChars();
6030     }
6031     return FlatContent(Vector<const uc16>(start + offset, length));
6032   }
6033 }
6034 
6035 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)6036 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6037                                           RobustnessFlag robust_flag,
6038                                           int offset,
6039                                           int length,
6040                                           int* length_return) {
6041   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
6042     return SmartArrayPointer<char>(NULL);
6043   }
6044   Heap* heap = GetHeap();
6045 
6046   // Negative length means the to the end of the string.
6047   if (length < 0) length = kMaxInt - offset;
6048 
6049   // Compute the size of the UTF-8 string. Start at the specified offset.
6050   Access<StringInputBuffer> buffer(
6051       heap->isolate()->objects_string_input_buffer());
6052   buffer->Reset(offset, this);
6053   int character_position = offset;
6054   int utf8_bytes = 0;
6055   int last = unibrow::Utf16::kNoPreviousCharacter;
6056   while (buffer->has_more() && character_position++ < offset + length) {
6057     uint16_t character = buffer->GetNext();
6058     utf8_bytes += unibrow::Utf8::Length(character, last);
6059     last = character;
6060   }
6061 
6062   if (length_return) {
6063     *length_return = utf8_bytes;
6064   }
6065 
6066   char* result = NewArray<char>(utf8_bytes + 1);
6067 
6068   // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
6069   buffer->Rewind();
6070   buffer->Seek(offset);
6071   character_position = offset;
6072   int utf8_byte_position = 0;
6073   last = unibrow::Utf16::kNoPreviousCharacter;
6074   while (buffer->has_more() && character_position++ < offset + length) {
6075     uint16_t character = buffer->GetNext();
6076     if (allow_nulls == DISALLOW_NULLS && character == 0) {
6077       character = ' ';
6078     }
6079     utf8_byte_position +=
6080         unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
6081     last = character;
6082   }
6083   result[utf8_byte_position] = 0;
6084   return SmartArrayPointer<char>(result);
6085 }
6086 
6087 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)6088 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6089                                           RobustnessFlag robust_flag,
6090                                           int* length_return) {
6091   return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6092 }
6093 
6094 
GetTwoByteData()6095 const uc16* String::GetTwoByteData() {
6096   return GetTwoByteData(0);
6097 }
6098 
6099 
GetTwoByteData(unsigned start)6100 const uc16* String::GetTwoByteData(unsigned start) {
6101   ASSERT(!IsAsciiRepresentationUnderneath());
6102   switch (StringShape(this).representation_tag()) {
6103     case kSeqStringTag:
6104       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
6105     case kExternalStringTag:
6106       return ExternalTwoByteString::cast(this)->
6107         ExternalTwoByteStringGetData(start);
6108     case kSlicedStringTag: {
6109       SlicedString* slice = SlicedString::cast(this);
6110       return slice->parent()->GetTwoByteData(start + slice->offset());
6111     }
6112     case kConsStringTag:
6113       UNREACHABLE();
6114       return NULL;
6115   }
6116   UNREACHABLE();
6117   return NULL;
6118 }
6119 
6120 
ToWideCString(RobustnessFlag robust_flag)6121 SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
6122   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
6123     return SmartArrayPointer<uc16>();
6124   }
6125   Heap* heap = GetHeap();
6126 
6127   Access<StringInputBuffer> buffer(
6128       heap->isolate()->objects_string_input_buffer());
6129   buffer->Reset(this);
6130 
6131   uc16* result = NewArray<uc16>(length() + 1);
6132 
6133   int i = 0;
6134   while (buffer->has_more()) {
6135     uint16_t character = buffer->GetNext();
6136     result[i++] = character;
6137   }
6138   result[i] = 0;
6139   return SmartArrayPointer<uc16>(result);
6140 }
6141 
6142 
SeqTwoByteStringGetData(unsigned start)6143 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
6144   return reinterpret_cast<uc16*>(
6145       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6146 }
6147 
6148 
SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6149 void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6150                                                            unsigned* offset_ptr,
6151                                                            unsigned max_chars) {
6152   unsigned chars_read = 0;
6153   unsigned offset = *offset_ptr;
6154   while (chars_read < max_chars) {
6155     uint16_t c = *reinterpret_cast<uint16_t*>(
6156         reinterpret_cast<char*>(this) -
6157             kHeapObjectTag + kHeaderSize + offset * kShortSize);
6158     if (c <= kMaxAsciiCharCode) {
6159       // Fast case for ASCII characters.   Cursor is an input output argument.
6160       if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6161                                                           rbb->util_buffer,
6162                                                           rbb->capacity,
6163                                                           rbb->cursor)) {
6164         break;
6165       }
6166     } else {
6167       if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6168                                                              rbb->util_buffer,
6169                                                              rbb->capacity,
6170                                                              rbb->cursor)) {
6171         break;
6172       }
6173     }
6174     offset++;
6175     chars_read++;
6176   }
6177   *offset_ptr = offset;
6178   rbb->remaining += chars_read;
6179 }
6180 
6181 
SeqAsciiStringReadBlock(unsigned * remaining,unsigned * offset_ptr,unsigned max_chars)6182 const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6183     unsigned* remaining,
6184     unsigned* offset_ptr,
6185     unsigned max_chars) {
6186   const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6187       kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6188   *remaining = max_chars;
6189   *offset_ptr += max_chars;
6190   return b;
6191 }
6192 
6193 
6194 // This will iterate unless the block of string data spans two 'halves' of
6195 // a ConsString, in which case it will recurse.  Since the block of string
6196 // data to be read has a maximum size this limits the maximum recursion
6197 // depth to something sane.  Since C++ does not have tail call recursion
6198 // elimination, the iteration must be explicit. Since this is not an
6199 // -IntoBuffer method it can delegate to one of the efficient
6200 // *AsciiStringReadBlock routines.
ConsStringReadBlock(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6201 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6202                                                      unsigned* offset_ptr,
6203                                                      unsigned max_chars) {
6204   ConsString* current = this;
6205   unsigned offset = *offset_ptr;
6206   int offset_correction = 0;
6207 
6208   while (true) {
6209     String* left = current->first();
6210     unsigned left_length = (unsigned)left->length();
6211     if (left_length > offset &&
6212         (max_chars <= left_length - offset ||
6213          (rbb->capacity <= left_length - offset &&
6214           (max_chars = left_length - offset, true)))) {  // comma operator!
6215       // Left hand side only - iterate unless we have reached the bottom of
6216       // the cons tree.  The assignment on the left of the comma operator is
6217       // in order to make use of the fact that the -IntoBuffer routines can
6218       // produce at most 'capacity' characters.  This enables us to postpone
6219       // the point where we switch to the -IntoBuffer routines (below) in order
6220       // to maximize the chances of delegating a big chunk of work to the
6221       // efficient *AsciiStringReadBlock routines.
6222       if (StringShape(left).IsCons()) {
6223         current = ConsString::cast(left);
6224         continue;
6225       } else {
6226         const unibrow::byte* answer =
6227             String::ReadBlock(left, rbb, &offset, max_chars);
6228         *offset_ptr = offset + offset_correction;
6229         return answer;
6230       }
6231     } else if (left_length <= offset) {
6232       // Right hand side only - iterate unless we have reached the bottom of
6233       // the cons tree.
6234       String* right = current->second();
6235       offset -= left_length;
6236       offset_correction += left_length;
6237       if (StringShape(right).IsCons()) {
6238         current = ConsString::cast(right);
6239         continue;
6240       } else {
6241         const unibrow::byte* answer =
6242             String::ReadBlock(right, rbb, &offset, max_chars);
6243         *offset_ptr = offset + offset_correction;
6244         return answer;
6245       }
6246     } else {
6247       // The block to be read spans two sides of the ConsString, so we call the
6248       // -IntoBuffer version, which will recurse.  The -IntoBuffer methods
6249       // are able to assemble data from several part strings because they use
6250       // the util_buffer to store their data and never return direct pointers
6251       // to their storage.  We don't try to read more than the buffer capacity
6252       // here or we can get too much recursion.
6253       ASSERT(rbb->remaining == 0);
6254       ASSERT(rbb->cursor == 0);
6255       current->ConsStringReadBlockIntoBuffer(
6256           rbb,
6257           &offset,
6258           max_chars > rbb->capacity ? rbb->capacity : max_chars);
6259       *offset_ptr = offset + offset_correction;
6260       return rbb->util_buffer;
6261     }
6262   }
6263 }
6264 
6265 
ExternalAsciiStringReadBlock(unsigned * remaining,unsigned * offset_ptr,unsigned max_chars)6266 const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6267       unsigned* remaining,
6268       unsigned* offset_ptr,
6269       unsigned max_chars) {
6270   // Cast const char* to unibrow::byte* (signedness difference).
6271   const unibrow::byte* b =
6272       reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
6273   *remaining = max_chars;
6274   *offset_ptr += max_chars;
6275   return b;
6276 }
6277 
6278 
ExternalTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6279 void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6280       ReadBlockBuffer* rbb,
6281       unsigned* offset_ptr,
6282       unsigned max_chars) {
6283   unsigned chars_read = 0;
6284   unsigned offset = *offset_ptr;
6285   const uint16_t* data = GetChars();
6286   while (chars_read < max_chars) {
6287     uint16_t c = data[offset];
6288     if (c <= kMaxAsciiCharCode) {
6289       // Fast case for ASCII characters. Cursor is an input output argument.
6290       if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6291                                                           rbb->util_buffer,
6292                                                           rbb->capacity,
6293                                                           rbb->cursor))
6294         break;
6295     } else {
6296       if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6297                                                              rbb->util_buffer,
6298                                                              rbb->capacity,
6299                                                              rbb->cursor))
6300         break;
6301     }
6302     offset++;
6303     chars_read++;
6304   }
6305   *offset_ptr = offset;
6306   rbb->remaining += chars_read;
6307 }
6308 
6309 
SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6310 void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6311                                                  unsigned* offset_ptr,
6312                                                  unsigned max_chars) {
6313   unsigned capacity = rbb->capacity - rbb->cursor;
6314   if (max_chars > capacity) max_chars = capacity;
6315   memcpy(rbb->util_buffer + rbb->cursor,
6316          reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6317              *offset_ptr * kCharSize,
6318          max_chars);
6319   rbb->remaining += max_chars;
6320   *offset_ptr += max_chars;
6321   rbb->cursor += max_chars;
6322 }
6323 
6324 
ExternalAsciiStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6325 void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6326       ReadBlockBuffer* rbb,
6327       unsigned* offset_ptr,
6328       unsigned max_chars) {
6329   unsigned capacity = rbb->capacity - rbb->cursor;
6330   if (max_chars > capacity) max_chars = capacity;
6331   memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
6332   rbb->remaining += max_chars;
6333   *offset_ptr += max_chars;
6334   rbb->cursor += max_chars;
6335 }
6336 
6337 
6338 // This method determines the type of string involved and then copies
6339 // a whole chunk of characters into a buffer, or returns a pointer to a buffer
6340 // where they can be found.  The pointer is not necessarily valid across a GC
6341 // (see AsciiStringReadBlock).
ReadBlock(String * input,ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6342 const unibrow::byte* String::ReadBlock(String* input,
6343                                        ReadBlockBuffer* rbb,
6344                                        unsigned* offset_ptr,
6345                                        unsigned max_chars) {
6346   ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6347   if (max_chars == 0) {
6348     rbb->remaining = 0;
6349     return NULL;
6350   }
6351   switch (StringShape(input).representation_tag()) {
6352     case kSeqStringTag:
6353       if (input->IsAsciiRepresentation()) {
6354         SeqAsciiString* str = SeqAsciiString::cast(input);
6355         return str->SeqAsciiStringReadBlock(&rbb->remaining,
6356                                             offset_ptr,
6357                                             max_chars);
6358       } else {
6359         SeqTwoByteString* str = SeqTwoByteString::cast(input);
6360         str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6361                                                  offset_ptr,
6362                                                  max_chars);
6363         return rbb->util_buffer;
6364       }
6365     case kConsStringTag:
6366       return ConsString::cast(input)->ConsStringReadBlock(rbb,
6367                                                           offset_ptr,
6368                                                           max_chars);
6369     case kExternalStringTag:
6370       if (input->IsAsciiRepresentation()) {
6371         return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6372             &rbb->remaining,
6373             offset_ptr,
6374             max_chars);
6375       } else {
6376         ExternalTwoByteString::cast(input)->
6377             ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6378                                                      offset_ptr,
6379                                                      max_chars);
6380         return rbb->util_buffer;
6381       }
6382     case kSlicedStringTag:
6383       return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6384                                                               offset_ptr,
6385                                                               max_chars);
6386     default:
6387       break;
6388   }
6389 
6390   UNREACHABLE();
6391   return 0;
6392 }
6393 
6394 
PostGarbageCollectionProcessing()6395 void Relocatable::PostGarbageCollectionProcessing() {
6396   Isolate* isolate = Isolate::Current();
6397   Relocatable* current = isolate->relocatable_top();
6398   while (current != NULL) {
6399     current->PostGarbageCollection();
6400     current = current->prev_;
6401   }
6402 }
6403 
6404 
6405 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()6406 int Relocatable::ArchiveSpacePerThread() {
6407   return sizeof(Isolate::Current()->relocatable_top());
6408 }
6409 
6410 
6411 // Archive statics that are thread local.
ArchiveState(Isolate * isolate,char * to)6412 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
6413   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6414   isolate->set_relocatable_top(NULL);
6415   return to + ArchiveSpacePerThread();
6416 }
6417 
6418 
6419 // Restore statics that are thread local.
RestoreState(Isolate * isolate,char * from)6420 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
6421   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
6422   return from + ArchiveSpacePerThread();
6423 }
6424 
6425 
Iterate(ObjectVisitor * v,char * thread_storage)6426 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6427   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6428   Iterate(v, top);
6429   return thread_storage + ArchiveSpacePerThread();
6430 }
6431 
6432 
Iterate(ObjectVisitor * v)6433 void Relocatable::Iterate(ObjectVisitor* v) {
6434   Isolate* isolate = Isolate::Current();
6435   Iterate(v, isolate->relocatable_top());
6436 }
6437 
6438 
Iterate(ObjectVisitor * v,Relocatable * top)6439 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6440   Relocatable* current = top;
6441   while (current != NULL) {
6442     current->IterateInstance(v);
6443     current = current->prev_;
6444   }
6445 }
6446 
6447 
FlatStringReader(Isolate * isolate,Handle<String> str)6448 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6449     : Relocatable(isolate),
6450       str_(str.location()),
6451       length_(str->length()) {
6452   PostGarbageCollection();
6453 }
6454 
6455 
FlatStringReader(Isolate * isolate,Vector<const char> input)6456 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6457     : Relocatable(isolate),
6458       str_(0),
6459       is_ascii_(true),
6460       length_(input.length()),
6461       start_(input.start()) { }
6462 
6463 
PostGarbageCollection()6464 void FlatStringReader::PostGarbageCollection() {
6465   if (str_ == NULL) return;
6466   Handle<String> str(str_);
6467   ASSERT(str->IsFlat());
6468   String::FlatContent content = str->GetFlatContent();
6469   ASSERT(content.IsFlat());
6470   is_ascii_ = content.IsAscii();
6471   if (is_ascii_) {
6472     start_ = content.ToAsciiVector().start();
6473   } else {
6474     start_ = content.ToUC16Vector().start();
6475   }
6476 }
6477 
6478 
Seek(unsigned pos)6479 void StringInputBuffer::Seek(unsigned pos) {
6480   Reset(pos, input_);
6481 }
6482 
6483 
Seek(unsigned pos)6484 void SafeStringInputBuffer::Seek(unsigned pos) {
6485   Reset(pos, input_);
6486 }
6487 
6488 
6489 // This method determines the type of string involved and then copies
6490 // a whole chunk of characters into a buffer.  It can be used with strings
6491 // that have been glued together to form a ConsString and which must cooperate
6492 // to fill up a buffer.
ReadBlockIntoBuffer(String * input,ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6493 void String::ReadBlockIntoBuffer(String* input,
6494                                  ReadBlockBuffer* rbb,
6495                                  unsigned* offset_ptr,
6496                                  unsigned max_chars) {
6497   ASSERT(*offset_ptr <= (unsigned)input->length());
6498   if (max_chars == 0) return;
6499 
6500   switch (StringShape(input).representation_tag()) {
6501     case kSeqStringTag:
6502       if (input->IsAsciiRepresentation()) {
6503         SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
6504                                                                  offset_ptr,
6505                                                                  max_chars);
6506         return;
6507       } else {
6508         SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6509                                                                      offset_ptr,
6510                                                                      max_chars);
6511         return;
6512       }
6513     case kConsStringTag:
6514       ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6515                                                              offset_ptr,
6516                                                              max_chars);
6517       return;
6518     case kExternalStringTag:
6519       if (input->IsAsciiRepresentation()) {
6520         ExternalAsciiString::cast(input)->
6521             ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6522       } else {
6523         ExternalTwoByteString::cast(input)->
6524             ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6525                                                      offset_ptr,
6526                                                      max_chars);
6527        }
6528        return;
6529     case kSlicedStringTag:
6530       SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6531                                                                  offset_ptr,
6532                                                                  max_chars);
6533       return;
6534     default:
6535       break;
6536   }
6537 
6538   UNREACHABLE();
6539   return;
6540 }
6541 
6542 
ReadBlock(String * input,unibrow::byte * util_buffer,unsigned capacity,unsigned * remaining,unsigned * offset_ptr)6543 const unibrow::byte* String::ReadBlock(String* input,
6544                                        unibrow::byte* util_buffer,
6545                                        unsigned capacity,
6546                                        unsigned* remaining,
6547                                        unsigned* offset_ptr) {
6548   ASSERT(*offset_ptr <= (unsigned)input->length());
6549   unsigned chars = input->length() - *offset_ptr;
6550   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6551   const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
6552   ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6553   *remaining = rbb.remaining;
6554   return answer;
6555 }
6556 
6557 
ReadBlock(String ** raw_input,unibrow::byte * util_buffer,unsigned capacity,unsigned * remaining,unsigned * offset_ptr)6558 const unibrow::byte* String::ReadBlock(String** raw_input,
6559                                        unibrow::byte* util_buffer,
6560                                        unsigned capacity,
6561                                        unsigned* remaining,
6562                                        unsigned* offset_ptr) {
6563   Handle<String> input(raw_input);
6564   ASSERT(*offset_ptr <= (unsigned)input->length());
6565   unsigned chars = input->length() - *offset_ptr;
6566   if (chars > capacity) chars = capacity;
6567   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6568   ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
6569   ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6570   *remaining = rbb.remaining;
6571   return rbb.util_buffer;
6572 }
6573 
6574 
6575 // This will iterate unless the block of string data spans two 'halves' of
6576 // a ConsString, in which case it will recurse.  Since the block of string
6577 // data to be read has a maximum size this limits the maximum recursion
6578 // depth to something sane.  Since C++ does not have tail call recursion
6579 // elimination, the iteration must be explicit.
ConsStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6580 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6581                                                unsigned* offset_ptr,
6582                                                unsigned max_chars) {
6583   ConsString* current = this;
6584   unsigned offset = *offset_ptr;
6585   int offset_correction = 0;
6586 
6587   while (true) {
6588     String* left = current->first();
6589     unsigned left_length = (unsigned)left->length();
6590     if (left_length > offset &&
6591       max_chars <= left_length - offset) {
6592       // Left hand side only - iterate unless we have reached the bottom of
6593       // the cons tree.
6594       if (StringShape(left).IsCons()) {
6595         current = ConsString::cast(left);
6596         continue;
6597       } else {
6598         String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6599         *offset_ptr = offset + offset_correction;
6600         return;
6601       }
6602     } else if (left_length <= offset) {
6603       // Right hand side only - iterate unless we have reached the bottom of
6604       // the cons tree.
6605       offset -= left_length;
6606       offset_correction += left_length;
6607       String* right = current->second();
6608       if (StringShape(right).IsCons()) {
6609         current = ConsString::cast(right);
6610         continue;
6611       } else {
6612         String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6613         *offset_ptr = offset + offset_correction;
6614         return;
6615       }
6616     } else {
6617       // The block to be read spans two sides of the ConsString, so we recurse.
6618       // First recurse on the left.
6619       max_chars -= left_length - offset;
6620       String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6621       // We may have reached the max or there may not have been enough space
6622       // in the buffer for the characters in the left hand side.
6623       if (offset == left_length) {
6624         // Recurse on the right.
6625         String* right = String::cast(current->second());
6626         offset -= left_length;
6627         offset_correction += left_length;
6628         String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6629       }
6630       *offset_ptr = offset + offset_correction;
6631       return;
6632     }
6633   }
6634 }
6635 
6636 
ConsStringGet(int index)6637 uint16_t ConsString::ConsStringGet(int index) {
6638   ASSERT(index >= 0 && index < this->length());
6639 
6640   // Check for a flattened cons string
6641   if (second()->length() == 0) {
6642     String* left = first();
6643     return left->Get(index);
6644   }
6645 
6646   String* string = String::cast(this);
6647 
6648   while (true) {
6649     if (StringShape(string).IsCons()) {
6650       ConsString* cons_string = ConsString::cast(string);
6651       String* left = cons_string->first();
6652       if (left->length() > index) {
6653         string = left;
6654       } else {
6655         index -= left->length();
6656         string = cons_string->second();
6657       }
6658     } else {
6659       return string->Get(index);
6660     }
6661   }
6662 
6663   UNREACHABLE();
6664   return 0;
6665 }
6666 
6667 
SlicedStringGet(int index)6668 uint16_t SlicedString::SlicedStringGet(int index) {
6669   return parent()->Get(offset() + index);
6670 }
6671 
6672 
SlicedStringReadBlock(ReadBlockBuffer * buffer,unsigned * offset_ptr,unsigned chars)6673 const unibrow::byte* SlicedString::SlicedStringReadBlock(
6674     ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6675   unsigned offset = this->offset();
6676   *offset_ptr += offset;
6677   const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6678                                                   buffer, offset_ptr, chars);
6679   *offset_ptr -= offset;
6680   return answer;
6681 }
6682 
6683 
SlicedStringReadBlockIntoBuffer(ReadBlockBuffer * buffer,unsigned * offset_ptr,unsigned chars)6684 void SlicedString::SlicedStringReadBlockIntoBuffer(
6685     ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6686   unsigned offset = this->offset();
6687   *offset_ptr += offset;
6688   String::ReadBlockIntoBuffer(String::cast(parent()),
6689                               buffer, offset_ptr, chars);
6690   *offset_ptr -= offset;
6691 }
6692 
6693 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)6694 void String::WriteToFlat(String* src,
6695                          sinkchar* sink,
6696                          int f,
6697                          int t) {
6698   String* source = src;
6699   int from = f;
6700   int to = t;
6701   while (true) {
6702     ASSERT(0 <= from && from <= to && to <= source->length());
6703     switch (StringShape(source).full_representation_tag()) {
6704       case kAsciiStringTag | kExternalStringTag: {
6705         CopyChars(sink,
6706                   ExternalAsciiString::cast(source)->GetChars() + from,
6707                   to - from);
6708         return;
6709       }
6710       case kTwoByteStringTag | kExternalStringTag: {
6711         const uc16* data =
6712             ExternalTwoByteString::cast(source)->GetChars();
6713         CopyChars(sink,
6714                   data + from,
6715                   to - from);
6716         return;
6717       }
6718       case kAsciiStringTag | kSeqStringTag: {
6719         CopyChars(sink,
6720                   SeqAsciiString::cast(source)->GetChars() + from,
6721                   to - from);
6722         return;
6723       }
6724       case kTwoByteStringTag | kSeqStringTag: {
6725         CopyChars(sink,
6726                   SeqTwoByteString::cast(source)->GetChars() + from,
6727                   to - from);
6728         return;
6729       }
6730       case kAsciiStringTag | kConsStringTag:
6731       case kTwoByteStringTag | kConsStringTag: {
6732         ConsString* cons_string = ConsString::cast(source);
6733         String* first = cons_string->first();
6734         int boundary = first->length();
6735         if (to - boundary >= boundary - from) {
6736           // Right hand side is longer.  Recurse over left.
6737           if (from < boundary) {
6738             WriteToFlat(first, sink, from, boundary);
6739             sink += boundary - from;
6740             from = 0;
6741           } else {
6742             from -= boundary;
6743           }
6744           to -= boundary;
6745           source = cons_string->second();
6746         } else {
6747           // Left hand side is longer.  Recurse over right.
6748           if (to > boundary) {
6749             String* second = cons_string->second();
6750             // When repeatedly appending to a string, we get a cons string that
6751             // is unbalanced to the left, a list, essentially.  We inline the
6752             // common case of sequential ascii right child.
6753             if (to - boundary == 1) {
6754               sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
6755             } else if (second->IsSeqAsciiString()) {
6756               CopyChars(sink + boundary - from,
6757                         SeqAsciiString::cast(second)->GetChars(),
6758                         to - boundary);
6759             } else {
6760               WriteToFlat(second,
6761                           sink + boundary - from,
6762                           0,
6763                           to - boundary);
6764             }
6765             to = boundary;
6766           }
6767           source = first;
6768         }
6769         break;
6770       }
6771       case kAsciiStringTag | kSlicedStringTag:
6772       case kTwoByteStringTag | kSlicedStringTag: {
6773         SlicedString* slice = SlicedString::cast(source);
6774         unsigned offset = slice->offset();
6775         WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6776         return;
6777       }
6778     }
6779   }
6780 }
6781 
6782 
6783 template <typename IteratorA, typename IteratorB>
CompareStringContents(IteratorA * ia,IteratorB * ib)6784 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6785   // General slow case check.  We know that the ia and ib iterators
6786   // have the same length.
6787   while (ia->has_more()) {
6788     uint32_t ca = ia->GetNext();
6789     uint32_t cb = ib->GetNext();
6790     ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6791     ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6792     if (ca != cb)
6793       return false;
6794   }
6795   return true;
6796 }
6797 
6798 
6799 // Compares the contents of two strings by reading and comparing
6800 // int-sized blocks of characters.
6801 template <typename Char>
CompareRawStringContents(Vector<Char> a,Vector<Char> b)6802 static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6803   int length = a.length();
6804   ASSERT_EQ(length, b.length());
6805   const Char* pa = a.start();
6806   const Char* pb = b.start();
6807   int i = 0;
6808 #ifndef V8_HOST_CAN_READ_UNALIGNED
6809   // If this architecture isn't comfortable reading unaligned ints
6810   // then we have to check that the strings are aligned before
6811   // comparing them blockwise.
6812   const int kAlignmentMask = sizeof(uint32_t) - 1;  // NOLINT
6813   uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6814   uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
6815   if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
6816 #endif
6817     const int kStepSize = sizeof(int) / sizeof(Char);  // NOLINT
6818     int endpoint = length - kStepSize;
6819     // Compare blocks until we reach near the end of the string.
6820     for (; i <= endpoint; i += kStepSize) {
6821       uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6822       uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6823       if (wa != wb) {
6824         return false;
6825       }
6826     }
6827 #ifndef V8_HOST_CAN_READ_UNALIGNED
6828   }
6829 #endif
6830   // Compare the remaining characters that didn't fit into a block.
6831   for (; i < length; i++) {
6832     if (a[i] != b[i]) {
6833       return false;
6834     }
6835   }
6836   return true;
6837 }
6838 
6839 
6840 template <typename IteratorA>
CompareStringContentsPartial(Isolate * isolate,IteratorA * ia,String * b)6841 static inline bool CompareStringContentsPartial(Isolate* isolate,
6842                                                 IteratorA* ia,
6843                                                 String* b) {
6844   String::FlatContent content = b->GetFlatContent();
6845   if (content.IsFlat()) {
6846     if (content.IsAscii()) {
6847       VectorIterator<char> ib(content.ToAsciiVector());
6848       return CompareStringContents(ia, &ib);
6849     } else {
6850       VectorIterator<uc16> ib(content.ToUC16Vector());
6851       return CompareStringContents(ia, &ib);
6852     }
6853   } else {
6854     isolate->objects_string_compare_buffer_b()->Reset(0, b);
6855     return CompareStringContents(ia,
6856                                  isolate->objects_string_compare_buffer_b());
6857   }
6858 }
6859 
6860 
SlowEquals(String * other)6861 bool String::SlowEquals(String* other) {
6862   // Fast check: negative check with lengths.
6863   int len = length();
6864   if (len != other->length()) return false;
6865   if (len == 0) return true;
6866 
6867   // Fast check: if hash code is computed for both strings
6868   // a fast negative check can be performed.
6869   if (HasHashCode() && other->HasHashCode()) {
6870 #ifdef DEBUG
6871     if (FLAG_enable_slow_asserts) {
6872       if (Hash() != other->Hash()) {
6873         bool found_difference = false;
6874         for (int i = 0; i < len; i++) {
6875           if (Get(i) != other->Get(i)) {
6876             found_difference = true;
6877             break;
6878           }
6879         }
6880         ASSERT(found_difference);
6881       }
6882     }
6883 #endif
6884     if (Hash() != other->Hash()) return false;
6885   }
6886 
6887   // We know the strings are both non-empty. Compare the first chars
6888   // before we try to flatten the strings.
6889   if (this->Get(0) != other->Get(0)) return false;
6890 
6891   String* lhs = this->TryFlattenGetString();
6892   String* rhs = other->TryFlattenGetString();
6893 
6894   if (StringShape(lhs).IsSequentialAscii() &&
6895       StringShape(rhs).IsSequentialAscii()) {
6896     const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6897     const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
6898     return CompareRawStringContents(Vector<const char>(str1, len),
6899                                     Vector<const char>(str2, len));
6900   }
6901 
6902   Isolate* isolate = GetIsolate();
6903   String::FlatContent lhs_content = lhs->GetFlatContent();
6904   String::FlatContent rhs_content = rhs->GetFlatContent();
6905   if (lhs_content.IsFlat()) {
6906     if (lhs_content.IsAscii()) {
6907       Vector<const char> vec1 = lhs_content.ToAsciiVector();
6908       if (rhs_content.IsFlat()) {
6909         if (rhs_content.IsAscii()) {
6910           Vector<const char> vec2 = rhs_content.ToAsciiVector();
6911           return CompareRawStringContents(vec1, vec2);
6912         } else {
6913           VectorIterator<char> buf1(vec1);
6914           VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
6915           return CompareStringContents(&buf1, &ib);
6916         }
6917       } else {
6918         VectorIterator<char> buf1(vec1);
6919         isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6920         return CompareStringContents(&buf1,
6921             isolate->objects_string_compare_buffer_b());
6922       }
6923     } else {
6924       Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6925       if (rhs_content.IsFlat()) {
6926         if (rhs_content.IsAscii()) {
6927           VectorIterator<uc16> buf1(vec1);
6928           VectorIterator<char> ib(rhs_content.ToAsciiVector());
6929           return CompareStringContents(&buf1, &ib);
6930         } else {
6931           Vector<const uc16> vec2(rhs_content.ToUC16Vector());
6932           return CompareRawStringContents(vec1, vec2);
6933         }
6934       } else {
6935         VectorIterator<uc16> buf1(vec1);
6936         isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6937         return CompareStringContents(&buf1,
6938             isolate->objects_string_compare_buffer_b());
6939       }
6940     }
6941   } else {
6942     isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6943     return CompareStringContentsPartial(isolate,
6944         isolate->objects_string_compare_buffer_a(), rhs);
6945   }
6946 }
6947 
6948 
MarkAsUndetectable()6949 bool String::MarkAsUndetectable() {
6950   if (StringShape(this).IsSymbol()) return false;
6951 
6952   Map* map = this->map();
6953   Heap* heap = GetHeap();
6954   if (map == heap->string_map()) {
6955     this->set_map(heap->undetectable_string_map());
6956     return true;
6957   } else if (map == heap->ascii_string_map()) {
6958     this->set_map(heap->undetectable_ascii_string_map());
6959     return true;
6960   }
6961   // Rest cannot be marked as undetectable
6962   return false;
6963 }
6964 
6965 
IsEqualTo(Vector<const char> str)6966 bool String::IsEqualTo(Vector<const char> str) {
6967   Isolate* isolate = GetIsolate();
6968   int slen = length();
6969   Access<UnicodeCache::Utf8Decoder>
6970       decoder(isolate->unicode_cache()->utf8_decoder());
6971   decoder->Reset(str.start(), str.length());
6972   int i;
6973   for (i = 0; i < slen && decoder->has_more(); i++) {
6974     uint32_t r = decoder->GetNext();
6975     if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
6976       if (i > slen - 1) return false;
6977       if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
6978       if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
6979     } else {
6980       if (Get(i) != r) return false;
6981     }
6982   }
6983   return i == slen && !decoder->has_more();
6984 }
6985 
6986 
IsAsciiEqualTo(Vector<const char> str)6987 bool String::IsAsciiEqualTo(Vector<const char> str) {
6988   int slen = length();
6989   if (str.length() != slen) return false;
6990   FlatContent content = GetFlatContent();
6991   if (content.IsAscii()) {
6992     return CompareChars(content.ToAsciiVector().start(),
6993                         str.start(), slen) == 0;
6994   }
6995   for (int i = 0; i < slen; i++) {
6996     if (Get(i) != static_cast<uint16_t>(str[i])) return false;
6997   }
6998   return true;
6999 }
7000 
7001 
IsTwoByteEqualTo(Vector<const uc16> str)7002 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
7003   int slen = length();
7004   if (str.length() != slen) return false;
7005   FlatContent content = GetFlatContent();
7006   if (content.IsTwoByte()) {
7007     return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
7008   }
7009   for (int i = 0; i < slen; i++) {
7010     if (Get(i) != str[i]) return false;
7011   }
7012   return true;
7013 }
7014 
7015 
ComputeAndSetHash()7016 uint32_t String::ComputeAndSetHash() {
7017   // Should only be called if hash code has not yet been computed.
7018   ASSERT(!HasHashCode());
7019 
7020   const int len = length();
7021 
7022   // Compute the hash code.
7023   uint32_t field = 0;
7024   if (StringShape(this).IsSequentialAscii()) {
7025     field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
7026                                  len,
7027                                  GetHeap()->HashSeed());
7028   } else if (StringShape(this).IsSequentialTwoByte()) {
7029     field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
7030                                  len,
7031                                  GetHeap()->HashSeed());
7032   } else {
7033     StringInputBuffer buffer(this);
7034     field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
7035   }
7036 
7037   // Store the hash code in the object.
7038   set_hash_field(field);
7039 
7040   // Check the hash code is there.
7041   ASSERT(HasHashCode());
7042   uint32_t result = field >> kHashShift;
7043   ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
7044   return result;
7045 }
7046 
7047 
ComputeArrayIndex(unibrow::CharacterStream * buffer,uint32_t * index,int length)7048 bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
7049                                uint32_t* index,
7050                                int length) {
7051   if (length == 0 || length > kMaxArrayIndexSize) return false;
7052   uc32 ch = buffer->GetNext();
7053 
7054   // If the string begins with a '0' character, it must only consist
7055   // of it to be a legal array index.
7056   if (ch == '0') {
7057     *index = 0;
7058     return length == 1;
7059   }
7060 
7061   // Convert string to uint32 array index; character by character.
7062   int d = ch - '0';
7063   if (d < 0 || d > 9) return false;
7064   uint32_t result = d;
7065   while (buffer->has_more()) {
7066     d = buffer->GetNext() - '0';
7067     if (d < 0 || d > 9) return false;
7068     // Check that the new result is below the 32 bit limit.
7069     if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7070     result = (result * 10) + d;
7071   }
7072 
7073   *index = result;
7074   return true;
7075 }
7076 
7077 
SlowAsArrayIndex(uint32_t * index)7078 bool String::SlowAsArrayIndex(uint32_t* index) {
7079   if (length() <= kMaxCachedArrayIndexLength) {
7080     Hash();  // force computation of hash code
7081     uint32_t field = hash_field();
7082     if ((field & kIsNotArrayIndexMask) != 0) return false;
7083     // Isolate the array index form the full hash field.
7084     *index = (kArrayIndexHashMask & field) >> kHashShift;
7085     return true;
7086   } else {
7087     StringInputBuffer buffer(this);
7088     return ComputeArrayIndex(&buffer, index, length());
7089   }
7090 }
7091 
7092 
MakeArrayIndexHash(uint32_t value,int length)7093 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
7094   // For array indexes mix the length into the hash as an array index could
7095   // be zero.
7096   ASSERT(length > 0);
7097   ASSERT(length <= String::kMaxArrayIndexSize);
7098   ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7099          (1 << String::kArrayIndexValueBits));
7100 
7101   value <<= String::kHashShift;
7102   value |= length << String::kArrayIndexHashLengthShift;
7103 
7104   ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7105   ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7106          (value & String::kContainsCachedArrayIndexMask) == 0);
7107   return value;
7108 }
7109 
7110 
AddSurrogatePair(uc32 c)7111 void StringHasher::AddSurrogatePair(uc32 c) {
7112   uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7113   AddCharacter(lead);
7114   uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7115   AddCharacter(trail);
7116 }
7117 
7118 
AddSurrogatePairNoIndex(uc32 c)7119 void StringHasher::AddSurrogatePairNoIndex(uc32 c) {
7120   uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7121   AddCharacterNoIndex(lead);
7122   uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7123   AddCharacterNoIndex(trail);
7124 }
7125 
7126 
GetHashField()7127 uint32_t StringHasher::GetHashField() {
7128   ASSERT(is_valid());
7129   if (length_ <= String::kMaxHashCalcLength) {
7130     if (is_array_index()) {
7131       return MakeArrayIndexHash(array_index(), length_);
7132     }
7133     return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
7134   } else {
7135     return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
7136   }
7137 }
7138 
7139 
ComputeHashField(unibrow::CharacterStream * buffer,int length,uint32_t seed)7140 uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
7141                                   int length,
7142                                   uint32_t seed) {
7143   StringHasher hasher(length, seed);
7144 
7145   // Very long strings have a trivial hash that doesn't inspect the
7146   // string contents.
7147   if (hasher.has_trivial_hash()) {
7148     return hasher.GetHashField();
7149   }
7150 
7151   // Do the iterative array index computation as long as there is a
7152   // chance this is an array index.
7153   while (buffer->has_more() && hasher.is_array_index()) {
7154     hasher.AddCharacter(buffer->GetNext());
7155   }
7156 
7157   // Process the remaining characters without updating the array
7158   // index.
7159   while (buffer->has_more()) {
7160     hasher.AddCharacterNoIndex(buffer->GetNext());
7161   }
7162 
7163   return hasher.GetHashField();
7164 }
7165 
7166 
SubString(int start,int end,PretenureFlag pretenure)7167 MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
7168   Heap* heap = GetHeap();
7169   if (start == 0 && end == length()) return this;
7170   MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
7171   return result;
7172 }
7173 
7174 
PrintOn(FILE * file)7175 void String::PrintOn(FILE* file) {
7176   int length = this->length();
7177   for (int i = 0; i < length; i++) {
7178     fprintf(file, "%c", Get(i));
7179   }
7180 }
7181 
7182 
CreateOneBackPointer(Object * transition_target)7183 void Map::CreateOneBackPointer(Object* transition_target) {
7184   if (!transition_target->IsMap()) return;
7185   Map* target = Map::cast(transition_target);
7186 #ifdef DEBUG
7187   // Verify target.
7188   Object* source_prototype = prototype();
7189   Object* target_prototype = target->prototype();
7190   ASSERT(source_prototype->IsJSReceiver() ||
7191          source_prototype->IsMap() ||
7192          source_prototype->IsNull());
7193   ASSERT(target_prototype->IsJSReceiver() ||
7194          target_prototype->IsNull());
7195   ASSERT(source_prototype->IsMap() ||
7196          source_prototype == target_prototype);
7197 #endif
7198   // Point target back to source.  set_prototype() will not let us set
7199   // the prototype to a map, as we do here.
7200   *RawField(target, kPrototypeOffset) = this;
7201 }
7202 
7203 
CreateBackPointers()7204 void Map::CreateBackPointers() {
7205   DescriptorArray* descriptors = instance_descriptors();
7206   for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
7207     switch (descriptors->GetType(i)) {
7208       case MAP_TRANSITION:
7209       case CONSTANT_TRANSITION:
7210         CreateOneBackPointer(descriptors->GetValue(i));
7211         break;
7212       case ELEMENTS_TRANSITION: {
7213         Object* object = descriptors->GetValue(i);
7214         if (object->IsMap()) {
7215           CreateOneBackPointer(object);
7216         } else {
7217           FixedArray* array = FixedArray::cast(object);
7218           for (int i = 0; i < array->length(); ++i) {
7219             CreateOneBackPointer(array->get(i));
7220           }
7221         }
7222         break;
7223       }
7224       case CALLBACKS: {
7225         Object* object = descriptors->GetValue(i);
7226         if (object->IsAccessorPair()) {
7227           AccessorPair* accessors = AccessorPair::cast(object);
7228           CreateOneBackPointer(accessors->getter());
7229           CreateOneBackPointer(accessors->setter());
7230         }
7231         break;
7232       }
7233       case NORMAL:
7234       case FIELD:
7235       case CONSTANT_FUNCTION:
7236       case HANDLER:
7237       case INTERCEPTOR:
7238       case NULL_DESCRIPTOR:
7239         break;
7240     }
7241   }
7242 }
7243 
7244 
RestoreOneBackPointer(Object * object,Object * real_prototype,bool * keep_entry)7245 bool Map::RestoreOneBackPointer(Object* object,
7246                                 Object* real_prototype,
7247                                 bool* keep_entry) {
7248   if (!object->IsMap()) return false;
7249   Map* map = Map::cast(object);
7250   if (Marking::MarkBitFrom(map).Get()) {
7251     *keep_entry = true;
7252     return false;
7253   }
7254   ASSERT(map->prototype() == this || map->prototype() == real_prototype);
7255   // Getter prototype() is read-only, set_prototype() has side effects.
7256   *RawField(map, Map::kPrototypeOffset) = real_prototype;
7257   return true;
7258 }
7259 
7260 
ClearNonLiveTransitions(Heap * heap,Object * real_prototype)7261 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
7262   DescriptorArray* d = DescriptorArray::cast(
7263       *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7264   if (d->IsEmpty()) return;
7265   Smi* NullDescriptorDetails =
7266     PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
7267   FixedArray* contents = FixedArray::cast(
7268       d->get(DescriptorArray::kContentArrayIndex));
7269   ASSERT(contents->length() >= 2);
7270   for (int i = 0; i < contents->length(); i += 2) {
7271     // If the pair (value, details) is a map transition, check if the target is
7272     // live. If not, null the descriptor. Also drop the back pointer for that
7273     // map transition, so that this map is not reached again by following a back
7274     // pointer from a non-live object.
7275     bool keep_entry = false;
7276     PropertyDetails details(Smi::cast(contents->get(i + 1)));
7277     switch (details.type()) {
7278       case MAP_TRANSITION:
7279       case CONSTANT_TRANSITION:
7280         RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
7281         break;
7282       case ELEMENTS_TRANSITION: {
7283         Object* object = contents->get(i);
7284         if (object->IsMap()) {
7285           RestoreOneBackPointer(object, real_prototype, &keep_entry);
7286         } else {
7287           FixedArray* array = FixedArray::cast(object);
7288           for (int j = 0; j < array->length(); ++j) {
7289             if (RestoreOneBackPointer(array->get(j),
7290                                       real_prototype,
7291                                       &keep_entry)) {
7292               array->set_undefined(j);
7293             }
7294           }
7295         }
7296         break;
7297       }
7298       case CALLBACKS: {
7299         Object* object = contents->get(i);
7300         if (object->IsAccessorPair()) {
7301           AccessorPair* accessors = AccessorPair::cast(object);
7302           if (RestoreOneBackPointer(accessors->getter(),
7303                                     real_prototype,
7304                                     &keep_entry)) {
7305             accessors->set_getter(heap->the_hole_value());
7306           }
7307           if (RestoreOneBackPointer(accessors->setter(),
7308                                     real_prototype,
7309                                     &keep_entry)) {
7310             accessors->set_setter(heap->the_hole_value());
7311           }
7312         } else {
7313           keep_entry = true;
7314         }
7315         break;
7316       }
7317       case NORMAL:
7318       case FIELD:
7319       case CONSTANT_FUNCTION:
7320       case HANDLER:
7321       case INTERCEPTOR:
7322       case NULL_DESCRIPTOR:
7323         keep_entry = true;
7324         break;
7325     }
7326     // Make sure that an entry containing only dead transitions gets collected.
7327     // What we *really* want to do here is removing this entry completely, but
7328     // for technical reasons we can't do this, so we zero it out instead.
7329     if (!keep_entry) {
7330       contents->set_unchecked(i + 1, NullDescriptorDetails);
7331       contents->set_null_unchecked(heap, i);
7332     }
7333   }
7334 }
7335 
7336 
Hash()7337 int Map::Hash() {
7338   // For performance reasons we only hash the 3 most variable fields of a map:
7339   // constructor, prototype and bit_field2.
7340 
7341   // Shift away the tag.
7342   int hash = (static_cast<uint32_t>(
7343         reinterpret_cast<uintptr_t>(constructor())) >> 2);
7344 
7345   // XOR-ing the prototype and constructor directly yields too many zero bits
7346   // when the two pointers are close (which is fairly common).
7347   // To avoid this we shift the prototype 4 bits relatively to the constructor.
7348   hash ^= (static_cast<uint32_t>(
7349         reinterpret_cast<uintptr_t>(prototype())) << 2);
7350 
7351   return hash ^ (hash >> 16) ^ bit_field2();
7352 }
7353 
7354 
EquivalentToForNormalization(Map * other,PropertyNormalizationMode mode)7355 bool Map::EquivalentToForNormalization(Map* other,
7356                                        PropertyNormalizationMode mode) {
7357   return
7358     constructor() == other->constructor() &&
7359     prototype() == other->prototype() &&
7360     inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7361                               0 :
7362                               other->inobject_properties()) &&
7363     instance_type() == other->instance_type() &&
7364     bit_field() == other->bit_field() &&
7365     bit_field2() == other->bit_field2() &&
7366     (bit_field3() & ~(1<<Map::kIsShared)) ==
7367         (other->bit_field3() & ~(1<<Map::kIsShared));
7368 }
7369 
7370 
JSFunctionIterateBody(int object_size,ObjectVisitor * v)7371 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7372   // Iterate over all fields in the body but take care in dealing with
7373   // the code entry.
7374   IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7375   v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7376   IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7377 }
7378 
7379 
MarkForLazyRecompilation()7380 void JSFunction::MarkForLazyRecompilation() {
7381   ASSERT(is_compiled() && !IsOptimized());
7382   ASSERT(shared()->allows_lazy_compilation() ||
7383          code()->optimizable());
7384   Builtins* builtins = GetIsolate()->builtins();
7385   ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
7386 }
7387 
7388 
EnsureCompiled(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)7389 bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7390                                         ClearExceptionFlag flag) {
7391   return shared->is_compiled() || CompileLazy(shared, flag);
7392 }
7393 
7394 
CompileLazyHelper(CompilationInfo * info,ClearExceptionFlag flag)7395 static bool CompileLazyHelper(CompilationInfo* info,
7396                               ClearExceptionFlag flag) {
7397   // Compile the source information to a code object.
7398   ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7399   ASSERT(!info->isolate()->has_pending_exception());
7400   bool result = Compiler::CompileLazy(info);
7401   ASSERT(result != Isolate::Current()->has_pending_exception());
7402   if (!result && flag == CLEAR_EXCEPTION) {
7403     info->isolate()->clear_pending_exception();
7404   }
7405   return result;
7406 }
7407 
7408 
CompileLazy(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)7409 bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7410                                      ClearExceptionFlag flag) {
7411   CompilationInfo info(shared);
7412   return CompileLazyHelper(&info, flag);
7413 }
7414 
7415 
CompileLazy(Handle<JSFunction> function,ClearExceptionFlag flag)7416 bool JSFunction::CompileLazy(Handle<JSFunction> function,
7417                              ClearExceptionFlag flag) {
7418   bool result = true;
7419   if (function->shared()->is_compiled()) {
7420     function->ReplaceCode(function->shared()->code());
7421     function->shared()->set_code_age(0);
7422   } else {
7423     CompilationInfo info(function);
7424     result = CompileLazyHelper(&info, flag);
7425     ASSERT(!result || function->is_compiled());
7426   }
7427   return result;
7428 }
7429 
7430 
CompileOptimized(Handle<JSFunction> function,int osr_ast_id,ClearExceptionFlag flag)7431 bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7432                                   int osr_ast_id,
7433                                   ClearExceptionFlag flag) {
7434   CompilationInfo info(function);
7435   info.SetOptimizing(osr_ast_id);
7436   return CompileLazyHelper(&info, flag);
7437 }
7438 
7439 
IsInlineable()7440 bool JSFunction::IsInlineable() {
7441   if (IsBuiltin()) return false;
7442   SharedFunctionInfo* shared_info = shared();
7443   // Check that the function has a script associated with it.
7444   if (!shared_info->script()->IsScript()) return false;
7445   if (shared_info->optimization_disabled()) return false;
7446   Code* code = shared_info->code();
7447   if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7448   // If we never ran this (unlikely) then lets try to optimize it.
7449   if (code->kind() != Code::FUNCTION) return true;
7450   return code->optimizable();
7451 }
7452 
7453 
SetInstancePrototype(Object * value)7454 MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
7455   ASSERT(value->IsJSReceiver());
7456   Heap* heap = GetHeap();
7457   if (has_initial_map()) {
7458     // If the function has allocated the initial map
7459     // replace it with a copy containing the new prototype.
7460     Map* new_map;
7461     MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
7462     if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7463     new_map->set_prototype(value);
7464     MaybeObject* maybe_object =
7465         set_initial_map_and_cache_transitions(new_map);
7466     if (maybe_object->IsFailure()) return maybe_object;
7467   } else {
7468     // Put the value in the initial map field until an initial map is
7469     // needed.  At that point, a new initial map is created and the
7470     // prototype is put into the initial map where it belongs.
7471     set_prototype_or_initial_map(value);
7472   }
7473   heap->ClearInstanceofCache();
7474   return value;
7475 }
7476 
7477 
SetPrototype(Object * value)7478 MaybeObject* JSFunction::SetPrototype(Object* value) {
7479   ASSERT(should_have_prototype());
7480   Object* construct_prototype = value;
7481 
7482   // If the value is not a JSReceiver, store the value in the map's
7483   // constructor field so it can be accessed.  Also, set the prototype
7484   // used for constructing objects to the original object prototype.
7485   // See ECMA-262 13.2.2.
7486   if (!value->IsJSReceiver()) {
7487     // Copy the map so this does not affect unrelated functions.
7488     // Remove map transitions because they point to maps with a
7489     // different prototype.
7490     Map* new_map;
7491     { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
7492       if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7493     }
7494     Heap* heap = new_map->GetHeap();
7495     set_map(new_map);
7496     new_map->set_constructor(value);
7497     new_map->set_non_instance_prototype(true);
7498     construct_prototype =
7499         heap->isolate()->context()->global_context()->
7500             initial_object_prototype();
7501   } else {
7502     map()->set_non_instance_prototype(false);
7503   }
7504 
7505   return SetInstancePrototype(construct_prototype);
7506 }
7507 
7508 
RemovePrototype()7509 Object* JSFunction::RemovePrototype() {
7510   Context* global_context = context()->global_context();
7511   Map* no_prototype_map = shared()->is_classic_mode()
7512       ? global_context->function_without_prototype_map()
7513       : global_context->strict_mode_function_without_prototype_map();
7514 
7515   if (map() == no_prototype_map) {
7516     // Be idempotent.
7517     return this;
7518   }
7519 
7520   ASSERT(map() == (shared()->is_classic_mode()
7521                    ? global_context->function_map()
7522                    : global_context->strict_mode_function_map()));
7523 
7524   set_map(no_prototype_map);
7525   set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
7526   return this;
7527 }
7528 
7529 
SetInstanceClassName(String * name)7530 Object* JSFunction::SetInstanceClassName(String* name) {
7531   shared()->set_instance_class_name(name);
7532   return this;
7533 }
7534 
7535 
PrintName(FILE * out)7536 void JSFunction::PrintName(FILE* out) {
7537   SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
7538   PrintF(out, "%s", *name);
7539 }
7540 
7541 
GlobalContextFromLiterals(FixedArray * literals)7542 Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7543   return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7544 }
7545 
7546 
Initialize(const char * to_string,Object * to_number,byte kind)7547 MaybeObject* Oddball::Initialize(const char* to_string,
7548                                  Object* to_number,
7549                                  byte kind) {
7550   String* symbol;
7551   { MaybeObject* maybe_symbol =
7552         Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
7553     if (!maybe_symbol->To(&symbol)) return maybe_symbol;
7554   }
7555   set_to_string(symbol);
7556   set_to_number(to_number);
7557   set_kind(kind);
7558   return this;
7559 }
7560 
7561 
DebugName()7562 String* SharedFunctionInfo::DebugName() {
7563   Object* n = name();
7564   if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7565   return String::cast(n);
7566 }
7567 
7568 
HasSourceCode()7569 bool SharedFunctionInfo::HasSourceCode() {
7570   return !script()->IsUndefined() &&
7571          !reinterpret_cast<Script*>(script())->source()->IsUndefined();
7572 }
7573 
7574 
GetSourceCode()7575 Handle<Object> SharedFunctionInfo::GetSourceCode() {
7576   if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
7577   Handle<String> source(String::cast(Script::cast(script())->source()));
7578   return SubString(source, start_position(), end_position());
7579 }
7580 
7581 
SourceSize()7582 int SharedFunctionInfo::SourceSize() {
7583   return end_position() - start_position();
7584 }
7585 
7586 
CalculateInstanceSize()7587 int SharedFunctionInfo::CalculateInstanceSize() {
7588   int instance_size =
7589       JSObject::kHeaderSize +
7590       expected_nof_properties() * kPointerSize;
7591   if (instance_size > JSObject::kMaxInstanceSize) {
7592     instance_size = JSObject::kMaxInstanceSize;
7593   }
7594   return instance_size;
7595 }
7596 
7597 
CalculateInObjectProperties()7598 int SharedFunctionInfo::CalculateInObjectProperties() {
7599   return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7600 }
7601 
7602 
CanGenerateInlineConstructor(Object * prototype)7603 bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7604   // Check the basic conditions for generating inline constructor code.
7605   if (!FLAG_inline_new
7606       || !has_only_simple_this_property_assignments()
7607       || this_property_assignments_count() == 0) {
7608     return false;
7609   }
7610 
7611   // If the prototype is null inline constructors cause no problems.
7612   if (!prototype->IsJSObject()) {
7613     ASSERT(prototype->IsNull());
7614     return true;
7615   }
7616 
7617   Heap* heap = GetHeap();
7618 
7619   // Traverse the proposed prototype chain looking for setters for properties of
7620   // the same names as are set by the inline constructor.
7621   for (Object* obj = prototype;
7622        obj != heap->null_value();
7623        obj = obj->GetPrototype()) {
7624     JSObject* js_object = JSObject::cast(obj);
7625     for (int i = 0; i < this_property_assignments_count(); i++) {
7626       LookupResult result(heap->isolate());
7627       String* name = GetThisPropertyAssignmentName(i);
7628       js_object->LocalLookupRealNamedProperty(name, &result);
7629       if (result.IsFound() && result.type() == CALLBACKS) {
7630         return false;
7631       }
7632     }
7633   }
7634 
7635   return true;
7636 }
7637 
7638 
ForbidInlineConstructor()7639 void SharedFunctionInfo::ForbidInlineConstructor() {
7640   set_compiler_hints(BooleanBit::set(compiler_hints(),
7641                                      kHasOnlySimpleThisPropertyAssignments,
7642                                      false));
7643 }
7644 
7645 
SetThisPropertyAssignmentsInfo(bool only_simple_this_property_assignments,FixedArray * assignments)7646 void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
7647     bool only_simple_this_property_assignments,
7648     FixedArray* assignments) {
7649   set_compiler_hints(BooleanBit::set(compiler_hints(),
7650                                      kHasOnlySimpleThisPropertyAssignments,
7651                                      only_simple_this_property_assignments));
7652   set_this_property_assignments(assignments);
7653   set_this_property_assignments_count(assignments->length() / 3);
7654 }
7655 
7656 
ClearThisPropertyAssignmentsInfo()7657 void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
7658   Heap* heap = GetHeap();
7659   set_compiler_hints(BooleanBit::set(compiler_hints(),
7660                                      kHasOnlySimpleThisPropertyAssignments,
7661                                      false));
7662   set_this_property_assignments(heap->undefined_value());
7663   set_this_property_assignments_count(0);
7664 }
7665 
7666 
GetThisPropertyAssignmentName(int index)7667 String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7668   Object* obj = this_property_assignments();
7669   ASSERT(obj->IsFixedArray());
7670   ASSERT(index < this_property_assignments_count());
7671   obj = FixedArray::cast(obj)->get(index * 3);
7672   ASSERT(obj->IsString());
7673   return String::cast(obj);
7674 }
7675 
7676 
IsThisPropertyAssignmentArgument(int index)7677 bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7678   Object* obj = this_property_assignments();
7679   ASSERT(obj->IsFixedArray());
7680   ASSERT(index < this_property_assignments_count());
7681   obj = FixedArray::cast(obj)->get(index * 3 + 1);
7682   return Smi::cast(obj)->value() != -1;
7683 }
7684 
7685 
GetThisPropertyAssignmentArgument(int index)7686 int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7687   ASSERT(IsThisPropertyAssignmentArgument(index));
7688   Object* obj =
7689       FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7690   return Smi::cast(obj)->value();
7691 }
7692 
7693 
GetThisPropertyAssignmentConstant(int index)7694 Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7695   ASSERT(!IsThisPropertyAssignmentArgument(index));
7696   Object* obj =
7697       FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7698   return obj;
7699 }
7700 
7701 
7702 // Support function for printing the source code to a StringStream
7703 // without any allocation in the heap.
SourceCodePrint(StringStream * accumulator,int max_length)7704 void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7705                                          int max_length) {
7706   // For some native functions there is no source.
7707   if (!HasSourceCode()) {
7708     accumulator->Add("<No Source>");
7709     return;
7710   }
7711 
7712   // Get the source for the script which this function came from.
7713   // Don't use String::cast because we don't want more assertion errors while
7714   // we are already creating a stack dump.
7715   String* script_source =
7716       reinterpret_cast<String*>(Script::cast(script())->source());
7717 
7718   if (!script_source->LooksValid()) {
7719     accumulator->Add("<Invalid Source>");
7720     return;
7721   }
7722 
7723   if (!is_toplevel()) {
7724     accumulator->Add("function ");
7725     Object* name = this->name();
7726     if (name->IsString() && String::cast(name)->length() > 0) {
7727       accumulator->PrintName(name);
7728     }
7729   }
7730 
7731   int len = end_position() - start_position();
7732   if (len <= max_length || max_length < 0) {
7733     accumulator->Put(script_source, start_position(), end_position());
7734   } else {
7735     accumulator->Put(script_source,
7736                      start_position(),
7737                      start_position() + max_length);
7738     accumulator->Add("...\n");
7739   }
7740 }
7741 
7742 
IsCodeEquivalent(Code * code,Code * recompiled)7743 static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7744   if (code->instruction_size() != recompiled->instruction_size()) return false;
7745   ByteArray* code_relocation = code->relocation_info();
7746   ByteArray* recompiled_relocation = recompiled->relocation_info();
7747   int length = code_relocation->length();
7748   if (length != recompiled_relocation->length()) return false;
7749   int compare = memcmp(code_relocation->GetDataStartAddress(),
7750                        recompiled_relocation->GetDataStartAddress(),
7751                        length);
7752   return compare == 0;
7753 }
7754 
7755 
EnableDeoptimizationSupport(Code * recompiled)7756 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7757   ASSERT(!has_deoptimization_support());
7758   AssertNoAllocation no_allocation;
7759   Code* code = this->code();
7760   if (IsCodeEquivalent(code, recompiled)) {
7761     // Copy the deoptimization data from the recompiled code.
7762     code->set_deoptimization_data(recompiled->deoptimization_data());
7763     code->set_has_deoptimization_support(true);
7764   } else {
7765     // TODO(3025757): In case the recompiled isn't equivalent to the
7766     // old code, we have to replace it. We should try to avoid this
7767     // altogether because it flushes valuable type feedback by
7768     // effectively resetting all IC state.
7769     set_code(recompiled);
7770   }
7771   ASSERT(has_deoptimization_support());
7772 }
7773 
7774 
DisableOptimization()7775 void SharedFunctionInfo::DisableOptimization() {
7776   // Disable optimization for the shared function info and mark the
7777   // code as non-optimizable. The marker on the shared function info
7778   // is there because we flush non-optimized code thereby loosing the
7779   // non-optimizable information for the code. When the code is
7780   // regenerated and set on the shared function info it is marked as
7781   // non-optimizable if optimization is disabled for the shared
7782   // function info.
7783   set_optimization_disabled(true);
7784   // Code should be the lazy compilation stub or else unoptimized.  If the
7785   // latter, disable optimization for the code too.
7786   ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7787   if (code()->kind() == Code::FUNCTION) {
7788     code()->set_optimizable(false);
7789   }
7790   if (FLAG_trace_opt) {
7791     PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
7792   }
7793 }
7794 
7795 
VerifyBailoutId(int id)7796 bool SharedFunctionInfo::VerifyBailoutId(int id) {
7797   ASSERT(id != AstNode::kNoNumber);
7798   Code* unoptimized = code();
7799   DeoptimizationOutputData* data =
7800       DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7801   unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7802   USE(ignore);
7803   return true;  // Return true if there was no ASSERT.
7804 }
7805 
7806 
StartInobjectSlackTracking(Map * map)7807 void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7808   ASSERT(!IsInobjectSlackTrackingInProgress());
7809 
7810   if (!FLAG_clever_optimizations) return;
7811 
7812   // Only initiate the tracking the first time.
7813   if (live_objects_may_exist()) return;
7814   set_live_objects_may_exist(true);
7815 
7816   // No tracking during the snapshot construction phase.
7817   if (Serializer::enabled()) return;
7818 
7819   if (map->unused_property_fields() == 0) return;
7820 
7821   // Nonzero counter is a leftover from the previous attempt interrupted
7822   // by GC, keep it.
7823   if (construction_count() == 0) {
7824     set_construction_count(kGenerousAllocationCount);
7825   }
7826   set_initial_map(map);
7827   Builtins* builtins = map->GetHeap()->isolate()->builtins();
7828   ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
7829             construct_stub());
7830   set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
7831 }
7832 
7833 
7834 // Called from GC, hence reinterpret_cast and unchecked accessors.
DetachInitialMap()7835 void SharedFunctionInfo::DetachInitialMap() {
7836   Map* map = reinterpret_cast<Map*>(initial_map());
7837 
7838   // Make the map remember to restore the link if it survives the GC.
7839   map->set_bit_field2(
7840       map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7841 
7842   // Undo state changes made by StartInobjectTracking (except the
7843   // construction_count). This way if the initial map does not survive the GC
7844   // then StartInobjectTracking will be called again the next time the
7845   // constructor is called. The countdown will continue and (possibly after
7846   // several more GCs) CompleteInobjectSlackTracking will eventually be called.
7847   Heap* heap = map->GetHeap();
7848   set_initial_map(heap->raw_unchecked_undefined_value());
7849   Builtins* builtins = heap->isolate()->builtins();
7850   ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
7851             *RawField(this, kConstructStubOffset));
7852   set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
7853   // It is safe to clear the flag: it will be set again if the map is live.
7854   set_live_objects_may_exist(false);
7855 }
7856 
7857 
7858 // Called from GC, hence reinterpret_cast and unchecked accessors.
AttachInitialMap(Map * map)7859 void SharedFunctionInfo::AttachInitialMap(Map* map) {
7860   map->set_bit_field2(
7861       map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7862 
7863   // Resume inobject slack tracking.
7864   set_initial_map(map);
7865   Builtins* builtins = map->GetHeap()->isolate()->builtins();
7866   ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
7867             *RawField(this, kConstructStubOffset));
7868   set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
7869   // The map survived the gc, so there may be objects referencing it.
7870   set_live_objects_may_exist(true);
7871 }
7872 
7873 
ResetForNewContext(int new_ic_age)7874 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
7875   code()->ClearInlineCaches();
7876   set_ic_age(new_ic_age);
7877   if (code()->kind() == Code::FUNCTION) {
7878     code()->set_profiler_ticks(0);
7879     if (optimization_disabled() &&
7880         opt_count() >= Compiler::kDefaultMaxOptCount) {
7881       // Re-enable optimizations if they were disabled due to opt_count limit.
7882       set_optimization_disabled(false);
7883       code()->set_optimizable(true);
7884     }
7885     set_opt_count(0);
7886   }
7887 }
7888 
7889 
GetMinInobjectSlack(Map * map,void * data)7890 static void GetMinInobjectSlack(Map* map, void* data) {
7891   int slack = map->unused_property_fields();
7892   if (*reinterpret_cast<int*>(data) > slack) {
7893     *reinterpret_cast<int*>(data) = slack;
7894   }
7895 }
7896 
7897 
ShrinkInstanceSize(Map * map,void * data)7898 static void ShrinkInstanceSize(Map* map, void* data) {
7899   int slack = *reinterpret_cast<int*>(data);
7900   map->set_inobject_properties(map->inobject_properties() - slack);
7901   map->set_unused_property_fields(map->unused_property_fields() - slack);
7902   map->set_instance_size(map->instance_size() - slack * kPointerSize);
7903 
7904   // Visitor id might depend on the instance size, recalculate it.
7905   map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7906 }
7907 
7908 
CompleteInobjectSlackTracking()7909 void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7910   ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7911   Map* map = Map::cast(initial_map());
7912 
7913   Heap* heap = map->GetHeap();
7914   set_initial_map(heap->undefined_value());
7915   Builtins* builtins = heap->isolate()->builtins();
7916   ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
7917             construct_stub());
7918   set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
7919 
7920   int slack = map->unused_property_fields();
7921   map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7922   if (slack != 0) {
7923     // Resize the initial map and all maps in its transition tree.
7924     map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
7925 
7926     // Give the correct expected_nof_properties to initial maps created later.
7927     ASSERT(expected_nof_properties() >= slack);
7928     set_expected_nof_properties(expected_nof_properties() - slack);
7929   }
7930 }
7931 
7932 
SharedFunctionInfoIterateBody(ObjectVisitor * v)7933 void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
7934   v->VisitSharedFunctionInfo(this);
7935   SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
7936 }
7937 
7938 
7939 #define DECLARE_TAG(ignore1, name, ignore2) name,
7940 const char* const VisitorSynchronization::kTags[
7941     VisitorSynchronization::kNumberOfSyncTags] = {
7942   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7943 };
7944 #undef DECLARE_TAG
7945 
7946 
7947 #define DECLARE_TAG(ignore1, ignore2, name) name,
7948 const char* const VisitorSynchronization::kTagNames[
7949     VisitorSynchronization::kNumberOfSyncTags] = {
7950   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7951 };
7952 #undef DECLARE_TAG
7953 
7954 
VisitCodeTarget(RelocInfo * rinfo)7955 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
7956   ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
7957   Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7958   Object* old_target = target;
7959   VisitPointer(&target);
7960   CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
7961 }
7962 
7963 
VisitCodeEntry(Address entry_address)7964 void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7965   Object* code = Code::GetObjectFromEntryAddress(entry_address);
7966   Object* old_code = code;
7967   VisitPointer(&code);
7968   if (code != old_code) {
7969     Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7970   }
7971 }
7972 
7973 
VisitGlobalPropertyCell(RelocInfo * rinfo)7974 void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7975   ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7976   Object* cell = rinfo->target_cell();
7977   Object* old_cell = cell;
7978   VisitPointer(&cell);
7979   if (cell != old_cell) {
7980     rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7981   }
7982 }
7983 
7984 
VisitDebugTarget(RelocInfo * rinfo)7985 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
7986   ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
7987           rinfo->IsPatchedReturnSequence()) ||
7988          (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
7989           rinfo->IsPatchedDebugBreakSlotSequence()));
7990   Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
7991   Object* old_target = target;
7992   VisitPointer(&target);
7993   CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
7994 }
7995 
VisitEmbeddedPointer(RelocInfo * rinfo)7996 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
7997   ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
7998   VisitPointer(rinfo->target_object_address());
7999 }
8000 
VisitExternalReference(RelocInfo * rinfo)8001 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
8002   Address* p = rinfo->target_reference_address();
8003   VisitExternalReferences(p, p + 1);
8004 }
8005 
InvalidateRelocation()8006 void Code::InvalidateRelocation() {
8007   set_relocation_info(GetHeap()->empty_byte_array());
8008 }
8009 
8010 
Relocate(intptr_t delta)8011 void Code::Relocate(intptr_t delta) {
8012   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
8013     it.rinfo()->apply(delta);
8014   }
8015   CPU::FlushICache(instruction_start(), instruction_size());
8016 }
8017 
8018 
CopyFrom(const CodeDesc & desc)8019 void Code::CopyFrom(const CodeDesc& desc) {
8020   ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
8021 
8022   // copy code
8023   memmove(instruction_start(), desc.buffer, desc.instr_size);
8024 
8025   // copy reloc info
8026   memmove(relocation_start(),
8027           desc.buffer + desc.buffer_size - desc.reloc_size,
8028           desc.reloc_size);
8029 
8030   // unbox handles and relocate
8031   intptr_t delta = instruction_start() - desc.buffer;
8032   int mode_mask = RelocInfo::kCodeTargetMask |
8033                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
8034                   RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
8035                   RelocInfo::kApplyMask;
8036   Assembler* origin = desc.origin;  // Needed to find target_object on X64.
8037   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
8038     RelocInfo::Mode mode = it.rinfo()->rmode();
8039     if (mode == RelocInfo::EMBEDDED_OBJECT) {
8040       Handle<Object> p = it.rinfo()->target_object_handle(origin);
8041       it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
8042     } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
8043       Handle<JSGlobalPropertyCell> cell  = it.rinfo()->target_cell_handle();
8044       it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
8045     } else if (RelocInfo::IsCodeTarget(mode)) {
8046       // rewrite code handles in inline cache targets to direct
8047       // pointers to the first instruction in the code object
8048       Handle<Object> p = it.rinfo()->target_object_handle(origin);
8049       Code* code = Code::cast(*p);
8050       it.rinfo()->set_target_address(code->instruction_start(),
8051                                      SKIP_WRITE_BARRIER);
8052     } else {
8053       it.rinfo()->apply(delta);
8054     }
8055   }
8056   CPU::FlushICache(instruction_start(), instruction_size());
8057 }
8058 
8059 
8060 // Locate the source position which is closest to the address in the code. This
8061 // is using the source position information embedded in the relocation info.
8062 // The position returned is relative to the beginning of the script where the
8063 // source for this function is found.
SourcePosition(Address pc)8064 int Code::SourcePosition(Address pc) {
8065   int distance = kMaxInt;
8066   int position = RelocInfo::kNoPosition;  // Initially no position found.
8067   // Run through all the relocation info to find the best matching source
8068   // position. All the code needs to be considered as the sequence of the
8069   // instructions in the code does not necessarily follow the same order as the
8070   // source.
8071   RelocIterator it(this, RelocInfo::kPositionMask);
8072   while (!it.done()) {
8073     // Only look at positions after the current pc.
8074     if (it.rinfo()->pc() < pc) {
8075       // Get position and distance.
8076 
8077       int dist = static_cast<int>(pc - it.rinfo()->pc());
8078       int pos = static_cast<int>(it.rinfo()->data());
8079       // If this position is closer than the current candidate or if it has the
8080       // same distance as the current candidate and the position is higher then
8081       // this position is the new candidate.
8082       if ((dist < distance) ||
8083           (dist == distance && pos > position)) {
8084         position = pos;
8085         distance = dist;
8086       }
8087     }
8088     it.next();
8089   }
8090   return position;
8091 }
8092 
8093 
8094 // Same as Code::SourcePosition above except it only looks for statement
8095 // positions.
SourceStatementPosition(Address pc)8096 int Code::SourceStatementPosition(Address pc) {
8097   // First find the position as close as possible using all position
8098   // information.
8099   int position = SourcePosition(pc);
8100   // Now find the closest statement position before the position.
8101   int statement_position = 0;
8102   RelocIterator it(this, RelocInfo::kPositionMask);
8103   while (!it.done()) {
8104     if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
8105       int p = static_cast<int>(it.rinfo()->data());
8106       if (statement_position < p && p <= position) {
8107         statement_position = p;
8108       }
8109     }
8110     it.next();
8111   }
8112   return statement_position;
8113 }
8114 
8115 
GetSafepointEntry(Address pc)8116 SafepointEntry Code::GetSafepointEntry(Address pc) {
8117   SafepointTable table(this);
8118   return table.FindEntry(pc);
8119 }
8120 
8121 
SetNoStackCheckTable()8122 void Code::SetNoStackCheckTable() {
8123   // Indicate the absence of a stack-check table by a table start after the
8124   // end of the instructions.  Table start must be aligned, so round up.
8125   set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
8126 }
8127 
8128 
FindFirstMap()8129 Map* Code::FindFirstMap() {
8130   ASSERT(is_inline_cache_stub());
8131   AssertNoAllocation no_allocation;
8132   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8133   for (RelocIterator it(this, mask); !it.done(); it.next()) {
8134     RelocInfo* info = it.rinfo();
8135     Object* object = info->target_object();
8136     if (object->IsMap()) return Map::cast(object);
8137   }
8138   return NULL;
8139 }
8140 
8141 
ClearInlineCaches()8142 void Code::ClearInlineCaches() {
8143   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
8144              RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
8145              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
8146              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
8147   for (RelocIterator it(this, mask); !it.done(); it.next()) {
8148     RelocInfo* info = it.rinfo();
8149     Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
8150     if (target->is_inline_cache_stub()) {
8151       IC::Clear(info->pc());
8152     }
8153   }
8154 }
8155 
8156 
8157 #ifdef ENABLE_DISASSEMBLER
8158 
DeoptimizationInputDataPrint(FILE * out)8159 void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
8160   disasm::NameConverter converter;
8161   int deopt_count = DeoptCount();
8162   PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
8163   if (0 == deopt_count) return;
8164 
8165   PrintF(out, "%6s  %6s  %6s %6s %12s\n", "index", "ast id", "argc", "pc",
8166          FLAG_print_code_verbose ? "commands" : "");
8167   for (int i = 0; i < deopt_count; i++) {
8168     PrintF(out, "%6d  %6d  %6d %6d",
8169            i,
8170            AstId(i)->value(),
8171            ArgumentsStackHeight(i)->value(),
8172            Pc(i)->value());
8173 
8174     if (!FLAG_print_code_verbose) {
8175       PrintF(out, "\n");
8176       continue;
8177     }
8178     // Print details of the frame translation.
8179     int translation_index = TranslationIndex(i)->value();
8180     TranslationIterator iterator(TranslationByteArray(), translation_index);
8181     Translation::Opcode opcode =
8182         static_cast<Translation::Opcode>(iterator.Next());
8183     ASSERT(Translation::BEGIN == opcode);
8184     int frame_count = iterator.Next();
8185     int jsframe_count = iterator.Next();
8186     PrintF(out, "  %s {frame count=%d, js frame count=%d}\n",
8187            Translation::StringFor(opcode),
8188            frame_count,
8189            jsframe_count);
8190 
8191     while (iterator.HasNext() &&
8192            Translation::BEGIN !=
8193            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8194       PrintF(out, "%24s    %s ", "", Translation::StringFor(opcode));
8195 
8196       switch (opcode) {
8197         case Translation::BEGIN:
8198           UNREACHABLE();
8199           break;
8200 
8201         case Translation::JS_FRAME: {
8202           int ast_id = iterator.Next();
8203           int function_id = iterator.Next();
8204           JSFunction* function =
8205               JSFunction::cast(LiteralArray()->get(function_id));
8206           unsigned height = iterator.Next();
8207           PrintF(out, "{ast_id=%d, function=", ast_id);
8208           function->PrintName(out);
8209           PrintF(out, ", height=%u}", height);
8210           break;
8211         }
8212 
8213         case Translation::ARGUMENTS_ADAPTOR_FRAME:
8214         case Translation::CONSTRUCT_STUB_FRAME: {
8215           int function_id = iterator.Next();
8216           JSFunction* function =
8217               JSFunction::cast(LiteralArray()->get(function_id));
8218           unsigned height = iterator.Next();
8219           PrintF(out, "{function=");
8220           function->PrintName(out);
8221           PrintF(out, ", height=%u}", height);
8222           break;
8223         }
8224 
8225         case Translation::DUPLICATE:
8226           break;
8227 
8228         case Translation::REGISTER: {
8229           int reg_code = iterator.Next();
8230             PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8231           break;
8232         }
8233 
8234         case Translation::INT32_REGISTER: {
8235           int reg_code = iterator.Next();
8236           PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8237           break;
8238         }
8239 
8240         case Translation::DOUBLE_REGISTER: {
8241           int reg_code = iterator.Next();
8242           PrintF(out, "{input=%s}",
8243                  DoubleRegister::AllocationIndexToString(reg_code));
8244           break;
8245         }
8246 
8247         case Translation::STACK_SLOT: {
8248           int input_slot_index = iterator.Next();
8249           PrintF(out, "{input=%d}", input_slot_index);
8250           break;
8251         }
8252 
8253         case Translation::INT32_STACK_SLOT: {
8254           int input_slot_index = iterator.Next();
8255           PrintF(out, "{input=%d}", input_slot_index);
8256           break;
8257         }
8258 
8259         case Translation::DOUBLE_STACK_SLOT: {
8260           int input_slot_index = iterator.Next();
8261           PrintF(out, "{input=%d}", input_slot_index);
8262           break;
8263         }
8264 
8265         case Translation::LITERAL: {
8266           unsigned literal_index = iterator.Next();
8267           PrintF(out, "{literal_id=%u}", literal_index);
8268           break;
8269         }
8270 
8271         case Translation::ARGUMENTS_OBJECT:
8272           break;
8273       }
8274       PrintF(out, "\n");
8275     }
8276   }
8277 }
8278 
8279 
DeoptimizationOutputDataPrint(FILE * out)8280 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8281   PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
8282          this->DeoptPoints());
8283   if (this->DeoptPoints() == 0) return;
8284 
8285   PrintF("%6s  %8s  %s\n", "ast id", "pc", "state");
8286   for (int i = 0; i < this->DeoptPoints(); i++) {
8287     int pc_and_state = this->PcAndState(i)->value();
8288     PrintF("%6d  %8d  %s\n",
8289            this->AstId(i)->value(),
8290            FullCodeGenerator::PcField::decode(pc_and_state),
8291            FullCodeGenerator::State2String(
8292                FullCodeGenerator::StateField::decode(pc_and_state)));
8293   }
8294 }
8295 
8296 
8297 // Identify kind of code.
Kind2String(Kind kind)8298 const char* Code::Kind2String(Kind kind) {
8299   switch (kind) {
8300     case FUNCTION: return "FUNCTION";
8301     case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
8302     case STUB: return "STUB";
8303     case BUILTIN: return "BUILTIN";
8304     case LOAD_IC: return "LOAD_IC";
8305     case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8306     case STORE_IC: return "STORE_IC";
8307     case KEYED_STORE_IC: return "KEYED_STORE_IC";
8308     case CALL_IC: return "CALL_IC";
8309     case KEYED_CALL_IC: return "KEYED_CALL_IC";
8310     case UNARY_OP_IC: return "UNARY_OP_IC";
8311     case BINARY_OP_IC: return "BINARY_OP_IC";
8312     case COMPARE_IC: return "COMPARE_IC";
8313     case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
8314   }
8315   UNREACHABLE();
8316   return NULL;
8317 }
8318 
8319 
ICState2String(InlineCacheState state)8320 const char* Code::ICState2String(InlineCacheState state) {
8321   switch (state) {
8322     case UNINITIALIZED: return "UNINITIALIZED";
8323     case PREMONOMORPHIC: return "PREMONOMORPHIC";
8324     case MONOMORPHIC: return "MONOMORPHIC";
8325     case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8326     case MEGAMORPHIC: return "MEGAMORPHIC";
8327     case DEBUG_BREAK: return "DEBUG_BREAK";
8328     case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8329   }
8330   UNREACHABLE();
8331   return NULL;
8332 }
8333 
8334 
PropertyType2String(PropertyType type)8335 const char* Code::PropertyType2String(PropertyType type) {
8336   switch (type) {
8337     case NORMAL: return "NORMAL";
8338     case FIELD: return "FIELD";
8339     case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8340     case CALLBACKS: return "CALLBACKS";
8341     case HANDLER: return "HANDLER";
8342     case INTERCEPTOR: return "INTERCEPTOR";
8343     case MAP_TRANSITION: return "MAP_TRANSITION";
8344     case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
8345     case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8346     case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8347   }
8348   UNREACHABLE();  // keep the compiler happy
8349   return NULL;
8350 }
8351 
8352 
PrintExtraICState(FILE * out,Kind kind,ExtraICState extra)8353 void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8354   const char* name = NULL;
8355   switch (kind) {
8356     case CALL_IC:
8357       if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8358         name = "STRING_INDEX_OUT_OF_BOUNDS";
8359       }
8360       break;
8361     case STORE_IC:
8362     case KEYED_STORE_IC:
8363       if (extra == kStrictMode) {
8364         name = "STRICT";
8365       }
8366       break;
8367     default:
8368       break;
8369   }
8370   if (name != NULL) {
8371     PrintF(out, "extra_ic_state = %s\n", name);
8372   } else {
8373     PrintF(out, "extra_ic_state = %d\n", extra);
8374   }
8375 }
8376 
8377 
Disassemble(const char * name,FILE * out)8378 void Code::Disassemble(const char* name, FILE* out) {
8379   PrintF(out, "kind = %s\n", Kind2String(kind()));
8380   if (is_inline_cache_stub()) {
8381     PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
8382     PrintExtraICState(out, kind(), extra_ic_state());
8383     if (ic_state() == MONOMORPHIC) {
8384       PrintF(out, "type = %s\n", PropertyType2String(type()));
8385     }
8386     if (is_call_stub() || is_keyed_call_stub()) {
8387       PrintF(out, "argc = %d\n", arguments_count());
8388     }
8389   }
8390   if ((name != NULL) && (name[0] != '\0')) {
8391     PrintF(out, "name = %s\n", name);
8392   }
8393   if (kind() == OPTIMIZED_FUNCTION) {
8394     PrintF(out, "stack_slots = %d\n", stack_slots());
8395   }
8396 
8397   PrintF(out, "Instructions (size = %d)\n", instruction_size());
8398   Disassembler::Decode(out, this);
8399   PrintF(out, "\n");
8400 
8401   if (kind() == FUNCTION) {
8402     DeoptimizationOutputData* data =
8403         DeoptimizationOutputData::cast(this->deoptimization_data());
8404     data->DeoptimizationOutputDataPrint(out);
8405   } else if (kind() == OPTIMIZED_FUNCTION) {
8406     DeoptimizationInputData* data =
8407         DeoptimizationInputData::cast(this->deoptimization_data());
8408     data->DeoptimizationInputDataPrint(out);
8409   }
8410   PrintF("\n");
8411 
8412   if (kind() == OPTIMIZED_FUNCTION) {
8413     SafepointTable table(this);
8414     PrintF(out, "Safepoints (size = %u)\n", table.size());
8415     for (unsigned i = 0; i < table.length(); i++) {
8416       unsigned pc_offset = table.GetPcOffset(i);
8417       PrintF(out, "%p  %4d  ", (instruction_start() + pc_offset), pc_offset);
8418       table.PrintEntry(i);
8419       PrintF(out, " (sp -> fp)");
8420       SafepointEntry entry = table.GetEntry(i);
8421       if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8422         PrintF(out, "  %6d", entry.deoptimization_index());
8423       } else {
8424         PrintF(out, "  <none>");
8425       }
8426       if (entry.argument_count() > 0) {
8427         PrintF(out, " argc: %d", entry.argument_count());
8428       }
8429       PrintF(out, "\n");
8430     }
8431     PrintF(out, "\n");
8432   } else if (kind() == FUNCTION) {
8433     unsigned offset = stack_check_table_offset();
8434     // If there is no stack check table, the "table start" will at or after
8435     // (due to alignment) the end of the instruction stream.
8436     if (static_cast<int>(offset) < instruction_size()) {
8437       unsigned* address =
8438           reinterpret_cast<unsigned*>(instruction_start() + offset);
8439       unsigned length = address[0];
8440       PrintF(out, "Stack checks (size = %u)\n", length);
8441       PrintF(out, "ast_id  pc_offset\n");
8442       for (unsigned i = 0; i < length; ++i) {
8443         unsigned index = (2 * i) + 1;
8444         PrintF(out, "%6u  %9u\n", address[index], address[index + 1]);
8445       }
8446       PrintF(out, "\n");
8447     }
8448   }
8449 
8450   PrintF("RelocInfo (size = %d)\n", relocation_size());
8451   for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8452   PrintF(out, "\n");
8453 }
8454 #endif  // ENABLE_DISASSEMBLER
8455 
8456 
SetFastElementsCapacityAndLength(int capacity,int length,SetFastElementsCapacityMode set_capacity_mode)8457 MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8458     int capacity,
8459     int length,
8460     SetFastElementsCapacityMode set_capacity_mode) {
8461   Heap* heap = GetHeap();
8462   // We should never end in here with a pixel or external array.
8463   ASSERT(!HasExternalArrayElements());
8464 
8465   // Allocate a new fast elements backing store.
8466   FixedArray* new_elements;
8467   { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8468     if (!maybe->To(&new_elements)) return maybe;
8469   }
8470 
8471   // Find the new map to use for this object if there is a map change.
8472   Map* new_map = NULL;
8473   if (elements()->map() != heap->non_strict_arguments_elements_map()) {
8474     // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8475     // it, or if it's allowed and the old elements array contained only SMIs.
8476     bool has_fast_smi_only_elements =
8477         (set_capacity_mode == kForceSmiOnlyElements) ||
8478         ((set_capacity_mode == kAllowSmiOnlyElements) &&
8479          (elements()->map()->has_fast_smi_only_elements() ||
8480           elements() == heap->empty_fixed_array()));
8481     ElementsKind elements_kind = has_fast_smi_only_elements
8482         ? FAST_SMI_ONLY_ELEMENTS
8483         : FAST_ELEMENTS;
8484     MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
8485     if (!maybe->To(&new_map)) return maybe;
8486   }
8487 
8488   FixedArrayBase* old_elements = elements();
8489   ElementsKind elements_kind = GetElementsKind();
8490   ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8491   ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
8492       ? FAST_SMI_ONLY_ELEMENTS
8493       : FAST_ELEMENTS;
8494   //  int copy_size = Min(old_elements_raw->length(), new_elements->length());
8495   accessor->CopyElements(this, new_elements, to_kind);
8496   if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8497     set_map_and_elements(new_map, new_elements);
8498   } else {
8499     FixedArray* parameter_map = FixedArray::cast(old_elements);
8500     parameter_map->set(1, new_elements);
8501   }
8502 
8503   if (FLAG_trace_elements_transitions) {
8504     PrintElementsTransition(stdout, elements_kind, old_elements,
8505                             GetElementsKind(), new_elements);
8506   }
8507 
8508   // Update the length if necessary.
8509   if (IsJSArray()) {
8510     JSArray::cast(this)->set_length(Smi::FromInt(length));
8511   }
8512 
8513   return new_elements;
8514 }
8515 
8516 
SetFastDoubleElementsCapacityAndLength(int capacity,int length)8517 MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8518     int capacity,
8519     int length) {
8520   Heap* heap = GetHeap();
8521   // We should never end in here with a pixel or external array.
8522   ASSERT(!HasExternalArrayElements());
8523 
8524   FixedArrayBase* elems;
8525   { MaybeObject* maybe_obj =
8526         heap->AllocateUninitializedFixedDoubleArray(capacity);
8527     if (!maybe_obj->To(&elems)) return maybe_obj;
8528   }
8529 
8530   Map* new_map;
8531   { MaybeObject* maybe_obj =
8532         GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
8533     if (!maybe_obj->To(&new_map)) return maybe_obj;
8534   }
8535 
8536   FixedArrayBase* old_elements = elements();
8537   ElementsKind elements_kind = GetElementsKind();
8538   ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8539   accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
8540   if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8541     set_map_and_elements(new_map, elems);
8542   } else {
8543     FixedArray* parameter_map = FixedArray::cast(old_elements);
8544     parameter_map->set(1, elems);
8545   }
8546 
8547   if (FLAG_trace_elements_transitions) {
8548     PrintElementsTransition(stdout, elements_kind, old_elements,
8549                             FAST_DOUBLE_ELEMENTS, elems);
8550   }
8551 
8552   if (IsJSArray()) {
8553     JSArray::cast(this)->set_length(Smi::FromInt(length));
8554   }
8555 
8556   return this;
8557 }
8558 
8559 
Initialize(int capacity)8560 MaybeObject* JSArray::Initialize(int capacity) {
8561   Heap* heap = GetHeap();
8562   ASSERT(capacity >= 0);
8563   set_length(Smi::FromInt(0));
8564   FixedArray* new_elements;
8565   if (capacity == 0) {
8566     new_elements = heap->empty_fixed_array();
8567   } else {
8568     MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
8569     if (!maybe_obj->To(&new_elements)) return maybe_obj;
8570   }
8571   set_elements(new_elements);
8572   return this;
8573 }
8574 
8575 
Expand(int required_size)8576 void JSArray::Expand(int required_size) {
8577   GetIsolate()->factory()->SetElementsCapacityAndLength(
8578       Handle<JSArray>(this), required_size, required_size);
8579 }
8580 
8581 
SetElementsLength(Object * len)8582 MaybeObject* JSArray::SetElementsLength(Object* len) {
8583   // We should never end in here with a pixel or external array.
8584   ASSERT(AllowsSetElementsLength());
8585   return GetElementsAccessor()->SetLength(this, len);
8586 }
8587 
8588 
GetPrototypeTransition(Object * prototype)8589 Object* Map::GetPrototypeTransition(Object* prototype) {
8590   FixedArray* cache = prototype_transitions();
8591   int number_of_transitions = NumberOfProtoTransitions();
8592   const int proto_offset =
8593       kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8594   const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8595   const int step = kProtoTransitionElementsPerEntry;
8596   for (int i = 0; i < number_of_transitions; i++) {
8597     if (cache->get(proto_offset + i * step) == prototype) {
8598       Object* map = cache->get(map_offset + i * step);
8599       ASSERT(map->IsMap());
8600       return map;
8601     }
8602   }
8603   return NULL;
8604 }
8605 
8606 
PutPrototypeTransition(Object * prototype,Map * map)8607 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
8608   ASSERT(map->IsMap());
8609   ASSERT(HeapObject::cast(prototype)->map()->IsMap());
8610   // Don't cache prototype transition if this map is shared.
8611   if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8612 
8613   FixedArray* cache = prototype_transitions();
8614 
8615   const int step = kProtoTransitionElementsPerEntry;
8616   const int header = kProtoTransitionHeaderSize;
8617 
8618   int capacity = (cache->length() - header) / step;
8619 
8620   int transitions = NumberOfProtoTransitions() + 1;
8621 
8622   if (transitions > capacity) {
8623     if (capacity > kMaxCachedPrototypeTransitions) return this;
8624 
8625     FixedArray* new_cache;
8626     // Grow array by factor 2 over and above what we need.
8627     { MaybeObject* maybe_cache =
8628           GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
8629       if (!maybe_cache->To(&new_cache)) return maybe_cache;
8630     }
8631 
8632     for (int i = 0; i < capacity * step; i++) {
8633       new_cache->set(i + header, cache->get(i + header));
8634     }
8635     cache = new_cache;
8636     set_prototype_transitions(cache);
8637   }
8638 
8639   int last = transitions - 1;
8640 
8641   cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8642   cache->set(header + last * step + kProtoTransitionMapOffset, map);
8643   SetNumberOfProtoTransitions(transitions);
8644 
8645   return cache;
8646 }
8647 
8648 
SetPrototype(Object * value,bool skip_hidden_prototypes)8649 MaybeObject* JSReceiver::SetPrototype(Object* value,
8650                                       bool skip_hidden_prototypes) {
8651 #ifdef DEBUG
8652   int size = Size();
8653 #endif
8654 
8655   Heap* heap = GetHeap();
8656   // Silently ignore the change if value is not a JSObject or null.
8657   // SpiderMonkey behaves this way.
8658   if (!value->IsJSReceiver() && !value->IsNull()) return value;
8659 
8660   // From 8.6.2 Object Internal Methods
8661   // ...
8662   // In addition, if [[Extensible]] is false the value of the [[Class]] and
8663   // [[Prototype]] internal properties of the object may not be modified.
8664   // ...
8665   // Implementation specific extensions that modify [[Class]], [[Prototype]]
8666   // or [[Extensible]] must not violate the invariants defined in the preceding
8667   // paragraph.
8668   if (!this->map()->is_extensible()) {
8669     HandleScope scope(heap->isolate());
8670     Handle<Object> handle(this, heap->isolate());
8671     return heap->isolate()->Throw(
8672         *FACTORY->NewTypeError("non_extensible_proto",
8673                                HandleVector<Object>(&handle, 1)));
8674   }
8675 
8676   // Before we can set the prototype we need to be sure
8677   // prototype cycles are prevented.
8678   // It is sufficient to validate that the receiver is not in the new prototype
8679   // chain.
8680   for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
8681     if (JSReceiver::cast(pt) == this) {
8682       // Cycle detected.
8683       HandleScope scope(heap->isolate());
8684       return heap->isolate()->Throw(
8685           *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
8686     }
8687   }
8688 
8689   JSReceiver* real_receiver = this;
8690 
8691   if (skip_hidden_prototypes) {
8692     // Find the first object in the chain whose prototype object is not
8693     // hidden and set the new prototype on that object.
8694     Object* current_proto = real_receiver->GetPrototype();
8695     while (current_proto->IsJSObject() &&
8696           JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8697       real_receiver = JSReceiver::cast(current_proto);
8698       current_proto = current_proto->GetPrototype();
8699     }
8700   }
8701 
8702   // Set the new prototype of the object.
8703   Map* map = real_receiver->map();
8704 
8705   // Nothing to do if prototype is already set.
8706   if (map->prototype() == value) return value;
8707 
8708   Object* new_map = map->GetPrototypeTransition(value);
8709   if (new_map == NULL) {
8710     { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8711       if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8712     }
8713 
8714     { MaybeObject* maybe_new_cache =
8715           map->PutPrototypeTransition(value, Map::cast(new_map));
8716       if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8717     }
8718 
8719     Map::cast(new_map)->set_prototype(value);
8720   }
8721   ASSERT(Map::cast(new_map)->prototype() == value);
8722   real_receiver->set_map(Map::cast(new_map));
8723 
8724   heap->ClearInstanceofCache();
8725   ASSERT(size == Size());
8726   return value;
8727 }
8728 
8729 
EnsureCanContainElements(Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)8730 MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8731                                                 uint32_t first_arg,
8732                                                 uint32_t arg_count,
8733                                                 EnsureElementsMode mode) {
8734   // Elements in |Arguments| are ordered backwards (because they're on the
8735   // stack), but the method that's called here iterates over them in forward
8736   // direction.
8737   return EnsureCanContainElements(
8738       args->arguments() - first_arg - (arg_count - 1),
8739       arg_count, mode);
8740 }
8741 
8742 
HasElementWithInterceptor(JSReceiver * receiver,uint32_t index)8743 bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
8744   Isolate* isolate = GetIsolate();
8745   // Make sure that the top context does not change when doing
8746   // callbacks or interceptor calls.
8747   AssertNoContextChange ncc;
8748   HandleScope scope(isolate);
8749   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8750   Handle<JSReceiver> receiver_handle(receiver);
8751   Handle<JSObject> holder_handle(this);
8752   CustomArguments args(isolate, interceptor->data(), receiver, this);
8753   v8::AccessorInfo info(args.end());
8754   if (!interceptor->query()->IsUndefined()) {
8755     v8::IndexedPropertyQuery query =
8756         v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
8757     LOG(isolate,
8758         ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
8759     v8::Handle<v8::Integer> result;
8760     {
8761       // Leaving JavaScript.
8762       VMState state(isolate, EXTERNAL);
8763       result = query(index, info);
8764     }
8765     if (!result.IsEmpty()) {
8766       ASSERT(result->IsInt32());
8767       return true;  // absence of property is signaled by empty handle.
8768     }
8769   } else if (!interceptor->getter()->IsUndefined()) {
8770     v8::IndexedPropertyGetter getter =
8771         v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
8772     LOG(isolate,
8773         ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
8774     v8::Handle<v8::Value> result;
8775     {
8776       // Leaving JavaScript.
8777       VMState state(isolate, EXTERNAL);
8778       result = getter(index, info);
8779     }
8780     if (!result.IsEmpty()) return true;
8781   }
8782 
8783   if (holder_handle->GetElementsAccessor()->HasElement(
8784           *receiver_handle, *holder_handle, index)) {
8785     return true;
8786   }
8787 
8788   if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
8789   Object* pt = holder_handle->GetPrototype();
8790   if (pt->IsJSProxy()) {
8791     // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8792     return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8793         receiver, index) != ABSENT;
8794   }
8795   if (pt->IsNull()) return false;
8796   return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
8797 }
8798 
8799 
HasLocalElement(uint32_t index)8800 JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
8801   // Check access rights if needed.
8802   if (IsAccessCheckNeeded()) {
8803     Heap* heap = GetHeap();
8804     if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8805       heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8806       return UNDEFINED_ELEMENT;
8807     }
8808   }
8809 
8810   if (IsJSGlobalProxy()) {
8811     Object* proto = GetPrototype();
8812     if (proto->IsNull()) return UNDEFINED_ELEMENT;
8813     ASSERT(proto->IsJSGlobalObject());
8814     return JSObject::cast(proto)->HasLocalElement(index);
8815   }
8816 
8817   // Check for lookup interceptor
8818   if (HasIndexedInterceptor()) {
8819     return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8820                                                   : UNDEFINED_ELEMENT;
8821   }
8822 
8823   // Handle [] on String objects.
8824   if (this->IsStringObjectWithCharacterAt(index)) {
8825     return STRING_CHARACTER_ELEMENT;
8826   }
8827 
8828   switch (GetElementsKind()) {
8829     case FAST_SMI_ONLY_ELEMENTS:
8830     case FAST_ELEMENTS: {
8831       uint32_t length = IsJSArray() ?
8832           static_cast<uint32_t>
8833               (Smi::cast(JSArray::cast(this)->length())->value()) :
8834           static_cast<uint32_t>(FixedArray::cast(elements())->length());
8835       if ((index < length) &&
8836           !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8837         return FAST_ELEMENT;
8838       }
8839       break;
8840     }
8841     case FAST_DOUBLE_ELEMENTS: {
8842       uint32_t length = IsJSArray() ?
8843           static_cast<uint32_t>
8844               (Smi::cast(JSArray::cast(this)->length())->value()) :
8845           static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8846       if ((index < length) &&
8847           !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8848         return FAST_ELEMENT;
8849       }
8850       break;
8851     }
8852     case EXTERNAL_PIXEL_ELEMENTS: {
8853       ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
8854       if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8855       break;
8856     }
8857     case EXTERNAL_BYTE_ELEMENTS:
8858     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8859     case EXTERNAL_SHORT_ELEMENTS:
8860     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8861     case EXTERNAL_INT_ELEMENTS:
8862     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8863     case EXTERNAL_FLOAT_ELEMENTS:
8864     case EXTERNAL_DOUBLE_ELEMENTS: {
8865       ExternalArray* array = ExternalArray::cast(elements());
8866       if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8867       break;
8868     }
8869     case DICTIONARY_ELEMENTS: {
8870       if (element_dictionary()->FindEntry(index) !=
8871           SeededNumberDictionary::kNotFound) {
8872         return DICTIONARY_ELEMENT;
8873       }
8874       break;
8875     }
8876     case NON_STRICT_ARGUMENTS_ELEMENTS: {
8877       // Aliased parameters and non-aliased elements in a fast backing store
8878       // behave as FAST_ELEMENT.  Non-aliased elements in a dictionary
8879       // backing store behave as DICTIONARY_ELEMENT.
8880       FixedArray* parameter_map = FixedArray::cast(elements());
8881       uint32_t length = parameter_map->length();
8882       Object* probe =
8883           index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8884       if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8885       // If not aliased, check the arguments.
8886       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8887       if (arguments->IsDictionary()) {
8888         SeededNumberDictionary* dictionary =
8889             SeededNumberDictionary::cast(arguments);
8890         if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
8891           return DICTIONARY_ELEMENT;
8892         }
8893       } else {
8894         length = arguments->length();
8895         probe = (index < length) ? arguments->get(index) : NULL;
8896         if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8897       }
8898       break;
8899     }
8900   }
8901 
8902   return UNDEFINED_ELEMENT;
8903 }
8904 
8905 
HasElementWithReceiver(JSReceiver * receiver,uint32_t index)8906 bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
8907   // Check access rights if needed.
8908   if (IsAccessCheckNeeded()) {
8909     Heap* heap = GetHeap();
8910     if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8911       heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8912       return false;
8913     }
8914   }
8915 
8916   // Check for lookup interceptor
8917   if (HasIndexedInterceptor()) {
8918     return HasElementWithInterceptor(receiver, index);
8919   }
8920 
8921   ElementsAccessor* accessor = GetElementsAccessor();
8922   if (accessor->HasElement(receiver, this, index)) {
8923     return true;
8924   }
8925 
8926   // Handle [] on String objects.
8927   if (this->IsStringObjectWithCharacterAt(index)) return true;
8928 
8929   Object* pt = GetPrototype();
8930   if (pt->IsNull()) return false;
8931   if (pt->IsJSProxy()) {
8932     // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8933     return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8934         receiver, index) != ABSENT;
8935   }
8936   return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8937 }
8938 
8939 
SetElementWithInterceptor(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)8940 MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
8941                                                  Object* value,
8942                                                  PropertyAttributes attributes,
8943                                                  StrictModeFlag strict_mode,
8944                                                  bool check_prototype,
8945                                                  SetPropertyMode set_mode) {
8946   Isolate* isolate = GetIsolate();
8947   // Make sure that the top context does not change when doing
8948   // callbacks or interceptor calls.
8949   AssertNoContextChange ncc;
8950   HandleScope scope(isolate);
8951   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8952   Handle<JSObject> this_handle(this);
8953   Handle<Object> value_handle(value, isolate);
8954   if (!interceptor->setter()->IsUndefined()) {
8955     v8::IndexedPropertySetter setter =
8956         v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
8957     LOG(isolate,
8958         ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8959     CustomArguments args(isolate, interceptor->data(), this, this);
8960     v8::AccessorInfo info(args.end());
8961     v8::Handle<v8::Value> result;
8962     {
8963       // Leaving JavaScript.
8964       VMState state(isolate, EXTERNAL);
8965       result = setter(index, v8::Utils::ToLocal(value_handle), info);
8966     }
8967     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8968     if (!result.IsEmpty()) return *value_handle;
8969   }
8970   MaybeObject* raw_result =
8971       this_handle->SetElementWithoutInterceptor(index,
8972                                                 *value_handle,
8973                                                 attributes,
8974                                                 strict_mode,
8975                                                 check_prototype,
8976                                                 set_mode);
8977   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8978   return raw_result;
8979 }
8980 
8981 
GetElementWithCallback(Object * receiver,Object * structure,uint32_t index,Object * holder)8982 MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8983                                               Object* structure,
8984                                               uint32_t index,
8985                                               Object* holder) {
8986   Isolate* isolate = GetIsolate();
8987   ASSERT(!structure->IsForeign());
8988 
8989   // api style callbacks.
8990   if (structure->IsAccessorInfo()) {
8991     Handle<AccessorInfo> data(AccessorInfo::cast(structure));
8992     Object* fun_obj = data->getter();
8993     v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
8994     HandleScope scope(isolate);
8995     Handle<JSObject> self(JSObject::cast(receiver));
8996     Handle<JSObject> holder_handle(JSObject::cast(holder));
8997     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8998     Handle<String> key = isolate->factory()->NumberToString(number);
8999     LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
9000     CustomArguments args(isolate, data->data(), *self, *holder_handle);
9001     v8::AccessorInfo info(args.end());
9002     v8::Handle<v8::Value> result;
9003     {
9004       // Leaving JavaScript.
9005       VMState state(isolate, EXTERNAL);
9006       result = call_fun(v8::Utils::ToLocal(key), info);
9007     }
9008     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9009     if (result.IsEmpty()) return isolate->heap()->undefined_value();
9010     return *v8::Utils::OpenHandle(*result);
9011   }
9012 
9013   // __defineGetter__ callback
9014   if (structure->IsAccessorPair()) {
9015     Object* getter = AccessorPair::cast(structure)->getter();
9016     if (getter->IsSpecFunction()) {
9017       // TODO(rossberg): nicer would be to cast to some JSCallable here...
9018       return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
9019     }
9020     // Getter is not a function.
9021     return isolate->heap()->undefined_value();
9022   }
9023 
9024   UNREACHABLE();
9025   return NULL;
9026 }
9027 
9028 
SetElementWithCallback(Object * structure,uint32_t index,Object * value,JSObject * holder,StrictModeFlag strict_mode)9029 MaybeObject* JSObject::SetElementWithCallback(Object* structure,
9030                                               uint32_t index,
9031                                               Object* value,
9032                                               JSObject* holder,
9033                                               StrictModeFlag strict_mode) {
9034   Isolate* isolate = GetIsolate();
9035   HandleScope scope(isolate);
9036 
9037   // We should never get here to initialize a const with the hole
9038   // value since a const declaration would conflict with the setter.
9039   ASSERT(!value->IsTheHole());
9040   Handle<Object> value_handle(value, isolate);
9041 
9042   // To accommodate both the old and the new api we switch on the
9043   // data structure used to store the callbacks.  Eventually foreign
9044   // callbacks should be phased out.
9045   ASSERT(!structure->IsForeign());
9046 
9047   if (structure->IsAccessorInfo()) {
9048     // api style callbacks
9049     Handle<JSObject> self(this);
9050     Handle<JSObject> holder_handle(JSObject::cast(holder));
9051     Handle<AccessorInfo> data(AccessorInfo::cast(structure));
9052     Object* call_obj = data->setter();
9053     v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9054     if (call_fun == NULL) return value;
9055     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9056     Handle<String> key(isolate->factory()->NumberToString(number));
9057     LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9058     CustomArguments args(isolate, data->data(), *self, *holder_handle);
9059     v8::AccessorInfo info(args.end());
9060     {
9061       // Leaving JavaScript.
9062       VMState state(isolate, EXTERNAL);
9063       call_fun(v8::Utils::ToLocal(key),
9064                v8::Utils::ToLocal(value_handle),
9065                info);
9066     }
9067     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9068     return *value_handle;
9069   }
9070 
9071   if (structure->IsAccessorPair()) {
9072     Handle<Object> setter(AccessorPair::cast(structure)->setter());
9073     if (setter->IsSpecFunction()) {
9074       // TODO(rossberg): nicer would be to cast to some JSCallable here...
9075       return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
9076     } else {
9077       if (strict_mode == kNonStrictMode) {
9078         return value;
9079       }
9080       Handle<Object> holder_handle(holder, isolate);
9081       Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
9082       Handle<Object> args[2] = { key, holder_handle };
9083       return isolate->Throw(
9084           *isolate->factory()->NewTypeError("no_setter_in_callback",
9085                                             HandleVector(args, 2)));
9086     }
9087   }
9088 
9089   UNREACHABLE();
9090   return NULL;
9091 }
9092 
9093 
HasFastArgumentsElements()9094 bool JSObject::HasFastArgumentsElements() {
9095   Heap* heap = GetHeap();
9096   if (!elements()->IsFixedArray()) return false;
9097   FixedArray* elements = FixedArray::cast(this->elements());
9098   if (elements->map() != heap->non_strict_arguments_elements_map()) {
9099     return false;
9100   }
9101   FixedArray* arguments = FixedArray::cast(elements->get(1));
9102   return !arguments->IsDictionary();
9103 }
9104 
9105 
HasDictionaryArgumentsElements()9106 bool JSObject::HasDictionaryArgumentsElements() {
9107   Heap* heap = GetHeap();
9108   if (!elements()->IsFixedArray()) return false;
9109   FixedArray* elements = FixedArray::cast(this->elements());
9110   if (elements->map() != heap->non_strict_arguments_elements_map()) {
9111     return false;
9112   }
9113   FixedArray* arguments = FixedArray::cast(elements->get(1));
9114   return arguments->IsDictionary();
9115 }
9116 
9117 
9118 // Adding n elements in fast case is O(n*n).
9119 // Note: revisit design to have dual undefined values to capture absent
9120 // elements.
SetFastElement(uint32_t index,Object * value,StrictModeFlag strict_mode,bool check_prototype)9121 MaybeObject* JSObject::SetFastElement(uint32_t index,
9122                                       Object* value,
9123                                       StrictModeFlag strict_mode,
9124                                       bool check_prototype) {
9125   ASSERT(HasFastTypeElements() ||
9126          HasFastArgumentsElements());
9127 
9128   FixedArray* backing_store = FixedArray::cast(elements());
9129   if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9130     backing_store = FixedArray::cast(backing_store->get(1));
9131   } else {
9132     MaybeObject* maybe = EnsureWritableFastElements();
9133     if (!maybe->To(&backing_store)) return maybe;
9134   }
9135   uint32_t capacity = static_cast<uint32_t>(backing_store->length());
9136 
9137   if (check_prototype &&
9138       (index >= capacity || backing_store->get(index)->IsTheHole())) {
9139     bool found;
9140     MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9141                                                                    value,
9142                                                                    &found,
9143                                                                    strict_mode);
9144     if (found) return result;
9145   }
9146 
9147   uint32_t new_capacity = capacity;
9148   // Check if the length property of this object needs to be updated.
9149   uint32_t array_length = 0;
9150   bool must_update_array_length = false;
9151   if (IsJSArray()) {
9152     CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9153     if (index >= array_length) {
9154       must_update_array_length = true;
9155       array_length = index + 1;
9156     }
9157   }
9158   // Check if the capacity of the backing store needs to be increased, or if
9159   // a transition to slow elements is necessary.
9160   if (index >= capacity) {
9161     bool convert_to_slow = true;
9162     if ((index - capacity) < kMaxGap) {
9163       new_capacity = NewElementsCapacity(index + 1);
9164       ASSERT(new_capacity > index);
9165       if (!ShouldConvertToSlowElements(new_capacity)) {
9166         convert_to_slow = false;
9167       }
9168     }
9169     if (convert_to_slow) {
9170       MaybeObject* result = NormalizeElements();
9171       if (result->IsFailure()) return result;
9172       return SetDictionaryElement(index, value, NONE, strict_mode,
9173                                   check_prototype);
9174     }
9175   }
9176   // Convert to fast double elements if appropriate.
9177   if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9178     MaybeObject* maybe =
9179         SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9180     if (maybe->IsFailure()) return maybe;
9181     FixedDoubleArray::cast(elements())->set(index, value->Number());
9182     return value;
9183   }
9184   // Change elements kind from SMI_ONLY to generic FAST if necessary.
9185   if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9186     Map* new_map;
9187     { MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9188                                                             FAST_ELEMENTS);
9189       if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9190     }
9191     set_map(new_map);
9192     if (FLAG_trace_elements_transitions) {
9193       PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9194                               FAST_ELEMENTS, elements());
9195     }
9196   }
9197   // Increase backing store capacity if that's been decided previously.
9198   if (new_capacity != capacity) {
9199     FixedArray* new_elements;
9200     SetFastElementsCapacityMode set_capacity_mode =
9201         value->IsSmi() && HasFastSmiOnlyElements()
9202             ? kAllowSmiOnlyElements
9203             : kDontAllowSmiOnlyElements;
9204     { MaybeObject* maybe =
9205           SetFastElementsCapacityAndLength(new_capacity,
9206                                            array_length,
9207                                            set_capacity_mode);
9208       if (!maybe->To(&new_elements)) return maybe;
9209     }
9210     new_elements->set(index, value);
9211     return value;
9212   }
9213   // Finally, set the new element and length.
9214   ASSERT(elements()->IsFixedArray());
9215   backing_store->set(index, value);
9216   if (must_update_array_length) {
9217     JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9218   }
9219   return value;
9220 }
9221 
9222 
SetDictionaryElement(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)9223 MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9224                                             Object* value,
9225                                             PropertyAttributes attributes,
9226                                             StrictModeFlag strict_mode,
9227                                             bool check_prototype,
9228                                             SetPropertyMode set_mode) {
9229   ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9230   Isolate* isolate = GetIsolate();
9231   Heap* heap = isolate->heap();
9232 
9233   // Insert element in the dictionary.
9234   FixedArray* elements = FixedArray::cast(this->elements());
9235   bool is_arguments =
9236       (elements->map() == heap->non_strict_arguments_elements_map());
9237   SeededNumberDictionary* dictionary = NULL;
9238   if (is_arguments) {
9239     dictionary = SeededNumberDictionary::cast(elements->get(1));
9240   } else {
9241     dictionary = SeededNumberDictionary::cast(elements);
9242   }
9243 
9244   int entry = dictionary->FindEntry(index);
9245   if (entry != SeededNumberDictionary::kNotFound) {
9246     Object* element = dictionary->ValueAt(entry);
9247     PropertyDetails details = dictionary->DetailsAt(entry);
9248     if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
9249       return SetElementWithCallback(element, index, value, this, strict_mode);
9250     } else {
9251       dictionary->UpdateMaxNumberKey(index);
9252       // If a value has not been initialized we allow writing to it even if it
9253       // is read-only (a declared const that has not been initialized).  If a
9254       // value is being defined we skip attribute checks completely.
9255       if (set_mode == DEFINE_PROPERTY) {
9256         details = PropertyDetails(attributes, NORMAL, details.index());
9257         dictionary->DetailsAtPut(entry, details);
9258       } else if (details.IsReadOnly() && !element->IsTheHole()) {
9259         if (strict_mode == kNonStrictMode) {
9260           return isolate->heap()->undefined_value();
9261         } else {
9262           Handle<Object> holder(this);
9263           Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9264           Handle<Object> args[2] = { number, holder };
9265           Handle<Object> error =
9266               isolate->factory()->NewTypeError("strict_read_only_property",
9267                                                HandleVector(args, 2));
9268           return isolate->Throw(*error);
9269         }
9270       }
9271       // Elements of the arguments object in slow mode might be slow aliases.
9272       if (is_arguments && element->IsAliasedArgumentsEntry()) {
9273         AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
9274         Context* context = Context::cast(elements->get(0));
9275         int context_index = entry->aliased_context_slot();
9276         ASSERT(!context->get(context_index)->IsTheHole());
9277         context->set(context_index, value);
9278         // For elements that are still writable we keep slow aliasing.
9279         if (!details.IsReadOnly()) value = element;
9280       }
9281       dictionary->ValueAtPut(entry, value);
9282     }
9283   } else {
9284     // Index not already used. Look for an accessor in the prototype chain.
9285     if (check_prototype) {
9286       bool found;
9287       MaybeObject* result =
9288           SetElementWithCallbackSetterInPrototypes(
9289               index, value, &found, strict_mode);
9290       if (found) return result;
9291     }
9292     // When we set the is_extensible flag to false we always force the
9293     // element into dictionary mode (and force them to stay there).
9294     if (!map()->is_extensible()) {
9295       if (strict_mode == kNonStrictMode) {
9296         return isolate->heap()->undefined_value();
9297       } else {
9298         Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9299         Handle<String> name = isolate->factory()->NumberToString(number);
9300         Handle<Object> args[1] = { name };
9301         Handle<Object> error =
9302             isolate->factory()->NewTypeError("object_not_extensible",
9303                                              HandleVector(args, 1));
9304         return isolate->Throw(*error);
9305       }
9306     }
9307     FixedArrayBase* new_dictionary;
9308     PropertyDetails details = PropertyDetails(attributes, NORMAL);
9309     MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details);
9310     if (!maybe->To(&new_dictionary)) return maybe;
9311     if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
9312       if (is_arguments) {
9313         elements->set(1, new_dictionary);
9314       } else {
9315         set_elements(new_dictionary);
9316       }
9317       dictionary = SeededNumberDictionary::cast(new_dictionary);
9318     }
9319   }
9320 
9321   // Update the array length if this JSObject is an array.
9322   if (IsJSArray()) {
9323     MaybeObject* result =
9324         JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9325     if (result->IsFailure()) return result;
9326   }
9327 
9328   // Attempt to put this object back in fast case.
9329   if (ShouldConvertToFastElements()) {
9330     uint32_t new_length = 0;
9331     if (IsJSArray()) {
9332       CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9333     } else {
9334       new_length = dictionary->max_number_key() + 1;
9335     }
9336     SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9337         ? kAllowSmiOnlyElements
9338         : kDontAllowSmiOnlyElements;
9339     bool has_smi_only_elements = false;
9340     bool should_convert_to_fast_double_elements =
9341         ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9342     if (has_smi_only_elements) {
9343       set_capacity_mode = kForceSmiOnlyElements;
9344     }
9345     MaybeObject* result = should_convert_to_fast_double_elements
9346         ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
9347         : SetFastElementsCapacityAndLength(new_length,
9348                                            new_length,
9349                                            set_capacity_mode);
9350     if (result->IsFailure()) return result;
9351 #ifdef DEBUG
9352     if (FLAG_trace_normalization) {
9353       PrintF("Object elements are fast case again:\n");
9354       Print();
9355     }
9356 #endif
9357   }
9358   return value;
9359 }
9360 
9361 
SetFastDoubleElement(uint32_t index,Object * value,StrictModeFlag strict_mode,bool check_prototype)9362 MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9363     uint32_t index,
9364     Object* value,
9365     StrictModeFlag strict_mode,
9366     bool check_prototype) {
9367   ASSERT(HasFastDoubleElements());
9368 
9369   FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
9370   uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
9371 
9372   // If storing to an element that isn't in the array, pass the store request
9373   // up the prototype chain before storing in the receiver's elements.
9374   if (check_prototype &&
9375       (index >= elms_length ||
9376        FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
9377     bool found;
9378     MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9379                                                                    value,
9380                                                                    &found,
9381                                                                    strict_mode);
9382     if (found) return result;
9383   }
9384 
9385   // If the value object is not a heap number, switch to fast elements and try
9386   // again.
9387   bool value_is_smi = value->IsSmi();
9388   if (!value->IsNumber()) {
9389     Object* obj;
9390     uint32_t length = elms_length;
9391     if (IsJSArray()) {
9392       CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9393     }
9394     MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9395         elms_length,
9396         length,
9397         kDontAllowSmiOnlyElements);
9398     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9399     return SetFastElement(index,
9400                           value,
9401                           strict_mode,
9402                           check_prototype);
9403   }
9404 
9405   double double_value = value_is_smi
9406       ? static_cast<double>(Smi::cast(value)->value())
9407       : HeapNumber::cast(value)->value();
9408 
9409   // Check whether there is extra space in the fixed array.
9410   if (index < elms_length) {
9411     FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9412     elms->set(index, double_value);
9413     if (IsJSArray()) {
9414       // Update the length of the array if needed.
9415       uint32_t array_length = 0;
9416       CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9417       if (index >= array_length) {
9418         JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
9419       }
9420     }
9421     return value;
9422   }
9423 
9424   // Allow gap in fast case.
9425   if ((index - elms_length) < kMaxGap) {
9426     // Try allocating extra space.
9427     int new_capacity = NewElementsCapacity(index+1);
9428     if (!ShouldConvertToSlowElements(new_capacity)) {
9429       ASSERT(static_cast<uint32_t>(new_capacity) > index);
9430       Object* obj;
9431       { MaybeObject* maybe_obj =
9432             SetFastDoubleElementsCapacityAndLength(new_capacity,
9433                                                    index + 1);
9434         if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9435       }
9436       FixedDoubleArray::cast(elements())->set(index, double_value);
9437       return value;
9438     }
9439   }
9440 
9441   // Otherwise default to slow case.
9442   ASSERT(HasFastDoubleElements());
9443   ASSERT(map()->has_fast_double_elements());
9444   ASSERT(elements()->IsFixedDoubleArray());
9445   Object* obj;
9446   { MaybeObject* maybe_obj = NormalizeElements();
9447     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9448   }
9449   ASSERT(HasDictionaryElements());
9450   return SetElement(index, value, NONE, strict_mode, check_prototype);
9451 }
9452 
9453 
SetElement(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_proto)9454 MaybeObject* JSReceiver::SetElement(uint32_t index,
9455                                     Object* value,
9456                                     PropertyAttributes attributes,
9457                                     StrictModeFlag strict_mode,
9458                                     bool check_proto) {
9459   if (IsJSProxy()) {
9460     return JSProxy::cast(this)->SetElementWithHandler(
9461         index, value, strict_mode);
9462   } else {
9463     return JSObject::cast(this)->SetElement(
9464         index, value, attributes, strict_mode, check_proto);
9465   }
9466 }
9467 
9468 
SetOwnElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,StrictModeFlag strict_mode)9469 Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9470                                        uint32_t index,
9471                                        Handle<Object> value,
9472                                        StrictModeFlag strict_mode) {
9473   ASSERT(!object->HasExternalArrayElements());
9474   CALL_HEAP_FUNCTION(
9475       object->GetIsolate(),
9476       object->SetElement(index, *value, NONE, strict_mode, false),
9477       Object);
9478 }
9479 
9480 
SetElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attr,StrictModeFlag strict_mode,SetPropertyMode set_mode)9481 Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9482                                     uint32_t index,
9483                                     Handle<Object> value,
9484                                     PropertyAttributes attr,
9485                                     StrictModeFlag strict_mode,
9486                                     SetPropertyMode set_mode) {
9487   if (object->HasExternalArrayElements()) {
9488     if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9489       bool has_exception;
9490       Handle<Object> number = Execution::ToNumber(value, &has_exception);
9491       if (has_exception) return Handle<Object>();
9492       value = number;
9493     }
9494   }
9495   CALL_HEAP_FUNCTION(
9496       object->GetIsolate(),
9497       object->SetElement(index, *value, attr, strict_mode, true, set_mode),
9498       Object);
9499 }
9500 
9501 
SetElement(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)9502 MaybeObject* JSObject::SetElement(uint32_t index,
9503                                   Object* value,
9504                                   PropertyAttributes attributes,
9505                                   StrictModeFlag strict_mode,
9506                                   bool check_prototype,
9507                                   SetPropertyMode set_mode) {
9508   // Check access rights if needed.
9509   if (IsAccessCheckNeeded()) {
9510     Heap* heap = GetHeap();
9511     if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
9512       HandleScope scope(heap->isolate());
9513       Handle<Object> value_handle(value);
9514       heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9515       return *value_handle;
9516     }
9517   }
9518 
9519   if (IsJSGlobalProxy()) {
9520     Object* proto = GetPrototype();
9521     if (proto->IsNull()) return value;
9522     ASSERT(proto->IsJSGlobalObject());
9523     return JSObject::cast(proto)->SetElement(index,
9524                                              value,
9525                                              attributes,
9526                                              strict_mode,
9527                                              check_prototype,
9528                                              set_mode);
9529   }
9530 
9531   // Don't allow element properties to be redefined for external arrays.
9532   if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
9533     Isolate* isolate = GetHeap()->isolate();
9534     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9535     Handle<Object> args[] = { Handle<Object>(this), number };
9536     Handle<Object> error = isolate->factory()->NewTypeError(
9537         "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
9538     return isolate->Throw(*error);
9539   }
9540 
9541   // Normalize the elements to enable attributes on the property.
9542   if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
9543     SeededNumberDictionary* dictionary;
9544     MaybeObject* maybe_object = NormalizeElements();
9545     if (!maybe_object->To(&dictionary)) return maybe_object;
9546     // Make sure that we never go back to fast case.
9547     dictionary->set_requires_slow_elements();
9548   }
9549 
9550   // Check for lookup interceptor
9551   if (HasIndexedInterceptor()) {
9552     return SetElementWithInterceptor(index,
9553                                      value,
9554                                      attributes,
9555                                      strict_mode,
9556                                      check_prototype,
9557                                      set_mode);
9558   }
9559 
9560   return SetElementWithoutInterceptor(index,
9561                                       value,
9562                                       attributes,
9563                                       strict_mode,
9564                                       check_prototype,
9565                                       set_mode);
9566 }
9567 
9568 
SetElementWithoutInterceptor(uint32_t index,Object * value,PropertyAttributes attr,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)9569 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
9570                                                     Object* value,
9571                                                     PropertyAttributes attr,
9572                                                     StrictModeFlag strict_mode,
9573                                                     bool check_prototype,
9574                                                     SetPropertyMode set_mode) {
9575   ASSERT(HasDictionaryElements() ||
9576          HasDictionaryArgumentsElements() ||
9577          (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
9578   Isolate* isolate = GetIsolate();
9579   switch (GetElementsKind()) {
9580     case FAST_SMI_ONLY_ELEMENTS:
9581     case FAST_ELEMENTS:
9582       return SetFastElement(index, value, strict_mode, check_prototype);
9583     case FAST_DOUBLE_ELEMENTS:
9584       return SetFastDoubleElement(index, value, strict_mode, check_prototype);
9585     case EXTERNAL_PIXEL_ELEMENTS: {
9586       ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
9587       return pixels->SetValue(index, value);
9588     }
9589     case EXTERNAL_BYTE_ELEMENTS: {
9590       ExternalByteArray* array = ExternalByteArray::cast(elements());
9591       return array->SetValue(index, value);
9592     }
9593     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9594       ExternalUnsignedByteArray* array =
9595           ExternalUnsignedByteArray::cast(elements());
9596       return array->SetValue(index, value);
9597     }
9598     case EXTERNAL_SHORT_ELEMENTS: {
9599       ExternalShortArray* array = ExternalShortArray::cast(elements());
9600       return array->SetValue(index, value);
9601     }
9602     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9603       ExternalUnsignedShortArray* array =
9604           ExternalUnsignedShortArray::cast(elements());
9605       return array->SetValue(index, value);
9606     }
9607     case EXTERNAL_INT_ELEMENTS: {
9608       ExternalIntArray* array = ExternalIntArray::cast(elements());
9609       return array->SetValue(index, value);
9610     }
9611     case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9612       ExternalUnsignedIntArray* array =
9613           ExternalUnsignedIntArray::cast(elements());
9614       return array->SetValue(index, value);
9615     }
9616     case EXTERNAL_FLOAT_ELEMENTS: {
9617       ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9618       return array->SetValue(index, value);
9619     }
9620     case EXTERNAL_DOUBLE_ELEMENTS: {
9621       ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9622       return array->SetValue(index, value);
9623     }
9624     case DICTIONARY_ELEMENTS:
9625       return SetDictionaryElement(index, value, attr, strict_mode,
9626                                   check_prototype, set_mode);
9627     case NON_STRICT_ARGUMENTS_ELEMENTS: {
9628       FixedArray* parameter_map = FixedArray::cast(elements());
9629       uint32_t length = parameter_map->length();
9630       Object* probe =
9631           (index < length - 2) ? parameter_map->get(index + 2) : NULL;
9632       if (probe != NULL && !probe->IsTheHole()) {
9633         Context* context = Context::cast(parameter_map->get(0));
9634         int context_index = Smi::cast(probe)->value();
9635         ASSERT(!context->get(context_index)->IsTheHole());
9636         context->set(context_index, value);
9637         // Redefining attributes of an aliased element destroys fast aliasing.
9638         if (set_mode == SET_PROPERTY || attr == NONE) return value;
9639         parameter_map->set_the_hole(index + 2);
9640         // For elements that are still writable we re-establish slow aliasing.
9641         if ((attr & READ_ONLY) == 0) {
9642           MaybeObject* maybe_entry =
9643               isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
9644           if (!maybe_entry->ToObject(&value)) return maybe_entry;
9645         }
9646       }
9647       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9648       if (arguments->IsDictionary()) {
9649         return SetDictionaryElement(index, value, attr, strict_mode,
9650                                     check_prototype, set_mode);
9651       } else {
9652         return SetFastElement(index, value, strict_mode, check_prototype);
9653       }
9654     }
9655   }
9656   // All possible cases have been handled above. Add a return to avoid the
9657   // complaints from the compiler.
9658   UNREACHABLE();
9659   return isolate->heap()->null_value();
9660 }
9661 
9662 
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)9663 Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9664                                                 ElementsKind to_kind) {
9665   CALL_HEAP_FUNCTION(object->GetIsolate(),
9666                      object->TransitionElementsKind(to_kind),
9667                      Object);
9668 }
9669 
9670 
TransitionElementsKind(ElementsKind to_kind)9671 MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
9672   ElementsKind from_kind = map()->elements_kind();
9673 
9674   Isolate* isolate = GetIsolate();
9675   if ((from_kind == FAST_SMI_ONLY_ELEMENTS ||
9676       elements() == isolate->heap()->empty_fixed_array()) &&
9677       to_kind == FAST_ELEMENTS) {
9678     ASSERT(from_kind != FAST_ELEMENTS);
9679     MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9680     Map* new_map;
9681     if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9682     set_map(new_map);
9683     if (FLAG_trace_elements_transitions) {
9684       FixedArrayBase* elms = FixedArrayBase::cast(elements());
9685       PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9686     }
9687     return this;
9688   }
9689 
9690   FixedArrayBase* elms = FixedArrayBase::cast(elements());
9691   uint32_t capacity = static_cast<uint32_t>(elms->length());
9692   uint32_t length = capacity;
9693 
9694   if (IsJSArray()) {
9695     Object* raw_length = JSArray::cast(this)->length();
9696     if (raw_length->IsUndefined()) {
9697       // If length is undefined, then JSArray is being initialized and has no
9698       // elements, assume a length of zero.
9699       length = 0;
9700     } else {
9701       CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9702     }
9703   }
9704 
9705   if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9706       to_kind == FAST_DOUBLE_ELEMENTS) {
9707     MaybeObject* maybe_result =
9708         SetFastDoubleElementsCapacityAndLength(capacity, length);
9709     if (maybe_result->IsFailure()) return maybe_result;
9710     return this;
9711   }
9712 
9713   if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
9714     MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9715         capacity, length, kDontAllowSmiOnlyElements);
9716     if (maybe_result->IsFailure()) return maybe_result;
9717     return this;
9718   }
9719 
9720   // This method should never be called for any other case than the ones
9721   // handled above.
9722   UNREACHABLE();
9723   return GetIsolate()->heap()->null_value();
9724 }
9725 
9726 
9727 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)9728 bool Map::IsValidElementsTransition(ElementsKind from_kind,
9729                                     ElementsKind to_kind) {
9730   return
9731       (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9732           (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9733       (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9734 }
9735 
9736 
JSArrayUpdateLengthFromIndex(uint32_t index,Object * value)9737 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9738                                                    Object* value) {
9739   uint32_t old_len = 0;
9740   CHECK(length()->ToArrayIndex(&old_len));
9741   // Check to see if we need to update the length. For now, we make
9742   // sure that the length stays within 32-bits (unsigned).
9743   if (index >= old_len && index != 0xffffffff) {
9744     Object* len;
9745     { MaybeObject* maybe_len =
9746           GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
9747       if (!maybe_len->ToObject(&len)) return maybe_len;
9748     }
9749     set_length(len);
9750   }
9751   return value;
9752 }
9753 
9754 
GetElementWithInterceptor(Object * receiver,uint32_t index)9755 MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
9756                                                  uint32_t index) {
9757   Isolate* isolate = GetIsolate();
9758   // Make sure that the top context does not change when doing
9759   // callbacks or interceptor calls.
9760   AssertNoContextChange ncc;
9761   HandleScope scope(isolate);
9762   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9763   Handle<Object> this_handle(receiver, isolate);
9764   Handle<JSObject> holder_handle(this, isolate);
9765   if (!interceptor->getter()->IsUndefined()) {
9766     v8::IndexedPropertyGetter getter =
9767         v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
9768     LOG(isolate,
9769         ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9770     CustomArguments args(isolate, interceptor->data(), receiver, this);
9771     v8::AccessorInfo info(args.end());
9772     v8::Handle<v8::Value> result;
9773     {
9774       // Leaving JavaScript.
9775       VMState state(isolate, EXTERNAL);
9776       result = getter(index, info);
9777     }
9778     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9779     if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9780   }
9781 
9782   Heap* heap = holder_handle->GetHeap();
9783   ElementsAccessor* handler = holder_handle->GetElementsAccessor();
9784   MaybeObject* raw_result = handler->Get(*this_handle,
9785                                          *holder_handle,
9786                                          index);
9787   if (raw_result != heap->the_hole_value()) return raw_result;
9788 
9789   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9790 
9791   Object* pt = holder_handle->GetPrototype();
9792   if (pt == heap->null_value()) return heap->undefined_value();
9793   return pt->GetElementWithReceiver(*this_handle, index);
9794 }
9795 
9796 
HasDenseElements()9797 bool JSObject::HasDenseElements() {
9798   int capacity = 0;
9799   int used = 0;
9800   GetElementsCapacityAndUsage(&capacity, &used);
9801   return (capacity == 0) || (used > (capacity / 2));
9802 }
9803 
9804 
GetElementsCapacityAndUsage(int * capacity,int * used)9805 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9806   *capacity = 0;
9807   *used = 0;
9808 
9809   FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9810   FixedArray* backing_store = NULL;
9811   switch (GetElementsKind()) {
9812     case NON_STRICT_ARGUMENTS_ELEMENTS:
9813       backing_store_base =
9814           FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9815       backing_store = FixedArray::cast(backing_store_base);
9816       if (backing_store->IsDictionary()) {
9817         SeededNumberDictionary* dictionary =
9818             SeededNumberDictionary::cast(backing_store);
9819         *capacity = dictionary->Capacity();
9820         *used = dictionary->NumberOfElements();
9821         break;
9822       }
9823       // Fall through.
9824     case FAST_SMI_ONLY_ELEMENTS:
9825     case FAST_ELEMENTS:
9826       backing_store = FixedArray::cast(backing_store_base);
9827       *capacity = backing_store->length();
9828       for (int i = 0; i < *capacity; ++i) {
9829         if (!backing_store->get(i)->IsTheHole()) ++(*used);
9830       }
9831       break;
9832     case DICTIONARY_ELEMENTS: {
9833       SeededNumberDictionary* dictionary =
9834           SeededNumberDictionary::cast(FixedArray::cast(elements()));
9835       *capacity = dictionary->Capacity();
9836       *used = dictionary->NumberOfElements();
9837       break;
9838     }
9839     case FAST_DOUBLE_ELEMENTS: {
9840       FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9841       *capacity = elms->length();
9842       for (int i = 0; i < *capacity; i++) {
9843         if (!elms->is_the_hole(i)) ++(*used);
9844       }
9845       break;
9846     }
9847     case EXTERNAL_BYTE_ELEMENTS:
9848     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9849     case EXTERNAL_SHORT_ELEMENTS:
9850     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9851     case EXTERNAL_INT_ELEMENTS:
9852     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9853     case EXTERNAL_FLOAT_ELEMENTS:
9854     case EXTERNAL_DOUBLE_ELEMENTS:
9855     case EXTERNAL_PIXEL_ELEMENTS:
9856       // External arrays are considered 100% used.
9857       ExternalArray* external_array = ExternalArray::cast(elements());
9858       *capacity = external_array->length();
9859       *used = external_array->length();
9860       break;
9861   }
9862 }
9863 
9864 
ShouldConvertToSlowElements(int new_capacity)9865 bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
9866   STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
9867                 kMaxUncheckedFastElementsLength);
9868   if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
9869       (new_capacity <= kMaxUncheckedFastElementsLength &&
9870        GetHeap()->InNewSpace(this))) {
9871     return false;
9872   }
9873   // If the fast-case backing storage takes up roughly three times as
9874   // much space (in machine words) as a dictionary backing storage
9875   // would, the object should have slow elements.
9876   int old_capacity = 0;
9877   int used_elements = 0;
9878   GetElementsCapacityAndUsage(&old_capacity, &used_elements);
9879   int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
9880       SeededNumberDictionary::kEntrySize;
9881   return 3 * dictionary_size <= new_capacity;
9882 }
9883 
9884 
ShouldConvertToFastElements()9885 bool JSObject::ShouldConvertToFastElements() {
9886   ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9887   // If the elements are sparse, we should not go back to fast case.
9888   if (!HasDenseElements()) return false;
9889   // An object requiring access checks is never allowed to have fast
9890   // elements.  If it had fast elements we would skip security checks.
9891   if (IsAccessCheckNeeded()) return false;
9892 
9893   FixedArray* elements = FixedArray::cast(this->elements());
9894   SeededNumberDictionary* dictionary = NULL;
9895   if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
9896     dictionary = SeededNumberDictionary::cast(elements->get(1));
9897   } else {
9898     dictionary = SeededNumberDictionary::cast(elements);
9899   }
9900   // If an element has been added at a very high index in the elements
9901   // dictionary, we cannot go back to fast case.
9902   if (dictionary->requires_slow_elements()) return false;
9903   // If the dictionary backing storage takes up roughly half as much
9904   // space (in machine words) as a fast-case backing storage would,
9905   // the object should have fast elements.
9906   uint32_t array_size = 0;
9907   if (IsJSArray()) {
9908     CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
9909   } else {
9910     array_size = dictionary->max_number_key();
9911   }
9912   uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
9913       SeededNumberDictionary::kEntrySize;
9914   return 2 * dictionary_size >= array_size;
9915 }
9916 
9917 
ShouldConvertToFastDoubleElements(bool * has_smi_only_elements)9918 bool JSObject::ShouldConvertToFastDoubleElements(
9919     bool* has_smi_only_elements) {
9920   *has_smi_only_elements = false;
9921   if (FLAG_unbox_double_arrays) {
9922     ASSERT(HasDictionaryElements());
9923     SeededNumberDictionary* dictionary =
9924         SeededNumberDictionary::cast(elements());
9925     bool found_double = false;
9926     for (int i = 0; i < dictionary->Capacity(); i++) {
9927       Object* key = dictionary->KeyAt(i);
9928       if (key->IsNumber()) {
9929         Object* value = dictionary->ValueAt(i);
9930         if (!value->IsNumber()) return false;
9931         if (!value->IsSmi()) {
9932           found_double = true;
9933         }
9934       }
9935     }
9936     *has_smi_only_elements = !found_double;
9937     return found_double;
9938   } else {
9939     return false;
9940   }
9941 }
9942 
9943 
9944 // Certain compilers request function template instantiation when they
9945 // see the definition of the other template functions in the
9946 // class. This requires us to have the template functions put
9947 // together, so even though this function belongs in objects-debug.cc,
9948 // we keep it here instead to satisfy certain compilers.
9949 #ifdef OBJECT_PRINT
9950 template<typename Shape, typename Key>
Print(FILE * out)9951 void Dictionary<Shape, Key>::Print(FILE* out) {
9952   int capacity = HashTable<Shape, Key>::Capacity();
9953   for (int i = 0; i < capacity; i++) {
9954     Object* k = HashTable<Shape, Key>::KeyAt(i);
9955     if (HashTable<Shape, Key>::IsKey(k)) {
9956       PrintF(out, " ");
9957       if (k->IsString()) {
9958         String::cast(k)->StringPrint(out);
9959       } else {
9960         k->ShortPrint(out);
9961       }
9962       PrintF(out, ": ");
9963       ValueAt(i)->ShortPrint(out);
9964       PrintF(out, "\n");
9965     }
9966   }
9967 }
9968 #endif
9969 
9970 
9971 template<typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)9972 void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
9973   int pos = 0;
9974   int capacity = HashTable<Shape, Key>::Capacity();
9975   AssertNoAllocation no_gc;
9976   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
9977   for (int i = 0; i < capacity; i++) {
9978     Object* k =  Dictionary<Shape, Key>::KeyAt(i);
9979     if (Dictionary<Shape, Key>::IsKey(k)) {
9980       elements->set(pos++, ValueAt(i), mode);
9981     }
9982   }
9983   ASSERT(pos == elements->length());
9984 }
9985 
9986 
GetNamedInterceptor()9987 InterceptorInfo* JSObject::GetNamedInterceptor() {
9988   ASSERT(map()->has_named_interceptor());
9989   JSFunction* constructor = JSFunction::cast(map()->constructor());
9990   ASSERT(constructor->shared()->IsApiFunction());
9991   Object* result =
9992       constructor->shared()->get_api_func_data()->named_property_handler();
9993   return InterceptorInfo::cast(result);
9994 }
9995 
9996 
GetIndexedInterceptor()9997 InterceptorInfo* JSObject::GetIndexedInterceptor() {
9998   ASSERT(map()->has_indexed_interceptor());
9999   JSFunction* constructor = JSFunction::cast(map()->constructor());
10000   ASSERT(constructor->shared()->IsApiFunction());
10001   Object* result =
10002       constructor->shared()->get_api_func_data()->indexed_property_handler();
10003   return InterceptorInfo::cast(result);
10004 }
10005 
10006 
GetPropertyPostInterceptor(JSReceiver * receiver,String * name,PropertyAttributes * attributes)10007 MaybeObject* JSObject::GetPropertyPostInterceptor(
10008     JSReceiver* receiver,
10009     String* name,
10010     PropertyAttributes* attributes) {
10011   // Check local property in holder, ignore interceptor.
10012   LookupResult result(GetIsolate());
10013   LocalLookupRealNamedProperty(name, &result);
10014   if (result.IsProperty()) {
10015     return GetProperty(receiver, &result, name, attributes);
10016   }
10017   // Continue searching via the prototype chain.
10018   Object* pt = GetPrototype();
10019   *attributes = ABSENT;
10020   if (pt->IsNull()) return GetHeap()->undefined_value();
10021   return pt->GetPropertyWithReceiver(receiver, name, attributes);
10022 }
10023 
10024 
GetLocalPropertyPostInterceptor(JSReceiver * receiver,String * name,PropertyAttributes * attributes)10025 MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
10026     JSReceiver* receiver,
10027     String* name,
10028     PropertyAttributes* attributes) {
10029   // Check local property in holder, ignore interceptor.
10030   LookupResult result(GetIsolate());
10031   LocalLookupRealNamedProperty(name, &result);
10032   if (result.IsProperty()) {
10033     return GetProperty(receiver, &result, name, attributes);
10034   }
10035   return GetHeap()->undefined_value();
10036 }
10037 
10038 
GetPropertyWithInterceptor(JSReceiver * receiver,String * name,PropertyAttributes * attributes)10039 MaybeObject* JSObject::GetPropertyWithInterceptor(
10040     JSReceiver* receiver,
10041     String* name,
10042     PropertyAttributes* attributes) {
10043   Isolate* isolate = GetIsolate();
10044   InterceptorInfo* interceptor = GetNamedInterceptor();
10045   HandleScope scope(isolate);
10046   Handle<JSReceiver> receiver_handle(receiver);
10047   Handle<JSObject> holder_handle(this);
10048   Handle<String> name_handle(name);
10049 
10050   if (!interceptor->getter()->IsUndefined()) {
10051     v8::NamedPropertyGetter getter =
10052         v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
10053     LOG(isolate,
10054         ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10055     CustomArguments args(isolate, interceptor->data(), receiver, this);
10056     v8::AccessorInfo info(args.end());
10057     v8::Handle<v8::Value> result;
10058     {
10059       // Leaving JavaScript.
10060       VMState state(isolate, EXTERNAL);
10061       result = getter(v8::Utils::ToLocal(name_handle), info);
10062     }
10063     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
10064     if (!result.IsEmpty()) {
10065       *attributes = NONE;
10066       return *v8::Utils::OpenHandle(*result);
10067     }
10068   }
10069 
10070   MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
10071       *receiver_handle,
10072       *name_handle,
10073       attributes);
10074   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
10075   return result;
10076 }
10077 
10078 
HasRealNamedProperty(String * key)10079 bool JSObject::HasRealNamedProperty(String* key) {
10080   // Check access rights if needed.
10081   Isolate* isolate = GetIsolate();
10082   if (IsAccessCheckNeeded()) {
10083     if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10084       isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10085       return false;
10086     }
10087   }
10088 
10089   LookupResult result(isolate);
10090   LocalLookupRealNamedProperty(key, &result);
10091   return result.IsProperty() && (result.type() != INTERCEPTOR);
10092 }
10093 
10094 
HasRealElementProperty(uint32_t index)10095 bool JSObject::HasRealElementProperty(uint32_t index) {
10096   // Check access rights if needed.
10097   if (IsAccessCheckNeeded()) {
10098     Heap* heap = GetHeap();
10099     if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10100       heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10101       return false;
10102     }
10103   }
10104 
10105   // Handle [] on String objects.
10106   if (this->IsStringObjectWithCharacterAt(index)) return true;
10107 
10108   switch (GetElementsKind()) {
10109     case FAST_SMI_ONLY_ELEMENTS:
10110     case FAST_ELEMENTS: {
10111       uint32_t length = IsJSArray() ?
10112           static_cast<uint32_t>(
10113               Smi::cast(JSArray::cast(this)->length())->value()) :
10114           static_cast<uint32_t>(FixedArray::cast(elements())->length());
10115       return (index < length) &&
10116           !FixedArray::cast(elements())->get(index)->IsTheHole();
10117     }
10118     case FAST_DOUBLE_ELEMENTS: {
10119       uint32_t length = IsJSArray() ?
10120           static_cast<uint32_t>(
10121               Smi::cast(JSArray::cast(this)->length())->value()) :
10122           static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
10123       return (index < length) &&
10124           !FixedDoubleArray::cast(elements())->is_the_hole(index);
10125       break;
10126     }
10127     case EXTERNAL_PIXEL_ELEMENTS: {
10128       ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
10129       return index < static_cast<uint32_t>(pixels->length());
10130     }
10131     case EXTERNAL_BYTE_ELEMENTS:
10132     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10133     case EXTERNAL_SHORT_ELEMENTS:
10134     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10135     case EXTERNAL_INT_ELEMENTS:
10136     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10137     case EXTERNAL_FLOAT_ELEMENTS:
10138     case EXTERNAL_DOUBLE_ELEMENTS: {
10139       ExternalArray* array = ExternalArray::cast(elements());
10140       return index < static_cast<uint32_t>(array->length());
10141     }
10142     case DICTIONARY_ELEMENTS: {
10143       return element_dictionary()->FindEntry(index)
10144           != SeededNumberDictionary::kNotFound;
10145     }
10146     case NON_STRICT_ARGUMENTS_ELEMENTS:
10147       UNIMPLEMENTED();
10148       break;
10149   }
10150   // All possibilities have been handled above already.
10151   UNREACHABLE();
10152   return GetHeap()->null_value();
10153 }
10154 
10155 
HasRealNamedCallbackProperty(String * key)10156 bool JSObject::HasRealNamedCallbackProperty(String* key) {
10157   // Check access rights if needed.
10158   Isolate* isolate = GetIsolate();
10159   if (IsAccessCheckNeeded()) {
10160     if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10161       isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10162       return false;
10163     }
10164   }
10165 
10166   LookupResult result(isolate);
10167   LocalLookupRealNamedProperty(key, &result);
10168   return result.IsFound() && (result.type() == CALLBACKS);
10169 }
10170 
10171 
NumberOfLocalProperties(PropertyAttributes filter)10172 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
10173   return HasFastProperties() ?
10174       map()->NumberOfDescribedProperties(filter) :
10175       property_dictionary()->NumberOfElementsFilterAttributes(filter);
10176 }
10177 
10178 
SwapPairs(FixedArray * numbers,int i,int j)10179 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
10180   Object* temp = get(i);
10181   set(i, get(j));
10182   set(j, temp);
10183   if (this != numbers) {
10184     temp = numbers->get(i);
10185     numbers->set(i, Smi::cast(numbers->get(j)));
10186     numbers->set(j, Smi::cast(temp));
10187   }
10188 }
10189 
10190 
InsertionSortPairs(FixedArray * content,FixedArray * numbers,int len)10191 static void InsertionSortPairs(FixedArray* content,
10192                                FixedArray* numbers,
10193                                int len) {
10194   for (int i = 1; i < len; i++) {
10195     int j = i;
10196     while (j > 0 &&
10197            (NumberToUint32(numbers->get(j - 1)) >
10198             NumberToUint32(numbers->get(j)))) {
10199       content->SwapPairs(numbers, j - 1, j);
10200       j--;
10201     }
10202   }
10203 }
10204 
10205 
HeapSortPairs(FixedArray * content,FixedArray * numbers,int len)10206 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
10207   // In-place heap sort.
10208   ASSERT(content->length() == numbers->length());
10209 
10210   // Bottom-up max-heap construction.
10211   for (int i = 1; i < len; ++i) {
10212     int child_index = i;
10213     while (child_index > 0) {
10214       int parent_index = ((child_index + 1) >> 1) - 1;
10215       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10216       uint32_t child_value = NumberToUint32(numbers->get(child_index));
10217       if (parent_value < child_value) {
10218         content->SwapPairs(numbers, parent_index, child_index);
10219       } else {
10220         break;
10221       }
10222       child_index = parent_index;
10223     }
10224   }
10225 
10226   // Extract elements and create sorted array.
10227   for (int i = len - 1; i > 0; --i) {
10228     // Put max element at the back of the array.
10229     content->SwapPairs(numbers, 0, i);
10230     // Sift down the new top element.
10231     int parent_index = 0;
10232     while (true) {
10233       int child_index = ((parent_index + 1) << 1) - 1;
10234       if (child_index >= i) break;
10235       uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10236       uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10237       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10238       if (child_index + 1 >= i || child1_value > child2_value) {
10239         if (parent_value > child1_value) break;
10240         content->SwapPairs(numbers, parent_index, child_index);
10241         parent_index = child_index;
10242       } else {
10243         if (parent_value > child2_value) break;
10244         content->SwapPairs(numbers, parent_index, child_index + 1);
10245         parent_index = child_index + 1;
10246       }
10247     }
10248   }
10249 }
10250 
10251 
10252 // Sort this array and the numbers as pairs wrt. the (distinct) numbers.
SortPairs(FixedArray * numbers,uint32_t len)10253 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10254   ASSERT(this->length() == numbers->length());
10255   // For small arrays, simply use insertion sort.
10256   if (len <= 10) {
10257     InsertionSortPairs(this, numbers, len);
10258     return;
10259   }
10260   // Check the range of indices.
10261   uint32_t min_index = NumberToUint32(numbers->get(0));
10262   uint32_t max_index = min_index;
10263   uint32_t i;
10264   for (i = 1; i < len; i++) {
10265     if (NumberToUint32(numbers->get(i)) < min_index) {
10266       min_index = NumberToUint32(numbers->get(i));
10267     } else if (NumberToUint32(numbers->get(i)) > max_index) {
10268       max_index = NumberToUint32(numbers->get(i));
10269     }
10270   }
10271   if (max_index - min_index + 1 == len) {
10272     // Indices form a contiguous range, unless there are duplicates.
10273     // Do an in-place linear time sort assuming distinct numbers, but
10274     // avoid hanging in case they are not.
10275     for (i = 0; i < len; i++) {
10276       uint32_t p;
10277       uint32_t j = 0;
10278       // While the current element at i is not at its correct position p,
10279       // swap the elements at these two positions.
10280       while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
10281              j++ < len) {
10282         SwapPairs(numbers, i, p);
10283       }
10284     }
10285   } else {
10286     HeapSortPairs(this, numbers, len);
10287     return;
10288   }
10289 }
10290 
10291 
10292 // Fill in the names of local properties into the supplied storage. The main
10293 // purpose of this function is to provide reflection information for the object
10294 // mirrors.
GetLocalPropertyNames(FixedArray * storage,int index)10295 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
10296   ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
10297   if (HasFastProperties()) {
10298     DescriptorArray* descs = map()->instance_descriptors();
10299     for (int i = 0; i < descs->number_of_descriptors(); i++) {
10300       if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
10301     }
10302     ASSERT(storage->length() >= index);
10303   } else {
10304     property_dictionary()->CopyKeysTo(storage,
10305                                       index,
10306                                       StringDictionary::UNSORTED);
10307   }
10308 }
10309 
10310 
NumberOfLocalElements(PropertyAttributes filter)10311 int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10312   return GetLocalElementKeys(NULL, filter);
10313 }
10314 
10315 
NumberOfEnumElements()10316 int JSObject::NumberOfEnumElements() {
10317   // Fast case for objects with no elements.
10318   if (!IsJSValue() && HasFastElements()) {
10319     uint32_t length = IsJSArray() ?
10320         static_cast<uint32_t>(
10321             Smi::cast(JSArray::cast(this)->length())->value()) :
10322         static_cast<uint32_t>(FixedArray::cast(elements())->length());
10323     if (length == 0) return 0;
10324   }
10325   // Compute the number of enumerable elements.
10326   return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10327 }
10328 
10329 
GetLocalElementKeys(FixedArray * storage,PropertyAttributes filter)10330 int JSObject::GetLocalElementKeys(FixedArray* storage,
10331                                   PropertyAttributes filter) {
10332   int counter = 0;
10333   switch (GetElementsKind()) {
10334     case FAST_SMI_ONLY_ELEMENTS:
10335     case FAST_ELEMENTS: {
10336       int length = IsJSArray() ?
10337           Smi::cast(JSArray::cast(this)->length())->value() :
10338           FixedArray::cast(elements())->length();
10339       for (int i = 0; i < length; i++) {
10340         if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10341           if (storage != NULL) {
10342             storage->set(counter, Smi::FromInt(i));
10343           }
10344           counter++;
10345         }
10346       }
10347       ASSERT(!storage || storage->length() >= counter);
10348       break;
10349     }
10350     case FAST_DOUBLE_ELEMENTS: {
10351       int length = IsJSArray() ?
10352           Smi::cast(JSArray::cast(this)->length())->value() :
10353           FixedDoubleArray::cast(elements())->length();
10354       for (int i = 0; i < length; i++) {
10355         if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10356           if (storage != NULL) {
10357             storage->set(counter, Smi::FromInt(i));
10358           }
10359           counter++;
10360         }
10361       }
10362       ASSERT(!storage || storage->length() >= counter);
10363       break;
10364     }
10365     case EXTERNAL_PIXEL_ELEMENTS: {
10366       int length = ExternalPixelArray::cast(elements())->length();
10367       while (counter < length) {
10368         if (storage != NULL) {
10369           storage->set(counter, Smi::FromInt(counter));
10370         }
10371         counter++;
10372       }
10373       ASSERT(!storage || storage->length() >= counter);
10374       break;
10375     }
10376     case EXTERNAL_BYTE_ELEMENTS:
10377     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10378     case EXTERNAL_SHORT_ELEMENTS:
10379     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10380     case EXTERNAL_INT_ELEMENTS:
10381     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10382     case EXTERNAL_FLOAT_ELEMENTS:
10383     case EXTERNAL_DOUBLE_ELEMENTS: {
10384       int length = ExternalArray::cast(elements())->length();
10385       while (counter < length) {
10386         if (storage != NULL) {
10387           storage->set(counter, Smi::FromInt(counter));
10388         }
10389         counter++;
10390       }
10391       ASSERT(!storage || storage->length() >= counter);
10392       break;
10393     }
10394     case DICTIONARY_ELEMENTS: {
10395       if (storage != NULL) {
10396         element_dictionary()->CopyKeysTo(storage,
10397                                          filter,
10398                                          SeededNumberDictionary::SORTED);
10399       }
10400       counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
10401       break;
10402     }
10403     case NON_STRICT_ARGUMENTS_ELEMENTS: {
10404       FixedArray* parameter_map = FixedArray::cast(elements());
10405       int mapped_length = parameter_map->length() - 2;
10406       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10407       if (arguments->IsDictionary()) {
10408         // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10409         // will insert in storage starting at index 0.
10410         SeededNumberDictionary* dictionary =
10411             SeededNumberDictionary::cast(arguments);
10412         if (storage != NULL) {
10413           dictionary->CopyKeysTo(
10414               storage, filter, SeededNumberDictionary::UNSORTED);
10415         }
10416         counter += dictionary->NumberOfElementsFilterAttributes(filter);
10417         for (int i = 0; i < mapped_length; ++i) {
10418           if (!parameter_map->get(i + 2)->IsTheHole()) {
10419             if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10420             ++counter;
10421           }
10422         }
10423         if (storage != NULL) storage->SortPairs(storage, counter);
10424 
10425       } else {
10426         int backing_length = arguments->length();
10427         int i = 0;
10428         for (; i < mapped_length; ++i) {
10429           if (!parameter_map->get(i + 2)->IsTheHole()) {
10430             if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10431             ++counter;
10432           } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10433             if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10434             ++counter;
10435           }
10436         }
10437         for (; i < backing_length; ++i) {
10438           if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10439           ++counter;
10440         }
10441       }
10442       break;
10443     }
10444   }
10445 
10446   if (this->IsJSValue()) {
10447     Object* val = JSValue::cast(this)->value();
10448     if (val->IsString()) {
10449       String* str = String::cast(val);
10450       if (storage) {
10451         for (int i = 0; i < str->length(); i++) {
10452           storage->set(counter + i, Smi::FromInt(i));
10453         }
10454       }
10455       counter += str->length();
10456     }
10457   }
10458   ASSERT(!storage || storage->length() == counter);
10459   return counter;
10460 }
10461 
10462 
GetEnumElementKeys(FixedArray * storage)10463 int JSObject::GetEnumElementKeys(FixedArray* storage) {
10464   return GetLocalElementKeys(storage,
10465                              static_cast<PropertyAttributes>(DONT_ENUM));
10466 }
10467 
10468 
10469 // StringKey simply carries a string object as key.
10470 class StringKey : public HashTableKey {
10471  public:
StringKey(String * string)10472   explicit StringKey(String* string) :
10473       string_(string),
10474       hash_(HashForObject(string)) { }
10475 
IsMatch(Object * string)10476   bool IsMatch(Object* string) {
10477     // We know that all entries in a hash table had their hash keys created.
10478     // Use that knowledge to have fast failure.
10479     if (hash_ != HashForObject(string)) {
10480       return false;
10481     }
10482     return string_->Equals(String::cast(string));
10483   }
10484 
Hash()10485   uint32_t Hash() { return hash_; }
10486 
HashForObject(Object * other)10487   uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
10488 
AsObject()10489   Object* AsObject() { return string_; }
10490 
10491   String* string_;
10492   uint32_t hash_;
10493 };
10494 
10495 
10496 // StringSharedKeys are used as keys in the eval cache.
10497 class StringSharedKey : public HashTableKey {
10498  public:
StringSharedKey(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int scope_position)10499   StringSharedKey(String* source,
10500                   SharedFunctionInfo* shared,
10501                   LanguageMode language_mode,
10502                   int scope_position)
10503       : source_(source),
10504         shared_(shared),
10505         language_mode_(language_mode),
10506         scope_position_(scope_position) { }
10507 
IsMatch(Object * other)10508   bool IsMatch(Object* other) {
10509     if (!other->IsFixedArray()) return false;
10510     FixedArray* other_array = FixedArray::cast(other);
10511     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10512     if (shared != shared_) return false;
10513     int language_unchecked = Smi::cast(other_array->get(2))->value();
10514     ASSERT(language_unchecked == CLASSIC_MODE ||
10515            language_unchecked == STRICT_MODE ||
10516            language_unchecked == EXTENDED_MODE);
10517     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10518     if (language_mode != language_mode_) return false;
10519     int scope_position = Smi::cast(other_array->get(3))->value();
10520     if (scope_position != scope_position_) return false;
10521     String* source = String::cast(other_array->get(1));
10522     return source->Equals(source_);
10523   }
10524 
StringSharedHashHelper(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int scope_position)10525   static uint32_t StringSharedHashHelper(String* source,
10526                                          SharedFunctionInfo* shared,
10527                                          LanguageMode language_mode,
10528                                          int scope_position) {
10529     uint32_t hash = source->Hash();
10530     if (shared->HasSourceCode()) {
10531       // Instead of using the SharedFunctionInfo pointer in the hash
10532       // code computation, we use a combination of the hash of the
10533       // script source code and the start position of the calling scope.
10534       // We do this to ensure that the cache entries can survive garbage
10535       // collection.
10536       Script* script = Script::cast(shared->script());
10537       hash ^= String::cast(script->source())->Hash();
10538       if (language_mode == STRICT_MODE) hash ^= 0x8000;
10539       if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
10540       hash += scope_position;
10541     }
10542     return hash;
10543   }
10544 
Hash()10545   uint32_t Hash() {
10546     return StringSharedHashHelper(
10547         source_, shared_, language_mode_, scope_position_);
10548   }
10549 
HashForObject(Object * obj)10550   uint32_t HashForObject(Object* obj) {
10551     FixedArray* other_array = FixedArray::cast(obj);
10552     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10553     String* source = String::cast(other_array->get(1));
10554     int language_unchecked = Smi::cast(other_array->get(2))->value();
10555     ASSERT(language_unchecked == CLASSIC_MODE ||
10556            language_unchecked == STRICT_MODE ||
10557            language_unchecked == EXTENDED_MODE);
10558     LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10559     int scope_position = Smi::cast(other_array->get(3))->value();
10560     return StringSharedHashHelper(
10561         source, shared, language_mode, scope_position);
10562   }
10563 
AsObject()10564   MUST_USE_RESULT MaybeObject* AsObject() {
10565     Object* obj;
10566     { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
10567       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10568     }
10569     FixedArray* other_array = FixedArray::cast(obj);
10570     other_array->set(0, shared_);
10571     other_array->set(1, source_);
10572     other_array->set(2, Smi::FromInt(language_mode_));
10573     other_array->set(3, Smi::FromInt(scope_position_));
10574     return other_array;
10575   }
10576 
10577  private:
10578   String* source_;
10579   SharedFunctionInfo* shared_;
10580   LanguageMode language_mode_;
10581   int scope_position_;
10582 };
10583 
10584 
10585 // RegExpKey carries the source and flags of a regular expression as key.
10586 class RegExpKey : public HashTableKey {
10587  public:
RegExpKey(String * string,JSRegExp::Flags flags)10588   RegExpKey(String* string, JSRegExp::Flags flags)
10589       : string_(string),
10590         flags_(Smi::FromInt(flags.value())) { }
10591 
10592   // Rather than storing the key in the hash table, a pointer to the
10593   // stored value is stored where the key should be.  IsMatch then
10594   // compares the search key to the found object, rather than comparing
10595   // a key to a key.
IsMatch(Object * obj)10596   bool IsMatch(Object* obj) {
10597     FixedArray* val = FixedArray::cast(obj);
10598     return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10599         && (flags_ == val->get(JSRegExp::kFlagsIndex));
10600   }
10601 
Hash()10602   uint32_t Hash() { return RegExpHash(string_, flags_); }
10603 
AsObject()10604   Object* AsObject() {
10605     // Plain hash maps, which is where regexp keys are used, don't
10606     // use this function.
10607     UNREACHABLE();
10608     return NULL;
10609   }
10610 
HashForObject(Object * obj)10611   uint32_t HashForObject(Object* obj) {
10612     FixedArray* val = FixedArray::cast(obj);
10613     return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10614                       Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10615   }
10616 
RegExpHash(String * string,Smi * flags)10617   static uint32_t RegExpHash(String* string, Smi* flags) {
10618     return string->Hash() + flags->value();
10619   }
10620 
10621   String* string_;
10622   Smi* flags_;
10623 };
10624 
10625 // Utf8SymbolKey carries a vector of chars as key.
10626 class Utf8SymbolKey : public HashTableKey {
10627  public:
Utf8SymbolKey(Vector<const char> string,uint32_t seed)10628   explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10629       : string_(string), hash_field_(0), seed_(seed) { }
10630 
IsMatch(Object * string)10631   bool IsMatch(Object* string) {
10632     return String::cast(string)->IsEqualTo(string_);
10633   }
10634 
Hash()10635   uint32_t Hash() {
10636     if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
10637     unibrow::Utf8InputBuffer<> buffer(string_.start(),
10638                                       static_cast<unsigned>(string_.length()));
10639     chars_ = buffer.Utf16Length();
10640     hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
10641     uint32_t result = hash_field_ >> String::kHashShift;
10642     ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
10643     return result;
10644   }
10645 
HashForObject(Object * other)10646   uint32_t HashForObject(Object* other) {
10647     return String::cast(other)->Hash();
10648   }
10649 
AsObject()10650   MaybeObject* AsObject() {
10651     if (hash_field_ == 0) Hash();
10652     return Isolate::Current()->heap()->AllocateSymbol(
10653         string_, chars_, hash_field_);
10654   }
10655 
10656   Vector<const char> string_;
10657   uint32_t hash_field_;
10658   int chars_;  // Caches the number of characters when computing the hash code.
10659   uint32_t seed_;
10660 };
10661 
10662 
10663 template <typename Char>
10664 class SequentialSymbolKey : public HashTableKey {
10665  public:
SequentialSymbolKey(Vector<const Char> string,uint32_t seed)10666   explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10667       : string_(string), hash_field_(0), seed_(seed) { }
10668 
Hash()10669   uint32_t Hash() {
10670     StringHasher hasher(string_.length(), seed_);
10671 
10672     // Very long strings have a trivial hash that doesn't inspect the
10673     // string contents.
10674     if (hasher.has_trivial_hash()) {
10675       hash_field_ = hasher.GetHashField();
10676     } else {
10677       int i = 0;
10678       // Do the iterative array index computation as long as there is a
10679       // chance this is an array index.
10680       while (i < string_.length() && hasher.is_array_index()) {
10681         hasher.AddCharacter(static_cast<uc32>(string_[i]));
10682         i++;
10683       }
10684 
10685       // Process the remaining characters without updating the array
10686       // index.
10687       while (i < string_.length()) {
10688         hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10689         i++;
10690       }
10691       hash_field_ = hasher.GetHashField();
10692     }
10693 
10694     uint32_t result = hash_field_ >> String::kHashShift;
10695     ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
10696     return result;
10697   }
10698 
10699 
HashForObject(Object * other)10700   uint32_t HashForObject(Object* other) {
10701     return String::cast(other)->Hash();
10702   }
10703 
10704   Vector<const Char> string_;
10705   uint32_t hash_field_;
10706   uint32_t seed_;
10707 };
10708 
10709 
10710 
10711 class AsciiSymbolKey : public SequentialSymbolKey<char> {
10712  public:
AsciiSymbolKey(Vector<const char> str,uint32_t seed)10713   AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10714       : SequentialSymbolKey<char>(str, seed) { }
10715 
IsMatch(Object * string)10716   bool IsMatch(Object* string) {
10717     return String::cast(string)->IsAsciiEqualTo(string_);
10718   }
10719 
AsObject()10720   MaybeObject* AsObject() {
10721     if (hash_field_ == 0) Hash();
10722     return HEAP->AllocateAsciiSymbol(string_, hash_field_);
10723   }
10724 };
10725 
10726 
10727 class SubStringAsciiSymbolKey : public HashTableKey {
10728  public:
SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,int from,int length,uint32_t seed)10729   explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10730                                    int from,
10731                                    int length,
10732                                    uint32_t seed)
10733       : string_(string), from_(from), length_(length), seed_(seed) { }
10734 
Hash()10735   uint32_t Hash() {
10736     ASSERT(length_ >= 0);
10737     ASSERT(from_ + length_ <= string_->length());
10738     StringHasher hasher(length_, string_->GetHeap()->HashSeed());
10739 
10740     // Very long strings have a trivial hash that doesn't inspect the
10741     // string contents.
10742     if (hasher.has_trivial_hash()) {
10743       hash_field_ = hasher.GetHashField();
10744     } else {
10745       int i = 0;
10746       // Do the iterative array index computation as long as there is a
10747       // chance this is an array index.
10748       while (i < length_ && hasher.is_array_index()) {
10749         hasher.AddCharacter(static_cast<uc32>(
10750             string_->SeqAsciiStringGet(i + from_)));
10751         i++;
10752       }
10753 
10754       // Process the remaining characters without updating the array
10755       // index.
10756       while (i < length_) {
10757         hasher.AddCharacterNoIndex(static_cast<uc32>(
10758             string_->SeqAsciiStringGet(i + from_)));
10759         i++;
10760       }
10761       hash_field_ = hasher.GetHashField();
10762     }
10763 
10764     uint32_t result = hash_field_ >> String::kHashShift;
10765     ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
10766     return result;
10767   }
10768 
10769 
HashForObject(Object * other)10770   uint32_t HashForObject(Object* other) {
10771     return String::cast(other)->Hash();
10772   }
10773 
IsMatch(Object * string)10774   bool IsMatch(Object* string) {
10775     Vector<const char> chars(string_->GetChars() + from_, length_);
10776     return String::cast(string)->IsAsciiEqualTo(chars);
10777   }
10778 
AsObject()10779   MaybeObject* AsObject() {
10780     if (hash_field_ == 0) Hash();
10781     Vector<const char> chars(string_->GetChars() + from_, length_);
10782     return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10783   }
10784 
10785  private:
10786   Handle<SeqAsciiString> string_;
10787   int from_;
10788   int length_;
10789   uint32_t hash_field_;
10790   uint32_t seed_;
10791 };
10792 
10793 
10794 class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10795  public:
TwoByteSymbolKey(Vector<const uc16> str,uint32_t seed)10796   explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10797       : SequentialSymbolKey<uc16>(str, seed) { }
10798 
IsMatch(Object * string)10799   bool IsMatch(Object* string) {
10800     return String::cast(string)->IsTwoByteEqualTo(string_);
10801   }
10802 
AsObject()10803   MaybeObject* AsObject() {
10804     if (hash_field_ == 0) Hash();
10805     return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
10806   }
10807 };
10808 
10809 
10810 // SymbolKey carries a string/symbol object as key.
10811 class SymbolKey : public HashTableKey {
10812  public:
SymbolKey(String * string)10813   explicit SymbolKey(String* string)
10814       : string_(string) { }
10815 
IsMatch(Object * string)10816   bool IsMatch(Object* string) {
10817     return String::cast(string)->Equals(string_);
10818   }
10819 
Hash()10820   uint32_t Hash() { return string_->Hash(); }
10821 
HashForObject(Object * other)10822   uint32_t HashForObject(Object* other) {
10823     return String::cast(other)->Hash();
10824   }
10825 
AsObject()10826   MaybeObject* AsObject() {
10827     // Attempt to flatten the string, so that symbols will most often
10828     // be flat strings.
10829     string_ = string_->TryFlattenGetString();
10830     Heap* heap = string_->GetHeap();
10831     // Transform string to symbol if possible.
10832     Map* map = heap->SymbolMapForString(string_);
10833     if (map != NULL) {
10834       string_->set_map_no_write_barrier(map);
10835       ASSERT(string_->IsSymbol());
10836       return string_;
10837     }
10838     // Otherwise allocate a new symbol.
10839     StringInputBuffer buffer(string_);
10840     return heap->AllocateInternalSymbol(&buffer,
10841                                         string_->length(),
10842                                         string_->hash_field());
10843   }
10844 
StringHash(Object * obj)10845   static uint32_t StringHash(Object* obj) {
10846     return String::cast(obj)->Hash();
10847   }
10848 
10849   String* string_;
10850 };
10851 
10852 
10853 template<typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)10854 void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
10855   IteratePointers(v, 0, kElementsStartOffset);
10856 }
10857 
10858 
10859 template<typename Shape, typename Key>
IterateElements(ObjectVisitor * v)10860 void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
10861   IteratePointers(v,
10862                   kElementsStartOffset,
10863                   kHeaderSize + length() * kPointerSize);
10864 }
10865 
10866 
10867 template<typename Shape, typename Key>
Allocate(int at_least_space_for,PretenureFlag pretenure)10868 MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10869                                              PretenureFlag pretenure) {
10870   int capacity = ComputeCapacity(at_least_space_for);
10871   if (capacity > HashTable::kMaxCapacity) {
10872     return Failure::OutOfMemoryException();
10873   }
10874 
10875   Object* obj;
10876   { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10877         AllocateHashTable(EntryToIndex(capacity), pretenure);
10878     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10879   }
10880   HashTable::cast(obj)->SetNumberOfElements(0);
10881   HashTable::cast(obj)->SetNumberOfDeletedElements(0);
10882   HashTable::cast(obj)->SetCapacity(capacity);
10883   return obj;
10884 }
10885 
10886 
10887 // Find entry for key otherwise return kNotFound.
FindEntry(String * key)10888 int StringDictionary::FindEntry(String* key) {
10889   if (!key->IsSymbol()) {
10890     return HashTable<StringDictionaryShape, String*>::FindEntry(key);
10891   }
10892 
10893   // Optimized for symbol key. Knowledge of the key type allows:
10894   // 1. Move the check if the key is a symbol out of the loop.
10895   // 2. Avoid comparing hash codes in symbol to symbol comparison.
10896   // 3. Detect a case when a dictionary key is not a symbol but the key is.
10897   //    In case of positive result the dictionary key may be replaced by
10898   //    the symbol with minimal performance penalty. It gives a chance to
10899   //    perform further lookups in code stubs (and significant performance boost
10900   //    a certain style of code).
10901 
10902   // EnsureCapacity will guarantee the hash table is never full.
10903   uint32_t capacity = Capacity();
10904   uint32_t entry = FirstProbe(key->Hash(), capacity);
10905   uint32_t count = 1;
10906 
10907   while (true) {
10908     int index = EntryToIndex(entry);
10909     Object* element = get(index);
10910     if (element->IsUndefined()) break;  // Empty entry.
10911     if (key == element) return entry;
10912     if (!element->IsSymbol() &&
10913         !element->IsTheHole() &&
10914         String::cast(element)->Equals(key)) {
10915       // Replace a non-symbol key by the equivalent symbol for faster further
10916       // lookups.
10917       set(index, key);
10918       return entry;
10919     }
10920     ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
10921     entry = NextProbe(entry, count++, capacity);
10922   }
10923   return kNotFound;
10924 }
10925 
10926 
ContainsTransition(int entry)10927 bool StringDictionary::ContainsTransition(int entry) {
10928   switch (DetailsAt(entry).type()) {
10929     case MAP_TRANSITION:
10930     case CONSTANT_TRANSITION:
10931     case ELEMENTS_TRANSITION:
10932       return true;
10933     case CALLBACKS: {
10934       Object* value = ValueAt(entry);
10935       if (!value->IsAccessorPair()) return false;
10936       AccessorPair* accessors = AccessorPair::cast(value);
10937       return accessors->getter()->IsMap() || accessors->setter()->IsMap();
10938     }
10939     case NORMAL:
10940     case FIELD:
10941     case CONSTANT_FUNCTION:
10942     case HANDLER:
10943     case INTERCEPTOR:
10944     case NULL_DESCRIPTOR:
10945       return false;
10946   }
10947   UNREACHABLE();  // Keep the compiler happy.
10948   return false;
10949 }
10950 
10951 
10952 template<typename Shape, typename Key>
Rehash(HashTable * new_table,Key key)10953 MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
10954   ASSERT(NumberOfElements() < new_table->Capacity());
10955 
10956   AssertNoAllocation no_gc;
10957   WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
10958 
10959   // Copy prefix to new array.
10960   for (int i = kPrefixStartIndex;
10961        i < kPrefixStartIndex + Shape::kPrefixSize;
10962        i++) {
10963     new_table->set(i, get(i), mode);
10964   }
10965 
10966   // Rehash the elements.
10967   int capacity = Capacity();
10968   for (int i = 0; i < capacity; i++) {
10969     uint32_t from_index = EntryToIndex(i);
10970     Object* k = get(from_index);
10971     if (IsKey(k)) {
10972       uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
10973       uint32_t insertion_index =
10974           EntryToIndex(new_table->FindInsertionEntry(hash));
10975       for (int j = 0; j < Shape::kEntrySize; j++) {
10976         new_table->set(insertion_index + j, get(from_index + j), mode);
10977       }
10978     }
10979   }
10980   new_table->SetNumberOfElements(NumberOfElements());
10981   new_table->SetNumberOfDeletedElements(0);
10982   return new_table;
10983 }
10984 
10985 
10986 template<typename Shape, typename Key>
EnsureCapacity(int n,Key key)10987 MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
10988   int capacity = Capacity();
10989   int nof = NumberOfElements() + n;
10990   int nod = NumberOfDeletedElements();
10991   // Return if:
10992   //   50% is still free after adding n elements and
10993   //   at most 50% of the free elements are deleted elements.
10994   if (nod <= (capacity - nof) >> 1) {
10995     int needed_free = nof >> 1;
10996     if (nof + needed_free <= capacity) return this;
10997   }
10998 
10999   const int kMinCapacityForPretenure = 256;
11000   bool pretenure =
11001       (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
11002   Object* obj;
11003   { MaybeObject* maybe_obj =
11004         Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
11005     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11006   }
11007 
11008   return Rehash(HashTable::cast(obj), key);
11009 }
11010 
11011 
11012 template<typename Shape, typename Key>
Shrink(Key key)11013 MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
11014   int capacity = Capacity();
11015   int nof = NumberOfElements();
11016 
11017   // Shrink to fit the number of elements if only a quarter of the
11018   // capacity is filled with elements.
11019   if (nof > (capacity >> 2)) return this;
11020   // Allocate a new dictionary with room for at least the current
11021   // number of elements. The allocation method will make sure that
11022   // there is extra room in the dictionary for additions. Don't go
11023   // lower than room for 16 elements.
11024   int at_least_room_for = nof;
11025   if (at_least_room_for < 16) return this;
11026 
11027   const int kMinCapacityForPretenure = 256;
11028   bool pretenure =
11029       (at_least_room_for > kMinCapacityForPretenure) &&
11030       !GetHeap()->InNewSpace(this);
11031   Object* obj;
11032   { MaybeObject* maybe_obj =
11033         Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
11034     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11035   }
11036 
11037   return Rehash(HashTable::cast(obj), key);
11038 }
11039 
11040 
11041 template<typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)11042 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
11043   uint32_t capacity = Capacity();
11044   uint32_t entry = FirstProbe(hash, capacity);
11045   uint32_t count = 1;
11046   // EnsureCapacity will guarantee the hash table is never full.
11047   while (true) {
11048     Object* element = KeyAt(entry);
11049     if (element->IsUndefined() || element->IsTheHole()) break;
11050     entry = NextProbe(entry, count++, capacity);
11051   }
11052   return entry;
11053 }
11054 
11055 // Force instantiation of template instances class.
11056 // Please note this list is compiler dependent.
11057 
11058 template class HashTable<SymbolTableShape, HashTableKey*>;
11059 
11060 template class HashTable<CompilationCacheShape, HashTableKey*>;
11061 
11062 template class HashTable<MapCacheShape, HashTableKey*>;
11063 
11064 template class HashTable<ObjectHashTableShape<1>, Object*>;
11065 
11066 template class HashTable<ObjectHashTableShape<2>, Object*>;
11067 
11068 template class Dictionary<StringDictionaryShape, String*>;
11069 
11070 template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
11071 
11072 template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11073 
11074 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11075     Allocate(int at_least_space_for);
11076 
11077 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11078     Allocate(int at_least_space_for);
11079 
11080 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
11081     int);
11082 
11083 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
11084     uint32_t, Object*);
11085 
11086 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11087     AtPut(uint32_t, Object*);
11088 
11089 template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11090     SlowReverseLookup(Object* value);
11091 
11092 template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11093     SlowReverseLookup(Object* value);
11094 
11095 template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11096     Object*);
11097 
11098 template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
11099     FixedArray*,
11100     PropertyAttributes,
11101     Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
11102 
11103 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11104     int, JSObject::DeleteMode);
11105 
11106 template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11107     DeleteProperty(int, JSObject::DeleteMode);
11108 
11109 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11110     String*);
11111 
11112 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
11113     uint32_t);
11114 
11115 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
11116     FixedArray*,
11117     int,
11118     Dictionary<StringDictionaryShape, String*>::SortMode);
11119 
11120 template int
11121 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11122     PropertyAttributes);
11123 
11124 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
11125     String*, Object*, PropertyDetails);
11126 
11127 template MaybeObject*
11128 Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11129 
11130 template int
11131 Dictionary<SeededNumberDictionaryShape, uint32_t>::
11132     NumberOfElementsFilterAttributes(PropertyAttributes);
11133 
11134 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
11135     uint32_t, Object*, PropertyDetails);
11136 
11137 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11138     uint32_t, Object*, PropertyDetails);
11139 
11140 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11141     EnsureCapacity(int, uint32_t);
11142 
11143 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11144     EnsureCapacity(int, uint32_t);
11145 
11146 template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11147     EnsureCapacity(int, String*);
11148 
11149 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11150     AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11151 
11152 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11153     AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11154 
11155 template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
11156     String*, Object*, PropertyDetails, uint32_t);
11157 
11158 template
11159 int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
11160 
11161 template
11162 int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
11163 
11164 template
11165 int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
11166 
11167 
11168 // Collates undefined and unexisting elements below limit from position
11169 // zero of the elements. The object stays in Dictionary mode.
PrepareSlowElementsForSort(uint32_t limit)11170 MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
11171   ASSERT(HasDictionaryElements());
11172   // Must stay in dictionary mode, either because of requires_slow_elements,
11173   // or because we are not going to sort (and therefore compact) all of the
11174   // elements.
11175   SeededNumberDictionary* dict = element_dictionary();
11176   HeapNumber* result_double = NULL;
11177   if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11178     // Allocate space for result before we start mutating the object.
11179     Object* new_double;
11180     { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
11181       if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11182     }
11183     result_double = HeapNumber::cast(new_double);
11184   }
11185 
11186   Object* obj;
11187   { MaybeObject* maybe_obj =
11188         SeededNumberDictionary::Allocate(dict->NumberOfElements());
11189     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11190   }
11191   SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
11192 
11193   AssertNoAllocation no_alloc;
11194 
11195   uint32_t pos = 0;
11196   uint32_t undefs = 0;
11197   int capacity = dict->Capacity();
11198   for (int i = 0; i < capacity; i++) {
11199     Object* k = dict->KeyAt(i);
11200     if (dict->IsKey(k)) {
11201       ASSERT(k->IsNumber());
11202       ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11203       ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11204       ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11205       Object* value = dict->ValueAt(i);
11206       PropertyDetails details = dict->DetailsAt(i);
11207       if (details.type() == CALLBACKS) {
11208         // Bail out and do the sorting of undefineds and array holes in JS.
11209         return Smi::FromInt(-1);
11210       }
11211       uint32_t key = NumberToUint32(k);
11212       // In the following we assert that adding the entry to the new dictionary
11213       // does not cause GC.  This is the case because we made sure to allocate
11214       // the dictionary big enough above, so it need not grow.
11215       if (key < limit) {
11216         if (value->IsUndefined()) {
11217           undefs++;
11218         } else {
11219           if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11220             // Adding an entry with the key beyond smi-range requires
11221             // allocation. Bailout.
11222             return Smi::FromInt(-1);
11223           }
11224           new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
11225           pos++;
11226         }
11227       } else {
11228         if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11229           // Adding an entry with the key beyond smi-range requires
11230           // allocation. Bailout.
11231           return Smi::FromInt(-1);
11232         }
11233         new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
11234       }
11235     }
11236   }
11237 
11238   uint32_t result = pos;
11239   PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
11240   Heap* heap = GetHeap();
11241   while (undefs > 0) {
11242     if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11243       // Adding an entry with the key beyond smi-range requires
11244       // allocation. Bailout.
11245       return Smi::FromInt(-1);
11246     }
11247     new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
11248         ToObjectUnchecked();
11249     pos++;
11250     undefs--;
11251   }
11252 
11253   set_elements(new_dict);
11254 
11255   if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11256     return Smi::FromInt(static_cast<int>(result));
11257   }
11258 
11259   ASSERT_NE(NULL, result_double);
11260   result_double->set_value(static_cast<double>(result));
11261   return result_double;
11262 }
11263 
11264 
11265 // Collects all defined (non-hole) and non-undefined (array) elements at
11266 // the start of the elements array.
11267 // If the object is in dictionary mode, it is converted to fast elements
11268 // mode.
PrepareElementsForSort(uint32_t limit)11269 MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
11270   Heap* heap = GetHeap();
11271 
11272   if (HasDictionaryElements()) {
11273     // Convert to fast elements containing only the existing properties.
11274     // Ordering is irrelevant, since we are going to sort anyway.
11275     SeededNumberDictionary* dict = element_dictionary();
11276     if (IsJSArray() || dict->requires_slow_elements() ||
11277         dict->max_number_key() >= limit) {
11278       return PrepareSlowElementsForSort(limit);
11279     }
11280     // Convert to fast elements.
11281 
11282     Object* obj;
11283     { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11284                                                         FAST_ELEMENTS);
11285       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11286     }
11287     Map* new_map = Map::cast(obj);
11288 
11289     PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
11290     Object* new_array;
11291     { MaybeObject* maybe_new_array =
11292           heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
11293       if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11294     }
11295     FixedArray* fast_elements = FixedArray::cast(new_array);
11296     dict->CopyValuesTo(fast_elements);
11297 
11298     set_map(new_map);
11299     set_elements(fast_elements);
11300   } else if (HasExternalArrayElements()) {
11301     // External arrays cannot have holes or undefined elements.
11302     return Smi::FromInt(ExternalArray::cast(elements())->length());
11303   } else if (!HasFastDoubleElements()) {
11304     Object* obj;
11305     { MaybeObject* maybe_obj = EnsureWritableFastElements();
11306       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11307     }
11308   }
11309   ASSERT(HasFastTypeElements() || HasFastDoubleElements());
11310 
11311   // Collect holes at the end, undefined before that and the rest at the
11312   // start, and return the number of non-hole, non-undefined values.
11313 
11314   FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11315   uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
11316   if (limit > elements_length) {
11317     limit = elements_length ;
11318   }
11319   if (limit == 0) {
11320     return Smi::FromInt(0);
11321   }
11322 
11323   HeapNumber* result_double = NULL;
11324   if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11325     // Pessimistically allocate space for return value before
11326     // we start mutating the array.
11327     Object* new_double;
11328     { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
11329       if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11330     }
11331     result_double = HeapNumber::cast(new_double);
11332   }
11333 
11334   uint32_t result = 0;
11335   if (elements_base->map() == heap->fixed_double_array_map()) {
11336     FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11337     // Split elements into defined and the_hole, in that order.
11338     unsigned int holes = limit;
11339     // Assume most arrays contain no holes and undefined values, so minimize the
11340     // number of stores of non-undefined, non-the-hole values.
11341     for (unsigned int i = 0; i < holes; i++) {
11342       if (elements->is_the_hole(i)) {
11343         holes--;
11344       } else {
11345         continue;
11346       }
11347       // Position i needs to be filled.
11348       while (holes > i) {
11349         if (elements->is_the_hole(holes)) {
11350           holes--;
11351         } else {
11352           elements->set(i, elements->get_scalar(holes));
11353           break;
11354         }
11355       }
11356     }
11357     result = holes;
11358     while (holes < limit) {
11359       elements->set_the_hole(holes);
11360       holes++;
11361     }
11362   } else {
11363     FixedArray* elements = FixedArray::cast(elements_base);
11364     AssertNoAllocation no_alloc;
11365 
11366     // Split elements into defined, undefined and the_hole, in that order.  Only
11367     // count locations for undefined and the hole, and fill them afterwards.
11368     WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11369     unsigned int undefs = limit;
11370     unsigned int holes = limit;
11371     // Assume most arrays contain no holes and undefined values, so minimize the
11372     // number of stores of non-undefined, non-the-hole values.
11373     for (unsigned int i = 0; i < undefs; i++) {
11374       Object* current = elements->get(i);
11375       if (current->IsTheHole()) {
11376         holes--;
11377         undefs--;
11378       } else if (current->IsUndefined()) {
11379         undefs--;
11380       } else {
11381         continue;
11382       }
11383       // Position i needs to be filled.
11384       while (undefs > i) {
11385         current = elements->get(undefs);
11386         if (current->IsTheHole()) {
11387           holes--;
11388           undefs--;
11389         } else if (current->IsUndefined()) {
11390           undefs--;
11391         } else {
11392           elements->set(i, current, write_barrier);
11393           break;
11394         }
11395       }
11396     }
11397     result = undefs;
11398     while (undefs < holes) {
11399       elements->set_undefined(undefs);
11400       undefs++;
11401     }
11402     while (holes < limit) {
11403       elements->set_the_hole(holes);
11404       holes++;
11405     }
11406   }
11407 
11408   if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11409     return Smi::FromInt(static_cast<int>(result));
11410   }
11411   ASSERT_NE(NULL, result_double);
11412   result_double->set_value(static_cast<double>(result));
11413   return result_double;
11414 }
11415 
11416 
SetValue(uint32_t index,Object * value)11417 Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
11418   uint8_t clamped_value = 0;
11419   if (index < static_cast<uint32_t>(length())) {
11420     if (value->IsSmi()) {
11421       int int_value = Smi::cast(value)->value();
11422       if (int_value < 0) {
11423         clamped_value = 0;
11424       } else if (int_value > 255) {
11425         clamped_value = 255;
11426       } else {
11427         clamped_value = static_cast<uint8_t>(int_value);
11428       }
11429     } else if (value->IsHeapNumber()) {
11430       double double_value = HeapNumber::cast(value)->value();
11431       if (!(double_value > 0)) {
11432         // NaN and less than zero clamp to zero.
11433         clamped_value = 0;
11434       } else if (double_value > 255) {
11435         // Greater than 255 clamp to 255.
11436         clamped_value = 255;
11437       } else {
11438         // Other doubles are rounded to the nearest integer.
11439         clamped_value = static_cast<uint8_t>(double_value + 0.5);
11440       }
11441     } else {
11442       // Clamp undefined to zero (default). All other types have been
11443       // converted to a number type further up in the call chain.
11444       ASSERT(value->IsUndefined());
11445     }
11446     set(index, clamped_value);
11447   }
11448   return Smi::FromInt(clamped_value);
11449 }
11450 
11451 
11452 template<typename ExternalArrayClass, typename ValueType>
ExternalArrayIntSetter(Heap * heap,ExternalArrayClass * receiver,uint32_t index,Object * value)11453 static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11454                                            ExternalArrayClass* receiver,
11455                                            uint32_t index,
11456                                            Object* value) {
11457   ValueType cast_value = 0;
11458   if (index < static_cast<uint32_t>(receiver->length())) {
11459     if (value->IsSmi()) {
11460       int int_value = Smi::cast(value)->value();
11461       cast_value = static_cast<ValueType>(int_value);
11462     } else if (value->IsHeapNumber()) {
11463       double double_value = HeapNumber::cast(value)->value();
11464       cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11465     } else {
11466       // Clamp undefined to zero (default). All other types have been
11467       // converted to a number type further up in the call chain.
11468       ASSERT(value->IsUndefined());
11469     }
11470     receiver->set(index, cast_value);
11471   }
11472   return heap->NumberFromInt32(cast_value);
11473 }
11474 
11475 
SetValue(uint32_t index,Object * value)11476 MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
11477   return ExternalArrayIntSetter<ExternalByteArray, int8_t>
11478       (GetHeap(), this, index, value);
11479 }
11480 
11481 
SetValue(uint32_t index,Object * value)11482 MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11483                                                  Object* value) {
11484   return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
11485       (GetHeap(), this, index, value);
11486 }
11487 
11488 
SetValue(uint32_t index,Object * value)11489 MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11490                                           Object* value) {
11491   return ExternalArrayIntSetter<ExternalShortArray, int16_t>
11492       (GetHeap(), this, index, value);
11493 }
11494 
11495 
SetValue(uint32_t index,Object * value)11496 MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11497                                                   Object* value) {
11498   return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
11499       (GetHeap(), this, index, value);
11500 }
11501 
11502 
SetValue(uint32_t index,Object * value)11503 MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
11504   return ExternalArrayIntSetter<ExternalIntArray, int32_t>
11505       (GetHeap(), this, index, value);
11506 }
11507 
11508 
SetValue(uint32_t index,Object * value)11509 MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
11510   uint32_t cast_value = 0;
11511   Heap* heap = GetHeap();
11512   if (index < static_cast<uint32_t>(length())) {
11513     if (value->IsSmi()) {
11514       int int_value = Smi::cast(value)->value();
11515       cast_value = static_cast<uint32_t>(int_value);
11516     } else if (value->IsHeapNumber()) {
11517       double double_value = HeapNumber::cast(value)->value();
11518       cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11519     } else {
11520       // Clamp undefined to zero (default). All other types have been
11521       // converted to a number type further up in the call chain.
11522       ASSERT(value->IsUndefined());
11523     }
11524     set(index, cast_value);
11525   }
11526   return heap->NumberFromUint32(cast_value);
11527 }
11528 
11529 
SetValue(uint32_t index,Object * value)11530 MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
11531   float cast_value = static_cast<float>(OS::nan_value());
11532   Heap* heap = GetHeap();
11533   if (index < static_cast<uint32_t>(length())) {
11534     if (value->IsSmi()) {
11535       int int_value = Smi::cast(value)->value();
11536       cast_value = static_cast<float>(int_value);
11537     } else if (value->IsHeapNumber()) {
11538       double double_value = HeapNumber::cast(value)->value();
11539       cast_value = static_cast<float>(double_value);
11540     } else {
11541       // Clamp undefined to NaN (default). All other types have been
11542       // converted to a number type further up in the call chain.
11543       ASSERT(value->IsUndefined());
11544     }
11545     set(index, cast_value);
11546   }
11547   return heap->AllocateHeapNumber(cast_value);
11548 }
11549 
11550 
SetValue(uint32_t index,Object * value)11551 MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
11552   double double_value = OS::nan_value();
11553   Heap* heap = GetHeap();
11554   if (index < static_cast<uint32_t>(length())) {
11555     if (value->IsSmi()) {
11556       int int_value = Smi::cast(value)->value();
11557       double_value = static_cast<double>(int_value);
11558     } else if (value->IsHeapNumber()) {
11559       double_value = HeapNumber::cast(value)->value();
11560     } else {
11561       // Clamp undefined to NaN (default). All other types have been
11562       // converted to a number type further up in the call chain.
11563       ASSERT(value->IsUndefined());
11564     }
11565     set(index, double_value);
11566   }
11567   return heap->AllocateHeapNumber(double_value);
11568 }
11569 
11570 
GetPropertyCell(LookupResult * result)11571 JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
11572   ASSERT(!HasFastProperties());
11573   Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
11574   return JSGlobalPropertyCell::cast(value);
11575 }
11576 
11577 
EnsurePropertyCell(Handle<GlobalObject> global,Handle<String> name)11578 Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11579     Handle<GlobalObject> global,
11580     Handle<String> name) {
11581   Isolate* isolate = global->GetIsolate();
11582   CALL_HEAP_FUNCTION(isolate,
11583                      global->EnsurePropertyCell(*name),
11584                      JSGlobalPropertyCell);
11585 }
11586 
11587 
EnsurePropertyCell(String * name)11588 MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
11589   ASSERT(!HasFastProperties());
11590   int entry = property_dictionary()->FindEntry(name);
11591   if (entry == StringDictionary::kNotFound) {
11592     Heap* heap = GetHeap();
11593     Object* cell;
11594     { MaybeObject* maybe_cell =
11595           heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
11596       if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11597     }
11598     PropertyDetails details(NONE, NORMAL);
11599     details = details.AsDeleted();
11600     Object* dictionary;
11601     { MaybeObject* maybe_dictionary =
11602           property_dictionary()->Add(name, cell, details);
11603       if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11604     }
11605     set_properties(StringDictionary::cast(dictionary));
11606     return cell;
11607   } else {
11608     Object* value = property_dictionary()->ValueAt(entry);
11609     ASSERT(value->IsJSGlobalPropertyCell());
11610     return value;
11611   }
11612 }
11613 
11614 
LookupString(String * string,Object ** s)11615 MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
11616   SymbolKey key(string);
11617   return LookupKey(&key, s);
11618 }
11619 
11620 
11621 // This class is used for looking up two character strings in the symbol table.
11622 // If we don't have a hit we don't want to waste much time so we unroll the
11623 // string hash calculation loop here for speed.  Doesn't work if the two
11624 // characters form a decimal integer, since such strings have a different hash
11625 // algorithm.
11626 class TwoCharHashTableKey : public HashTableKey {
11627  public:
TwoCharHashTableKey(uint32_t c1,uint32_t c2,uint32_t seed)11628   TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
11629     : c1_(c1), c2_(c2) {
11630     // Char 1.
11631     uint32_t hash = seed;
11632     hash += c1;
11633     hash += hash << 10;
11634     hash ^= hash >> 6;
11635     // Char 2.
11636     hash += c2;
11637     hash += hash << 10;
11638     hash ^= hash >> 6;
11639     // GetHash.
11640     hash += hash << 3;
11641     hash ^= hash >> 11;
11642     hash += hash << 15;
11643     if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
11644 #ifdef DEBUG
11645     StringHasher hasher(2, seed);
11646     hasher.AddCharacter(c1);
11647     hasher.AddCharacter(c2);
11648     // If this assert fails then we failed to reproduce the two-character
11649     // version of the string hashing algorithm above.  One reason could be
11650     // that we were passed two digits as characters, since the hash
11651     // algorithm is different in that case.
11652     ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11653 #endif
11654     hash_ = hash;
11655   }
11656 
IsMatch(Object * o)11657   bool IsMatch(Object* o) {
11658     if (!o->IsString()) return false;
11659     String* other = String::cast(o);
11660     if (other->length() != 2) return false;
11661     if (other->Get(0) != c1_) return false;
11662     return other->Get(1) == c2_;
11663   }
11664 
Hash()11665   uint32_t Hash() { return hash_; }
HashForObject(Object * key)11666   uint32_t HashForObject(Object* key) {
11667     if (!key->IsString()) return 0;
11668     return String::cast(key)->Hash();
11669   }
11670 
AsObject()11671   Object* AsObject() {
11672     // The TwoCharHashTableKey is only used for looking in the symbol
11673     // table, not for adding to it.
11674     UNREACHABLE();
11675     return NULL;
11676   }
11677 
11678  private:
11679   uint32_t c1_;
11680   uint32_t c2_;
11681   uint32_t hash_;
11682 };
11683 
11684 
LookupSymbolIfExists(String * string,String ** symbol)11685 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11686   SymbolKey key(string);
11687   int entry = FindEntry(&key);
11688   if (entry == kNotFound) {
11689     return false;
11690   } else {
11691     String* result = String::cast(KeyAt(entry));
11692     ASSERT(StringShape(result).IsSymbol());
11693     *symbol = result;
11694     return true;
11695   }
11696 }
11697 
11698 
LookupTwoCharsSymbolIfExists(uint32_t c1,uint32_t c2,String ** symbol)11699 bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11700                                                uint32_t c2,
11701                                                String** symbol) {
11702   TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
11703   int entry = FindEntry(&key);
11704   if (entry == kNotFound) {
11705     return false;
11706   } else {
11707     String* result = String::cast(KeyAt(entry));
11708     ASSERT(StringShape(result).IsSymbol());
11709     *symbol = result;
11710     return true;
11711   }
11712 }
11713 
11714 
LookupSymbol(Vector<const char> str,Object ** s)11715 MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11716                                        Object** s) {
11717   Utf8SymbolKey key(str, GetHeap()->HashSeed());
11718   return LookupKey(&key, s);
11719 }
11720 
11721 
LookupAsciiSymbol(Vector<const char> str,Object ** s)11722 MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11723                                             Object** s) {
11724   AsciiSymbolKey key(str, GetHeap()->HashSeed());
11725   return LookupKey(&key, s);
11726 }
11727 
11728 
LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,int from,int length,Object ** s)11729 MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11730                                                      int from,
11731                                                      int length,
11732                                                      Object** s) {
11733   SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
11734   return LookupKey(&key, s);
11735 }
11736 
11737 
LookupTwoByteSymbol(Vector<const uc16> str,Object ** s)11738 MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11739                                               Object** s) {
11740   TwoByteSymbolKey key(str, GetHeap()->HashSeed());
11741   return LookupKey(&key, s);
11742 }
11743 
LookupKey(HashTableKey * key,Object ** s)11744 MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
11745   int entry = FindEntry(key);
11746 
11747   // Symbol already in table.
11748   if (entry != kNotFound) {
11749     *s = KeyAt(entry);
11750     return this;
11751   }
11752 
11753   // Adding new symbol. Grow table if needed.
11754   Object* obj;
11755   { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11756     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11757   }
11758 
11759   // Create symbol object.
11760   Object* symbol;
11761   { MaybeObject* maybe_symbol = key->AsObject();
11762     if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11763   }
11764 
11765   // If the symbol table grew as part of EnsureCapacity, obj is not
11766   // the current symbol table and therefore we cannot use
11767   // SymbolTable::cast here.
11768   SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11769 
11770   // Add the new symbol and return it along with the symbol table.
11771   entry = table->FindInsertionEntry(key->Hash());
11772   table->set(EntryToIndex(entry), symbol);
11773   table->ElementAdded();
11774   *s = symbol;
11775   return table;
11776 }
11777 
11778 
Lookup(String * src)11779 Object* CompilationCacheTable::Lookup(String* src) {
11780   StringKey key(src);
11781   int entry = FindEntry(&key);
11782   if (entry == kNotFound) return GetHeap()->undefined_value();
11783   return get(EntryToIndex(entry) + 1);
11784 }
11785 
11786 
LookupEval(String * src,Context * context,LanguageMode language_mode,int scope_position)11787 Object* CompilationCacheTable::LookupEval(String* src,
11788                                           Context* context,
11789                                           LanguageMode language_mode,
11790                                           int scope_position) {
11791   StringSharedKey key(src,
11792                       context->closure()->shared(),
11793                       language_mode,
11794                       scope_position);
11795   int entry = FindEntry(&key);
11796   if (entry == kNotFound) return GetHeap()->undefined_value();
11797   return get(EntryToIndex(entry) + 1);
11798 }
11799 
11800 
LookupRegExp(String * src,JSRegExp::Flags flags)11801 Object* CompilationCacheTable::LookupRegExp(String* src,
11802                                             JSRegExp::Flags flags) {
11803   RegExpKey key(src, flags);
11804   int entry = FindEntry(&key);
11805   if (entry == kNotFound) return GetHeap()->undefined_value();
11806   return get(EntryToIndex(entry) + 1);
11807 }
11808 
11809 
Put(String * src,Object * value)11810 MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
11811   StringKey key(src);
11812   Object* obj;
11813   { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11814     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11815   }
11816 
11817   CompilationCacheTable* cache =
11818       reinterpret_cast<CompilationCacheTable*>(obj);
11819   int entry = cache->FindInsertionEntry(key.Hash());
11820   cache->set(EntryToIndex(entry), src);
11821   cache->set(EntryToIndex(entry) + 1, value);
11822   cache->ElementAdded();
11823   return cache;
11824 }
11825 
11826 
PutEval(String * src,Context * context,SharedFunctionInfo * value,int scope_position)11827 MaybeObject* CompilationCacheTable::PutEval(String* src,
11828                                             Context* context,
11829                                             SharedFunctionInfo* value,
11830                                             int scope_position) {
11831   StringSharedKey key(src,
11832                       context->closure()->shared(),
11833                       value->language_mode(),
11834                       scope_position);
11835   Object* obj;
11836   { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11837     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11838   }
11839 
11840   CompilationCacheTable* cache =
11841       reinterpret_cast<CompilationCacheTable*>(obj);
11842   int entry = cache->FindInsertionEntry(key.Hash());
11843 
11844   Object* k;
11845   { MaybeObject* maybe_k = key.AsObject();
11846     if (!maybe_k->ToObject(&k)) return maybe_k;
11847   }
11848 
11849   cache->set(EntryToIndex(entry), k);
11850   cache->set(EntryToIndex(entry) + 1, value);
11851   cache->ElementAdded();
11852   return cache;
11853 }
11854 
11855 
PutRegExp(String * src,JSRegExp::Flags flags,FixedArray * value)11856 MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11857                                               JSRegExp::Flags flags,
11858                                               FixedArray* value) {
11859   RegExpKey key(src, flags);
11860   Object* obj;
11861   { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11862     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11863   }
11864 
11865   CompilationCacheTable* cache =
11866       reinterpret_cast<CompilationCacheTable*>(obj);
11867   int entry = cache->FindInsertionEntry(key.Hash());
11868   // We store the value in the key slot, and compare the search key
11869   // to the stored value with a custon IsMatch function during lookups.
11870   cache->set(EntryToIndex(entry), value);
11871   cache->set(EntryToIndex(entry) + 1, value);
11872   cache->ElementAdded();
11873   return cache;
11874 }
11875 
11876 
Remove(Object * value)11877 void CompilationCacheTable::Remove(Object* value) {
11878   Object* the_hole_value = GetHeap()->the_hole_value();
11879   for (int entry = 0, size = Capacity(); entry < size; entry++) {
11880     int entry_index = EntryToIndex(entry);
11881     int value_index = entry_index + 1;
11882     if (get(value_index) == value) {
11883       NoWriteBarrierSet(this, entry_index, the_hole_value);
11884       NoWriteBarrierSet(this, value_index, the_hole_value);
11885       ElementRemoved();
11886     }
11887   }
11888   return;
11889 }
11890 
11891 
11892 // SymbolsKey used for HashTable where key is array of symbols.
11893 class SymbolsKey : public HashTableKey {
11894  public:
SymbolsKey(FixedArray * symbols)11895   explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
11896 
IsMatch(Object * symbols)11897   bool IsMatch(Object* symbols) {
11898     FixedArray* o = FixedArray::cast(symbols);
11899     int len = symbols_->length();
11900     if (o->length() != len) return false;
11901     for (int i = 0; i < len; i++) {
11902       if (o->get(i) != symbols_->get(i)) return false;
11903     }
11904     return true;
11905   }
11906 
Hash()11907   uint32_t Hash() { return HashForObject(symbols_); }
11908 
HashForObject(Object * obj)11909   uint32_t HashForObject(Object* obj) {
11910     FixedArray* symbols = FixedArray::cast(obj);
11911     int len = symbols->length();
11912     uint32_t hash = 0;
11913     for (int i = 0; i < len; i++) {
11914       hash ^= String::cast(symbols->get(i))->Hash();
11915     }
11916     return hash;
11917   }
11918 
AsObject()11919   Object* AsObject() { return symbols_; }
11920 
11921  private:
11922   FixedArray* symbols_;
11923 };
11924 
11925 
Lookup(FixedArray * array)11926 Object* MapCache::Lookup(FixedArray* array) {
11927   SymbolsKey key(array);
11928   int entry = FindEntry(&key);
11929   if (entry == kNotFound) return GetHeap()->undefined_value();
11930   return get(EntryToIndex(entry) + 1);
11931 }
11932 
11933 
Put(FixedArray * array,Map * value)11934 MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
11935   SymbolsKey key(array);
11936   Object* obj;
11937   { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11938     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11939   }
11940 
11941   MapCache* cache = reinterpret_cast<MapCache*>(obj);
11942   int entry = cache->FindInsertionEntry(key.Hash());
11943   cache->set(EntryToIndex(entry), array);
11944   cache->set(EntryToIndex(entry) + 1, value);
11945   cache->ElementAdded();
11946   return cache;
11947 }
11948 
11949 
11950 template<typename Shape, typename Key>
Allocate(int at_least_space_for)11951 MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
11952   Object* obj;
11953   { MaybeObject* maybe_obj =
11954         HashTable<Shape, Key>::Allocate(at_least_space_for);
11955     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11956   }
11957   // Initialize the next enumeration index.
11958   Dictionary<Shape, Key>::cast(obj)->
11959       SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
11960   return obj;
11961 }
11962 
11963 
11964 template<typename Shape, typename Key>
GenerateNewEnumerationIndices()11965 MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
11966   Heap* heap = Dictionary<Shape, Key>::GetHeap();
11967   int length = HashTable<Shape, Key>::NumberOfElements();
11968 
11969   // Allocate and initialize iteration order array.
11970   Object* obj;
11971   { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
11972     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11973   }
11974   FixedArray* iteration_order = FixedArray::cast(obj);
11975   for (int i = 0; i < length; i++) {
11976     iteration_order->set(i, Smi::FromInt(i));
11977   }
11978 
11979   // Allocate array with enumeration order.
11980   { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
11981     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11982   }
11983   FixedArray* enumeration_order = FixedArray::cast(obj);
11984 
11985   // Fill the enumeration order array with property details.
11986   int capacity = HashTable<Shape, Key>::Capacity();
11987   int pos = 0;
11988   for (int i = 0; i < capacity; i++) {
11989     if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
11990       enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
11991     }
11992   }
11993 
11994   // Sort the arrays wrt. enumeration order.
11995   iteration_order->SortPairs(enumeration_order, enumeration_order->length());
11996 
11997   // Overwrite the enumeration_order with the enumeration indices.
11998   for (int i = 0; i < length; i++) {
11999     int index = Smi::cast(iteration_order->get(i))->value();
12000     int enum_index = PropertyDetails::kInitialIndex + i;
12001     enumeration_order->set(index, Smi::FromInt(enum_index));
12002   }
12003 
12004   // Update the dictionary with new indices.
12005   capacity = HashTable<Shape, Key>::Capacity();
12006   pos = 0;
12007   for (int i = 0; i < capacity; i++) {
12008     if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
12009       int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
12010       PropertyDetails details = DetailsAt(i);
12011       PropertyDetails new_details =
12012           PropertyDetails(details.attributes(), details.type(), enum_index);
12013       DetailsAtPut(i, new_details);
12014     }
12015   }
12016 
12017   // Set the next enumeration index.
12018   SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
12019   return this;
12020 }
12021 
12022 template<typename Shape, typename Key>
EnsureCapacity(int n,Key key)12023 MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
12024   // Check whether there are enough enumeration indices to add n elements.
12025   if (Shape::kIsEnumerable &&
12026       !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
12027     // If not, we generate new indices for the properties.
12028     Object* result;
12029     { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12030       if (!maybe_result->ToObject(&result)) return maybe_result;
12031     }
12032   }
12033   return HashTable<Shape, Key>::EnsureCapacity(n, key);
12034 }
12035 
12036 
12037 template<typename Shape, typename Key>
DeleteProperty(int entry,JSReceiver::DeleteMode mode)12038 Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
12039                                                JSReceiver::DeleteMode mode) {
12040   Heap* heap = Dictionary<Shape, Key>::GetHeap();
12041   PropertyDetails details = DetailsAt(entry);
12042   // Ignore attributes if forcing a deletion.
12043   if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
12044     return heap->false_value();
12045   }
12046   SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
12047   HashTable<Shape, Key>::ElementRemoved();
12048   return heap->true_value();
12049 }
12050 
12051 
12052 template<typename Shape, typename Key>
Shrink(Key key)12053 MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12054   return HashTable<Shape, Key>::Shrink(key);
12055 }
12056 
12057 
12058 template<typename Shape, typename Key>
AtPut(Key key,Object * value)12059 MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
12060   int entry = this->FindEntry(key);
12061 
12062   // If the entry is present set the value;
12063   if (entry != Dictionary<Shape, Key>::kNotFound) {
12064     ValueAtPut(entry, value);
12065     return this;
12066   }
12067 
12068   // Check whether the dictionary should be extended.
12069   Object* obj;
12070   { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12071     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12072   }
12073 
12074   Object* k;
12075   { MaybeObject* maybe_k = Shape::AsObject(key);
12076     if (!maybe_k->ToObject(&k)) return maybe_k;
12077   }
12078   PropertyDetails details = PropertyDetails(NONE, NORMAL);
12079 
12080   return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12081       Dictionary<Shape, Key>::Hash(key));
12082 }
12083 
12084 
12085 template<typename Shape, typename Key>
Add(Key key,Object * value,PropertyDetails details)12086 MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12087                                          Object* value,
12088                                          PropertyDetails details) {
12089   // Valdate key is absent.
12090   SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
12091   // Check whether the dictionary should be extended.
12092   Object* obj;
12093   { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12094     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12095   }
12096 
12097   return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12098       Dictionary<Shape, Key>::Hash(key));
12099 }
12100 
12101 
12102 // Add a key, value pair to the dictionary.
12103 template<typename Shape, typename Key>
AddEntry(Key key,Object * value,PropertyDetails details,uint32_t hash)12104 MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12105                                               Object* value,
12106                                               PropertyDetails details,
12107                                               uint32_t hash) {
12108   // Compute the key object.
12109   Object* k;
12110   { MaybeObject* maybe_k = Shape::AsObject(key);
12111     if (!maybe_k->ToObject(&k)) return maybe_k;
12112   }
12113 
12114   uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
12115   // Insert element at empty or deleted entry
12116   if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
12117     // Assign an enumeration index to the property and update
12118     // SetNextEnumerationIndex.
12119     int index = NextEnumerationIndex();
12120     details = PropertyDetails(details.attributes(), details.type(), index);
12121     SetNextEnumerationIndex(index + 1);
12122   }
12123   SetEntry(entry, k, value, details);
12124   ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12125           || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12126   HashTable<Shape, Key>::ElementAdded();
12127   return this;
12128 }
12129 
12130 
UpdateMaxNumberKey(uint32_t key)12131 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
12132   // If the dictionary requires slow elements an element has already
12133   // been added at a high index.
12134   if (requires_slow_elements()) return;
12135   // Check if this index is high enough that we should require slow
12136   // elements.
12137   if (key > kRequiresSlowElementsLimit) {
12138     set_requires_slow_elements();
12139     return;
12140   }
12141   // Update max key value.
12142   Object* max_index_object = get(kMaxNumberKeyIndex);
12143   if (!max_index_object->IsSmi() || max_number_key() < key) {
12144     FixedArray::set(kMaxNumberKeyIndex,
12145                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
12146   }
12147 }
12148 
12149 
AddNumberEntry(uint32_t key,Object * value,PropertyDetails details)12150 MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12151                                                     Object* value,
12152                                                     PropertyDetails details) {
12153   UpdateMaxNumberKey(key);
12154   SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12155   return Add(key, value, details);
12156 }
12157 
12158 
AddNumberEntry(uint32_t key,Object * value)12159 MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12160                                                       Object* value) {
12161   SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12162   return Add(key, value, PropertyDetails(NONE, NORMAL));
12163 }
12164 
12165 
AtNumberPut(uint32_t key,Object * value)12166 MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
12167   UpdateMaxNumberKey(key);
12168   return AtPut(key, value);
12169 }
12170 
12171 
AtNumberPut(uint32_t key,Object * value)12172 MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12173                                                    Object* value) {
12174   return AtPut(key, value);
12175 }
12176 
12177 
Set(Handle<SeededNumberDictionary> dictionary,uint32_t index,Handle<Object> value,PropertyDetails details)12178 Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12179     Handle<SeededNumberDictionary> dictionary,
12180     uint32_t index,
12181     Handle<Object> value,
12182     PropertyDetails details) {
12183   CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12184                      dictionary->Set(index, *value, details),
12185                      SeededNumberDictionary);
12186 }
12187 
12188 
Set(Handle<UnseededNumberDictionary> dictionary,uint32_t index,Handle<Object> value)12189 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12190     Handle<UnseededNumberDictionary> dictionary,
12191     uint32_t index,
12192     Handle<Object> value) {
12193   CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12194                      dictionary->Set(index, *value),
12195                      UnseededNumberDictionary);
12196 }
12197 
12198 
Set(uint32_t key,Object * value,PropertyDetails details)12199 MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12200                                          Object* value,
12201                                          PropertyDetails details) {
12202   int entry = FindEntry(key);
12203   if (entry == kNotFound) return AddNumberEntry(key, value, details);
12204   // Preserve enumeration index.
12205   details = PropertyDetails(details.attributes(),
12206                             details.type(),
12207                             DetailsAt(entry).index());
12208   MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
12209   Object* object_key;
12210   if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12211   SetEntry(entry, object_key, value, details);
12212   return this;
12213 }
12214 
12215 
Set(uint32_t key,Object * value)12216 MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12217                                            Object* value) {
12218   int entry = FindEntry(key);
12219   if (entry == kNotFound) return AddNumberEntry(key, value);
12220   MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12221   Object* object_key;
12222   if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12223   SetEntry(entry, object_key, value);
12224   return this;
12225 }
12226 
12227 
12228 
12229 template<typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyAttributes filter)12230 int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12231     PropertyAttributes filter) {
12232   int capacity = HashTable<Shape, Key>::Capacity();
12233   int result = 0;
12234   for (int i = 0; i < capacity; i++) {
12235     Object* k = HashTable<Shape, Key>::KeyAt(i);
12236     if (HashTable<Shape, Key>::IsKey(k)) {
12237       PropertyDetails details = DetailsAt(i);
12238       if (details.IsDeleted()) continue;
12239       PropertyAttributes attr = details.attributes();
12240       if ((attr & filter) == 0) result++;
12241     }
12242   }
12243   return result;
12244 }
12245 
12246 
12247 template<typename Shape, typename Key>
NumberOfEnumElements()12248 int Dictionary<Shape, Key>::NumberOfEnumElements() {
12249   return NumberOfElementsFilterAttributes(
12250       static_cast<PropertyAttributes>(DONT_ENUM));
12251 }
12252 
12253 
12254 template<typename Shape, typename Key>
CopyKeysTo(FixedArray * storage,PropertyAttributes filter,typename Dictionary<Shape,Key>::SortMode sort_mode)12255 void Dictionary<Shape, Key>::CopyKeysTo(
12256     FixedArray* storage,
12257     PropertyAttributes filter,
12258     typename Dictionary<Shape, Key>::SortMode sort_mode) {
12259   ASSERT(storage->length() >= NumberOfEnumElements());
12260   int capacity = HashTable<Shape, Key>::Capacity();
12261   int index = 0;
12262   for (int i = 0; i < capacity; i++) {
12263      Object* k = HashTable<Shape, Key>::KeyAt(i);
12264      if (HashTable<Shape, Key>::IsKey(k)) {
12265        PropertyDetails details = DetailsAt(i);
12266        if (details.IsDeleted()) continue;
12267        PropertyAttributes attr = details.attributes();
12268        if ((attr & filter) == 0) storage->set(index++, k);
12269      }
12270   }
12271   if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12272     storage->SortPairs(storage, index);
12273   }
12274   ASSERT(storage->length() >= index);
12275 }
12276 
12277 
CopyEnumKeysTo(FixedArray * storage,FixedArray * sort_array)12278 void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12279                                       FixedArray* sort_array) {
12280   ASSERT(storage->length() >= NumberOfEnumElements());
12281   int capacity = Capacity();
12282   int index = 0;
12283   for (int i = 0; i < capacity; i++) {
12284      Object* k = KeyAt(i);
12285      if (IsKey(k)) {
12286        PropertyDetails details = DetailsAt(i);
12287        if (details.IsDeleted() || details.IsDontEnum()) continue;
12288        storage->set(index, k);
12289        sort_array->set(index, Smi::FromInt(details.index()));
12290        index++;
12291      }
12292   }
12293   storage->SortPairs(sort_array, sort_array->length());
12294   ASSERT(storage->length() >= index);
12295 }
12296 
12297 
12298 template<typename Shape, typename Key>
CopyKeysTo(FixedArray * storage,int index,typename Dictionary<Shape,Key>::SortMode sort_mode)12299 void Dictionary<Shape, Key>::CopyKeysTo(
12300     FixedArray* storage,
12301     int index,
12302     typename Dictionary<Shape, Key>::SortMode sort_mode) {
12303   ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12304       static_cast<PropertyAttributes>(NONE)));
12305   int capacity = HashTable<Shape, Key>::Capacity();
12306   for (int i = 0; i < capacity; i++) {
12307     Object* k = HashTable<Shape, Key>::KeyAt(i);
12308     if (HashTable<Shape, Key>::IsKey(k)) {
12309       PropertyDetails details = DetailsAt(i);
12310       if (details.IsDeleted()) continue;
12311       storage->set(index++, k);
12312     }
12313   }
12314   if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12315     storage->SortPairs(storage, index);
12316   }
12317   ASSERT(storage->length() >= index);
12318 }
12319 
12320 
12321 // Backwards lookup (slow).
12322 template<typename Shape, typename Key>
SlowReverseLookup(Object * value)12323 Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12324   int capacity = HashTable<Shape, Key>::Capacity();
12325   for (int i = 0; i < capacity; i++) {
12326     Object* k =  HashTable<Shape, Key>::KeyAt(i);
12327     if (Dictionary<Shape, Key>::IsKey(k)) {
12328       Object* e = ValueAt(i);
12329       if (e->IsJSGlobalPropertyCell()) {
12330         e = JSGlobalPropertyCell::cast(e)->value();
12331       }
12332       if (e == value) return k;
12333     }
12334   }
12335   Heap* heap = Dictionary<Shape, Key>::GetHeap();
12336   return heap->undefined_value();
12337 }
12338 
12339 
TransformPropertiesToFastFor(JSObject * obj,int unused_property_fields)12340 MaybeObject* StringDictionary::TransformPropertiesToFastFor(
12341     JSObject* obj, int unused_property_fields) {
12342   // Make sure we preserve dictionary representation if there are too many
12343   // descriptors.
12344   if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12345 
12346   // Figure out if it is necessary to generate new enumeration indices.
12347   int max_enumeration_index =
12348       NextEnumerationIndex() +
12349           (DescriptorArray::kMaxNumberOfDescriptors -
12350            NumberOfElements());
12351   if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
12352     Object* result;
12353     { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12354       if (!maybe_result->ToObject(&result)) return maybe_result;
12355     }
12356   }
12357 
12358   int instance_descriptor_length = 0;
12359   int number_of_fields = 0;
12360 
12361   Heap* heap = GetHeap();
12362 
12363   // Compute the length of the instance descriptor.
12364   int capacity = Capacity();
12365   for (int i = 0; i < capacity; i++) {
12366     Object* k = KeyAt(i);
12367     if (IsKey(k)) {
12368       Object* value = ValueAt(i);
12369       PropertyType type = DetailsAt(i).type();
12370       ASSERT(type != FIELD);
12371       instance_descriptor_length++;
12372       if (type == NORMAL &&
12373           (!value->IsJSFunction() || heap->InNewSpace(value))) {
12374         number_of_fields += 1;
12375       }
12376     }
12377   }
12378 
12379   // Allocate the instance descriptor.
12380   DescriptorArray* descriptors;
12381   { MaybeObject* maybe_descriptors =
12382         DescriptorArray::Allocate(instance_descriptor_length);
12383     if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12384       return maybe_descriptors;
12385     }
12386   }
12387 
12388   DescriptorArray::WhitenessWitness witness(descriptors);
12389 
12390   int inobject_props = obj->map()->inobject_properties();
12391   int number_of_allocated_fields =
12392       number_of_fields + unused_property_fields - inobject_props;
12393   if (number_of_allocated_fields < 0) {
12394     // There is enough inobject space for all fields (including unused).
12395     number_of_allocated_fields = 0;
12396     unused_property_fields = inobject_props - number_of_fields;
12397   }
12398 
12399   // Allocate the fixed array for the fields.
12400   Object* fields;
12401   { MaybeObject* maybe_fields =
12402         heap->AllocateFixedArray(number_of_allocated_fields);
12403     if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12404   }
12405 
12406   // Fill in the instance descriptor and the fields.
12407   int next_descriptor = 0;
12408   int current_offset = 0;
12409   for (int i = 0; i < capacity; i++) {
12410     Object* k = KeyAt(i);
12411     if (IsKey(k)) {
12412       Object* value = ValueAt(i);
12413       // Ensure the key is a symbol before writing into the instance descriptor.
12414       Object* key;
12415       { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
12416         if (!maybe_key->ToObject(&key)) return maybe_key;
12417       }
12418       PropertyDetails details = DetailsAt(i);
12419       PropertyType type = details.type();
12420 
12421       if (value->IsJSFunction() && !heap->InNewSpace(value)) {
12422         ConstantFunctionDescriptor d(String::cast(key),
12423                                      JSFunction::cast(value),
12424                                      details.attributes(),
12425                                      details.index());
12426         descriptors->Set(next_descriptor++, &d, witness);
12427       } else if (type == NORMAL) {
12428         if (current_offset < inobject_props) {
12429           obj->InObjectPropertyAtPut(current_offset,
12430                                      value,
12431                                      UPDATE_WRITE_BARRIER);
12432         } else {
12433           int offset = current_offset - inobject_props;
12434           FixedArray::cast(fields)->set(offset, value);
12435         }
12436         FieldDescriptor d(String::cast(key),
12437                           current_offset++,
12438                           details.attributes(),
12439                           details.index());
12440         descriptors->Set(next_descriptor++, &d, witness);
12441       } else if (type == CALLBACKS) {
12442         if (value->IsAccessorPair()) {
12443           MaybeObject* maybe_copy =
12444               AccessorPair::cast(value)->CopyWithoutTransitions();
12445           if (!maybe_copy->To(&value)) return maybe_copy;
12446         }
12447         CallbacksDescriptor d(String::cast(key),
12448                               value,
12449                               details.attributes(),
12450                               details.index());
12451         descriptors->Set(next_descriptor++, &d, witness);
12452       } else {
12453         UNREACHABLE();
12454       }
12455     }
12456   }
12457   ASSERT(current_offset == number_of_fields);
12458 
12459   descriptors->Sort(witness);
12460   // Allocate new map.
12461   Object* new_map;
12462   { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12463     if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12464   }
12465 
12466   // Transform the object.
12467   obj->set_map(Map::cast(new_map));
12468   obj->map()->set_instance_descriptors(descriptors);
12469   obj->map()->set_unused_property_fields(unused_property_fields);
12470 
12471   obj->set_properties(FixedArray::cast(fields));
12472   ASSERT(obj->IsJSObject());
12473 
12474   descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
12475   // Check that it really works.
12476   ASSERT(obj->HasFastProperties());
12477 
12478   return obj;
12479 }
12480 
12481 
Contains(Object * key)12482 bool ObjectHashSet::Contains(Object* key) {
12483   ASSERT(IsKey(key));
12484 
12485   // If the object does not have an identity hash, it was never used as a key.
12486   { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12487     if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12488   }
12489   return (FindEntry(key) != kNotFound);
12490 }
12491 
12492 
Add(Object * key)12493 MaybeObject* ObjectHashSet::Add(Object* key) {
12494   ASSERT(IsKey(key));
12495 
12496   // Make sure the key object has an identity hash code.
12497   int hash;
12498   { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12499     if (maybe_hash->IsFailure()) return maybe_hash;
12500     hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12501   }
12502   int entry = FindEntry(key);
12503 
12504   // Check whether key is already present.
12505   if (entry != kNotFound) return this;
12506 
12507   // Check whether the hash set should be extended and add entry.
12508   Object* obj;
12509   { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12510     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12511   }
12512   ObjectHashSet* table = ObjectHashSet::cast(obj);
12513   entry = table->FindInsertionEntry(hash);
12514   table->set(EntryToIndex(entry), key);
12515   table->ElementAdded();
12516   return table;
12517 }
12518 
12519 
Remove(Object * key)12520 MaybeObject* ObjectHashSet::Remove(Object* key) {
12521   ASSERT(IsKey(key));
12522 
12523   // If the object does not have an identity hash, it was never used as a key.
12524   { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12525     if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12526   }
12527   int entry = FindEntry(key);
12528 
12529   // Check whether key is actually present.
12530   if (entry == kNotFound) return this;
12531 
12532   // Remove entry and try to shrink this hash set.
12533   set_the_hole(EntryToIndex(entry));
12534   ElementRemoved();
12535   return Shrink(key);
12536 }
12537 
12538 
Lookup(Object * key)12539 Object* ObjectHashTable::Lookup(Object* key) {
12540   ASSERT(IsKey(key));
12541 
12542   // If the object does not have an identity hash, it was never used as a key.
12543   { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12544     if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12545       return GetHeap()->undefined_value();
12546     }
12547   }
12548   int entry = FindEntry(key);
12549   if (entry == kNotFound) return GetHeap()->undefined_value();
12550   return get(EntryToIndex(entry) + 1);
12551 }
12552 
12553 
Put(Object * key,Object * value)12554 MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
12555   ASSERT(IsKey(key));
12556 
12557   // Make sure the key object has an identity hash code.
12558   int hash;
12559   { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12560     if (maybe_hash->IsFailure()) return maybe_hash;
12561     hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12562   }
12563   int entry = FindEntry(key);
12564 
12565   // Check whether to perform removal operation.
12566   if (value->IsUndefined()) {
12567     if (entry == kNotFound) return this;
12568     RemoveEntry(entry);
12569     return Shrink(key);
12570   }
12571 
12572   // Key is already in table, just overwrite value.
12573   if (entry != kNotFound) {
12574     set(EntryToIndex(entry) + 1, value);
12575     return this;
12576   }
12577 
12578   // Check whether the hash table should be extended.
12579   Object* obj;
12580   { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12581     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12582   }
12583   ObjectHashTable* table = ObjectHashTable::cast(obj);
12584   table->AddEntry(table->FindInsertionEntry(hash), key, value);
12585   return table;
12586 }
12587 
12588 
AddEntry(int entry,Object * key,Object * value)12589 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
12590   set(EntryToIndex(entry), key);
12591   set(EntryToIndex(entry) + 1, value);
12592   ElementAdded();
12593 }
12594 
12595 
RemoveEntry(int entry)12596 void ObjectHashTable::RemoveEntry(int entry) {
12597   set_the_hole(EntryToIndex(entry));
12598   set_the_hole(EntryToIndex(entry) + 1);
12599   ElementRemoved();
12600 }
12601 
12602 
12603 #ifdef ENABLE_DEBUGGER_SUPPORT
12604 // Check if there is a break point at this code position.
HasBreakPoint(int code_position)12605 bool DebugInfo::HasBreakPoint(int code_position) {
12606   // Get the break point info object for this code position.
12607   Object* break_point_info = GetBreakPointInfo(code_position);
12608 
12609   // If there is no break point info object or no break points in the break
12610   // point info object there is no break point at this code position.
12611   if (break_point_info->IsUndefined()) return false;
12612   return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12613 }
12614 
12615 
12616 // Get the break point info object for this code position.
GetBreakPointInfo(int code_position)12617 Object* DebugInfo::GetBreakPointInfo(int code_position) {
12618   // Find the index of the break point info object for this code position.
12619   int index = GetBreakPointInfoIndex(code_position);
12620 
12621   // Return the break point info object if any.
12622   if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
12623   return BreakPointInfo::cast(break_points()->get(index));
12624 }
12625 
12626 
12627 // Clear a break point at the specified code position.
ClearBreakPoint(Handle<DebugInfo> debug_info,int code_position,Handle<Object> break_point_object)12628 void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12629                                 int code_position,
12630                                 Handle<Object> break_point_object) {
12631   Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12632   if (break_point_info->IsUndefined()) return;
12633   BreakPointInfo::ClearBreakPoint(
12634       Handle<BreakPointInfo>::cast(break_point_info),
12635       break_point_object);
12636 }
12637 
12638 
SetBreakPoint(Handle<DebugInfo> debug_info,int code_position,int source_position,int statement_position,Handle<Object> break_point_object)12639 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12640                               int code_position,
12641                               int source_position,
12642                               int statement_position,
12643                               Handle<Object> break_point_object) {
12644   Isolate* isolate = Isolate::Current();
12645   Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12646   if (!break_point_info->IsUndefined()) {
12647     BreakPointInfo::SetBreakPoint(
12648         Handle<BreakPointInfo>::cast(break_point_info),
12649         break_point_object);
12650     return;
12651   }
12652 
12653   // Adding a new break point for a code position which did not have any
12654   // break points before. Try to find a free slot.
12655   int index = kNoBreakPointInfo;
12656   for (int i = 0; i < debug_info->break_points()->length(); i++) {
12657     if (debug_info->break_points()->get(i)->IsUndefined()) {
12658       index = i;
12659       break;
12660     }
12661   }
12662   if (index == kNoBreakPointInfo) {
12663     // No free slot - extend break point info array.
12664     Handle<FixedArray> old_break_points =
12665         Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
12666     Handle<FixedArray> new_break_points =
12667         isolate->factory()->NewFixedArray(
12668             old_break_points->length() +
12669             Debug::kEstimatedNofBreakPointsInFunction);
12670 
12671     debug_info->set_break_points(*new_break_points);
12672     for (int i = 0; i < old_break_points->length(); i++) {
12673       new_break_points->set(i, old_break_points->get(i));
12674     }
12675     index = old_break_points->length();
12676   }
12677   ASSERT(index != kNoBreakPointInfo);
12678 
12679   // Allocate new BreakPointInfo object and set the break point.
12680   Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12681       isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
12682   new_break_point_info->set_code_position(Smi::FromInt(code_position));
12683   new_break_point_info->set_source_position(Smi::FromInt(source_position));
12684   new_break_point_info->
12685       set_statement_position(Smi::FromInt(statement_position));
12686   new_break_point_info->set_break_point_objects(
12687       isolate->heap()->undefined_value());
12688   BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12689   debug_info->break_points()->set(index, *new_break_point_info);
12690 }
12691 
12692 
12693 // Get the break point objects for a code position.
GetBreakPointObjects(int code_position)12694 Object* DebugInfo::GetBreakPointObjects(int code_position) {
12695   Object* break_point_info = GetBreakPointInfo(code_position);
12696   if (break_point_info->IsUndefined()) {
12697     return GetHeap()->undefined_value();
12698   }
12699   return BreakPointInfo::cast(break_point_info)->break_point_objects();
12700 }
12701 
12702 
12703 // Get the total number of break points.
GetBreakPointCount()12704 int DebugInfo::GetBreakPointCount() {
12705   if (break_points()->IsUndefined()) return 0;
12706   int count = 0;
12707   for (int i = 0; i < break_points()->length(); i++) {
12708     if (!break_points()->get(i)->IsUndefined()) {
12709       BreakPointInfo* break_point_info =
12710           BreakPointInfo::cast(break_points()->get(i));
12711       count += break_point_info->GetBreakPointCount();
12712     }
12713   }
12714   return count;
12715 }
12716 
12717 
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)12718 Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12719                                       Handle<Object> break_point_object) {
12720   Heap* heap = debug_info->GetHeap();
12721   if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
12722   for (int i = 0; i < debug_info->break_points()->length(); i++) {
12723     if (!debug_info->break_points()->get(i)->IsUndefined()) {
12724       Handle<BreakPointInfo> break_point_info =
12725           Handle<BreakPointInfo>(BreakPointInfo::cast(
12726               debug_info->break_points()->get(i)));
12727       if (BreakPointInfo::HasBreakPointObject(break_point_info,
12728                                               break_point_object)) {
12729         return *break_point_info;
12730       }
12731     }
12732   }
12733   return heap->undefined_value();
12734 }
12735 
12736 
12737 // Find the index of the break point info object for the specified code
12738 // position.
GetBreakPointInfoIndex(int code_position)12739 int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12740   if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12741   for (int i = 0; i < break_points()->length(); i++) {
12742     if (!break_points()->get(i)->IsUndefined()) {
12743       BreakPointInfo* break_point_info =
12744           BreakPointInfo::cast(break_points()->get(i));
12745       if (break_point_info->code_position()->value() == code_position) {
12746         return i;
12747       }
12748     }
12749   }
12750   return kNoBreakPointInfo;
12751 }
12752 
12753 
12754 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)12755 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12756                                      Handle<Object> break_point_object) {
12757   Isolate* isolate = Isolate::Current();
12758   // If there are no break points just ignore.
12759   if (break_point_info->break_point_objects()->IsUndefined()) return;
12760   // If there is a single break point clear it if it is the same.
12761   if (!break_point_info->break_point_objects()->IsFixedArray()) {
12762     if (break_point_info->break_point_objects() == *break_point_object) {
12763       break_point_info->set_break_point_objects(
12764           isolate->heap()->undefined_value());
12765     }
12766     return;
12767   }
12768   // If there are multiple break points shrink the array
12769   ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12770   Handle<FixedArray> old_array =
12771       Handle<FixedArray>(
12772           FixedArray::cast(break_point_info->break_point_objects()));
12773   Handle<FixedArray> new_array =
12774       isolate->factory()->NewFixedArray(old_array->length() - 1);
12775   int found_count = 0;
12776   for (int i = 0; i < old_array->length(); i++) {
12777     if (old_array->get(i) == *break_point_object) {
12778       ASSERT(found_count == 0);
12779       found_count++;
12780     } else {
12781       new_array->set(i - found_count, old_array->get(i));
12782     }
12783   }
12784   // If the break point was found in the list change it.
12785   if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12786 }
12787 
12788 
12789 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)12790 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12791                                    Handle<Object> break_point_object) {
12792   // If there was no break point objects before just set it.
12793   if (break_point_info->break_point_objects()->IsUndefined()) {
12794     break_point_info->set_break_point_objects(*break_point_object);
12795     return;
12796   }
12797   // If the break point object is the same as before just ignore.
12798   if (break_point_info->break_point_objects() == *break_point_object) return;
12799   // If there was one break point object before replace with array.
12800   if (!break_point_info->break_point_objects()->IsFixedArray()) {
12801     Handle<FixedArray> array = FACTORY->NewFixedArray(2);
12802     array->set(0, break_point_info->break_point_objects());
12803     array->set(1, *break_point_object);
12804     break_point_info->set_break_point_objects(*array);
12805     return;
12806   }
12807   // If there was more than one break point before extend array.
12808   Handle<FixedArray> old_array =
12809       Handle<FixedArray>(
12810           FixedArray::cast(break_point_info->break_point_objects()));
12811   Handle<FixedArray> new_array =
12812       FACTORY->NewFixedArray(old_array->length() + 1);
12813   for (int i = 0; i < old_array->length(); i++) {
12814     // If the break point was there before just ignore.
12815     if (old_array->get(i) == *break_point_object) return;
12816     new_array->set(i, old_array->get(i));
12817   }
12818   // Add the new break point.
12819   new_array->set(old_array->length(), *break_point_object);
12820   break_point_info->set_break_point_objects(*new_array);
12821 }
12822 
12823 
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)12824 bool BreakPointInfo::HasBreakPointObject(
12825     Handle<BreakPointInfo> break_point_info,
12826     Handle<Object> break_point_object) {
12827   // No break point.
12828   if (break_point_info->break_point_objects()->IsUndefined()) return false;
12829   // Single break point.
12830   if (!break_point_info->break_point_objects()->IsFixedArray()) {
12831     return break_point_info->break_point_objects() == *break_point_object;
12832   }
12833   // Multiple break points.
12834   FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12835   for (int i = 0; i < array->length(); i++) {
12836     if (array->get(i) == *break_point_object) {
12837       return true;
12838     }
12839   }
12840   return false;
12841 }
12842 
12843 
12844 // Get the number of break points.
GetBreakPointCount()12845 int BreakPointInfo::GetBreakPointCount() {
12846   // No break point.
12847   if (break_point_objects()->IsUndefined()) return 0;
12848   // Single break point.
12849   if (!break_point_objects()->IsFixedArray()) return 1;
12850   // Multiple break points.
12851   return FixedArray::cast(break_point_objects())->length();
12852 }
12853 #endif  // ENABLE_DEBUGGER_SUPPORT
12854 
12855 
GetField(Object * object,Smi * index)12856 MaybeObject* JSDate::GetField(Object* object, Smi* index) {
12857   return JSDate::cast(object)->DoGetField(
12858       static_cast<FieldIndex>(index->value()));
12859 }
12860 
12861 
DoGetField(FieldIndex index)12862 Object* JSDate::DoGetField(FieldIndex index) {
12863   ASSERT(index != kDateValue);
12864 
12865   DateCache* date_cache = GetIsolate()->date_cache();
12866 
12867   if (index < kFirstUncachedField) {
12868     Object* stamp = cache_stamp();
12869     if (stamp != date_cache->stamp() && stamp->IsSmi()) {
12870       // Since the stamp is not NaN, the value is also not NaN.
12871       int64_t local_time_ms =
12872           date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
12873       SetLocalFields(local_time_ms, date_cache);
12874     }
12875     switch (index) {
12876       case kYear: return year();
12877       case kMonth: return month();
12878       case kDay: return day();
12879       case kWeekday: return weekday();
12880       case kHour: return hour();
12881       case kMinute: return min();
12882       case kSecond: return sec();
12883       default: UNREACHABLE();
12884     }
12885   }
12886 
12887   if (index >= kFirstUTCField) {
12888     return GetUTCField(index, value()->Number(), date_cache);
12889   }
12890 
12891   double time = value()->Number();
12892   if (isnan(time)) return GetIsolate()->heap()->nan_value();
12893 
12894   int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
12895   int days = DateCache::DaysFromTime(local_time_ms);
12896 
12897   if (index == kDays) return Smi::FromInt(days);
12898 
12899   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12900   if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
12901   ASSERT(index == kTimeInDay);
12902   return Smi::FromInt(time_in_day_ms);
12903 }
12904 
12905 
GetUTCField(FieldIndex index,double value,DateCache * date_cache)12906 Object* JSDate::GetUTCField(FieldIndex index,
12907                             double value,
12908                             DateCache* date_cache) {
12909   ASSERT(index >= kFirstUTCField);
12910 
12911   if (isnan(value)) return GetIsolate()->heap()->nan_value();
12912 
12913   int64_t time_ms = static_cast<int64_t>(value);
12914 
12915   if (index == kTimezoneOffset) {
12916     return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
12917   }
12918 
12919   int days = DateCache::DaysFromTime(time_ms);
12920 
12921   if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
12922 
12923   if (index <= kDayUTC) {
12924     int year, month, day;
12925     date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12926     if (index == kYearUTC) return Smi::FromInt(year);
12927     if (index == kMonthUTC) return Smi::FromInt(month);
12928     ASSERT(index == kDayUTC);
12929     return Smi::FromInt(day);
12930   }
12931 
12932   int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
12933   switch (index) {
12934     case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
12935     case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
12936     case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
12937     case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
12938     case kDaysUTC: return Smi::FromInt(days);
12939     case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
12940     default: UNREACHABLE();
12941   }
12942 
12943   UNREACHABLE();
12944   return NULL;
12945 }
12946 
12947 
SetValue(Object * value,bool is_value_nan)12948 void JSDate::SetValue(Object* value, bool is_value_nan) {
12949   set_value(value);
12950   if (is_value_nan) {
12951     HeapNumber* nan = GetIsolate()->heap()->nan_value();
12952     set_cache_stamp(nan, SKIP_WRITE_BARRIER);
12953     set_year(nan, SKIP_WRITE_BARRIER);
12954     set_month(nan, SKIP_WRITE_BARRIER);
12955     set_day(nan, SKIP_WRITE_BARRIER);
12956     set_hour(nan, SKIP_WRITE_BARRIER);
12957     set_min(nan, SKIP_WRITE_BARRIER);
12958     set_sec(nan, SKIP_WRITE_BARRIER);
12959     set_weekday(nan, SKIP_WRITE_BARRIER);
12960   } else {
12961     set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
12962   }
12963 }
12964 
12965 
SetLocalFields(int64_t local_time_ms,DateCache * date_cache)12966 void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
12967   int days = DateCache::DaysFromTime(local_time_ms);
12968   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12969   int year, month, day;
12970   date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12971   int weekday = date_cache->Weekday(days);
12972   int hour = time_in_day_ms / (60 * 60 * 1000);
12973   int min = (time_in_day_ms / (60 * 1000)) % 60;
12974   int sec = (time_in_day_ms / 1000) % 60;
12975   set_cache_stamp(date_cache->stamp());
12976   set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
12977   set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
12978   set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
12979   set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
12980   set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
12981   set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
12982   set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
12983 }
12984 
12985 } }  // namespace v8::internal
12986