• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2006-2009 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 "debug.h"
34 #include "execution.h"
35 #include "objects-inl.h"
36 #include "macro-assembler.h"
37 #include "scanner.h"
38 #include "scopeinfo.h"
39 #include "string-stream.h"
40 #include "utils.h"
41 
42 #ifdef ENABLE_DISASSEMBLER
43 #include "disassembler.h"
44 #endif
45 
46 
47 namespace v8 {
48 namespace internal {
49 
50 // Getters and setters are stored in a fixed array property.  These are
51 // constants for their indices.
52 const int kGetterIndex = 0;
53 const int kSetterIndex = 1;
54 
55 
CreateJSValue(JSFunction * constructor,Object * value)56 static Object* CreateJSValue(JSFunction* constructor, Object* value) {
57   Object* result = Heap::AllocateJSObject(constructor);
58   if (result->IsFailure()) return result;
59   JSValue::cast(result)->set_value(value);
60   return result;
61 }
62 
63 
ToObject(Context * global_context)64 Object* Object::ToObject(Context* global_context) {
65   if (IsNumber()) {
66     return CreateJSValue(global_context->number_function(), this);
67   } else if (IsBoolean()) {
68     return CreateJSValue(global_context->boolean_function(), this);
69   } else if (IsString()) {
70     return CreateJSValue(global_context->string_function(), this);
71   }
72   ASSERT(IsJSObject());
73   return this;
74 }
75 
76 
ToObject()77 Object* Object::ToObject() {
78   Context* global_context = Top::context()->global_context();
79   if (IsJSObject()) {
80     return this;
81   } else if (IsNumber()) {
82     return CreateJSValue(global_context->number_function(), this);
83   } else if (IsBoolean()) {
84     return CreateJSValue(global_context->boolean_function(), this);
85   } else if (IsString()) {
86     return CreateJSValue(global_context->string_function(), this);
87   }
88 
89   // Throw a type error.
90   return Failure::InternalError();
91 }
92 
93 
ToBoolean()94 Object* Object::ToBoolean() {
95   if (IsTrue()) return Heap::true_value();
96   if (IsFalse()) return Heap::false_value();
97   if (IsSmi()) {
98     return Heap::ToBoolean(Smi::cast(this)->value() != 0);
99   }
100   if (IsUndefined() || IsNull()) return Heap::false_value();
101   // Undetectable object is false
102   if (IsUndetectableObject()) {
103     return Heap::false_value();
104   }
105   if (IsString()) {
106     return Heap::ToBoolean(String::cast(this)->length() != 0);
107   }
108   if (IsHeapNumber()) {
109     return HeapNumber::cast(this)->HeapNumberToBoolean();
110   }
111   return Heap::true_value();
112 }
113 
114 
Lookup(String * name,LookupResult * result)115 void Object::Lookup(String* name, LookupResult* result) {
116   if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result);
117   Object* holder = NULL;
118   Context* global_context = Top::context()->global_context();
119   if (IsString()) {
120     holder = global_context->string_function()->instance_prototype();
121   } else if (IsNumber()) {
122     holder = global_context->number_function()->instance_prototype();
123   } else if (IsBoolean()) {
124     holder = global_context->boolean_function()->instance_prototype();
125   }
126   ASSERT(holder != NULL);  // Cannot handle null or undefined.
127   JSObject::cast(holder)->Lookup(name, result);
128 }
129 
130 
GetPropertyWithReceiver(Object * receiver,String * name,PropertyAttributes * attributes)131 Object* Object::GetPropertyWithReceiver(Object* receiver,
132                                         String* name,
133                                         PropertyAttributes* attributes) {
134   LookupResult result;
135   Lookup(name, &result);
136   Object* value = GetProperty(receiver, &result, name, attributes);
137   ASSERT(*attributes <= ABSENT);
138   return value;
139 }
140 
141 
GetPropertyWithCallback(Object * receiver,Object * structure,String * name,Object * holder)142 Object* Object::GetPropertyWithCallback(Object* receiver,
143                                         Object* structure,
144                                         String* name,
145                                         Object* holder) {
146   // To accommodate both the old and the new api we switch on the
147   // data structure used to store the callbacks.  Eventually proxy
148   // callbacks should be phased out.
149   if (structure->IsProxy()) {
150     AccessorDescriptor* callback =
151         reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
152     Object* value = (callback->getter)(receiver, callback->data);
153     RETURN_IF_SCHEDULED_EXCEPTION();
154     return value;
155   }
156 
157   // api style callbacks.
158   if (structure->IsAccessorInfo()) {
159     AccessorInfo* data = AccessorInfo::cast(structure);
160     Object* fun_obj = data->getter();
161     v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
162     HandleScope scope;
163     JSObject* self = JSObject::cast(receiver);
164     JSObject* holder_handle = JSObject::cast(holder);
165     Handle<String> key(name);
166     LOG(ApiNamedPropertyAccess("load", self, name));
167     CustomArguments args(data->data(), self, holder_handle);
168     v8::AccessorInfo info(args.end());
169     v8::Handle<v8::Value> result;
170     {
171       // Leaving JavaScript.
172       VMState state(EXTERNAL);
173       result = call_fun(v8::Utils::ToLocal(key), info);
174     }
175     RETURN_IF_SCHEDULED_EXCEPTION();
176     if (result.IsEmpty()) return Heap::undefined_value();
177     return *v8::Utils::OpenHandle(*result);
178   }
179 
180   // __defineGetter__ callback
181   if (structure->IsFixedArray()) {
182     Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
183     if (getter->IsJSFunction()) {
184       return Object::GetPropertyWithDefinedGetter(receiver,
185                                                   JSFunction::cast(getter));
186     }
187     // Getter is not a function.
188     return Heap::undefined_value();
189   }
190 
191   UNREACHABLE();
192   return 0;
193 }
194 
195 
GetPropertyWithDefinedGetter(Object * receiver,JSFunction * getter)196 Object* Object::GetPropertyWithDefinedGetter(Object* receiver,
197                                              JSFunction* getter) {
198   HandleScope scope;
199   Handle<JSFunction> fun(JSFunction::cast(getter));
200   Handle<Object> self(receiver);
201 #ifdef ENABLE_DEBUGGER_SUPPORT
202   // Handle stepping into a getter if step into is active.
203   if (Debug::StepInActive()) {
204     Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
205   }
206 #endif
207   bool has_pending_exception;
208   Handle<Object> result =
209       Execution::Call(fun, self, 0, NULL, &has_pending_exception);
210   // Check for pending exception and return the result.
211   if (has_pending_exception) return Failure::Exception();
212   return *result;
213 }
214 
215 
216 // Only deal with CALLBACKS and INTERCEPTOR
GetPropertyWithFailedAccessCheck(Object * receiver,LookupResult * result,String * name,PropertyAttributes * attributes)217 Object* JSObject::GetPropertyWithFailedAccessCheck(
218     Object* receiver,
219     LookupResult* result,
220     String* name,
221     PropertyAttributes* attributes) {
222   if (result->IsProperty()) {
223     switch (result->type()) {
224       case CALLBACKS: {
225         // Only allow API accessors.
226         Object* obj = result->GetCallbackObject();
227         if (obj->IsAccessorInfo()) {
228           AccessorInfo* info = AccessorInfo::cast(obj);
229           if (info->all_can_read()) {
230             *attributes = result->GetAttributes();
231             return GetPropertyWithCallback(receiver,
232                                            result->GetCallbackObject(),
233                                            name,
234                                            result->holder());
235           }
236         }
237         break;
238       }
239       case NORMAL:
240       case FIELD:
241       case CONSTANT_FUNCTION: {
242         // Search ALL_CAN_READ accessors in prototype chain.
243         LookupResult r;
244         result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
245         if (r.IsProperty()) {
246           return GetPropertyWithFailedAccessCheck(receiver,
247                                                   &r,
248                                                   name,
249                                                   attributes);
250         }
251         break;
252       }
253       case INTERCEPTOR: {
254         // If the object has an interceptor, try real named properties.
255         // No access check in GetPropertyAttributeWithInterceptor.
256         LookupResult r;
257         result->holder()->LookupRealNamedProperty(name, &r);
258         if (r.IsProperty()) {
259           return GetPropertyWithFailedAccessCheck(receiver,
260                                                   &r,
261                                                   name,
262                                                   attributes);
263         }
264         break;
265       }
266       default:
267         UNREACHABLE();
268     }
269   }
270 
271   // No accessible property found.
272   *attributes = ABSENT;
273   Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
274   return Heap::undefined_value();
275 }
276 
277 
GetPropertyAttributeWithFailedAccessCheck(Object * receiver,LookupResult * result,String * name,bool continue_search)278 PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
279     Object* receiver,
280     LookupResult* result,
281     String* name,
282     bool continue_search) {
283   if (result->IsProperty()) {
284     switch (result->type()) {
285       case CALLBACKS: {
286         // Only allow API accessors.
287         Object* obj = result->GetCallbackObject();
288         if (obj->IsAccessorInfo()) {
289           AccessorInfo* info = AccessorInfo::cast(obj);
290           if (info->all_can_read()) {
291             return result->GetAttributes();
292           }
293         }
294         break;
295       }
296 
297       case NORMAL:
298       case FIELD:
299       case CONSTANT_FUNCTION: {
300         if (!continue_search) break;
301         // Search ALL_CAN_READ accessors in prototype chain.
302         LookupResult r;
303         result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
304         if (r.IsProperty()) {
305           return GetPropertyAttributeWithFailedAccessCheck(receiver,
306                                                            &r,
307                                                            name,
308                                                            continue_search);
309         }
310         break;
311       }
312 
313       case INTERCEPTOR: {
314         // If the object has an interceptor, try real named properties.
315         // No access check in GetPropertyAttributeWithInterceptor.
316         LookupResult r;
317         if (continue_search) {
318           result->holder()->LookupRealNamedProperty(name, &r);
319         } else {
320           result->holder()->LocalLookupRealNamedProperty(name, &r);
321         }
322         if (r.IsProperty()) {
323           return GetPropertyAttributeWithFailedAccessCheck(receiver,
324                                                            &r,
325                                                            name,
326                                                            continue_search);
327         }
328         break;
329       }
330 
331       default:
332         UNREACHABLE();
333     }
334   }
335 
336   Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
337   return ABSENT;
338 }
339 
340 
GetNormalizedProperty(LookupResult * result)341 Object* JSObject::GetNormalizedProperty(LookupResult* result) {
342   ASSERT(!HasFastProperties());
343   Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
344   if (IsGlobalObject()) {
345     value = JSGlobalPropertyCell::cast(value)->value();
346   }
347   ASSERT(!value->IsJSGlobalPropertyCell());
348   return value;
349 }
350 
351 
SetNormalizedProperty(LookupResult * result,Object * value)352 Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
353   ASSERT(!HasFastProperties());
354   if (IsGlobalObject()) {
355     JSGlobalPropertyCell* cell =
356         JSGlobalPropertyCell::cast(
357             property_dictionary()->ValueAt(result->GetDictionaryEntry()));
358     cell->set_value(value);
359   } else {
360     property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
361   }
362   return value;
363 }
364 
365 
SetNormalizedProperty(String * name,Object * value,PropertyDetails details)366 Object* JSObject::SetNormalizedProperty(String* name,
367                                         Object* value,
368                                         PropertyDetails details) {
369   ASSERT(!HasFastProperties());
370   int entry = property_dictionary()->FindEntry(name);
371   if (entry == StringDictionary::kNotFound) {
372     Object* store_value = value;
373     if (IsGlobalObject()) {
374       store_value = Heap::AllocateJSGlobalPropertyCell(value);
375       if (store_value->IsFailure()) return store_value;
376     }
377     Object* dict = property_dictionary()->Add(name, store_value, details);
378     if (dict->IsFailure()) return dict;
379     set_properties(StringDictionary::cast(dict));
380     return value;
381   }
382   // Preserve enumeration index.
383   details = PropertyDetails(details.attributes(),
384                             details.type(),
385                             property_dictionary()->DetailsAt(entry).index());
386   if (IsGlobalObject()) {
387     JSGlobalPropertyCell* cell =
388         JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
389     cell->set_value(value);
390     // Please note we have to update the property details.
391     property_dictionary()->DetailsAtPut(entry, details);
392   } else {
393     property_dictionary()->SetEntry(entry, name, value, details);
394   }
395   return value;
396 }
397 
398 
DeleteNormalizedProperty(String * name,DeleteMode mode)399 Object* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
400   ASSERT(!HasFastProperties());
401   StringDictionary* dictionary = property_dictionary();
402   int entry = dictionary->FindEntry(name);
403   if (entry != StringDictionary::kNotFound) {
404     // If we have a global object set the cell to the hole.
405     if (IsGlobalObject()) {
406       PropertyDetails details = dictionary->DetailsAt(entry);
407       if (details.IsDontDelete()) {
408         if (mode != FORCE_DELETION) return Heap::false_value();
409         // When forced to delete global properties, we have to make a
410         // map change to invalidate any ICs that think they can load
411         // from the DontDelete cell without checking if it contains
412         // the hole value.
413         Object* new_map = map()->CopyDropDescriptors();
414         if (new_map->IsFailure()) return new_map;
415         set_map(Map::cast(new_map));
416       }
417       JSGlobalPropertyCell* cell =
418           JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
419       cell->set_value(Heap::the_hole_value());
420       dictionary->DetailsAtPut(entry, details.AsDeleted());
421     } else {
422       return dictionary->DeleteProperty(entry, mode);
423     }
424   }
425   return Heap::true_value();
426 }
427 
428 
IsDirty()429 bool JSObject::IsDirty() {
430   Object* cons_obj = map()->constructor();
431   if (!cons_obj->IsJSFunction())
432     return true;
433   JSFunction* fun = JSFunction::cast(cons_obj);
434   if (!fun->shared()->function_data()->IsFunctionTemplateInfo())
435     return true;
436   // If the object is fully fast case and has the same map it was
437   // created with then no changes can have been made to it.
438   return map() != fun->initial_map()
439       || !HasFastElements()
440       || !HasFastProperties();
441 }
442 
443 
GetProperty(Object * receiver,LookupResult * result,String * name,PropertyAttributes * attributes)444 Object* Object::GetProperty(Object* receiver,
445                             LookupResult* result,
446                             String* name,
447                             PropertyAttributes* attributes) {
448   // Make sure that the top context does not change when doing
449   // callbacks or interceptor calls.
450   AssertNoContextChange ncc;
451 
452   // Traverse the prototype chain from the current object (this) to
453   // the holder and check for access rights. This avoid traversing the
454   // objects more than once in case of interceptors, because the
455   // holder will always be the interceptor holder and the search may
456   // only continue with a current object just after the interceptor
457   // holder in the prototype chain.
458   Object* last = result->IsProperty() ? result->holder() : Heap::null_value();
459   for (Object* current = this; true; current = current->GetPrototype()) {
460     if (current->IsAccessCheckNeeded()) {
461       // Check if we're allowed to read from the current object. Note
462       // that even though we may not actually end up loading the named
463       // property from the current object, we still check that we have
464       // access to it.
465       JSObject* checked = JSObject::cast(current);
466       if (!Top::MayNamedAccess(checked, name, v8::ACCESS_GET)) {
467         return checked->GetPropertyWithFailedAccessCheck(receiver,
468                                                          result,
469                                                          name,
470                                                          attributes);
471       }
472     }
473     // Stop traversing the chain once we reach the last object in the
474     // chain; either the holder of the result or null in case of an
475     // absent property.
476     if (current == last) break;
477   }
478 
479   if (!result->IsProperty()) {
480     *attributes = ABSENT;
481     return Heap::undefined_value();
482   }
483   *attributes = result->GetAttributes();
484   Object* value;
485   JSObject* holder = result->holder();
486   switch (result->type()) {
487     case NORMAL:
488       value = holder->GetNormalizedProperty(result);
489       ASSERT(!value->IsTheHole() || result->IsReadOnly());
490       return value->IsTheHole() ? Heap::undefined_value() : value;
491     case FIELD:
492       value = holder->FastPropertyAt(result->GetFieldIndex());
493       ASSERT(!value->IsTheHole() || result->IsReadOnly());
494       return value->IsTheHole() ? Heap::undefined_value() : value;
495     case CONSTANT_FUNCTION:
496       return result->GetConstantFunction();
497     case CALLBACKS:
498       return GetPropertyWithCallback(receiver,
499                                      result->GetCallbackObject(),
500                                      name,
501                                      holder);
502     case INTERCEPTOR: {
503       JSObject* recvr = JSObject::cast(receiver);
504       return holder->GetPropertyWithInterceptor(recvr, name, attributes);
505     }
506     default:
507       UNREACHABLE();
508       return NULL;
509   }
510 }
511 
512 
GetElementWithReceiver(Object * receiver,uint32_t index)513 Object* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
514   // Non-JS objects do not have integer indexed properties.
515   if (!IsJSObject()) return Heap::undefined_value();
516   return JSObject::cast(this)->GetElementWithReceiver(JSObject::cast(receiver),
517                                                       index);
518 }
519 
520 
GetPrototype()521 Object* Object::GetPrototype() {
522   // The object is either a number, a string, a boolean, or a real JS object.
523   if (IsJSObject()) return JSObject::cast(this)->map()->prototype();
524   Context* context = Top::context()->global_context();
525 
526   if (IsNumber()) return context->number_function()->instance_prototype();
527   if (IsString()) return context->string_function()->instance_prototype();
528   if (IsBoolean()) {
529     return context->boolean_function()->instance_prototype();
530   } else {
531     return Heap::null_value();
532   }
533 }
534 
535 
ShortPrint()536 void Object::ShortPrint() {
537   HeapStringAllocator allocator;
538   StringStream accumulator(&allocator);
539   ShortPrint(&accumulator);
540   accumulator.OutputToStdOut();
541 }
542 
543 
ShortPrint(StringStream * accumulator)544 void Object::ShortPrint(StringStream* accumulator) {
545   if (IsSmi()) {
546     Smi::cast(this)->SmiPrint(accumulator);
547   } else if (IsFailure()) {
548     Failure::cast(this)->FailurePrint(accumulator);
549   } else {
550     HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
551   }
552 }
553 
554 
SmiPrint()555 void Smi::SmiPrint() {
556   PrintF("%d", value());
557 }
558 
559 
SmiPrint(StringStream * accumulator)560 void Smi::SmiPrint(StringStream* accumulator) {
561   accumulator->Add("%d", value());
562 }
563 
564 
FailurePrint(StringStream * accumulator)565 void Failure::FailurePrint(StringStream* accumulator) {
566   accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
567 }
568 
569 
FailurePrint()570 void Failure::FailurePrint() {
571   PrintF("Failure(%p)", reinterpret_cast<void*>(value()));
572 }
573 
574 
RetryAfterGC(int requested_bytes,AllocationSpace space)575 Failure* Failure::RetryAfterGC(int requested_bytes, AllocationSpace space) {
576   ASSERT((space & ~kSpaceTagMask) == 0);
577   // TODO(X64): Stop using Smi validation for non-smi checks, even if they
578   // happen to be identical at the moment.
579 
580   int requested = requested_bytes >> kObjectAlignmentBits;
581   int value = (requested << kSpaceTagSize) | space;
582   // We can't very well allocate a heap number in this situation, and if the
583   // requested memory is so large it seems reasonable to say that this is an
584   // out of memory situation.  This fixes a crash in
585   // js1_5/Regress/regress-303213.js.
586   if (value >> kSpaceTagSize != requested ||
587       !Smi::IsValid(value) ||
588       value != ((value << kFailureTypeTagSize) >> kFailureTypeTagSize) ||
589       !Smi::IsValid(value << kFailureTypeTagSize)) {
590     Top::context()->mark_out_of_memory();
591     return Failure::OutOfMemoryException();
592   }
593   return Construct(RETRY_AFTER_GC, value);
594 }
595 
596 
597 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
598 // English?  Returns false for non-ASCII or words that don't start with
599 // a capital letter.  The a/an rule follows pronunciation in English.
600 // We don't use the BBC's overcorrect "an historic occasion" though if
601 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)602 static bool AnWord(String* str) {
603   if (str->length() == 0) return false;  // A nothing.
604   int c0 = str->Get(0);
605   int c1 = str->length() > 1 ? str->Get(1) : 0;
606   if (c0 == 'U') {
607     if (c1 > 'Z') {
608       return true;  // An Umpire, but a UTF8String, a U.
609     }
610   } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
611     return true;    // An Ape, an ABCBook.
612   } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
613            (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
614             c0 == 'S' || c0 == 'X')) {
615     return true;    // An MP3File, an M.
616   }
617   return false;
618 }
619 
620 
TryFlatten()621 Object* String::TryFlatten() {
622 #ifdef DEBUG
623   // Do not attempt to flatten in debug mode when allocation is not
624   // allowed.  This is to avoid an assertion failure when allocating.
625   // Flattening strings is the only case where we always allow
626   // allocation because no GC is performed if the allocation fails.
627   if (!Heap::IsAllocationAllowed()) return this;
628 #endif
629 
630   switch (StringShape(this).representation_tag()) {
631     case kConsStringTag: {
632       ConsString* cs = ConsString::cast(this);
633       if (cs->second()->length() == 0) {
634         return this;
635       }
636       // There's little point in putting the flat string in new space if the
637       // cons string is in old space.  It can never get GCed until there is
638       // an old space GC.
639       PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
640       int len = length();
641       Object* object;
642       String* result;
643       if (IsAsciiRepresentation()) {
644         object = Heap::AllocateRawAsciiString(len, tenure);
645         if (object->IsFailure()) return object;
646         result = String::cast(object);
647         String* first = cs->first();
648         int first_length = first->length();
649         char* dest = SeqAsciiString::cast(result)->GetChars();
650         WriteToFlat(first, dest, 0, first_length);
651         String* second = cs->second();
652         WriteToFlat(second,
653                     dest + first_length,
654                     0,
655                     len - first_length);
656       } else {
657         object = Heap::AllocateRawTwoByteString(len, tenure);
658         if (object->IsFailure()) return object;
659         result = String::cast(object);
660         uc16* dest = SeqTwoByteString::cast(result)->GetChars();
661         String* first = cs->first();
662         int first_length = first->length();
663         WriteToFlat(first, dest, 0, first_length);
664         String* second = cs->second();
665         WriteToFlat(second,
666                     dest + first_length,
667                     0,
668                     len - first_length);
669       }
670       cs->set_first(result);
671       cs->set_second(Heap::empty_string());
672       return this;
673     }
674     default:
675       return this;
676   }
677 }
678 
679 
MakeExternal(v8::String::ExternalStringResource * resource)680 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
681 #ifdef DEBUG
682   if (FLAG_enable_slow_asserts) {
683     // Assert that the resource and the string are equivalent.
684     ASSERT(static_cast<size_t>(this->length()) == resource->length());
685     SmartPointer<uc16> smart_chars(NewArray<uc16>(this->length()));
686     String::WriteToFlat(this, *smart_chars, 0, this->length());
687     ASSERT(memcmp(*smart_chars,
688                   resource->data(),
689                   resource->length() * sizeof(**smart_chars)) == 0);
690   }
691 #endif  // DEBUG
692 
693   int size = this->Size();  // Byte size of the original string.
694   if (size < ExternalString::kSize) {
695     // The string is too small to fit an external String in its place. This can
696     // only happen for zero length strings.
697     return false;
698   }
699   ASSERT(size >= ExternalString::kSize);
700   bool is_symbol = this->IsSymbol();
701   int length = this->length();
702   int hash_field = this->hash_field();
703 
704   // Morph the object to an external string by adjusting the map and
705   // reinitializing the fields.
706   this->set_map(Heap::external_string_map());
707   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
708   self->set_length(length);
709   self->set_hash_field(hash_field);
710   self->set_resource(resource);
711   // Additionally make the object into an external symbol if the original string
712   // was a symbol to start with.
713   if (is_symbol) {
714     self->Hash();  // Force regeneration of the hash value.
715     // Now morph this external string into a external symbol.
716     this->set_map(Heap::external_symbol_map());
717   }
718 
719   // Fill the remainder of the string with dead wood.
720   int new_size = this->Size();  // Byte size of the external String object.
721   Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size);
722   return true;
723 }
724 
725 
MakeExternal(v8::String::ExternalAsciiStringResource * resource)726 bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
727 #ifdef DEBUG
728   if (FLAG_enable_slow_asserts) {
729     // Assert that the resource and the string are equivalent.
730     ASSERT(static_cast<size_t>(this->length()) == resource->length());
731     SmartPointer<char> smart_chars(NewArray<char>(this->length()));
732     String::WriteToFlat(this, *smart_chars, 0, this->length());
733     ASSERT(memcmp(*smart_chars,
734                   resource->data(),
735                   resource->length()*sizeof(**smart_chars)) == 0);
736   }
737 #endif  // DEBUG
738 
739   int size = this->Size();  // Byte size of the original string.
740   if (size < ExternalString::kSize) {
741     // The string is too small to fit an external String in its place. This can
742     // only happen for zero length strings.
743     return false;
744   }
745   ASSERT(size >= ExternalString::kSize);
746   bool is_symbol = this->IsSymbol();
747   int length = this->length();
748   int hash_field = this->hash_field();
749 
750   // Morph the object to an external string by adjusting the map and
751   // reinitializing the fields.
752   this->set_map(Heap::external_ascii_string_map());
753   ExternalAsciiString* self = ExternalAsciiString::cast(this);
754   self->set_length(length);
755   self->set_hash_field(hash_field);
756   self->set_resource(resource);
757   // Additionally make the object into an external symbol if the original string
758   // was a symbol to start with.
759   if (is_symbol) {
760     self->Hash();  // Force regeneration of the hash value.
761     // Now morph this external string into a external symbol.
762     this->set_map(Heap::external_ascii_symbol_map());
763   }
764 
765   // Fill the remainder of the string with dead wood.
766   int new_size = this->Size();  // Byte size of the external String object.
767   Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size);
768   return true;
769 }
770 
771 
StringShortPrint(StringStream * accumulator)772 void String::StringShortPrint(StringStream* accumulator) {
773   int len = length();
774   if (len > kMaxShortPrintLength) {
775     accumulator->Add("<Very long string[%u]>", len);
776     return;
777   }
778 
779   if (!LooksValid()) {
780     accumulator->Add("<Invalid String>");
781     return;
782   }
783 
784   StringInputBuffer buf(this);
785 
786   bool truncated = false;
787   if (len > kMaxShortPrintLength) {
788     len = kMaxShortPrintLength;
789     truncated = true;
790   }
791   bool ascii = true;
792   for (int i = 0; i < len; i++) {
793     int c = buf.GetNext();
794 
795     if (c < 32 || c >= 127) {
796       ascii = false;
797     }
798   }
799   buf.Reset(this);
800   if (ascii) {
801     accumulator->Add("<String[%u]: ", length());
802     for (int i = 0; i < len; i++) {
803       accumulator->Put(buf.GetNext());
804     }
805     accumulator->Put('>');
806   } else {
807     // Backslash indicates that the string contains control
808     // characters and that backslashes are therefore escaped.
809     accumulator->Add("<String[%u]\\: ", length());
810     for (int i = 0; i < len; i++) {
811       int c = buf.GetNext();
812       if (c == '\n') {
813         accumulator->Add("\\n");
814       } else if (c == '\r') {
815         accumulator->Add("\\r");
816       } else if (c == '\\') {
817         accumulator->Add("\\\\");
818       } else if (c < 32 || c > 126) {
819         accumulator->Add("\\x%02x", c);
820       } else {
821         accumulator->Put(c);
822       }
823     }
824     if (truncated) {
825       accumulator->Put('.');
826       accumulator->Put('.');
827       accumulator->Put('.');
828     }
829     accumulator->Put('>');
830   }
831   return;
832 }
833 
834 
JSObjectShortPrint(StringStream * accumulator)835 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
836   switch (map()->instance_type()) {
837     case JS_ARRAY_TYPE: {
838       double length = JSArray::cast(this)->length()->Number();
839       accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
840       break;
841     }
842     case JS_REGEXP_TYPE: {
843       accumulator->Add("<JS RegExp>");
844       break;
845     }
846     case JS_FUNCTION_TYPE: {
847       Object* fun_name = JSFunction::cast(this)->shared()->name();
848       bool printed = false;
849       if (fun_name->IsString()) {
850         String* str = String::cast(fun_name);
851         if (str->length() > 0) {
852           accumulator->Add("<JS Function ");
853           accumulator->Put(str);
854           accumulator->Put('>');
855           printed = true;
856         }
857       }
858       if (!printed) {
859         accumulator->Add("<JS Function>");
860       }
861       break;
862     }
863     // All other JSObjects are rather similar to each other (JSObject,
864     // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
865     default: {
866       Object* constructor = map()->constructor();
867       bool printed = false;
868       if (constructor->IsHeapObject() &&
869           !Heap::Contains(HeapObject::cast(constructor))) {
870         accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
871       } else {
872         bool global_object = IsJSGlobalProxy();
873         if (constructor->IsJSFunction()) {
874           if (!Heap::Contains(JSFunction::cast(constructor)->shared())) {
875             accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
876           } else {
877             Object* constructor_name =
878                 JSFunction::cast(constructor)->shared()->name();
879             if (constructor_name->IsString()) {
880               String* str = String::cast(constructor_name);
881               if (str->length() > 0) {
882                 bool vowel = AnWord(str);
883                 accumulator->Add("<%sa%s ",
884                        global_object ? "Global Object: " : "",
885                        vowel ? "n" : "");
886                 accumulator->Put(str);
887                 accumulator->Put('>');
888                 printed = true;
889               }
890             }
891           }
892         }
893         if (!printed) {
894           accumulator->Add("<JS %sObject", global_object ? "Global " : "");
895         }
896       }
897       if (IsJSValue()) {
898         accumulator->Add(" value = ");
899         JSValue::cast(this)->value()->ShortPrint(accumulator);
900       }
901       accumulator->Put('>');
902       break;
903     }
904   }
905 }
906 
907 
HeapObjectShortPrint(StringStream * accumulator)908 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
909   // if (!Heap::InNewSpace(this)) PrintF("*", this);
910   if (!Heap::Contains(this)) {
911     accumulator->Add("!!!INVALID POINTER!!!");
912     return;
913   }
914   if (!Heap::Contains(map())) {
915     accumulator->Add("!!!INVALID MAP!!!");
916     return;
917   }
918 
919   accumulator->Add("%p ", this);
920 
921   if (IsString()) {
922     String::cast(this)->StringShortPrint(accumulator);
923     return;
924   }
925   if (IsJSObject()) {
926     JSObject::cast(this)->JSObjectShortPrint(accumulator);
927     return;
928   }
929   switch (map()->instance_type()) {
930     case MAP_TYPE:
931       accumulator->Add("<Map>");
932       break;
933     case FIXED_ARRAY_TYPE:
934       accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
935       break;
936     case BYTE_ARRAY_TYPE:
937       accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
938       break;
939     case PIXEL_ARRAY_TYPE:
940       accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length());
941       break;
942     case EXTERNAL_BYTE_ARRAY_TYPE:
943       accumulator->Add("<ExternalByteArray[%u]>",
944                        ExternalByteArray::cast(this)->length());
945       break;
946     case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
947       accumulator->Add("<ExternalUnsignedByteArray[%u]>",
948                        ExternalUnsignedByteArray::cast(this)->length());
949       break;
950     case EXTERNAL_SHORT_ARRAY_TYPE:
951       accumulator->Add("<ExternalShortArray[%u]>",
952                        ExternalShortArray::cast(this)->length());
953       break;
954     case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
955       accumulator->Add("<ExternalUnsignedShortArray[%u]>",
956                        ExternalUnsignedShortArray::cast(this)->length());
957       break;
958     case EXTERNAL_INT_ARRAY_TYPE:
959       accumulator->Add("<ExternalIntArray[%u]>",
960                        ExternalIntArray::cast(this)->length());
961       break;
962     case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
963       accumulator->Add("<ExternalUnsignedIntArray[%u]>",
964                        ExternalUnsignedIntArray::cast(this)->length());
965       break;
966     case EXTERNAL_FLOAT_ARRAY_TYPE:
967       accumulator->Add("<ExternalFloatArray[%u]>",
968                        ExternalFloatArray::cast(this)->length());
969       break;
970     case SHARED_FUNCTION_INFO_TYPE:
971       accumulator->Add("<SharedFunctionInfo>");
972       break;
973 #define MAKE_STRUCT_CASE(NAME, Name, name) \
974   case NAME##_TYPE:                        \
975     accumulator->Put('<');                 \
976     accumulator->Add(#Name);               \
977     accumulator->Put('>');                 \
978     break;
979   STRUCT_LIST(MAKE_STRUCT_CASE)
980 #undef MAKE_STRUCT_CASE
981     case CODE_TYPE:
982       accumulator->Add("<Code>");
983       break;
984     case ODDBALL_TYPE: {
985       if (IsUndefined())
986         accumulator->Add("<undefined>");
987       else if (IsTheHole())
988         accumulator->Add("<the hole>");
989       else if (IsNull())
990         accumulator->Add("<null>");
991       else if (IsTrue())
992         accumulator->Add("<true>");
993       else if (IsFalse())
994         accumulator->Add("<false>");
995       else
996         accumulator->Add("<Odd Oddball>");
997       break;
998     }
999     case HEAP_NUMBER_TYPE:
1000       accumulator->Add("<Number: ");
1001       HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1002       accumulator->Put('>');
1003       break;
1004     case PROXY_TYPE:
1005       accumulator->Add("<Proxy>");
1006       break;
1007     case JS_GLOBAL_PROPERTY_CELL_TYPE:
1008       accumulator->Add("Cell for ");
1009       JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1010       break;
1011     default:
1012       accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1013       break;
1014   }
1015 }
1016 
1017 
SlowSizeFromMap(Map * map)1018 int HeapObject::SlowSizeFromMap(Map* map) {
1019   // Avoid calling functions such as FixedArray::cast during GC, which
1020   // read map pointer of this object again.
1021   InstanceType instance_type = map->instance_type();
1022   uint32_t type = static_cast<uint32_t>(instance_type);
1023 
1024   if (instance_type < FIRST_NONSTRING_TYPE
1025       && (StringShape(instance_type).IsSequential())) {
1026     if ((type & kStringEncodingMask) == kAsciiStringTag) {
1027       SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this);
1028       return seq_ascii_this->SeqAsciiStringSize(instance_type);
1029     } else {
1030       SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this);
1031       return self->SeqTwoByteStringSize(instance_type);
1032     }
1033   }
1034 
1035   switch (instance_type) {
1036     case FIXED_ARRAY_TYPE:
1037       return reinterpret_cast<FixedArray*>(this)->FixedArraySize();
1038     case BYTE_ARRAY_TYPE:
1039       return reinterpret_cast<ByteArray*>(this)->ByteArraySize();
1040     case CODE_TYPE:
1041       return reinterpret_cast<Code*>(this)->CodeSize();
1042     case MAP_TYPE:
1043       return Map::kSize;
1044     default:
1045       return map->instance_size();
1046   }
1047 }
1048 
1049 
Iterate(ObjectVisitor * v)1050 void HeapObject::Iterate(ObjectVisitor* v) {
1051   // Handle header
1052   IteratePointer(v, kMapOffset);
1053   // Handle object body
1054   Map* m = map();
1055   IterateBody(m->instance_type(), SizeFromMap(m), v);
1056 }
1057 
1058 
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)1059 void HeapObject::IterateBody(InstanceType type, int object_size,
1060                              ObjectVisitor* v) {
1061   // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1062   // During GC, the map pointer field is encoded.
1063   if (type < FIRST_NONSTRING_TYPE) {
1064     switch (type & kStringRepresentationMask) {
1065       case kSeqStringTag:
1066         break;
1067       case kConsStringTag:
1068         reinterpret_cast<ConsString*>(this)->ConsStringIterateBody(v);
1069         break;
1070       case kExternalStringTag:
1071         if ((type & kStringEncodingMask) == kAsciiStringTag) {
1072           reinterpret_cast<ExternalAsciiString*>(this)->
1073               ExternalAsciiStringIterateBody(v);
1074         } else {
1075           reinterpret_cast<ExternalTwoByteString*>(this)->
1076               ExternalTwoByteStringIterateBody(v);
1077         }
1078         break;
1079     }
1080     return;
1081   }
1082 
1083   switch (type) {
1084     case FIXED_ARRAY_TYPE:
1085       reinterpret_cast<FixedArray*>(this)->FixedArrayIterateBody(v);
1086       break;
1087     case JS_OBJECT_TYPE:
1088     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1089     case JS_VALUE_TYPE:
1090     case JS_ARRAY_TYPE:
1091     case JS_REGEXP_TYPE:
1092     case JS_FUNCTION_TYPE:
1093     case JS_GLOBAL_PROXY_TYPE:
1094     case JS_GLOBAL_OBJECT_TYPE:
1095     case JS_BUILTINS_OBJECT_TYPE:
1096       reinterpret_cast<JSObject*>(this)->JSObjectIterateBody(object_size, v);
1097       break;
1098     case ODDBALL_TYPE:
1099       reinterpret_cast<Oddball*>(this)->OddballIterateBody(v);
1100       break;
1101     case PROXY_TYPE:
1102       reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v);
1103       break;
1104     case MAP_TYPE:
1105       reinterpret_cast<Map*>(this)->MapIterateBody(v);
1106       break;
1107     case CODE_TYPE:
1108       reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1109       break;
1110     case JS_GLOBAL_PROPERTY_CELL_TYPE:
1111       reinterpret_cast<JSGlobalPropertyCell*>(this)
1112           ->JSGlobalPropertyCellIterateBody(v);
1113       break;
1114     case HEAP_NUMBER_TYPE:
1115     case FILLER_TYPE:
1116     case BYTE_ARRAY_TYPE:
1117     case PIXEL_ARRAY_TYPE:
1118     case EXTERNAL_BYTE_ARRAY_TYPE:
1119     case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1120     case EXTERNAL_SHORT_ARRAY_TYPE:
1121     case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1122     case EXTERNAL_INT_ARRAY_TYPE:
1123     case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1124     case EXTERNAL_FLOAT_ARRAY_TYPE:
1125       break;
1126     case SHARED_FUNCTION_INFO_TYPE: {
1127       SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
1128       shared->SharedFunctionInfoIterateBody(v);
1129       break;
1130     }
1131 #define MAKE_STRUCT_CASE(NAME, Name, name) \
1132         case NAME##_TYPE:
1133       STRUCT_LIST(MAKE_STRUCT_CASE)
1134 #undef MAKE_STRUCT_CASE
1135       IterateStructBody(object_size, v);
1136       break;
1137     default:
1138       PrintF("Unknown type: %d\n", type);
1139       UNREACHABLE();
1140   }
1141 }
1142 
1143 
IterateStructBody(int object_size,ObjectVisitor * v)1144 void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) {
1145   IteratePointers(v, HeapObject::kHeaderSize, object_size);
1146 }
1147 
1148 
HeapNumberToBoolean()1149 Object* HeapNumber::HeapNumberToBoolean() {
1150   // NaN, +0, and -0 should return the false object
1151   switch (fpclassify(value())) {
1152     case FP_NAN:  // fall through
1153     case FP_ZERO: return Heap::false_value();
1154     default: return Heap::true_value();
1155   }
1156 }
1157 
1158 
HeapNumberPrint()1159 void HeapNumber::HeapNumberPrint() {
1160   PrintF("%.16g", Number());
1161 }
1162 
1163 
HeapNumberPrint(StringStream * accumulator)1164 void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1165   // The Windows version of vsnprintf can allocate when printing a %g string
1166   // into a buffer that may not be big enough.  We don't want random memory
1167   // allocation when producing post-crash stack traces, so we print into a
1168   // buffer that is plenty big enough for any floating point number, then
1169   // print that using vsnprintf (which may truncate but never allocate if
1170   // there is no more space in the buffer).
1171   EmbeddedVector<char, 100> buffer;
1172   OS::SNPrintF(buffer, "%.16g", Number());
1173   accumulator->Add("%s", buffer.start());
1174 }
1175 
1176 
class_name()1177 String* JSObject::class_name() {
1178   if (IsJSFunction()) {
1179     return Heap::function_class_symbol();
1180   }
1181   if (map()->constructor()->IsJSFunction()) {
1182     JSFunction* constructor = JSFunction::cast(map()->constructor());
1183     return String::cast(constructor->shared()->instance_class_name());
1184   }
1185   // If the constructor is not present, return "Object".
1186   return Heap::Object_symbol();
1187 }
1188 
1189 
constructor_name()1190 String* JSObject::constructor_name() {
1191   if (IsJSFunction()) {
1192     return JSFunction::cast(this)->IsBoilerplate() ?
1193       Heap::function_class_symbol() : Heap::closure_symbol();
1194   }
1195   if (map()->constructor()->IsJSFunction()) {
1196     JSFunction* constructor = JSFunction::cast(map()->constructor());
1197     String* name = String::cast(constructor->shared()->name());
1198     return name->length() > 0 ? name : constructor->shared()->inferred_name();
1199   }
1200   // If the constructor is not present, return "Object".
1201   return Heap::Object_symbol();
1202 }
1203 
1204 
JSObjectIterateBody(int object_size,ObjectVisitor * v)1205 void JSObject::JSObjectIterateBody(int object_size, ObjectVisitor* v) {
1206   // Iterate over all fields in the body. Assumes all are Object*.
1207   IteratePointers(v, kPropertiesOffset, object_size);
1208 }
1209 
1210 
AddFastPropertyUsingMap(Map * new_map,String * name,Object * value)1211 Object* JSObject::AddFastPropertyUsingMap(Map* new_map,
1212                                           String* name,
1213                                           Object* value) {
1214   int index = new_map->PropertyIndexFor(name);
1215   if (map()->unused_property_fields() == 0) {
1216     ASSERT(map()->unused_property_fields() == 0);
1217     int new_unused = new_map->unused_property_fields();
1218     Object* values =
1219         properties()->CopySize(properties()->length() + new_unused + 1);
1220     if (values->IsFailure()) return values;
1221     set_properties(FixedArray::cast(values));
1222   }
1223   set_map(new_map);
1224   return FastPropertyAtPut(index, value);
1225 }
1226 
1227 
AddFastProperty(String * name,Object * value,PropertyAttributes attributes)1228 Object* JSObject::AddFastProperty(String* name,
1229                                   Object* value,
1230                                   PropertyAttributes attributes) {
1231   // Normalize the object if the name is an actual string (not the
1232   // hidden symbols) and is not a real identifier.
1233   StringInputBuffer buffer(name);
1234   if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) {
1235     Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1236     if (obj->IsFailure()) return obj;
1237     return AddSlowProperty(name, value, attributes);
1238   }
1239 
1240   DescriptorArray* old_descriptors = map()->instance_descriptors();
1241   // Compute the new index for new field.
1242   int index = map()->NextFreePropertyIndex();
1243 
1244   // Allocate new instance descriptors with (name, index) added
1245   FieldDescriptor new_field(name, index, attributes);
1246   Object* new_descriptors =
1247       old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1248   if (new_descriptors->IsFailure()) return new_descriptors;
1249 
1250   // Only allow map transition if the object's map is NOT equal to the
1251   // global object_function's map and there is not a transition for name.
1252   bool allow_map_transition =
1253         !old_descriptors->Contains(name) &&
1254         (Top::context()->global_context()->object_function()->map() != map());
1255 
1256   ASSERT(index < map()->inobject_properties() ||
1257          (index - map()->inobject_properties()) < properties()->length() ||
1258          map()->unused_property_fields() == 0);
1259   // Allocate a new map for the object.
1260   Object* r = map()->CopyDropDescriptors();
1261   if (r->IsFailure()) return r;
1262   Map* new_map = Map::cast(r);
1263   if (allow_map_transition) {
1264     // Allocate new instance descriptors for the old map with map transition.
1265     MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
1266     Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1267     if (r->IsFailure()) return r;
1268     old_descriptors = DescriptorArray::cast(r);
1269   }
1270 
1271   if (map()->unused_property_fields() == 0) {
1272     if (properties()->length() > kMaxFastProperties) {
1273       Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1274       if (obj->IsFailure()) return obj;
1275       return AddSlowProperty(name, value, attributes);
1276     }
1277     // Make room for the new value
1278     Object* values =
1279         properties()->CopySize(properties()->length() + kFieldsAdded);
1280     if (values->IsFailure()) return values;
1281     set_properties(FixedArray::cast(values));
1282     new_map->set_unused_property_fields(kFieldsAdded - 1);
1283   } else {
1284     new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1285   }
1286   // We have now allocated all the necessary objects.
1287   // All the changes can be applied at once, so they are atomic.
1288   map()->set_instance_descriptors(old_descriptors);
1289   new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1290   set_map(new_map);
1291   return FastPropertyAtPut(index, value);
1292 }
1293 
1294 
AddConstantFunctionProperty(String * name,JSFunction * function,PropertyAttributes attributes)1295 Object* JSObject::AddConstantFunctionProperty(String* name,
1296                                               JSFunction* function,
1297                                               PropertyAttributes attributes) {
1298   ASSERT(!Heap::InNewSpace(function));
1299 
1300   // Allocate new instance descriptors with (name, function) added
1301   ConstantFunctionDescriptor d(name, function, attributes);
1302   Object* new_descriptors =
1303       map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1304   if (new_descriptors->IsFailure()) return new_descriptors;
1305 
1306   // Allocate a new map for the object.
1307   Object* new_map = map()->CopyDropDescriptors();
1308   if (new_map->IsFailure()) return new_map;
1309 
1310   DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1311   Map::cast(new_map)->set_instance_descriptors(descriptors);
1312   Map* old_map = map();
1313   set_map(Map::cast(new_map));
1314 
1315   // If the old map is the global object map (from new Object()),
1316   // then transitions are not added to it, so we are done.
1317   if (old_map == Top::context()->global_context()->object_function()->map()) {
1318     return function;
1319   }
1320 
1321   // Do not add CONSTANT_TRANSITIONS to global objects
1322   if (IsGlobalObject()) {
1323     return function;
1324   }
1325 
1326   // Add a CONSTANT_TRANSITION descriptor to the old map,
1327   // so future assignments to this property on other objects
1328   // of the same type will create a normal field, not a constant function.
1329   // Don't do this for special properties, with non-trival attributes.
1330   if (attributes != NONE) {
1331     return function;
1332   }
1333   ConstTransitionDescriptor mark(name);
1334   new_descriptors =
1335       old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1336   if (new_descriptors->IsFailure()) {
1337     return function;  // We have accomplished the main goal, so return success.
1338   }
1339   old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1340 
1341   return function;
1342 }
1343 
1344 
1345 // Add property in slow mode
AddSlowProperty(String * name,Object * value,PropertyAttributes attributes)1346 Object* JSObject::AddSlowProperty(String* name,
1347                                   Object* value,
1348                                   PropertyAttributes attributes) {
1349   ASSERT(!HasFastProperties());
1350   StringDictionary* dict = property_dictionary();
1351   Object* store_value = value;
1352   if (IsGlobalObject()) {
1353     // In case name is an orphaned property reuse the cell.
1354     int entry = dict->FindEntry(name);
1355     if (entry != StringDictionary::kNotFound) {
1356       store_value = dict->ValueAt(entry);
1357       JSGlobalPropertyCell::cast(store_value)->set_value(value);
1358       // Assign an enumeration index to the property and update
1359       // SetNextEnumerationIndex.
1360       int index = dict->NextEnumerationIndex();
1361       PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1362       dict->SetNextEnumerationIndex(index + 1);
1363       dict->SetEntry(entry, name, store_value, details);
1364       return value;
1365     }
1366     store_value = Heap::AllocateJSGlobalPropertyCell(value);
1367     if (store_value->IsFailure()) return store_value;
1368     JSGlobalPropertyCell::cast(store_value)->set_value(value);
1369   }
1370   PropertyDetails details = PropertyDetails(attributes, NORMAL);
1371   Object* result = dict->Add(name, store_value, details);
1372   if (result->IsFailure()) return result;
1373   if (dict != result) set_properties(StringDictionary::cast(result));
1374   return value;
1375 }
1376 
1377 
AddProperty(String * name,Object * value,PropertyAttributes attributes)1378 Object* JSObject::AddProperty(String* name,
1379                               Object* value,
1380                               PropertyAttributes attributes) {
1381   ASSERT(!IsJSGlobalProxy());
1382   if (HasFastProperties()) {
1383     // Ensure the descriptor array does not get too big.
1384     if (map()->instance_descriptors()->number_of_descriptors() <
1385         DescriptorArray::kMaxNumberOfDescriptors) {
1386       if (value->IsJSFunction() && !Heap::InNewSpace(value)) {
1387         return AddConstantFunctionProperty(name,
1388                                            JSFunction::cast(value),
1389                                            attributes);
1390       } else {
1391         return AddFastProperty(name, value, attributes);
1392       }
1393     } else {
1394       // Normalize the object to prevent very large instance descriptors.
1395       // This eliminates unwanted N^2 allocation and lookup behavior.
1396       Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1397       if (obj->IsFailure()) return obj;
1398     }
1399   }
1400   return AddSlowProperty(name, value, attributes);
1401 }
1402 
1403 
SetPropertyPostInterceptor(String * name,Object * value,PropertyAttributes attributes)1404 Object* JSObject::SetPropertyPostInterceptor(String* name,
1405                                              Object* value,
1406                                              PropertyAttributes attributes) {
1407   // Check local property, ignore interceptor.
1408   LookupResult result;
1409   LocalLookupRealNamedProperty(name, &result);
1410   if (result.IsFound()) {
1411     // An existing property, a map transition or a null descriptor was
1412     // found.  Use set property to handle all these cases.
1413     return SetProperty(&result, name, value, attributes);
1414   }
1415   // Add a new real property.
1416   return AddProperty(name, value, attributes);
1417 }
1418 
1419 
ReplaceSlowProperty(String * name,Object * value,PropertyAttributes attributes)1420 Object* JSObject::ReplaceSlowProperty(String* name,
1421                                       Object* value,
1422                                       PropertyAttributes attributes) {
1423   StringDictionary* dictionary = property_dictionary();
1424   int old_index = dictionary->FindEntry(name);
1425   int new_enumeration_index = 0;  // 0 means "Use the next available index."
1426   if (old_index != -1) {
1427     // All calls to ReplaceSlowProperty have had all transitions removed.
1428     ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1429     new_enumeration_index = dictionary->DetailsAt(old_index).index();
1430   }
1431 
1432   PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1433   return SetNormalizedProperty(name, value, new_details);
1434 }
1435 
1436 
ConvertDescriptorToFieldAndMapTransition(String * name,Object * new_value,PropertyAttributes attributes)1437 Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
1438     String* name,
1439     Object* new_value,
1440     PropertyAttributes attributes) {
1441   Map* old_map = map();
1442   Object* result = ConvertDescriptorToField(name, new_value, attributes);
1443   if (result->IsFailure()) return result;
1444   // If we get to this point we have succeeded - do not return failure
1445   // after this point.  Later stuff is optional.
1446   if (!HasFastProperties()) {
1447     return result;
1448   }
1449   // Do not add transitions to the map of "new Object()".
1450   if (map() == Top::context()->global_context()->object_function()->map()) {
1451     return result;
1452   }
1453 
1454   MapTransitionDescriptor transition(name,
1455                                      map(),
1456                                      attributes);
1457   Object* new_descriptors =
1458       old_map->instance_descriptors()->
1459           CopyInsert(&transition, KEEP_TRANSITIONS);
1460   if (new_descriptors->IsFailure()) return result;  // Yes, return _result_.
1461   old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1462   return result;
1463 }
1464 
1465 
ConvertDescriptorToField(String * name,Object * new_value,PropertyAttributes attributes)1466 Object* JSObject::ConvertDescriptorToField(String* name,
1467                                            Object* new_value,
1468                                            PropertyAttributes attributes) {
1469   if (map()->unused_property_fields() == 0 &&
1470       properties()->length() > kMaxFastProperties) {
1471     Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1472     if (obj->IsFailure()) return obj;
1473     return ReplaceSlowProperty(name, new_value, attributes);
1474   }
1475 
1476   int index = map()->NextFreePropertyIndex();
1477   FieldDescriptor new_field(name, index, attributes);
1478   // Make a new DescriptorArray replacing an entry with FieldDescriptor.
1479   Object* descriptors_unchecked = map()->instance_descriptors()->
1480       CopyInsert(&new_field, REMOVE_TRANSITIONS);
1481   if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
1482   DescriptorArray* new_descriptors =
1483       DescriptorArray::cast(descriptors_unchecked);
1484 
1485   // Make a new map for the object.
1486   Object* new_map_unchecked = map()->CopyDropDescriptors();
1487   if (new_map_unchecked->IsFailure()) return new_map_unchecked;
1488   Map* new_map = Map::cast(new_map_unchecked);
1489   new_map->set_instance_descriptors(new_descriptors);
1490 
1491   // Make new properties array if necessary.
1492   FixedArray* new_properties = 0;  // Will always be NULL or a valid pointer.
1493   int new_unused_property_fields = map()->unused_property_fields() - 1;
1494   if (map()->unused_property_fields() == 0) {
1495      new_unused_property_fields = kFieldsAdded - 1;
1496      Object* new_properties_unchecked =
1497         properties()->CopySize(properties()->length() + kFieldsAdded);
1498     if (new_properties_unchecked->IsFailure()) return new_properties_unchecked;
1499     new_properties = FixedArray::cast(new_properties_unchecked);
1500   }
1501 
1502   // Update pointers to commit changes.
1503   // Object points to the new map.
1504   new_map->set_unused_property_fields(new_unused_property_fields);
1505   set_map(new_map);
1506   if (new_properties) {
1507     set_properties(FixedArray::cast(new_properties));
1508   }
1509   return FastPropertyAtPut(index, new_value);
1510 }
1511 
1512 
1513 
SetPropertyWithInterceptor(String * name,Object * value,PropertyAttributes attributes)1514 Object* JSObject::SetPropertyWithInterceptor(String* name,
1515                                              Object* value,
1516                                              PropertyAttributes attributes) {
1517   HandleScope scope;
1518   Handle<JSObject> this_handle(this);
1519   Handle<String> name_handle(name);
1520   Handle<Object> value_handle(value);
1521   Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1522   if (!interceptor->setter()->IsUndefined()) {
1523     LOG(ApiNamedPropertyAccess("interceptor-named-set", this, name));
1524     CustomArguments args(interceptor->data(), this, this);
1525     v8::AccessorInfo info(args.end());
1526     v8::NamedPropertySetter setter =
1527         v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1528     v8::Handle<v8::Value> result;
1529     {
1530       // Leaving JavaScript.
1531       VMState state(EXTERNAL);
1532       Handle<Object> value_unhole(value->IsTheHole() ?
1533                                   Heap::undefined_value() :
1534                                   value);
1535       result = setter(v8::Utils::ToLocal(name_handle),
1536                       v8::Utils::ToLocal(value_unhole),
1537                       info);
1538     }
1539     RETURN_IF_SCHEDULED_EXCEPTION();
1540     if (!result.IsEmpty()) return *value_handle;
1541   }
1542   Object* raw_result = this_handle->SetPropertyPostInterceptor(*name_handle,
1543                                                                *value_handle,
1544                                                                attributes);
1545   RETURN_IF_SCHEDULED_EXCEPTION();
1546   return raw_result;
1547 }
1548 
1549 
SetProperty(String * name,Object * value,PropertyAttributes attributes)1550 Object* JSObject::SetProperty(String* name,
1551                               Object* value,
1552                               PropertyAttributes attributes) {
1553   LookupResult result;
1554   LocalLookup(name, &result);
1555   return SetProperty(&result, name, value, attributes);
1556 }
1557 
1558 
SetPropertyWithCallback(Object * structure,String * name,Object * value,JSObject * holder)1559 Object* JSObject::SetPropertyWithCallback(Object* structure,
1560                                           String* name,
1561                                           Object* value,
1562                                           JSObject* holder) {
1563   HandleScope scope;
1564 
1565   // We should never get here to initialize a const with the hole
1566   // value since a const declaration would conflict with the setter.
1567   ASSERT(!value->IsTheHole());
1568   Handle<Object> value_handle(value);
1569 
1570   // To accommodate both the old and the new api we switch on the
1571   // data structure used to store the callbacks.  Eventually proxy
1572   // callbacks should be phased out.
1573   if (structure->IsProxy()) {
1574     AccessorDescriptor* callback =
1575         reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
1576     Object* obj = (callback->setter)(this,  value, callback->data);
1577     RETURN_IF_SCHEDULED_EXCEPTION();
1578     if (obj->IsFailure()) return obj;
1579     return *value_handle;
1580   }
1581 
1582   if (structure->IsAccessorInfo()) {
1583     // api style callbacks
1584     AccessorInfo* data = AccessorInfo::cast(structure);
1585     Object* call_obj = data->setter();
1586     v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1587     if (call_fun == NULL) return value;
1588     Handle<String> key(name);
1589     LOG(ApiNamedPropertyAccess("store", this, name));
1590     CustomArguments args(data->data(), this, JSObject::cast(holder));
1591     v8::AccessorInfo info(args.end());
1592     {
1593       // Leaving JavaScript.
1594       VMState state(EXTERNAL);
1595       call_fun(v8::Utils::ToLocal(key),
1596                v8::Utils::ToLocal(value_handle),
1597                info);
1598     }
1599     RETURN_IF_SCHEDULED_EXCEPTION();
1600     return *value_handle;
1601   }
1602 
1603   if (structure->IsFixedArray()) {
1604     Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1605     if (setter->IsJSFunction()) {
1606      return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
1607     } else {
1608       Handle<String> key(name);
1609       Handle<Object> holder_handle(holder);
1610       Handle<Object> args[2] = { key, holder_handle };
1611       return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
1612                                                HandleVector(args, 2)));
1613     }
1614   }
1615 
1616   UNREACHABLE();
1617   return 0;
1618 }
1619 
1620 
SetPropertyWithDefinedSetter(JSFunction * setter,Object * value)1621 Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1622                                                Object* value) {
1623   Handle<Object> value_handle(value);
1624   Handle<JSFunction> fun(JSFunction::cast(setter));
1625   Handle<JSObject> self(this);
1626 #ifdef ENABLE_DEBUGGER_SUPPORT
1627   // Handle stepping into a setter if step into is active.
1628   if (Debug::StepInActive()) {
1629     Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
1630   }
1631 #endif
1632   bool has_pending_exception;
1633   Object** argv[] = { value_handle.location() };
1634   Execution::Call(fun, self, 1, argv, &has_pending_exception);
1635   // Check for pending exception and return the result.
1636   if (has_pending_exception) return Failure::Exception();
1637   return *value_handle;
1638 }
1639 
1640 
LookupCallbackSetterInPrototypes(String * name,LookupResult * result)1641 void JSObject::LookupCallbackSetterInPrototypes(String* name,
1642                                                 LookupResult* result) {
1643   for (Object* pt = GetPrototype();
1644        pt != Heap::null_value();
1645        pt = pt->GetPrototype()) {
1646     JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
1647     if (result->IsProperty()) {
1648       if (result->IsReadOnly()) {
1649         result->NotFound();
1650         return;
1651       }
1652       if (result->type() == CALLBACKS) {
1653         return;
1654       }
1655     }
1656   }
1657   result->NotFound();
1658 }
1659 
1660 
LookupCallbackSetterInPrototypes(uint32_t index)1661 Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) {
1662   for (Object* pt = GetPrototype();
1663        pt != Heap::null_value();
1664        pt = pt->GetPrototype()) {
1665     if (!JSObject::cast(pt)->HasDictionaryElements()) {
1666         continue;
1667     }
1668     NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1669     int entry = dictionary->FindEntry(index);
1670     if (entry != NumberDictionary::kNotFound) {
1671       Object* element = dictionary->ValueAt(entry);
1672       PropertyDetails details = dictionary->DetailsAt(entry);
1673       if (details.type() == CALLBACKS) {
1674         // Only accessors allowed as elements.
1675         return FixedArray::cast(element)->get(kSetterIndex);
1676       }
1677     }
1678   }
1679   return Heap::undefined_value();
1680 }
1681 
1682 
LookupInDescriptor(String * name,LookupResult * result)1683 void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1684   DescriptorArray* descriptors = map()->instance_descriptors();
1685   int number = DescriptorLookupCache::Lookup(descriptors, name);
1686   if (number == DescriptorLookupCache::kAbsent) {
1687     number = descriptors->Search(name);
1688     DescriptorLookupCache::Update(descriptors, name, number);
1689   }
1690   if (number != DescriptorArray::kNotFound) {
1691     result->DescriptorResult(this, descriptors->GetDetails(number), number);
1692   } else {
1693     result->NotFound();
1694   }
1695 }
1696 
1697 
LocalLookupRealNamedProperty(String * name,LookupResult * result)1698 void JSObject::LocalLookupRealNamedProperty(String* name,
1699                                             LookupResult* result) {
1700   if (IsJSGlobalProxy()) {
1701     Object* proto = GetPrototype();
1702     if (proto->IsNull()) return result->NotFound();
1703     ASSERT(proto->IsJSGlobalObject());
1704     return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
1705   }
1706 
1707   if (HasFastProperties()) {
1708     LookupInDescriptor(name, result);
1709     if (result->IsFound()) {
1710       // A property, a map transition or a null descriptor was found.
1711       // We return all of these result types because
1712       // LocalLookupRealNamedProperty is used when setting properties
1713       // where map transitions and null descriptors are handled.
1714       ASSERT(result->holder() == this && result->type() != NORMAL);
1715       // Disallow caching for uninitialized constants. These can only
1716       // occur as fields.
1717       if (result->IsReadOnly() && result->type() == FIELD &&
1718           FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
1719         result->DisallowCaching();
1720       }
1721       return;
1722     }
1723   } else {
1724     int entry = property_dictionary()->FindEntry(name);
1725     if (entry != StringDictionary::kNotFound) {
1726       Object* value = property_dictionary()->ValueAt(entry);
1727       if (IsGlobalObject()) {
1728         PropertyDetails d = property_dictionary()->DetailsAt(entry);
1729         if (d.IsDeleted()) {
1730           result->NotFound();
1731           return;
1732         }
1733         value = JSGlobalPropertyCell::cast(value)->value();
1734       }
1735       // Make sure to disallow caching for uninitialized constants
1736       // found in the dictionary-mode objects.
1737       if (value->IsTheHole()) result->DisallowCaching();
1738       result->DictionaryResult(this, entry);
1739       return;
1740     }
1741     // Slow case object skipped during lookup. Do not use inline caching.
1742     if (!IsGlobalObject()) result->DisallowCaching();
1743   }
1744   result->NotFound();
1745 }
1746 
1747 
LookupRealNamedProperty(String * name,LookupResult * result)1748 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
1749   LocalLookupRealNamedProperty(name, result);
1750   if (result->IsProperty()) return;
1751 
1752   LookupRealNamedPropertyInPrototypes(name, result);
1753 }
1754 
1755 
LookupRealNamedPropertyInPrototypes(String * name,LookupResult * result)1756 void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
1757                                                    LookupResult* result) {
1758   for (Object* pt = GetPrototype();
1759        pt != Heap::null_value();
1760        pt = JSObject::cast(pt)->GetPrototype()) {
1761     JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
1762     if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
1763   }
1764   result->NotFound();
1765 }
1766 
1767 
1768 // We only need to deal with CALLBACKS and INTERCEPTORS
SetPropertyWithFailedAccessCheck(LookupResult * result,String * name,Object * value)1769 Object* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
1770                                                    String* name,
1771                                                    Object* value) {
1772   if (!result->IsProperty()) {
1773     LookupCallbackSetterInPrototypes(name, result);
1774   }
1775 
1776   if (result->IsProperty()) {
1777     if (!result->IsReadOnly()) {
1778       switch (result->type()) {
1779         case CALLBACKS: {
1780           Object* obj = result->GetCallbackObject();
1781           if (obj->IsAccessorInfo()) {
1782             AccessorInfo* info = AccessorInfo::cast(obj);
1783             if (info->all_can_write()) {
1784               return SetPropertyWithCallback(result->GetCallbackObject(),
1785                                              name,
1786                                              value,
1787                                              result->holder());
1788             }
1789           }
1790           break;
1791         }
1792         case INTERCEPTOR: {
1793           // Try lookup real named properties. Note that only property can be
1794           // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
1795           LookupResult r;
1796           LookupRealNamedProperty(name, &r);
1797           if (r.IsProperty()) {
1798             return SetPropertyWithFailedAccessCheck(&r, name, value);
1799           }
1800           break;
1801         }
1802         default: {
1803           break;
1804         }
1805       }
1806     }
1807   }
1808 
1809   Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
1810   return value;
1811 }
1812 
1813 
SetProperty(LookupResult * result,String * name,Object * value,PropertyAttributes attributes)1814 Object* JSObject::SetProperty(LookupResult* result,
1815                               String* name,
1816                               Object* value,
1817                               PropertyAttributes attributes) {
1818   // Make sure that the top context does not change when doing callbacks or
1819   // interceptor calls.
1820   AssertNoContextChange ncc;
1821 
1822   // Optimization for 2-byte strings often used as keys in a decompression
1823   // dictionary.  We make these short keys into symbols to avoid constantly
1824   // reallocating them.
1825   if (!name->IsSymbol() && name->length() <= 2) {
1826     Object* symbol_version = Heap::LookupSymbol(name);
1827     if (!symbol_version->IsFailure()) name = String::cast(symbol_version);
1828   }
1829 
1830   // Check access rights if needed.
1831   if (IsAccessCheckNeeded()
1832       && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
1833     return SetPropertyWithFailedAccessCheck(result, name, value);
1834   }
1835 
1836   if (IsJSGlobalProxy()) {
1837     Object* proto = GetPrototype();
1838     if (proto->IsNull()) return value;
1839     ASSERT(proto->IsJSGlobalObject());
1840     return JSObject::cast(proto)->SetProperty(result, name, value, attributes);
1841   }
1842 
1843   if (!result->IsProperty() && !IsJSContextExtensionObject()) {
1844     // We could not find a local property so let's check whether there is an
1845     // accessor that wants to handle the property.
1846     LookupResult accessor_result;
1847     LookupCallbackSetterInPrototypes(name, &accessor_result);
1848     if (accessor_result.IsProperty()) {
1849       return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
1850                                      name,
1851                                      value,
1852                                      accessor_result.holder());
1853     }
1854   }
1855   if (!result->IsFound()) {
1856     // Neither properties nor transitions found.
1857     return AddProperty(name, value, attributes);
1858   }
1859   if (result->IsReadOnly() && result->IsProperty()) return value;
1860   // This is a real property that is not read-only, or it is a
1861   // transition or null descriptor and there are no setters in the prototypes.
1862   switch (result->type()) {
1863     case NORMAL:
1864       return SetNormalizedProperty(result, value);
1865     case FIELD:
1866       return FastPropertyAtPut(result->GetFieldIndex(), value);
1867     case MAP_TRANSITION:
1868       if (attributes == result->GetAttributes()) {
1869         // Only use map transition if the attributes match.
1870         return AddFastPropertyUsingMap(result->GetTransitionMap(),
1871                                        name,
1872                                        value);
1873       }
1874       return ConvertDescriptorToField(name, value, attributes);
1875     case CONSTANT_FUNCTION:
1876       // Only replace the function if necessary.
1877       if (value == result->GetConstantFunction()) return value;
1878       // Preserve the attributes of this existing property.
1879       attributes = result->GetAttributes();
1880       return ConvertDescriptorToField(name, value, attributes);
1881     case CALLBACKS:
1882       return SetPropertyWithCallback(result->GetCallbackObject(),
1883                                      name,
1884                                      value,
1885                                      result->holder());
1886     case INTERCEPTOR:
1887       return SetPropertyWithInterceptor(name, value, attributes);
1888     case CONSTANT_TRANSITION:
1889       // Replace with a MAP_TRANSITION to a new map with a FIELD, even
1890       // if the value is a function.
1891       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
1892     case NULL_DESCRIPTOR:
1893       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
1894     default:
1895       UNREACHABLE();
1896   }
1897   UNREACHABLE();
1898   return value;
1899 }
1900 
1901 
1902 // Set a real local property, even if it is READ_ONLY.  If the property is not
1903 // present, add it with attributes NONE.  This code is an exact clone of
1904 // SetProperty, with the check for IsReadOnly and the check for a
1905 // callback setter removed.  The two lines looking up the LookupResult
1906 // result are also added.  If one of the functions is changed, the other
1907 // should be.
IgnoreAttributesAndSetLocalProperty(String * name,Object * value,PropertyAttributes attributes)1908 Object* JSObject::IgnoreAttributesAndSetLocalProperty(
1909     String* name,
1910     Object* value,
1911     PropertyAttributes attributes) {
1912   // Make sure that the top context does not change when doing callbacks or
1913   // interceptor calls.
1914   AssertNoContextChange ncc;
1915   LookupResult result;
1916   LocalLookup(name, &result);
1917   // Check access rights if needed.
1918   if (IsAccessCheckNeeded()
1919       && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
1920     return SetPropertyWithFailedAccessCheck(&result, name, value);
1921   }
1922 
1923   if (IsJSGlobalProxy()) {
1924     Object* proto = GetPrototype();
1925     if (proto->IsNull()) return value;
1926     ASSERT(proto->IsJSGlobalObject());
1927     return JSObject::cast(proto)->IgnoreAttributesAndSetLocalProperty(
1928         name,
1929         value,
1930         attributes);
1931   }
1932 
1933   // Check for accessor in prototype chain removed here in clone.
1934   if (!result.IsFound()) {
1935     // Neither properties nor transitions found.
1936     return AddProperty(name, value, attributes);
1937   }
1938   PropertyDetails details = PropertyDetails(attributes, NORMAL);
1939 
1940   // Check of IsReadOnly removed from here in clone.
1941   switch (result.type()) {
1942     case NORMAL:
1943       return SetNormalizedProperty(name, value, details);
1944     case FIELD:
1945       return FastPropertyAtPut(result.GetFieldIndex(), value);
1946     case MAP_TRANSITION:
1947       if (attributes == result.GetAttributes()) {
1948         // Only use map transition if the attributes match.
1949         return AddFastPropertyUsingMap(result.GetTransitionMap(),
1950                                        name,
1951                                        value);
1952       }
1953       return ConvertDescriptorToField(name, value, attributes);
1954     case CONSTANT_FUNCTION:
1955       // Only replace the function if necessary.
1956       if (value == result.GetConstantFunction()) return value;
1957       // Preserve the attributes of this existing property.
1958       attributes = result.GetAttributes();
1959       return ConvertDescriptorToField(name, value, attributes);
1960     case CALLBACKS:
1961     case INTERCEPTOR:
1962       // Override callback in clone
1963       return ConvertDescriptorToField(name, value, attributes);
1964     case CONSTANT_TRANSITION:
1965       // Replace with a MAP_TRANSITION to a new map with a FIELD, even
1966       // if the value is a function.
1967       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
1968     case NULL_DESCRIPTOR:
1969       return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
1970     default:
1971       UNREACHABLE();
1972   }
1973   UNREACHABLE();
1974   return value;
1975 }
1976 
1977 
GetPropertyAttributePostInterceptor(JSObject * receiver,String * name,bool continue_search)1978 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
1979       JSObject* receiver,
1980       String* name,
1981       bool continue_search) {
1982   // Check local property, ignore interceptor.
1983   LookupResult result;
1984   LocalLookupRealNamedProperty(name, &result);
1985   if (result.IsProperty()) return result.GetAttributes();
1986 
1987   if (continue_search) {
1988     // Continue searching via the prototype chain.
1989     Object* pt = GetPrototype();
1990     if (pt != Heap::null_value()) {
1991       return JSObject::cast(pt)->
1992         GetPropertyAttributeWithReceiver(receiver, name);
1993     }
1994   }
1995   return ABSENT;
1996 }
1997 
1998 
GetPropertyAttributeWithInterceptor(JSObject * receiver,String * name,bool continue_search)1999 PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2000       JSObject* receiver,
2001       String* name,
2002       bool continue_search) {
2003   // Make sure that the top context does not change when doing
2004   // callbacks or interceptor calls.
2005   AssertNoContextChange ncc;
2006 
2007   HandleScope scope;
2008   Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2009   Handle<JSObject> receiver_handle(receiver);
2010   Handle<JSObject> holder_handle(this);
2011   Handle<String> name_handle(name);
2012   CustomArguments args(interceptor->data(), receiver, this);
2013   v8::AccessorInfo info(args.end());
2014   if (!interceptor->query()->IsUndefined()) {
2015     v8::NamedPropertyQuery query =
2016         v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
2017     LOG(ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
2018     v8::Handle<v8::Boolean> result;
2019     {
2020       // Leaving JavaScript.
2021       VMState state(EXTERNAL);
2022       result = query(v8::Utils::ToLocal(name_handle), info);
2023     }
2024     if (!result.IsEmpty()) {
2025       // Convert the boolean result to a property attribute
2026       // specification.
2027       return result->IsTrue() ? NONE : ABSENT;
2028     }
2029   } else if (!interceptor->getter()->IsUndefined()) {
2030     v8::NamedPropertyGetter getter =
2031         v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
2032     LOG(ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
2033     v8::Handle<v8::Value> result;
2034     {
2035       // Leaving JavaScript.
2036       VMState state(EXTERNAL);
2037       result = getter(v8::Utils::ToLocal(name_handle), info);
2038     }
2039     if (!result.IsEmpty()) return NONE;
2040   }
2041   return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2042                                                             *name_handle,
2043                                                             continue_search);
2044 }
2045 
2046 
GetPropertyAttributeWithReceiver(JSObject * receiver,String * key)2047 PropertyAttributes JSObject::GetPropertyAttributeWithReceiver(
2048       JSObject* receiver,
2049       String* key) {
2050   uint32_t index = 0;
2051   if (key->AsArrayIndex(&index)) {
2052     if (HasElementWithReceiver(receiver, index)) return NONE;
2053     return ABSENT;
2054   }
2055   // Named property.
2056   LookupResult result;
2057   Lookup(key, &result);
2058   return GetPropertyAttribute(receiver, &result, key, true);
2059 }
2060 
2061 
GetPropertyAttribute(JSObject * receiver,LookupResult * result,String * name,bool continue_search)2062 PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
2063                                                   LookupResult* result,
2064                                                   String* name,
2065                                                   bool continue_search) {
2066   // Check access rights if needed.
2067   if (IsAccessCheckNeeded() &&
2068       !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
2069     return GetPropertyAttributeWithFailedAccessCheck(receiver,
2070                                                      result,
2071                                                      name,
2072                                                      continue_search);
2073   }
2074   if (result->IsProperty()) {
2075     switch (result->type()) {
2076       case NORMAL:  // fall through
2077       case FIELD:
2078       case CONSTANT_FUNCTION:
2079       case CALLBACKS:
2080         return result->GetAttributes();
2081       case INTERCEPTOR:
2082         return result->holder()->
2083           GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
2084       default:
2085         UNREACHABLE();
2086     }
2087   }
2088   return ABSENT;
2089 }
2090 
2091 
GetLocalPropertyAttribute(String * name)2092 PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
2093   // Check whether the name is an array index.
2094   uint32_t index = 0;
2095   if (name->AsArrayIndex(&index)) {
2096     if (HasLocalElement(index)) return NONE;
2097     return ABSENT;
2098   }
2099   // Named property.
2100   LookupResult result;
2101   LocalLookup(name, &result);
2102   return GetPropertyAttribute(this, &result, name, false);
2103 }
2104 
2105 
NormalizeProperties(PropertyNormalizationMode mode,int expected_additional_properties)2106 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2107                                       int expected_additional_properties) {
2108   if (!HasFastProperties()) return this;
2109 
2110   // The global object is always normalized.
2111   ASSERT(!IsGlobalObject());
2112 
2113   // Allocate new content.
2114   int property_count = map()->NumberOfDescribedProperties();
2115   if (expected_additional_properties > 0) {
2116     property_count += expected_additional_properties;
2117   } else {
2118     property_count += 2;  // Make space for two more properties.
2119   }
2120   Object* obj =
2121       StringDictionary::Allocate(property_count * 2);
2122   if (obj->IsFailure()) return obj;
2123   StringDictionary* dictionary = StringDictionary::cast(obj);
2124 
2125   DescriptorArray* descs = map()->instance_descriptors();
2126   for (int i = 0; i < descs->number_of_descriptors(); i++) {
2127     PropertyDetails details = descs->GetDetails(i);
2128     switch (details.type()) {
2129       case CONSTANT_FUNCTION: {
2130         PropertyDetails d =
2131             PropertyDetails(details.attributes(), NORMAL, details.index());
2132         Object* value = descs->GetConstantFunction(i);
2133         Object* result = dictionary->Add(descs->GetKey(i), value, d);
2134         if (result->IsFailure()) return result;
2135         dictionary = StringDictionary::cast(result);
2136         break;
2137       }
2138       case FIELD: {
2139         PropertyDetails d =
2140             PropertyDetails(details.attributes(), NORMAL, details.index());
2141         Object* value = FastPropertyAt(descs->GetFieldIndex(i));
2142         Object* result = dictionary->Add(descs->GetKey(i), value, d);
2143         if (result->IsFailure()) return result;
2144         dictionary = StringDictionary::cast(result);
2145         break;
2146       }
2147       case CALLBACKS: {
2148         PropertyDetails d =
2149             PropertyDetails(details.attributes(), CALLBACKS, details.index());
2150         Object* value = descs->GetCallbacksObject(i);
2151         Object* result = dictionary->Add(descs->GetKey(i), value, d);
2152         if (result->IsFailure()) return result;
2153         dictionary = StringDictionary::cast(result);
2154         break;
2155       }
2156       case MAP_TRANSITION:
2157       case CONSTANT_TRANSITION:
2158       case NULL_DESCRIPTOR:
2159       case INTERCEPTOR:
2160         break;
2161       default:
2162         UNREACHABLE();
2163     }
2164   }
2165 
2166   // Copy the next enumeration index from instance descriptor.
2167   int index = map()->instance_descriptors()->NextEnumerationIndex();
2168   dictionary->SetNextEnumerationIndex(index);
2169 
2170   // Allocate new map.
2171   obj = map()->CopyDropDescriptors();
2172   if (obj->IsFailure()) return obj;
2173   Map* new_map = Map::cast(obj);
2174 
2175   // Clear inobject properties if needed by adjusting the instance size and
2176   // putting in a filler object instead of the inobject properties.
2177   if (mode == CLEAR_INOBJECT_PROPERTIES && map()->inobject_properties() > 0) {
2178     int instance_size_delta = map()->inobject_properties() * kPointerSize;
2179     int new_instance_size = map()->instance_size() - instance_size_delta;
2180     new_map->set_inobject_properties(0);
2181     new_map->set_instance_size(new_instance_size);
2182     Heap::CreateFillerObjectAt(this->address() + new_instance_size,
2183                                instance_size_delta);
2184   }
2185   new_map->set_unused_property_fields(0);
2186 
2187   // We have now successfully allocated all the necessary objects.
2188   // Changes can now be made with the guarantee that all of them take effect.
2189   set_map(new_map);
2190   map()->set_instance_descriptors(Heap::empty_descriptor_array());
2191 
2192   set_properties(dictionary);
2193 
2194   Counters::props_to_dictionary.Increment();
2195 
2196 #ifdef DEBUG
2197   if (FLAG_trace_normalization) {
2198     PrintF("Object properties have been normalized:\n");
2199     Print();
2200   }
2201 #endif
2202   return this;
2203 }
2204 
2205 
TransformToFastProperties(int unused_property_fields)2206 Object* JSObject::TransformToFastProperties(int unused_property_fields) {
2207   if (HasFastProperties()) return this;
2208   ASSERT(!IsGlobalObject());
2209   return property_dictionary()->
2210       TransformPropertiesToFastFor(this, unused_property_fields);
2211 }
2212 
2213 
NormalizeElements()2214 Object* JSObject::NormalizeElements() {
2215   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
2216   if (HasDictionaryElements()) return this;
2217 
2218   // Get number of entries.
2219   FixedArray* array = FixedArray::cast(elements());
2220 
2221   // Compute the effective length.
2222   int length = IsJSArray() ?
2223                Smi::cast(JSArray::cast(this)->length())->value() :
2224                array->length();
2225   Object* obj = NumberDictionary::Allocate(length);
2226   if (obj->IsFailure()) return obj;
2227   NumberDictionary* dictionary = NumberDictionary::cast(obj);
2228   // Copy entries.
2229   for (int i = 0; i < length; i++) {
2230     Object* value = array->get(i);
2231     if (!value->IsTheHole()) {
2232       PropertyDetails details = PropertyDetails(NONE, NORMAL);
2233       Object* result = dictionary->AddNumberEntry(i, array->get(i), details);
2234       if (result->IsFailure()) return result;
2235       dictionary = NumberDictionary::cast(result);
2236     }
2237   }
2238   // Switch to using the dictionary as the backing storage for elements.
2239   set_elements(dictionary);
2240 
2241   Counters::elements_to_dictionary.Increment();
2242 
2243 #ifdef DEBUG
2244   if (FLAG_trace_normalization) {
2245     PrintF("Object elements have been normalized:\n");
2246     Print();
2247   }
2248 #endif
2249 
2250   return this;
2251 }
2252 
2253 
DeletePropertyPostInterceptor(String * name,DeleteMode mode)2254 Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) {
2255   // Check local property, ignore interceptor.
2256   LookupResult result;
2257   LocalLookupRealNamedProperty(name, &result);
2258   if (!result.IsProperty()) return Heap::true_value();
2259 
2260   // Normalize object if needed.
2261   Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2262   if (obj->IsFailure()) return obj;
2263 
2264   return DeleteNormalizedProperty(name, mode);
2265 }
2266 
2267 
DeletePropertyWithInterceptor(String * name)2268 Object* JSObject::DeletePropertyWithInterceptor(String* name) {
2269   HandleScope scope;
2270   Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2271   Handle<String> name_handle(name);
2272   Handle<JSObject> this_handle(this);
2273   if (!interceptor->deleter()->IsUndefined()) {
2274     v8::NamedPropertyDeleter deleter =
2275         v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
2276     LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
2277     CustomArguments args(interceptor->data(), this, this);
2278     v8::AccessorInfo info(args.end());
2279     v8::Handle<v8::Boolean> result;
2280     {
2281       // Leaving JavaScript.
2282       VMState state(EXTERNAL);
2283       result = deleter(v8::Utils::ToLocal(name_handle), info);
2284     }
2285     RETURN_IF_SCHEDULED_EXCEPTION();
2286     if (!result.IsEmpty()) {
2287       ASSERT(result->IsBoolean());
2288       return *v8::Utils::OpenHandle(*result);
2289     }
2290   }
2291   Object* raw_result =
2292       this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
2293   RETURN_IF_SCHEDULED_EXCEPTION();
2294   return raw_result;
2295 }
2296 
2297 
DeleteElementPostInterceptor(uint32_t index,DeleteMode mode)2298 Object* JSObject::DeleteElementPostInterceptor(uint32_t index,
2299                                                DeleteMode mode) {
2300   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
2301   switch (GetElementsKind()) {
2302     case FAST_ELEMENTS: {
2303       uint32_t length = IsJSArray() ?
2304       static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2305       static_cast<uint32_t>(FixedArray::cast(elements())->length());
2306       if (index < length) {
2307         FixedArray::cast(elements())->set_the_hole(index);
2308       }
2309       break;
2310     }
2311     case DICTIONARY_ELEMENTS: {
2312       NumberDictionary* dictionary = element_dictionary();
2313       int entry = dictionary->FindEntry(index);
2314       if (entry != NumberDictionary::kNotFound) {
2315         return dictionary->DeleteProperty(entry, mode);
2316       }
2317       break;
2318     }
2319     default:
2320       UNREACHABLE();
2321       break;
2322   }
2323   return Heap::true_value();
2324 }
2325 
2326 
DeleteElementWithInterceptor(uint32_t index)2327 Object* JSObject::DeleteElementWithInterceptor(uint32_t index) {
2328   // Make sure that the top context does not change when doing
2329   // callbacks or interceptor calls.
2330   AssertNoContextChange ncc;
2331   HandleScope scope;
2332   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
2333   if (interceptor->deleter()->IsUndefined()) return Heap::false_value();
2334   v8::IndexedPropertyDeleter deleter =
2335       v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
2336   Handle<JSObject> this_handle(this);
2337   LOG(ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
2338   CustomArguments args(interceptor->data(), this, this);
2339   v8::AccessorInfo info(args.end());
2340   v8::Handle<v8::Boolean> result;
2341   {
2342     // Leaving JavaScript.
2343     VMState state(EXTERNAL);
2344     result = deleter(index, info);
2345   }
2346   RETURN_IF_SCHEDULED_EXCEPTION();
2347   if (!result.IsEmpty()) {
2348     ASSERT(result->IsBoolean());
2349     return *v8::Utils::OpenHandle(*result);
2350   }
2351   Object* raw_result =
2352       this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
2353   RETURN_IF_SCHEDULED_EXCEPTION();
2354   return raw_result;
2355 }
2356 
2357 
DeleteElement(uint32_t index,DeleteMode mode)2358 Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
2359   // Check access rights if needed.
2360   if (IsAccessCheckNeeded() &&
2361       !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
2362     Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2363     return Heap::false_value();
2364   }
2365 
2366   if (IsJSGlobalProxy()) {
2367     Object* proto = GetPrototype();
2368     if (proto->IsNull()) return Heap::false_value();
2369     ASSERT(proto->IsJSGlobalObject());
2370     return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
2371   }
2372 
2373   if (HasIndexedInterceptor()) {
2374     // Skip interceptor if forcing deletion.
2375     if (mode == FORCE_DELETION) {
2376       return DeleteElementPostInterceptor(index, mode);
2377     }
2378     return DeleteElementWithInterceptor(index);
2379   }
2380 
2381   switch (GetElementsKind()) {
2382     case FAST_ELEMENTS: {
2383       uint32_t length = IsJSArray() ?
2384       static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2385       static_cast<uint32_t>(FixedArray::cast(elements())->length());
2386       if (index < length) {
2387         FixedArray::cast(elements())->set_the_hole(index);
2388       }
2389       break;
2390     }
2391     case PIXEL_ELEMENTS:
2392     case EXTERNAL_BYTE_ELEMENTS:
2393     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2394     case EXTERNAL_SHORT_ELEMENTS:
2395     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2396     case EXTERNAL_INT_ELEMENTS:
2397     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2398     case EXTERNAL_FLOAT_ELEMENTS:
2399       // Pixel and external array elements cannot be deleted. Just
2400       // silently ignore here.
2401       break;
2402     case DICTIONARY_ELEMENTS: {
2403       NumberDictionary* dictionary = element_dictionary();
2404       int entry = dictionary->FindEntry(index);
2405       if (entry != NumberDictionary::kNotFound) {
2406         return dictionary->DeleteProperty(entry, mode);
2407       }
2408       break;
2409     }
2410     default:
2411       UNREACHABLE();
2412       break;
2413   }
2414   return Heap::true_value();
2415 }
2416 
2417 
DeleteProperty(String * name,DeleteMode mode)2418 Object* JSObject::DeleteProperty(String* name, DeleteMode mode) {
2419   // ECMA-262, 3rd, 8.6.2.5
2420   ASSERT(name->IsString());
2421 
2422   // Check access rights if needed.
2423   if (IsAccessCheckNeeded() &&
2424       !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
2425     Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2426     return Heap::false_value();
2427   }
2428 
2429   if (IsJSGlobalProxy()) {
2430     Object* proto = GetPrototype();
2431     if (proto->IsNull()) return Heap::false_value();
2432     ASSERT(proto->IsJSGlobalObject());
2433     return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
2434   }
2435 
2436   uint32_t index = 0;
2437   if (name->AsArrayIndex(&index)) {
2438     return DeleteElement(index, mode);
2439   } else {
2440     LookupResult result;
2441     LocalLookup(name, &result);
2442     if (!result.IsProperty()) return Heap::true_value();
2443     // Ignore attributes if forcing a deletion.
2444     if (result.IsDontDelete() && mode != FORCE_DELETION) {
2445       return Heap::false_value();
2446     }
2447     // Check for interceptor.
2448     if (result.type() == INTERCEPTOR) {
2449       // Skip interceptor if forcing a deletion.
2450       if (mode == FORCE_DELETION) {
2451         return DeletePropertyPostInterceptor(name, mode);
2452       }
2453       return DeletePropertyWithInterceptor(name);
2454     }
2455     // Normalize object if needed.
2456     Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2457     if (obj->IsFailure()) return obj;
2458     // Make sure the properties are normalized before removing the entry.
2459     return DeleteNormalizedProperty(name, mode);
2460   }
2461 }
2462 
2463 
2464 // Check whether this object references another object.
ReferencesObject(Object * obj)2465 bool JSObject::ReferencesObject(Object* obj) {
2466   AssertNoAllocation no_alloc;
2467 
2468   // Is the object the constructor for this object?
2469   if (map()->constructor() == obj) {
2470     return true;
2471   }
2472 
2473   // Is the object the prototype for this object?
2474   if (map()->prototype() == obj) {
2475     return true;
2476   }
2477 
2478   // Check if the object is among the named properties.
2479   Object* key = SlowReverseLookup(obj);
2480   if (key != Heap::undefined_value()) {
2481     return true;
2482   }
2483 
2484   // Check if the object is among the indexed properties.
2485   switch (GetElementsKind()) {
2486     case PIXEL_ELEMENTS:
2487     case EXTERNAL_BYTE_ELEMENTS:
2488     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2489     case EXTERNAL_SHORT_ELEMENTS:
2490     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2491     case EXTERNAL_INT_ELEMENTS:
2492     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2493     case EXTERNAL_FLOAT_ELEMENTS:
2494       // Raw pixels and external arrays do not reference other
2495       // objects.
2496       break;
2497     case FAST_ELEMENTS: {
2498       int length = IsJSArray() ?
2499           Smi::cast(JSArray::cast(this)->length())->value() :
2500           FixedArray::cast(elements())->length();
2501       for (int i = 0; i < length; i++) {
2502         Object* element = FixedArray::cast(elements())->get(i);
2503         if (!element->IsTheHole() && element == obj) {
2504           return true;
2505         }
2506       }
2507       break;
2508     }
2509     case DICTIONARY_ELEMENTS: {
2510       key = element_dictionary()->SlowReverseLookup(obj);
2511       if (key != Heap::undefined_value()) {
2512         return true;
2513       }
2514       break;
2515     }
2516     default:
2517       UNREACHABLE();
2518       break;
2519   }
2520 
2521   // For functions check the context. Boilerplate functions do
2522   // not have to be traversed since they have no real context.
2523   if (IsJSFunction() && !JSFunction::cast(this)->IsBoilerplate()) {
2524     // Get the constructor function for arguments array.
2525     JSObject* arguments_boilerplate =
2526         Top::context()->global_context()->arguments_boilerplate();
2527     JSFunction* arguments_function =
2528         JSFunction::cast(arguments_boilerplate->map()->constructor());
2529 
2530     // Get the context and don't check if it is the global context.
2531     JSFunction* f = JSFunction::cast(this);
2532     Context* context = f->context();
2533     if (context->IsGlobalContext()) {
2534       return false;
2535     }
2536 
2537     // Check the non-special context slots.
2538     for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
2539       // Only check JS objects.
2540       if (context->get(i)->IsJSObject()) {
2541         JSObject* ctxobj = JSObject::cast(context->get(i));
2542         // If it is an arguments array check the content.
2543         if (ctxobj->map()->constructor() == arguments_function) {
2544           if (ctxobj->ReferencesObject(obj)) {
2545             return true;
2546           }
2547         } else if (ctxobj == obj) {
2548           return true;
2549         }
2550       }
2551     }
2552 
2553     // Check the context extension if any.
2554     if (context->has_extension()) {
2555       return context->extension()->ReferencesObject(obj);
2556     }
2557   }
2558 
2559   // No references to object.
2560   return false;
2561 }
2562 
2563 
2564 // Tests for the fast common case for property enumeration:
2565 // - This object and all prototypes has an enum cache (which means that it has
2566 //   no interceptors and needs no access checks).
2567 // - This object has no elements.
2568 // - No prototype has enumerable properties/elements.
IsSimpleEnum()2569 bool JSObject::IsSimpleEnum() {
2570   for (Object* o = this;
2571        o != Heap::null_value();
2572        o = JSObject::cast(o)->GetPrototype()) {
2573     JSObject* curr = JSObject::cast(o);
2574     if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
2575     ASSERT(!curr->HasNamedInterceptor());
2576     ASSERT(!curr->HasIndexedInterceptor());
2577     ASSERT(!curr->IsAccessCheckNeeded());
2578     if (curr->NumberOfEnumElements() > 0) return false;
2579     if (curr != this) {
2580       FixedArray* curr_fixed_array =
2581           FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
2582       if (curr_fixed_array->length() > 0) return false;
2583     }
2584   }
2585   return true;
2586 }
2587 
2588 
NumberOfDescribedProperties()2589 int Map::NumberOfDescribedProperties() {
2590   int result = 0;
2591   DescriptorArray* descs = instance_descriptors();
2592   for (int i = 0; i < descs->number_of_descriptors(); i++) {
2593     if (descs->IsProperty(i)) result++;
2594   }
2595   return result;
2596 }
2597 
2598 
PropertyIndexFor(String * name)2599 int Map::PropertyIndexFor(String* name) {
2600   DescriptorArray* descs = instance_descriptors();
2601   for (int i = 0; i < descs->number_of_descriptors(); i++) {
2602     if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
2603       return descs->GetFieldIndex(i);
2604     }
2605   }
2606   return -1;
2607 }
2608 
2609 
NextFreePropertyIndex()2610 int Map::NextFreePropertyIndex() {
2611   int max_index = -1;
2612   DescriptorArray* descs = instance_descriptors();
2613   for (int i = 0; i < descs->number_of_descriptors(); i++) {
2614     if (descs->GetType(i) == FIELD) {
2615       int current_index = descs->GetFieldIndex(i);
2616       if (current_index > max_index) max_index = current_index;
2617     }
2618   }
2619   return max_index + 1;
2620 }
2621 
2622 
FindAccessor(String * name)2623 AccessorDescriptor* Map::FindAccessor(String* name) {
2624   DescriptorArray* descs = instance_descriptors();
2625   for (int i = 0; i < descs->number_of_descriptors(); i++) {
2626     if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
2627       return descs->GetCallbacks(i);
2628     }
2629   }
2630   return NULL;
2631 }
2632 
2633 
LocalLookup(String * name,LookupResult * result)2634 void JSObject::LocalLookup(String* name, LookupResult* result) {
2635   ASSERT(name->IsString());
2636 
2637   if (IsJSGlobalProxy()) {
2638     Object* proto = GetPrototype();
2639     if (proto->IsNull()) return result->NotFound();
2640     ASSERT(proto->IsJSGlobalObject());
2641     return JSObject::cast(proto)->LocalLookup(name, result);
2642   }
2643 
2644   // Do not use inline caching if the object is a non-global object
2645   // that requires access checks.
2646   if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
2647     result->DisallowCaching();
2648   }
2649 
2650   // Check __proto__ before interceptor.
2651   if (name->Equals(Heap::Proto_symbol()) && !IsJSContextExtensionObject()) {
2652     result->ConstantResult(this);
2653     return;
2654   }
2655 
2656   // Check for lookup interceptor except when bootstrapping.
2657   if (HasNamedInterceptor() && !Bootstrapper::IsActive()) {
2658     result->InterceptorResult(this);
2659     return;
2660   }
2661 
2662   LocalLookupRealNamedProperty(name, result);
2663 }
2664 
2665 
Lookup(String * name,LookupResult * result)2666 void JSObject::Lookup(String* name, LookupResult* result) {
2667   // Ecma-262 3rd 8.6.2.4
2668   for (Object* current = this;
2669        current != Heap::null_value();
2670        current = JSObject::cast(current)->GetPrototype()) {
2671     JSObject::cast(current)->LocalLookup(name, result);
2672     if (result->IsProperty()) return;
2673   }
2674   result->NotFound();
2675 }
2676 
2677 
2678 // Search object and it's prototype chain for callback properties.
LookupCallback(String * name,LookupResult * result)2679 void JSObject::LookupCallback(String* name, LookupResult* result) {
2680   for (Object* current = this;
2681        current != Heap::null_value();
2682        current = JSObject::cast(current)->GetPrototype()) {
2683     JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
2684     if (result->IsProperty() && result->type() == CALLBACKS) return;
2685   }
2686   result->NotFound();
2687 }
2688 
2689 
DefineGetterSetter(String * name,PropertyAttributes attributes)2690 Object* JSObject::DefineGetterSetter(String* name,
2691                                      PropertyAttributes attributes) {
2692   // Make sure that the top context does not change when doing callbacks or
2693   // interceptor calls.
2694   AssertNoContextChange ncc;
2695 
2696   // Check access rights if needed.
2697   if (IsAccessCheckNeeded() &&
2698       !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
2699     Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
2700     return Heap::undefined_value();
2701   }
2702 
2703   // Try to flatten before operating on the string.
2704   name->TryFlattenIfNotFlat();
2705 
2706   // Check if there is an API defined callback object which prohibits
2707   // callback overwriting in this object or it's prototype chain.
2708   // This mechanism is needed for instance in a browser setting, where
2709   // certain accessors such as window.location should not be allowed
2710   // to be overwritten because allowing overwriting could potentially
2711   // cause security problems.
2712   LookupResult callback_result;
2713   LookupCallback(name, &callback_result);
2714   if (callback_result.IsFound()) {
2715     Object* obj = callback_result.GetCallbackObject();
2716     if (obj->IsAccessorInfo() &&
2717         AccessorInfo::cast(obj)->prohibits_overwriting()) {
2718       return Heap::undefined_value();
2719     }
2720   }
2721 
2722   uint32_t index;
2723   bool is_element = name->AsArrayIndex(&index);
2724   if (is_element && IsJSArray()) return Heap::undefined_value();
2725 
2726   if (is_element) {
2727     switch (GetElementsKind()) {
2728       case FAST_ELEMENTS:
2729         break;
2730       case PIXEL_ELEMENTS:
2731       case EXTERNAL_BYTE_ELEMENTS:
2732       case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2733       case EXTERNAL_SHORT_ELEMENTS:
2734       case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2735       case EXTERNAL_INT_ELEMENTS:
2736       case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2737       case EXTERNAL_FLOAT_ELEMENTS:
2738         // Ignore getters and setters on pixel and external array
2739         // elements.
2740         return Heap::undefined_value();
2741       case DICTIONARY_ELEMENTS: {
2742         // Lookup the index.
2743         NumberDictionary* dictionary = element_dictionary();
2744         int entry = dictionary->FindEntry(index);
2745         if (entry != NumberDictionary::kNotFound) {
2746           Object* result = dictionary->ValueAt(entry);
2747           PropertyDetails details = dictionary->DetailsAt(entry);
2748           if (details.IsReadOnly()) return Heap::undefined_value();
2749           if (details.type() == CALLBACKS) {
2750             // Only accessors allowed as elements.
2751             ASSERT(result->IsFixedArray());
2752             return result;
2753           }
2754         }
2755         break;
2756       }
2757       default:
2758         UNREACHABLE();
2759         break;
2760     }
2761   } else {
2762     // Lookup the name.
2763     LookupResult result;
2764     LocalLookup(name, &result);
2765     if (result.IsProperty()) {
2766       if (result.IsReadOnly()) return Heap::undefined_value();
2767       if (result.type() == CALLBACKS) {
2768         Object* obj = result.GetCallbackObject();
2769         if (obj->IsFixedArray()) {
2770           // The object might be in fast mode even though it has
2771           // a getter/setter.
2772           Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2773           if (ok->IsFailure()) return ok;
2774 
2775           PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
2776           SetNormalizedProperty(name, obj, details);
2777           return obj;
2778         }
2779       }
2780     }
2781   }
2782 
2783   // Allocate the fixed array to hold getter and setter.
2784   Object* structure = Heap::AllocateFixedArray(2, TENURED);
2785   if (structure->IsFailure()) return structure;
2786   PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
2787 
2788   if (is_element) {
2789     // Normalize object to make this operation simple.
2790     Object* ok = NormalizeElements();
2791     if (ok->IsFailure()) return ok;
2792 
2793     // Update the dictionary with the new CALLBACKS property.
2794     Object* dict =
2795         element_dictionary()->Set(index, structure, details);
2796     if (dict->IsFailure()) return dict;
2797 
2798     // If name is an index we need to stay in slow case.
2799     NumberDictionary* elements = NumberDictionary::cast(dict);
2800     elements->set_requires_slow_elements();
2801     // Set the potential new dictionary on the object.
2802     set_elements(NumberDictionary::cast(dict));
2803   } else {
2804     // Normalize object to make this operation simple.
2805     Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2806     if (ok->IsFailure()) return ok;
2807 
2808     // For the global object allocate a new map to invalidate the global inline
2809     // caches which have a global property cell reference directly in the code.
2810     if (IsGlobalObject()) {
2811       Object* new_map = map()->CopyDropDescriptors();
2812       if (new_map->IsFailure()) return new_map;
2813       set_map(Map::cast(new_map));
2814     }
2815 
2816     // Update the dictionary with the new CALLBACKS property.
2817     return SetNormalizedProperty(name, structure, details);
2818   }
2819 
2820   return structure;
2821 }
2822 
2823 
DefineAccessor(String * name,bool is_getter,JSFunction * fun,PropertyAttributes attributes)2824 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun,
2825                                  PropertyAttributes attributes) {
2826   // Check access rights if needed.
2827   if (IsAccessCheckNeeded() &&
2828       !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
2829     Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
2830     return Heap::undefined_value();
2831   }
2832 
2833   if (IsJSGlobalProxy()) {
2834     Object* proto = GetPrototype();
2835     if (proto->IsNull()) return this;
2836     ASSERT(proto->IsJSGlobalObject());
2837     return JSObject::cast(proto)->DefineAccessor(name, is_getter,
2838                                                  fun, attributes);
2839   }
2840 
2841   Object* array = DefineGetterSetter(name, attributes);
2842   if (array->IsFailure() || array->IsUndefined()) return array;
2843   FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
2844   return this;
2845 }
2846 
2847 
LookupAccessor(String * name,bool is_getter)2848 Object* JSObject::LookupAccessor(String* name, bool is_getter) {
2849   // Make sure that the top context does not change when doing callbacks or
2850   // interceptor calls.
2851   AssertNoContextChange ncc;
2852 
2853   // Check access rights if needed.
2854   if (IsAccessCheckNeeded() &&
2855       !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
2856     Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
2857     return Heap::undefined_value();
2858   }
2859 
2860   // Make the lookup and include prototypes.
2861   int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
2862   uint32_t index;
2863   if (name->AsArrayIndex(&index)) {
2864     for (Object* obj = this;
2865          obj != Heap::null_value();
2866          obj = JSObject::cast(obj)->GetPrototype()) {
2867       JSObject* js_object = JSObject::cast(obj);
2868       if (js_object->HasDictionaryElements()) {
2869         NumberDictionary* dictionary = js_object->element_dictionary();
2870         int entry = dictionary->FindEntry(index);
2871         if (entry != NumberDictionary::kNotFound) {
2872           Object* element = dictionary->ValueAt(entry);
2873           PropertyDetails details = dictionary->DetailsAt(entry);
2874           if (details.type() == CALLBACKS) {
2875             // Only accessors allowed as elements.
2876             return FixedArray::cast(element)->get(accessor_index);
2877           }
2878         }
2879       }
2880     }
2881   } else {
2882     for (Object* obj = this;
2883          obj != Heap::null_value();
2884          obj = JSObject::cast(obj)->GetPrototype()) {
2885       LookupResult result;
2886       JSObject::cast(obj)->LocalLookup(name, &result);
2887       if (result.IsProperty()) {
2888         if (result.IsReadOnly()) return Heap::undefined_value();
2889         if (result.type() == CALLBACKS) {
2890           Object* obj = result.GetCallbackObject();
2891           if (obj->IsFixedArray()) {
2892             return FixedArray::cast(obj)->get(accessor_index);
2893           }
2894         }
2895       }
2896     }
2897   }
2898   return Heap::undefined_value();
2899 }
2900 
2901 
SlowReverseLookup(Object * value)2902 Object* JSObject::SlowReverseLookup(Object* value) {
2903   if (HasFastProperties()) {
2904     DescriptorArray* descs = map()->instance_descriptors();
2905     for (int i = 0; i < descs->number_of_descriptors(); i++) {
2906       if (descs->GetType(i) == FIELD) {
2907         if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
2908           return descs->GetKey(i);
2909         }
2910       } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
2911         if (descs->GetConstantFunction(i) == value) {
2912           return descs->GetKey(i);
2913         }
2914       }
2915     }
2916     return Heap::undefined_value();
2917   } else {
2918     return property_dictionary()->SlowReverseLookup(value);
2919   }
2920 }
2921 
2922 
CopyDropDescriptors()2923 Object* Map::CopyDropDescriptors() {
2924   Object* result = Heap::AllocateMap(instance_type(), instance_size());
2925   if (result->IsFailure()) return result;
2926   Map::cast(result)->set_prototype(prototype());
2927   Map::cast(result)->set_constructor(constructor());
2928   // Don't copy descriptors, so map transitions always remain a forest.
2929   // If we retained the same descriptors we would have two maps
2930   // pointing to the same transition which is bad because the garbage
2931   // collector relies on being able to reverse pointers from transitions
2932   // to maps.  If properties need to be retained use CopyDropTransitions.
2933   Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array());
2934   // Please note instance_type and instance_size are set when allocated.
2935   Map::cast(result)->set_inobject_properties(inobject_properties());
2936   Map::cast(result)->set_unused_property_fields(unused_property_fields());
2937 
2938   // If the map has pre-allocated properties always start out with a descriptor
2939   // array describing these properties.
2940   if (pre_allocated_property_fields() > 0) {
2941     ASSERT(constructor()->IsJSFunction());
2942     JSFunction* ctor = JSFunction::cast(constructor());
2943     Object* descriptors =
2944         ctor->initial_map()->instance_descriptors()->RemoveTransitions();
2945     if (descriptors->IsFailure()) return descriptors;
2946     Map::cast(result)->set_instance_descriptors(
2947         DescriptorArray::cast(descriptors));
2948     Map::cast(result)->set_pre_allocated_property_fields(
2949         pre_allocated_property_fields());
2950   }
2951   Map::cast(result)->set_bit_field(bit_field());
2952   Map::cast(result)->set_bit_field2(bit_field2());
2953   Map::cast(result)->ClearCodeCache();
2954   return result;
2955 }
2956 
2957 
CopyDropTransitions()2958 Object* Map::CopyDropTransitions() {
2959   Object* new_map = CopyDropDescriptors();
2960   if (new_map->IsFailure()) return new_map;
2961   Object* descriptors = instance_descriptors()->RemoveTransitions();
2962   if (descriptors->IsFailure()) return descriptors;
2963   cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
2964   return cast(new_map);
2965 }
2966 
2967 
UpdateCodeCache(String * name,Code * code)2968 Object* Map::UpdateCodeCache(String* name, Code* code) {
2969   ASSERT(code->ic_state() == MONOMORPHIC);
2970   FixedArray* cache = code_cache();
2971 
2972   // When updating the code cache we disregard the type encoded in the
2973   // flags. This allows call constant stubs to overwrite call field
2974   // stubs, etc.
2975   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
2976 
2977   // First check whether we can update existing code cache without
2978   // extending it.
2979   int length = cache->length();
2980   int deleted_index = -1;
2981   for (int i = 0; i < length; i += 2) {
2982     Object* key = cache->get(i);
2983     if (key->IsNull()) {
2984       if (deleted_index < 0) deleted_index = i;
2985       continue;
2986     }
2987     if (key->IsUndefined()) {
2988       if (deleted_index >= 0) i = deleted_index;
2989       cache->set(i + 0, name);
2990       cache->set(i + 1, code);
2991       return this;
2992     }
2993     if (name->Equals(String::cast(key))) {
2994       Code::Flags found = Code::cast(cache->get(i + 1))->flags();
2995       if (Code::RemoveTypeFromFlags(found) == flags) {
2996         cache->set(i + 1, code);
2997         return this;
2998       }
2999     }
3000   }
3001 
3002   // Reached the end of the code cache.  If there were deleted
3003   // elements, reuse the space for the first of them.
3004   if (deleted_index >= 0) {
3005     cache->set(deleted_index + 0, name);
3006     cache->set(deleted_index + 1, code);
3007     return this;
3008   }
3009 
3010   // Extend the code cache with some new entries (at least one).
3011   int new_length = length + ((length >> 1) & ~1) + 2;
3012   ASSERT((new_length & 1) == 0);  // must be a multiple of two
3013   Object* result = cache->CopySize(new_length);
3014   if (result->IsFailure()) return result;
3015 
3016   // Add the (name, code) pair to the new cache.
3017   cache = FixedArray::cast(result);
3018   cache->set(length + 0, name);
3019   cache->set(length + 1, code);
3020   set_code_cache(cache);
3021   return this;
3022 }
3023 
3024 
FindInCodeCache(String * name,Code::Flags flags)3025 Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
3026   FixedArray* cache = code_cache();
3027   int length = cache->length();
3028   for (int i = 0; i < length; i += 2) {
3029     Object* key = cache->get(i);
3030     // Skip deleted elements.
3031     if (key->IsNull()) continue;
3032     if (key->IsUndefined()) return key;
3033     if (name->Equals(String::cast(key))) {
3034       Code* code = Code::cast(cache->get(i + 1));
3035       if (code->flags() == flags) return code;
3036     }
3037   }
3038   return Heap::undefined_value();
3039 }
3040 
3041 
IndexInCodeCache(Code * code)3042 int Map::IndexInCodeCache(Code* code) {
3043   FixedArray* array = code_cache();
3044   int len = array->length();
3045   for (int i = 0; i < len; i += 2) {
3046     if (array->get(i + 1) == code) return i + 1;
3047   }
3048   return -1;
3049 }
3050 
3051 
RemoveFromCodeCache(int index)3052 void Map::RemoveFromCodeCache(int index) {
3053   FixedArray* array = code_cache();
3054   ASSERT(array->length() >= index && array->get(index)->IsCode());
3055   // Use null instead of undefined for deleted elements to distinguish
3056   // deleted elements from unused elements.  This distinction is used
3057   // when looking up in the cache and when updating the cache.
3058   array->set_null(index - 1);  // key
3059   array->set_null(index);  // code
3060 }
3061 
3062 
FixedArrayIterateBody(ObjectVisitor * v)3063 void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) {
3064   IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize);
3065 }
3066 
3067 
HasKey(FixedArray * array,Object * key)3068 static bool HasKey(FixedArray* array, Object* key) {
3069   int len0 = array->length();
3070   for (int i = 0; i < len0; i++) {
3071     Object* element = array->get(i);
3072     if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
3073     if (element->IsString() &&
3074         key->IsString() && String::cast(element)->Equals(String::cast(key))) {
3075       return true;
3076     }
3077   }
3078   return false;
3079 }
3080 
3081 
AddKeysFromJSArray(JSArray * array)3082 Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
3083   ASSERT(!array->HasPixelElements() && !array->HasExternalArrayElements());
3084   switch (array->GetElementsKind()) {
3085     case JSObject::FAST_ELEMENTS:
3086       return UnionOfKeys(FixedArray::cast(array->elements()));
3087     case JSObject::DICTIONARY_ELEMENTS: {
3088       NumberDictionary* dict = array->element_dictionary();
3089       int size = dict->NumberOfElements();
3090 
3091       // Allocate a temporary fixed array.
3092       Object* object = Heap::AllocateFixedArray(size);
3093       if (object->IsFailure()) return object;
3094       FixedArray* key_array = FixedArray::cast(object);
3095 
3096       int capacity = dict->Capacity();
3097       int pos = 0;
3098       // Copy the elements from the JSArray to the temporary fixed array.
3099       for (int i = 0; i < capacity; i++) {
3100         if (dict->IsKey(dict->KeyAt(i))) {
3101           key_array->set(pos++, dict->ValueAt(i));
3102         }
3103       }
3104       // Compute the union of this and the temporary fixed array.
3105       return UnionOfKeys(key_array);
3106     }
3107     default:
3108       UNREACHABLE();
3109   }
3110   UNREACHABLE();
3111   return Heap::null_value();  // Failure case needs to "return" a value.
3112 }
3113 
3114 
UnionOfKeys(FixedArray * other)3115 Object* FixedArray::UnionOfKeys(FixedArray* other) {
3116   int len0 = length();
3117   int len1 = other->length();
3118   // Optimize if either is empty.
3119   if (len0 == 0) return other;
3120   if (len1 == 0) return this;
3121 
3122   // Compute how many elements are not in this.
3123   int extra = 0;
3124   for (int y = 0; y < len1; y++) {
3125     Object* value = other->get(y);
3126     if (!value->IsTheHole() && !HasKey(this, value)) extra++;
3127   }
3128 
3129   if (extra == 0) return this;
3130 
3131   // Allocate the result
3132   Object* obj = Heap::AllocateFixedArray(len0 + extra);
3133   if (obj->IsFailure()) return obj;
3134   // Fill in the content
3135   AssertNoAllocation no_gc;
3136   FixedArray* result = FixedArray::cast(obj);
3137   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
3138   for (int i = 0; i < len0; i++) {
3139     result->set(i, get(i), mode);
3140   }
3141   // Fill in the extra keys.
3142   int index = 0;
3143   for (int y = 0; y < len1; y++) {
3144     Object* value = other->get(y);
3145     if (!value->IsTheHole() && !HasKey(this, value)) {
3146       result->set(len0 + index, other->get(y), mode);
3147       index++;
3148     }
3149   }
3150   ASSERT(extra == index);
3151   return result;
3152 }
3153 
3154 
CopySize(int new_length)3155 Object* FixedArray::CopySize(int new_length) {
3156   if (new_length == 0) return Heap::empty_fixed_array();
3157   Object* obj = Heap::AllocateFixedArray(new_length);
3158   if (obj->IsFailure()) return obj;
3159   FixedArray* result = FixedArray::cast(obj);
3160   // Copy the content
3161   AssertNoAllocation no_gc;
3162   int len = length();
3163   if (new_length < len) len = new_length;
3164   result->set_map(map());
3165   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
3166   for (int i = 0; i < len; i++) {
3167     result->set(i, get(i), mode);
3168   }
3169   return result;
3170 }
3171 
3172 
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)3173 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
3174   AssertNoAllocation no_gc;
3175   WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
3176   for (int index = 0; index < len; index++) {
3177     dest->set(dest_pos+index, get(pos+index), mode);
3178   }
3179 }
3180 
3181 
3182 #ifdef DEBUG
IsEqualTo(FixedArray * other)3183 bool FixedArray::IsEqualTo(FixedArray* other) {
3184   if (length() != other->length()) return false;
3185   for (int i = 0 ; i < length(); ++i) {
3186     if (get(i) != other->get(i)) return false;
3187   }
3188   return true;
3189 }
3190 #endif
3191 
3192 
Allocate(int number_of_descriptors)3193 Object* DescriptorArray::Allocate(int number_of_descriptors) {
3194   if (number_of_descriptors == 0) {
3195     return Heap::empty_descriptor_array();
3196   }
3197   // Allocate the array of keys.
3198   Object* array =
3199       Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors));
3200   if (array->IsFailure()) return array;
3201   // Do not use DescriptorArray::cast on incomplete object.
3202   FixedArray* result = FixedArray::cast(array);
3203 
3204   // Allocate the content array and set it in the descriptor array.
3205   array = Heap::AllocateFixedArray(number_of_descriptors << 1);
3206   if (array->IsFailure()) return array;
3207   result->set(kContentArrayIndex, array);
3208   result->set(kEnumerationIndexIndex,
3209               Smi::FromInt(PropertyDetails::kInitialIndex));
3210   return result;
3211 }
3212 
3213 
SetEnumCache(FixedArray * bridge_storage,FixedArray * new_cache)3214 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
3215                                    FixedArray* new_cache) {
3216   ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
3217   if (HasEnumCache()) {
3218     FixedArray::cast(get(kEnumerationIndexIndex))->
3219       set(kEnumCacheBridgeCacheIndex, new_cache);
3220   } else {
3221     if (IsEmpty()) return;  // Do nothing for empty descriptor array.
3222     FixedArray::cast(bridge_storage)->
3223       set(kEnumCacheBridgeCacheIndex, new_cache);
3224     fast_set(FixedArray::cast(bridge_storage),
3225              kEnumCacheBridgeEnumIndex,
3226              get(kEnumerationIndexIndex));
3227     set(kEnumerationIndexIndex, bridge_storage);
3228   }
3229 }
3230 
3231 
CopyInsert(Descriptor * descriptor,TransitionFlag transition_flag)3232 Object* DescriptorArray::CopyInsert(Descriptor* descriptor,
3233                                     TransitionFlag transition_flag) {
3234   // Transitions are only kept when inserting another transition.
3235   // This precondition is not required by this function's implementation, but
3236   // is currently required by the semantics of maps, so we check it.
3237   // Conversely, we filter after replacing, so replacing a transition and
3238   // removing all other transitions is not supported.
3239   bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
3240   ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
3241   ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
3242 
3243   // Ensure the key is a symbol.
3244   Object* result = descriptor->KeyToSymbol();
3245   if (result->IsFailure()) return result;
3246 
3247   int transitions = 0;
3248   int null_descriptors = 0;
3249   if (remove_transitions) {
3250     for (int i = 0; i < number_of_descriptors(); i++) {
3251       if (IsTransition(i)) transitions++;
3252       if (IsNullDescriptor(i)) null_descriptors++;
3253     }
3254   } else {
3255     for (int i = 0; i < number_of_descriptors(); i++) {
3256       if (IsNullDescriptor(i)) null_descriptors++;
3257     }
3258   }
3259   int new_size = number_of_descriptors() - transitions - null_descriptors;
3260 
3261   // If key is in descriptor, we replace it in-place when filtering.
3262   // Count a null descriptor for key as inserted, not replaced.
3263   int index = Search(descriptor->GetKey());
3264   const bool inserting = (index == kNotFound);
3265   const bool replacing = !inserting;
3266   bool keep_enumeration_index = false;
3267   if (inserting) {
3268     ++new_size;
3269   }
3270   if (replacing) {
3271     // We are replacing an existing descriptor.  We keep the enumeration
3272     // index of a visible property.
3273     PropertyType t = PropertyDetails(GetDetails(index)).type();
3274     if (t == CONSTANT_FUNCTION ||
3275         t == FIELD ||
3276         t == CALLBACKS ||
3277         t == INTERCEPTOR) {
3278       keep_enumeration_index = true;
3279     } else if (remove_transitions) {
3280      // Replaced descriptor has been counted as removed if it is
3281      // a transition that will be replaced.  Adjust count in this case.
3282       ++new_size;
3283     }
3284   }
3285   result = Allocate(new_size);
3286   if (result->IsFailure()) return result;
3287   DescriptorArray* new_descriptors = DescriptorArray::cast(result);
3288   // Set the enumeration index in the descriptors and set the enumeration index
3289   // in the result.
3290   int enumeration_index = NextEnumerationIndex();
3291   if (!descriptor->GetDetails().IsTransition()) {
3292     if (keep_enumeration_index) {
3293       descriptor->SetEnumerationIndex(
3294           PropertyDetails(GetDetails(index)).index());
3295     } else {
3296       descriptor->SetEnumerationIndex(enumeration_index);
3297       ++enumeration_index;
3298     }
3299   }
3300   new_descriptors->SetNextEnumerationIndex(enumeration_index);
3301 
3302   // Copy the descriptors, filtering out transitions and null descriptors,
3303   // and inserting or replacing a descriptor.
3304   uint32_t descriptor_hash = descriptor->GetKey()->Hash();
3305   int from_index = 0;
3306   int to_index = 0;
3307 
3308   for (; from_index < number_of_descriptors(); from_index++) {
3309     String* key = GetKey(from_index);
3310     if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
3311       break;
3312     }
3313     if (IsNullDescriptor(from_index)) continue;
3314     if (remove_transitions && IsTransition(from_index)) continue;
3315     new_descriptors->CopyFrom(to_index++, this, from_index);
3316   }
3317 
3318   new_descriptors->Set(to_index++, descriptor);
3319   if (replacing) from_index++;
3320 
3321   for (; from_index < number_of_descriptors(); from_index++) {
3322     if (IsNullDescriptor(from_index)) continue;
3323     if (remove_transitions && IsTransition(from_index)) continue;
3324     new_descriptors->CopyFrom(to_index++, this, from_index);
3325   }
3326 
3327   ASSERT(to_index == new_descriptors->number_of_descriptors());
3328   SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
3329 
3330   return new_descriptors;
3331 }
3332 
3333 
RemoveTransitions()3334 Object* DescriptorArray::RemoveTransitions() {
3335   // Remove all transitions and null descriptors. Return a copy of the array
3336   // with all transitions removed, or a Failure object if the new array could
3337   // not be allocated.
3338 
3339   // Compute the size of the map transition entries to be removed.
3340   int num_removed = 0;
3341   for (int i = 0; i < number_of_descriptors(); i++) {
3342     if (!IsProperty(i)) num_removed++;
3343   }
3344 
3345   // Allocate the new descriptor array.
3346   Object* result = Allocate(number_of_descriptors() - num_removed);
3347   if (result->IsFailure()) return result;
3348   DescriptorArray* new_descriptors = DescriptorArray::cast(result);
3349 
3350   // Copy the content.
3351   int next_descriptor = 0;
3352   for (int i = 0; i < number_of_descriptors(); i++) {
3353     if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
3354   }
3355   ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
3356 
3357   return new_descriptors;
3358 }
3359 
3360 
Sort()3361 void DescriptorArray::Sort() {
3362   // In-place heap sort.
3363   int len = number_of_descriptors();
3364 
3365   // Bottom-up max-heap construction.
3366   for (int i = 1; i < len; ++i) {
3367     int child_index = i;
3368     while (child_index > 0) {
3369       int parent_index = ((child_index + 1) >> 1) - 1;
3370       uint32_t parent_hash = GetKey(parent_index)->Hash();
3371       uint32_t child_hash = GetKey(child_index)->Hash();
3372       if (parent_hash < child_hash) {
3373         Swap(parent_index, child_index);
3374       } else {
3375         break;
3376       }
3377       child_index = parent_index;
3378     }
3379   }
3380 
3381   // Extract elements and create sorted array.
3382   for (int i = len - 1; i > 0; --i) {
3383     // Put max element at the back of the array.
3384     Swap(0, i);
3385     // Sift down the new top element.
3386     int parent_index = 0;
3387     while (true) {
3388       int child_index = ((parent_index + 1) << 1) - 1;
3389       if (child_index >= i) break;
3390       uint32_t child1_hash = GetKey(child_index)->Hash();
3391       uint32_t child2_hash = GetKey(child_index + 1)->Hash();
3392       uint32_t parent_hash = GetKey(parent_index)->Hash();
3393       if (child_index + 1 >= i || child1_hash > child2_hash) {
3394         if (parent_hash > child1_hash) break;
3395         Swap(parent_index, child_index);
3396         parent_index = child_index;
3397       } else {
3398         if (parent_hash > child2_hash) break;
3399         Swap(parent_index, child_index + 1);
3400         parent_index = child_index + 1;
3401       }
3402     }
3403   }
3404 
3405   SLOW_ASSERT(IsSortedNoDuplicates());
3406 }
3407 
3408 
BinarySearch(String * name,int low,int high)3409 int DescriptorArray::BinarySearch(String* name, int low, int high) {
3410   uint32_t hash = name->Hash();
3411 
3412   while (low <= high) {
3413     int mid = (low + high) / 2;
3414     String* mid_name = GetKey(mid);
3415     uint32_t mid_hash = mid_name->Hash();
3416 
3417     if (mid_hash > hash) {
3418       high = mid - 1;
3419       continue;
3420     }
3421     if (mid_hash < hash) {
3422       low = mid + 1;
3423       continue;
3424     }
3425     // Found an element with the same hash-code.
3426     ASSERT(hash == mid_hash);
3427     // There might be more, so we find the first one and
3428     // check them all to see if we have a match.
3429     if (name == mid_name  && !is_null_descriptor(mid)) return mid;
3430     while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
3431     for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
3432       if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
3433     }
3434     break;
3435   }
3436   return kNotFound;
3437 }
3438 
3439 
LinearSearch(String * name,int len)3440 int DescriptorArray::LinearSearch(String* name, int len) {
3441   uint32_t hash = name->Hash();
3442   for (int number = 0; number < len; number++) {
3443     String* entry = GetKey(number);
3444     if ((entry->Hash() == hash) &&
3445         name->Equals(entry) &&
3446         !is_null_descriptor(number)) {
3447       return number;
3448     }
3449   }
3450   return kNotFound;
3451 }
3452 
3453 
3454 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)3455 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
3456   if (IsEmpty()) return other->IsEmpty();
3457   if (other->IsEmpty()) return false;
3458   if (length() != other->length()) return false;
3459   for (int i = 0; i < length(); ++i) {
3460     if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
3461   }
3462   return GetContentArray()->IsEqualTo(other->GetContentArray());
3463 }
3464 #endif
3465 
3466 
3467 static StaticResource<StringInputBuffer> string_input_buffer;
3468 
3469 
LooksValid()3470 bool String::LooksValid() {
3471   if (!Heap::Contains(this)) return false;
3472   return true;
3473 }
3474 
3475 
Utf8Length()3476 int String::Utf8Length() {
3477   if (IsAsciiRepresentation()) return length();
3478   // Attempt to flatten before accessing the string.  It probably
3479   // doesn't make Utf8Length faster, but it is very likely that
3480   // the string will be accessed later (for example by WriteUtf8)
3481   // so it's still a good idea.
3482   TryFlattenIfNotFlat();
3483   Access<StringInputBuffer> buffer(&string_input_buffer);
3484   buffer->Reset(0, this);
3485   int result = 0;
3486   while (buffer->has_more())
3487     result += unibrow::Utf8::Length(buffer->GetNext());
3488   return result;
3489 }
3490 
3491 
ToAsciiVector()3492 Vector<const char> String::ToAsciiVector() {
3493   ASSERT(IsAsciiRepresentation());
3494   ASSERT(IsFlat());
3495 
3496   int offset = 0;
3497   int length = this->length();
3498   StringRepresentationTag string_tag = StringShape(this).representation_tag();
3499   String* string = this;
3500   if (string_tag == kConsStringTag) {
3501     ConsString* cons = ConsString::cast(string);
3502     ASSERT(cons->second()->length() == 0);
3503     string = cons->first();
3504     string_tag = StringShape(string).representation_tag();
3505   }
3506   if (string_tag == kSeqStringTag) {
3507     SeqAsciiString* seq = SeqAsciiString::cast(string);
3508     char* start = seq->GetChars();
3509     return Vector<const char>(start + offset, length);
3510   }
3511   ASSERT(string_tag == kExternalStringTag);
3512   ExternalAsciiString* ext = ExternalAsciiString::cast(string);
3513   const char* start = ext->resource()->data();
3514   return Vector<const char>(start + offset, length);
3515 }
3516 
3517 
ToUC16Vector()3518 Vector<const uc16> String::ToUC16Vector() {
3519   ASSERT(IsTwoByteRepresentation());
3520   ASSERT(IsFlat());
3521 
3522   int offset = 0;
3523   int length = this->length();
3524   StringRepresentationTag string_tag = StringShape(this).representation_tag();
3525   String* string = this;
3526   if (string_tag == kConsStringTag) {
3527     ConsString* cons = ConsString::cast(string);
3528     ASSERT(cons->second()->length() == 0);
3529     string = cons->first();
3530     string_tag = StringShape(string).representation_tag();
3531   }
3532   if (string_tag == kSeqStringTag) {
3533     SeqTwoByteString* seq = SeqTwoByteString::cast(string);
3534     return Vector<const uc16>(seq->GetChars() + offset, length);
3535   }
3536   ASSERT(string_tag == kExternalStringTag);
3537   ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
3538   const uc16* start =
3539       reinterpret_cast<const uc16*>(ext->resource()->data());
3540   return Vector<const uc16>(start + offset, length);
3541 }
3542 
3543 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)3544 SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
3545                                      RobustnessFlag robust_flag,
3546                                      int offset,
3547                                      int length,
3548                                      int* length_return) {
3549   ASSERT(NativeAllocationChecker::allocation_allowed());
3550   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
3551     return SmartPointer<char>(NULL);
3552   }
3553 
3554   // Negative length means the to the end of the string.
3555   if (length < 0) length = kMaxInt - offset;
3556 
3557   // Compute the size of the UTF-8 string. Start at the specified offset.
3558   Access<StringInputBuffer> buffer(&string_input_buffer);
3559   buffer->Reset(offset, this);
3560   int character_position = offset;
3561   int utf8_bytes = 0;
3562   while (buffer->has_more()) {
3563     uint16_t character = buffer->GetNext();
3564     if (character_position < offset + length) {
3565       utf8_bytes += unibrow::Utf8::Length(character);
3566     }
3567     character_position++;
3568   }
3569 
3570   if (length_return) {
3571     *length_return = utf8_bytes;
3572   }
3573 
3574   char* result = NewArray<char>(utf8_bytes + 1);
3575 
3576   // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
3577   buffer->Rewind();
3578   buffer->Seek(offset);
3579   character_position = offset;
3580   int utf8_byte_position = 0;
3581   while (buffer->has_more()) {
3582     uint16_t character = buffer->GetNext();
3583     if (character_position < offset + length) {
3584       if (allow_nulls == DISALLOW_NULLS && character == 0) {
3585         character = ' ';
3586       }
3587       utf8_byte_position +=
3588           unibrow::Utf8::Encode(result + utf8_byte_position, character);
3589     }
3590     character_position++;
3591   }
3592   result[utf8_byte_position] = 0;
3593   return SmartPointer<char>(result);
3594 }
3595 
3596 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)3597 SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
3598                                      RobustnessFlag robust_flag,
3599                                      int* length_return) {
3600   return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
3601 }
3602 
3603 
GetTwoByteData()3604 const uc16* String::GetTwoByteData() {
3605   return GetTwoByteData(0);
3606 }
3607 
3608 
GetTwoByteData(unsigned start)3609 const uc16* String::GetTwoByteData(unsigned start) {
3610   ASSERT(!IsAsciiRepresentation());
3611   switch (StringShape(this).representation_tag()) {
3612     case kSeqStringTag:
3613       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
3614     case kExternalStringTag:
3615       return ExternalTwoByteString::cast(this)->
3616         ExternalTwoByteStringGetData(start);
3617     case kConsStringTag:
3618       UNREACHABLE();
3619       return NULL;
3620   }
3621   UNREACHABLE();
3622   return NULL;
3623 }
3624 
3625 
ToWideCString(RobustnessFlag robust_flag)3626 SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
3627   ASSERT(NativeAllocationChecker::allocation_allowed());
3628 
3629   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
3630     return SmartPointer<uc16>();
3631   }
3632 
3633   Access<StringInputBuffer> buffer(&string_input_buffer);
3634   buffer->Reset(this);
3635 
3636   uc16* result = NewArray<uc16>(length() + 1);
3637 
3638   int i = 0;
3639   while (buffer->has_more()) {
3640     uint16_t character = buffer->GetNext();
3641     result[i++] = character;
3642   }
3643   result[i] = 0;
3644   return SmartPointer<uc16>(result);
3645 }
3646 
3647 
SeqTwoByteStringGetData(unsigned start)3648 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
3649   return reinterpret_cast<uc16*>(
3650       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
3651 }
3652 
3653 
SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)3654 void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
3655                                                            unsigned* offset_ptr,
3656                                                            unsigned max_chars) {
3657   unsigned chars_read = 0;
3658   unsigned offset = *offset_ptr;
3659   while (chars_read < max_chars) {
3660     uint16_t c = *reinterpret_cast<uint16_t*>(
3661         reinterpret_cast<char*>(this) -
3662             kHeapObjectTag + kHeaderSize + offset * kShortSize);
3663     if (c <= kMaxAsciiCharCode) {
3664       // Fast case for ASCII characters.   Cursor is an input output argument.
3665       if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
3666                                                           rbb->util_buffer,
3667                                                           rbb->capacity,
3668                                                           rbb->cursor)) {
3669         break;
3670       }
3671     } else {
3672       if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
3673                                                              rbb->util_buffer,
3674                                                              rbb->capacity,
3675                                                              rbb->cursor)) {
3676         break;
3677       }
3678     }
3679     offset++;
3680     chars_read++;
3681   }
3682   *offset_ptr = offset;
3683   rbb->remaining += chars_read;
3684 }
3685 
3686 
SeqAsciiStringReadBlock(unsigned * remaining,unsigned * offset_ptr,unsigned max_chars)3687 const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
3688     unsigned* remaining,
3689     unsigned* offset_ptr,
3690     unsigned max_chars) {
3691   const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
3692       kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
3693   *remaining = max_chars;
3694   *offset_ptr += max_chars;
3695   return b;
3696 }
3697 
3698 
3699 // This will iterate unless the block of string data spans two 'halves' of
3700 // a ConsString, in which case it will recurse.  Since the block of string
3701 // data to be read has a maximum size this limits the maximum recursion
3702 // depth to something sane.  Since C++ does not have tail call recursion
3703 // elimination, the iteration must be explicit. Since this is not an
3704 // -IntoBuffer method it can delegate to one of the efficient
3705 // *AsciiStringReadBlock routines.
ConsStringReadBlock(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)3706 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
3707                                                      unsigned* offset_ptr,
3708                                                      unsigned max_chars) {
3709   ConsString* current = this;
3710   unsigned offset = *offset_ptr;
3711   int offset_correction = 0;
3712 
3713   while (true) {
3714     String* left = current->first();
3715     unsigned left_length = (unsigned)left->length();
3716     if (left_length > offset &&
3717         (max_chars <= left_length - offset ||
3718          (rbb->capacity <= left_length - offset &&
3719           (max_chars = left_length - offset, true)))) {  // comma operator!
3720       // Left hand side only - iterate unless we have reached the bottom of
3721       // the cons tree.  The assignment on the left of the comma operator is
3722       // in order to make use of the fact that the -IntoBuffer routines can
3723       // produce at most 'capacity' characters.  This enables us to postpone
3724       // the point where we switch to the -IntoBuffer routines (below) in order
3725       // to maximize the chances of delegating a big chunk of work to the
3726       // efficient *AsciiStringReadBlock routines.
3727       if (StringShape(left).IsCons()) {
3728         current = ConsString::cast(left);
3729         continue;
3730       } else {
3731         const unibrow::byte* answer =
3732             String::ReadBlock(left, rbb, &offset, max_chars);
3733         *offset_ptr = offset + offset_correction;
3734         return answer;
3735       }
3736     } else if (left_length <= offset) {
3737       // Right hand side only - iterate unless we have reached the bottom of
3738       // the cons tree.
3739       String* right = current->second();
3740       offset -= left_length;
3741       offset_correction += left_length;
3742       if (StringShape(right).IsCons()) {
3743         current = ConsString::cast(right);
3744         continue;
3745       } else {
3746         const unibrow::byte* answer =
3747             String::ReadBlock(right, rbb, &offset, max_chars);
3748         *offset_ptr = offset + offset_correction;
3749         return answer;
3750       }
3751     } else {
3752       // The block to be read spans two sides of the ConsString, so we call the
3753       // -IntoBuffer version, which will recurse.  The -IntoBuffer methods
3754       // are able to assemble data from several part strings because they use
3755       // the util_buffer to store their data and never return direct pointers
3756       // to their storage.  We don't try to read more than the buffer capacity
3757       // here or we can get too much recursion.
3758       ASSERT(rbb->remaining == 0);
3759       ASSERT(rbb->cursor == 0);
3760       current->ConsStringReadBlockIntoBuffer(
3761           rbb,
3762           &offset,
3763           max_chars > rbb->capacity ? rbb->capacity : max_chars);
3764       *offset_ptr = offset + offset_correction;
3765       return rbb->util_buffer;
3766     }
3767   }
3768 }
3769 
3770 
ExternalAsciiStringGet(int index)3771 uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
3772   ASSERT(index >= 0 && index < length());
3773   return resource()->data()[index];
3774 }
3775 
3776 
ExternalAsciiStringReadBlock(unsigned * remaining,unsigned * offset_ptr,unsigned max_chars)3777 const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
3778       unsigned* remaining,
3779       unsigned* offset_ptr,
3780       unsigned max_chars) {
3781   // Cast const char* to unibrow::byte* (signedness difference).
3782   const unibrow::byte* b =
3783       reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
3784   *remaining = max_chars;
3785   *offset_ptr += max_chars;
3786   return b;
3787 }
3788 
3789 
ExternalTwoByteStringGetData(unsigned start)3790 const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
3791       unsigned start) {
3792   return resource()->data() + start;
3793 }
3794 
3795 
ExternalTwoByteStringGet(int index)3796 uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
3797   ASSERT(index >= 0 && index < length());
3798   return resource()->data()[index];
3799 }
3800 
3801 
ExternalTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)3802 void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
3803       ReadBlockBuffer* rbb,
3804       unsigned* offset_ptr,
3805       unsigned max_chars) {
3806   unsigned chars_read = 0;
3807   unsigned offset = *offset_ptr;
3808   const uint16_t* data = resource()->data();
3809   while (chars_read < max_chars) {
3810     uint16_t c = data[offset];
3811     if (c <= kMaxAsciiCharCode) {
3812       // Fast case for ASCII characters. Cursor is an input output argument.
3813       if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
3814                                                           rbb->util_buffer,
3815                                                           rbb->capacity,
3816                                                           rbb->cursor))
3817         break;
3818     } else {
3819       if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
3820                                                              rbb->util_buffer,
3821                                                              rbb->capacity,
3822                                                              rbb->cursor))
3823         break;
3824     }
3825     offset++;
3826     chars_read++;
3827   }
3828   *offset_ptr = offset;
3829   rbb->remaining += chars_read;
3830 }
3831 
3832 
SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)3833 void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
3834                                                  unsigned* offset_ptr,
3835                                                  unsigned max_chars) {
3836   unsigned capacity = rbb->capacity - rbb->cursor;
3837   if (max_chars > capacity) max_chars = capacity;
3838   memcpy(rbb->util_buffer + rbb->cursor,
3839          reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
3840              *offset_ptr * kCharSize,
3841          max_chars);
3842   rbb->remaining += max_chars;
3843   *offset_ptr += max_chars;
3844   rbb->cursor += max_chars;
3845 }
3846 
3847 
ExternalAsciiStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)3848 void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
3849       ReadBlockBuffer* rbb,
3850       unsigned* offset_ptr,
3851       unsigned max_chars) {
3852   unsigned capacity = rbb->capacity - rbb->cursor;
3853   if (max_chars > capacity) max_chars = capacity;
3854   memcpy(rbb->util_buffer + rbb->cursor,
3855          resource()->data() + *offset_ptr,
3856          max_chars);
3857   rbb->remaining += max_chars;
3858   *offset_ptr += max_chars;
3859   rbb->cursor += max_chars;
3860 }
3861 
3862 
3863 // This method determines the type of string involved and then copies
3864 // a whole chunk of characters into a buffer, or returns a pointer to a buffer
3865 // where they can be found.  The pointer is not necessarily valid across a GC
3866 // (see AsciiStringReadBlock).
ReadBlock(String * input,ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)3867 const unibrow::byte* String::ReadBlock(String* input,
3868                                        ReadBlockBuffer* rbb,
3869                                        unsigned* offset_ptr,
3870                                        unsigned max_chars) {
3871   ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
3872   if (max_chars == 0) {
3873     rbb->remaining = 0;
3874     return NULL;
3875   }
3876   switch (StringShape(input).representation_tag()) {
3877     case kSeqStringTag:
3878       if (input->IsAsciiRepresentation()) {
3879         SeqAsciiString* str = SeqAsciiString::cast(input);
3880         return str->SeqAsciiStringReadBlock(&rbb->remaining,
3881                                             offset_ptr,
3882                                             max_chars);
3883       } else {
3884         SeqTwoByteString* str = SeqTwoByteString::cast(input);
3885         str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
3886                                                  offset_ptr,
3887                                                  max_chars);
3888         return rbb->util_buffer;
3889       }
3890     case kConsStringTag:
3891       return ConsString::cast(input)->ConsStringReadBlock(rbb,
3892                                                           offset_ptr,
3893                                                           max_chars);
3894     case kExternalStringTag:
3895       if (input->IsAsciiRepresentation()) {
3896         return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
3897             &rbb->remaining,
3898             offset_ptr,
3899             max_chars);
3900       } else {
3901         ExternalTwoByteString::cast(input)->
3902             ExternalTwoByteStringReadBlockIntoBuffer(rbb,
3903                                                      offset_ptr,
3904                                                      max_chars);
3905         return rbb->util_buffer;
3906       }
3907     default:
3908       break;
3909   }
3910 
3911   UNREACHABLE();
3912   return 0;
3913 }
3914 
3915 
3916 Relocatable* Relocatable::top_ = NULL;
3917 
3918 
PostGarbageCollectionProcessing()3919 void Relocatable::PostGarbageCollectionProcessing() {
3920   Relocatable* current = top_;
3921   while (current != NULL) {
3922     current->PostGarbageCollection();
3923     current = current->prev_;
3924   }
3925 }
3926 
3927 
3928 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()3929 int Relocatable::ArchiveSpacePerThread() {
3930   return sizeof(top_);
3931 }
3932 
3933 
3934 // Archive statics that are thread local.
ArchiveState(char * to)3935 char* Relocatable::ArchiveState(char* to) {
3936   *reinterpret_cast<Relocatable**>(to) = top_;
3937   top_ = NULL;
3938   return to + ArchiveSpacePerThread();
3939 }
3940 
3941 
3942 // Restore statics that are thread local.
RestoreState(char * from)3943 char* Relocatable::RestoreState(char* from) {
3944   top_ = *reinterpret_cast<Relocatable**>(from);
3945   return from + ArchiveSpacePerThread();
3946 }
3947 
3948 
Iterate(ObjectVisitor * v,char * thread_storage)3949 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
3950   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
3951   Iterate(v, top);
3952   return thread_storage + ArchiveSpacePerThread();
3953 }
3954 
3955 
Iterate(ObjectVisitor * v)3956 void Relocatable::Iterate(ObjectVisitor* v) {
3957   Iterate(v, top_);
3958 }
3959 
3960 
Iterate(ObjectVisitor * v,Relocatable * top)3961 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
3962   Relocatable* current = top;
3963   while (current != NULL) {
3964     current->IterateInstance(v);
3965     current = current->prev_;
3966   }
3967 }
3968 
3969 
FlatStringReader(Handle<String> str)3970 FlatStringReader::FlatStringReader(Handle<String> str)
3971     : str_(str.location()),
3972       length_(str->length()) {
3973   PostGarbageCollection();
3974 }
3975 
3976 
FlatStringReader(Vector<const char> input)3977 FlatStringReader::FlatStringReader(Vector<const char> input)
3978     : str_(0),
3979       is_ascii_(true),
3980       length_(input.length()),
3981       start_(input.start()) { }
3982 
3983 
PostGarbageCollection()3984 void FlatStringReader::PostGarbageCollection() {
3985   if (str_ == NULL) return;
3986   Handle<String> str(str_);
3987   ASSERT(str->IsFlat());
3988   is_ascii_ = str->IsAsciiRepresentation();
3989   if (is_ascii_) {
3990     start_ = str->ToAsciiVector().start();
3991   } else {
3992     start_ = str->ToUC16Vector().start();
3993   }
3994 }
3995 
3996 
Seek(unsigned pos)3997 void StringInputBuffer::Seek(unsigned pos) {
3998   Reset(pos, input_);
3999 }
4000 
4001 
Seek(unsigned pos)4002 void SafeStringInputBuffer::Seek(unsigned pos) {
4003   Reset(pos, input_);
4004 }
4005 
4006 
4007 // This method determines the type of string involved and then copies
4008 // a whole chunk of characters into a buffer.  It can be used with strings
4009 // that have been glued together to form a ConsString and which must cooperate
4010 // to fill up a buffer.
ReadBlockIntoBuffer(String * input,ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)4011 void String::ReadBlockIntoBuffer(String* input,
4012                                  ReadBlockBuffer* rbb,
4013                                  unsigned* offset_ptr,
4014                                  unsigned max_chars) {
4015   ASSERT(*offset_ptr <= (unsigned)input->length());
4016   if (max_chars == 0) return;
4017 
4018   switch (StringShape(input).representation_tag()) {
4019     case kSeqStringTag:
4020       if (input->IsAsciiRepresentation()) {
4021         SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
4022                                                                  offset_ptr,
4023                                                                  max_chars);
4024         return;
4025       } else {
4026         SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
4027                                                                      offset_ptr,
4028                                                                      max_chars);
4029         return;
4030       }
4031     case kConsStringTag:
4032       ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
4033                                                              offset_ptr,
4034                                                              max_chars);
4035       return;
4036     case kExternalStringTag:
4037       if (input->IsAsciiRepresentation()) {
4038         ExternalAsciiString::cast(input)->
4039             ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
4040       } else {
4041         ExternalTwoByteString::cast(input)->
4042             ExternalTwoByteStringReadBlockIntoBuffer(rbb,
4043                                                      offset_ptr,
4044                                                      max_chars);
4045        }
4046        return;
4047     default:
4048       break;
4049   }
4050 
4051   UNREACHABLE();
4052   return;
4053 }
4054 
4055 
ReadBlock(String * input,unibrow::byte * util_buffer,unsigned capacity,unsigned * remaining,unsigned * offset_ptr)4056 const unibrow::byte* String::ReadBlock(String* input,
4057                                        unibrow::byte* util_buffer,
4058                                        unsigned capacity,
4059                                        unsigned* remaining,
4060                                        unsigned* offset_ptr) {
4061   ASSERT(*offset_ptr <= (unsigned)input->length());
4062   unsigned chars = input->length() - *offset_ptr;
4063   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
4064   const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
4065   ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
4066   *remaining = rbb.remaining;
4067   return answer;
4068 }
4069 
4070 
ReadBlock(String ** raw_input,unibrow::byte * util_buffer,unsigned capacity,unsigned * remaining,unsigned * offset_ptr)4071 const unibrow::byte* String::ReadBlock(String** raw_input,
4072                                        unibrow::byte* util_buffer,
4073                                        unsigned capacity,
4074                                        unsigned* remaining,
4075                                        unsigned* offset_ptr) {
4076   Handle<String> input(raw_input);
4077   ASSERT(*offset_ptr <= (unsigned)input->length());
4078   unsigned chars = input->length() - *offset_ptr;
4079   if (chars > capacity) chars = capacity;
4080   ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
4081   ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
4082   ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
4083   *remaining = rbb.remaining;
4084   return rbb.util_buffer;
4085 }
4086 
4087 
4088 // This will iterate unless the block of string data spans two 'halves' of
4089 // a ConsString, in which case it will recurse.  Since the block of string
4090 // data to be read has a maximum size this limits the maximum recursion
4091 // depth to something sane.  Since C++ does not have tail call recursion
4092 // elimination, the iteration must be explicit.
ConsStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)4093 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4094                                                unsigned* offset_ptr,
4095                                                unsigned max_chars) {
4096   ConsString* current = this;
4097   unsigned offset = *offset_ptr;
4098   int offset_correction = 0;
4099 
4100   while (true) {
4101     String* left = current->first();
4102     unsigned left_length = (unsigned)left->length();
4103     if (left_length > offset &&
4104       max_chars <= left_length - offset) {
4105       // Left hand side only - iterate unless we have reached the bottom of
4106       // the cons tree.
4107       if (StringShape(left).IsCons()) {
4108         current = ConsString::cast(left);
4109         continue;
4110       } else {
4111         String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
4112         *offset_ptr = offset + offset_correction;
4113         return;
4114       }
4115     } else if (left_length <= offset) {
4116       // Right hand side only - iterate unless we have reached the bottom of
4117       // the cons tree.
4118       offset -= left_length;
4119       offset_correction += left_length;
4120       String* right = current->second();
4121       if (StringShape(right).IsCons()) {
4122         current = ConsString::cast(right);
4123         continue;
4124       } else {
4125         String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
4126         *offset_ptr = offset + offset_correction;
4127         return;
4128       }
4129     } else {
4130       // The block to be read spans two sides of the ConsString, so we recurse.
4131       // First recurse on the left.
4132       max_chars -= left_length - offset;
4133       String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
4134       // We may have reached the max or there may not have been enough space
4135       // in the buffer for the characters in the left hand side.
4136       if (offset == left_length) {
4137         // Recurse on the right.
4138         String* right = String::cast(current->second());
4139         offset -= left_length;
4140         offset_correction += left_length;
4141         String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
4142       }
4143       *offset_ptr = offset + offset_correction;
4144       return;
4145     }
4146   }
4147 }
4148 
4149 
ConsStringIterateBody(ObjectVisitor * v)4150 void ConsString::ConsStringIterateBody(ObjectVisitor* v) {
4151   IteratePointers(v, kFirstOffset, kSecondOffset + kPointerSize);
4152 }
4153 
4154 
JSGlobalPropertyCellIterateBody(ObjectVisitor * v)4155 void JSGlobalPropertyCell::JSGlobalPropertyCellIterateBody(ObjectVisitor* v) {
4156   IteratePointers(v, kValueOffset, kValueOffset + kPointerSize);
4157 }
4158 
4159 
ConsStringGet(int index)4160 uint16_t ConsString::ConsStringGet(int index) {
4161   ASSERT(index >= 0 && index < this->length());
4162 
4163   // Check for a flattened cons string
4164   if (second()->length() == 0) {
4165     String* left = first();
4166     return left->Get(index);
4167   }
4168 
4169   String* string = String::cast(this);
4170 
4171   while (true) {
4172     if (StringShape(string).IsCons()) {
4173       ConsString* cons_string = ConsString::cast(string);
4174       String* left = cons_string->first();
4175       if (left->length() > index) {
4176         string = left;
4177       } else {
4178         index -= left->length();
4179         string = cons_string->second();
4180       }
4181     } else {
4182       return string->Get(index);
4183     }
4184   }
4185 
4186   UNREACHABLE();
4187   return 0;
4188 }
4189 
4190 
4191 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)4192 void String::WriteToFlat(String* src,
4193                          sinkchar* sink,
4194                          int f,
4195                          int t) {
4196   String* source = src;
4197   int from = f;
4198   int to = t;
4199   while (true) {
4200     ASSERT(0 <= from && from <= to && to <= source->length());
4201     switch (StringShape(source).full_representation_tag()) {
4202       case kAsciiStringTag | kExternalStringTag: {
4203         CopyChars(sink,
4204                   ExternalAsciiString::cast(source)->resource()->data() + from,
4205                   to - from);
4206         return;
4207       }
4208       case kTwoByteStringTag | kExternalStringTag: {
4209         const uc16* data =
4210             ExternalTwoByteString::cast(source)->resource()->data();
4211         CopyChars(sink,
4212                   data + from,
4213                   to - from);
4214         return;
4215       }
4216       case kAsciiStringTag | kSeqStringTag: {
4217         CopyChars(sink,
4218                   SeqAsciiString::cast(source)->GetChars() + from,
4219                   to - from);
4220         return;
4221       }
4222       case kTwoByteStringTag | kSeqStringTag: {
4223         CopyChars(sink,
4224                   SeqTwoByteString::cast(source)->GetChars() + from,
4225                   to - from);
4226         return;
4227       }
4228       case kAsciiStringTag | kConsStringTag:
4229       case kTwoByteStringTag | kConsStringTag: {
4230         ConsString* cons_string = ConsString::cast(source);
4231         String* first = cons_string->first();
4232         int boundary = first->length();
4233         if (to - boundary >= boundary - from) {
4234           // Right hand side is longer.  Recurse over left.
4235           if (from < boundary) {
4236             WriteToFlat(first, sink, from, boundary);
4237             sink += boundary - from;
4238             from = 0;
4239           } else {
4240             from -= boundary;
4241           }
4242           to -= boundary;
4243           source = cons_string->second();
4244         } else {
4245           // Left hand side is longer.  Recurse over right.
4246           if (to > boundary) {
4247             String* second = cons_string->second();
4248             WriteToFlat(second,
4249                         sink + boundary - from,
4250                         0,
4251                         to - boundary);
4252             to = boundary;
4253           }
4254           source = first;
4255         }
4256         break;
4257       }
4258     }
4259   }
4260 }
4261 
4262 
4263 #define FIELD_ADDR(p, offset) \
4264   (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
4265 
ExternalAsciiStringIterateBody(ObjectVisitor * v)4266 void ExternalAsciiString::ExternalAsciiStringIterateBody(ObjectVisitor* v) {
4267   typedef v8::String::ExternalAsciiStringResource Resource;
4268   v->VisitExternalAsciiString(
4269       reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)));
4270 }
4271 
4272 
ExternalTwoByteStringIterateBody(ObjectVisitor * v)4273 void ExternalTwoByteString::ExternalTwoByteStringIterateBody(ObjectVisitor* v) {
4274   typedef v8::String::ExternalStringResource Resource;
4275   v->VisitExternalTwoByteString(
4276       reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)));
4277 }
4278 
4279 #undef FIELD_ADDR
4280 
4281 template <typename IteratorA, typename IteratorB>
CompareStringContents(IteratorA * ia,IteratorB * ib)4282 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
4283   // General slow case check.  We know that the ia and ib iterators
4284   // have the same length.
4285   while (ia->has_more()) {
4286     uc32 ca = ia->GetNext();
4287     uc32 cb = ib->GetNext();
4288     if (ca != cb)
4289       return false;
4290   }
4291   return true;
4292 }
4293 
4294 
4295 // Compares the contents of two strings by reading and comparing
4296 // int-sized blocks of characters.
4297 template <typename Char>
CompareRawStringContents(Vector<Char> a,Vector<Char> b)4298 static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
4299   int length = a.length();
4300   ASSERT_EQ(length, b.length());
4301   const Char* pa = a.start();
4302   const Char* pb = b.start();
4303   int i = 0;
4304 #ifndef V8_HOST_CAN_READ_UNALIGNED
4305   // If this architecture isn't comfortable reading unaligned ints
4306   // then we have to check that the strings are aligned before
4307   // comparing them blockwise.
4308   const int kAlignmentMask = sizeof(uint32_t) - 1;  // NOLINT
4309   uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
4310   uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
4311   if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
4312 #endif
4313     const int kStepSize = sizeof(int) / sizeof(Char);  // NOLINT
4314     int endpoint = length - kStepSize;
4315     // Compare blocks until we reach near the end of the string.
4316     for (; i <= endpoint; i += kStepSize) {
4317       uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
4318       uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
4319       if (wa != wb) {
4320         return false;
4321       }
4322     }
4323 #ifndef V8_HOST_CAN_READ_UNALIGNED
4324   }
4325 #endif
4326   // Compare the remaining characters that didn't fit into a block.
4327   for (; i < length; i++) {
4328     if (a[i] != b[i]) {
4329       return false;
4330     }
4331   }
4332   return true;
4333 }
4334 
4335 
4336 static StringInputBuffer string_compare_buffer_b;
4337 
4338 
4339 template <typename IteratorA>
CompareStringContentsPartial(IteratorA * ia,String * b)4340 static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
4341   if (b->IsFlat()) {
4342     if (b->IsAsciiRepresentation()) {
4343       VectorIterator<char> ib(b->ToAsciiVector());
4344       return CompareStringContents(ia, &ib);
4345     } else {
4346       VectorIterator<uc16> ib(b->ToUC16Vector());
4347       return CompareStringContents(ia, &ib);
4348     }
4349   } else {
4350     string_compare_buffer_b.Reset(0, b);
4351     return CompareStringContents(ia, &string_compare_buffer_b);
4352   }
4353 }
4354 
4355 
4356 static StringInputBuffer string_compare_buffer_a;
4357 
4358 
SlowEquals(String * other)4359 bool String::SlowEquals(String* other) {
4360   // Fast check: negative check with lengths.
4361   int len = length();
4362   if (len != other->length()) return false;
4363   if (len == 0) return true;
4364 
4365   // Fast check: if hash code is computed for both strings
4366   // a fast negative check can be performed.
4367   if (HasHashCode() && other->HasHashCode()) {
4368     if (Hash() != other->Hash()) return false;
4369   }
4370 
4371   if (StringShape(this).IsSequentialAscii() &&
4372       StringShape(other).IsSequentialAscii()) {
4373     const char* str1 = SeqAsciiString::cast(this)->GetChars();
4374     const char* str2 = SeqAsciiString::cast(other)->GetChars();
4375     return CompareRawStringContents(Vector<const char>(str1, len),
4376                                     Vector<const char>(str2, len));
4377   }
4378 
4379   if (this->IsFlat()) {
4380     if (IsAsciiRepresentation()) {
4381       Vector<const char> vec1 = this->ToAsciiVector();
4382       if (other->IsFlat()) {
4383         if (other->IsAsciiRepresentation()) {
4384           Vector<const char> vec2 = other->ToAsciiVector();
4385           return CompareRawStringContents(vec1, vec2);
4386         } else {
4387           VectorIterator<char> buf1(vec1);
4388           VectorIterator<uc16> ib(other->ToUC16Vector());
4389           return CompareStringContents(&buf1, &ib);
4390         }
4391       } else {
4392         VectorIterator<char> buf1(vec1);
4393         string_compare_buffer_b.Reset(0, other);
4394         return CompareStringContents(&buf1, &string_compare_buffer_b);
4395       }
4396     } else {
4397       Vector<const uc16> vec1 = this->ToUC16Vector();
4398       if (other->IsFlat()) {
4399         if (other->IsAsciiRepresentation()) {
4400           VectorIterator<uc16> buf1(vec1);
4401           VectorIterator<char> ib(other->ToAsciiVector());
4402           return CompareStringContents(&buf1, &ib);
4403         } else {
4404           Vector<const uc16> vec2(other->ToUC16Vector());
4405           return CompareRawStringContents(vec1, vec2);
4406         }
4407       } else {
4408         VectorIterator<uc16> buf1(vec1);
4409         string_compare_buffer_b.Reset(0, other);
4410         return CompareStringContents(&buf1, &string_compare_buffer_b);
4411       }
4412     }
4413   } else {
4414     string_compare_buffer_a.Reset(0, this);
4415     return CompareStringContentsPartial(&string_compare_buffer_a, other);
4416   }
4417 }
4418 
4419 
MarkAsUndetectable()4420 bool String::MarkAsUndetectable() {
4421   if (StringShape(this).IsSymbol()) return false;
4422 
4423   Map* map = this->map();
4424   if (map == Heap::string_map()) {
4425     this->set_map(Heap::undetectable_string_map());
4426     return true;
4427   } else if (map == Heap::ascii_string_map()) {
4428     this->set_map(Heap::undetectable_ascii_string_map());
4429     return true;
4430   }
4431   // Rest cannot be marked as undetectable
4432   return false;
4433 }
4434 
4435 
IsEqualTo(Vector<const char> str)4436 bool String::IsEqualTo(Vector<const char> str) {
4437   int slen = length();
4438   Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
4439   decoder->Reset(str.start(), str.length());
4440   int i;
4441   for (i = 0; i < slen && decoder->has_more(); i++) {
4442     uc32 r = decoder->GetNext();
4443     if (Get(i) != r) return false;
4444   }
4445   return i == slen && !decoder->has_more();
4446 }
4447 
4448 
ComputeAndSetHash()4449 uint32_t String::ComputeAndSetHash() {
4450   // Should only be called if hash code has not yet been computed.
4451   ASSERT(!(hash_field() & kHashComputedMask));
4452 
4453   // Compute the hash code.
4454   StringInputBuffer buffer(this);
4455   uint32_t field = ComputeHashField(&buffer, length());
4456 
4457   // Store the hash code in the object.
4458   set_hash_field(field);
4459 
4460   // Check the hash code is there.
4461   ASSERT(hash_field() & kHashComputedMask);
4462   uint32_t result = field >> kHashShift;
4463   ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
4464   return result;
4465 }
4466 
4467 
ComputeArrayIndex(unibrow::CharacterStream * buffer,uint32_t * index,int length)4468 bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
4469                                uint32_t* index,
4470                                int length) {
4471   if (length == 0 || length > kMaxArrayIndexSize) return false;
4472   uc32 ch = buffer->GetNext();
4473 
4474   // If the string begins with a '0' character, it must only consist
4475   // of it to be a legal array index.
4476   if (ch == '0') {
4477     *index = 0;
4478     return length == 1;
4479   }
4480 
4481   // Convert string to uint32 array index; character by character.
4482   int d = ch - '0';
4483   if (d < 0 || d > 9) return false;
4484   uint32_t result = d;
4485   while (buffer->has_more()) {
4486     d = buffer->GetNext() - '0';
4487     if (d < 0 || d > 9) return false;
4488     // Check that the new result is below the 32 bit limit.
4489     if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
4490     result = (result * 10) + d;
4491   }
4492 
4493   *index = result;
4494   return true;
4495 }
4496 
4497 
SlowAsArrayIndex(uint32_t * index)4498 bool String::SlowAsArrayIndex(uint32_t* index) {
4499   if (length() <= kMaxCachedArrayIndexLength) {
4500     Hash();  // force computation of hash code
4501     uint32_t field = hash_field();
4502     if ((field & kIsArrayIndexMask) == 0) return false;
4503     // Isolate the array index form the full hash field.
4504     *index = (kArrayIndexHashMask & field) >> kHashShift;
4505     return true;
4506   } else {
4507     StringInputBuffer buffer(this);
4508     return ComputeArrayIndex(&buffer, index, length());
4509   }
4510 }
4511 
4512 
HashField(uint32_t hash,bool is_array_index,int length=-1)4513 static inline uint32_t HashField(uint32_t hash,
4514                                  bool is_array_index,
4515                                  int length = -1) {
4516   uint32_t result =
4517       (hash << String::kHashShift) | String::kHashComputedMask;
4518   if (is_array_index) {
4519     // For array indexes mix the length into the hash as an array index could
4520     // be zero.
4521     ASSERT(length > 0);
4522     ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
4523            (1 << String::kArrayIndexValueBits));
4524     result |= String::kIsArrayIndexMask;
4525     result |= length << String::kArrayIndexHashLengthShift;
4526   }
4527   return result;
4528 }
4529 
4530 
GetHashField()4531 uint32_t StringHasher::GetHashField() {
4532   ASSERT(is_valid());
4533   if (length_ <= String::kMaxHashCalcLength) {
4534     if (is_array_index()) {
4535       return v8::internal::HashField(array_index(), true, length_);
4536     } else {
4537       return v8::internal::HashField(GetHash(), false);
4538     }
4539     uint32_t payload = v8::internal::HashField(GetHash(), false);
4540     return payload;
4541   } else {
4542     return v8::internal::HashField(length_, false);
4543   }
4544 }
4545 
4546 
ComputeHashField(unibrow::CharacterStream * buffer,int length)4547 uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
4548                                   int length) {
4549   StringHasher hasher(length);
4550 
4551   // Very long strings have a trivial hash that doesn't inspect the
4552   // string contents.
4553   if (hasher.has_trivial_hash()) {
4554     return hasher.GetHashField();
4555   }
4556 
4557   // Do the iterative array index computation as long as there is a
4558   // chance this is an array index.
4559   while (buffer->has_more() && hasher.is_array_index()) {
4560     hasher.AddCharacter(buffer->GetNext());
4561   }
4562 
4563   // Process the remaining characters without updating the array
4564   // index.
4565   while (buffer->has_more()) {
4566     hasher.AddCharacterNoIndex(buffer->GetNext());
4567   }
4568 
4569   return hasher.GetHashField();
4570 }
4571 
4572 
SubString(int start,int end)4573 Object* String::SubString(int start, int end) {
4574   if (start == 0 && end == length()) return this;
4575   Object* result = Heap::AllocateSubString(this, start, end);
4576   return result;
4577 }
4578 
4579 
PrintOn(FILE * file)4580 void String::PrintOn(FILE* file) {
4581   int length = this->length();
4582   for (int i = 0; i < length; i++) {
4583     fprintf(file, "%c", Get(i));
4584   }
4585 }
4586 
4587 
CreateBackPointers()4588 void Map::CreateBackPointers() {
4589   DescriptorArray* descriptors = instance_descriptors();
4590   for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
4591     if (descriptors->GetType(i) == MAP_TRANSITION) {
4592       // Get target.
4593       Map* target = Map::cast(descriptors->GetValue(i));
4594 #ifdef DEBUG
4595       // Verify target.
4596       Object* source_prototype = prototype();
4597       Object* target_prototype = target->prototype();
4598       ASSERT(source_prototype->IsJSObject() ||
4599              source_prototype->IsMap() ||
4600              source_prototype->IsNull());
4601       ASSERT(target_prototype->IsJSObject() ||
4602              target_prototype->IsNull());
4603       ASSERT(source_prototype->IsMap() ||
4604              source_prototype == target_prototype);
4605 #endif
4606       // Point target back to source.  set_prototype() will not let us set
4607       // the prototype to a map, as we do here.
4608       *RawField(target, kPrototypeOffset) = this;
4609     }
4610   }
4611 }
4612 
4613 
ClearNonLiveTransitions(Object * real_prototype)4614 void Map::ClearNonLiveTransitions(Object* real_prototype) {
4615   // Live DescriptorArray objects will be marked, so we must use
4616   // low-level accessors to get and modify their data.
4617   DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
4618       *RawField(this, Map::kInstanceDescriptorsOffset));
4619   if (d == Heap::raw_unchecked_empty_descriptor_array()) return;
4620   Smi* NullDescriptorDetails =
4621     PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
4622   FixedArray* contents = reinterpret_cast<FixedArray*>(
4623       d->get(DescriptorArray::kContentArrayIndex));
4624   ASSERT(contents->length() >= 2);
4625   for (int i = 0; i < contents->length(); i += 2) {
4626     // If the pair (value, details) is a map transition,
4627     // check if the target is live.  If not, null the descriptor.
4628     // Also drop the back pointer for that map transition, so that this
4629     // map is not reached again by following a back pointer from a
4630     // non-live object.
4631     PropertyDetails details(Smi::cast(contents->get(i + 1)));
4632     if (details.type() == MAP_TRANSITION) {
4633       Map* target = reinterpret_cast<Map*>(contents->get(i));
4634       ASSERT(target->IsHeapObject());
4635       if (!target->IsMarked()) {
4636         ASSERT(target->IsMap());
4637         contents->set(i + 1, NullDescriptorDetails);
4638         contents->set_null(i);
4639         ASSERT(target->prototype() == this ||
4640                target->prototype() == real_prototype);
4641         // Getter prototype() is read-only, set_prototype() has side effects.
4642         *RawField(target, Map::kPrototypeOffset) = real_prototype;
4643       }
4644     }
4645   }
4646 }
4647 
4648 
MapIterateBody(ObjectVisitor * v)4649 void Map::MapIterateBody(ObjectVisitor* v) {
4650   // Assumes all Object* members are contiguously allocated!
4651   IteratePointers(v, kPrototypeOffset, kCodeCacheOffset + kPointerSize);
4652 }
4653 
4654 
SetInstancePrototype(Object * value)4655 Object* JSFunction::SetInstancePrototype(Object* value) {
4656   ASSERT(value->IsJSObject());
4657 
4658   if (has_initial_map()) {
4659     initial_map()->set_prototype(value);
4660   } else {
4661     // Put the value in the initial map field until an initial map is
4662     // needed.  At that point, a new initial map is created and the
4663     // prototype is put into the initial map where it belongs.
4664     set_prototype_or_initial_map(value);
4665   }
4666   return value;
4667 }
4668 
4669 
4670 
SetPrototype(Object * value)4671 Object* JSFunction::SetPrototype(Object* value) {
4672   Object* construct_prototype = value;
4673 
4674   // If the value is not a JSObject, store the value in the map's
4675   // constructor field so it can be accessed.  Also, set the prototype
4676   // used for constructing objects to the original object prototype.
4677   // See ECMA-262 13.2.2.
4678   if (!value->IsJSObject()) {
4679     // Copy the map so this does not affect unrelated functions.
4680     // Remove map transitions because they point to maps with a
4681     // different prototype.
4682     Object* new_map = map()->CopyDropTransitions();
4683     if (new_map->IsFailure()) return new_map;
4684     set_map(Map::cast(new_map));
4685     map()->set_constructor(value);
4686     map()->set_non_instance_prototype(true);
4687     construct_prototype =
4688         Top::context()->global_context()->initial_object_prototype();
4689   } else {
4690     map()->set_non_instance_prototype(false);
4691   }
4692 
4693   return SetInstancePrototype(construct_prototype);
4694 }
4695 
4696 
SetInstanceClassName(String * name)4697 Object* JSFunction::SetInstanceClassName(String* name) {
4698   shared()->set_instance_class_name(name);
4699   return this;
4700 }
4701 
4702 
GlobalContextFromLiterals(FixedArray * literals)4703 Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
4704   return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
4705 }
4706 
4707 
OddballIterateBody(ObjectVisitor * v)4708 void Oddball::OddballIterateBody(ObjectVisitor* v) {
4709   // Assumes all Object* members are contiguously allocated!
4710   IteratePointers(v, kToStringOffset, kToNumberOffset + kPointerSize);
4711 }
4712 
4713 
Initialize(const char * to_string,Object * to_number)4714 Object* Oddball::Initialize(const char* to_string, Object* to_number) {
4715   Object* symbol = Heap::LookupAsciiSymbol(to_string);
4716   if (symbol->IsFailure()) return symbol;
4717   set_to_string(String::cast(symbol));
4718   set_to_number(to_number);
4719   return this;
4720 }
4721 
4722 
HasSourceCode()4723 bool SharedFunctionInfo::HasSourceCode() {
4724   return !script()->IsUndefined() &&
4725          !Script::cast(script())->source()->IsUndefined();
4726 }
4727 
4728 
GetSourceCode()4729 Object* SharedFunctionInfo::GetSourceCode() {
4730   HandleScope scope;
4731   if (script()->IsUndefined()) return Heap::undefined_value();
4732   Object* source = Script::cast(script())->source();
4733   if (source->IsUndefined()) return Heap::undefined_value();
4734   return *SubString(Handle<String>(String::cast(source)),
4735                     start_position(), end_position());
4736 }
4737 
4738 
CalculateInstanceSize()4739 int SharedFunctionInfo::CalculateInstanceSize() {
4740   int instance_size =
4741       JSObject::kHeaderSize +
4742       expected_nof_properties() * kPointerSize;
4743   if (instance_size > JSObject::kMaxInstanceSize) {
4744     instance_size = JSObject::kMaxInstanceSize;
4745   }
4746   return instance_size;
4747 }
4748 
4749 
CalculateInObjectProperties()4750 int SharedFunctionInfo::CalculateInObjectProperties() {
4751   return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
4752 }
4753 
4754 
CanGenerateInlineConstructor(Object * prototype)4755 bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
4756   // Check the basic conditions for generating inline constructor code.
4757   if (!FLAG_inline_new
4758       || !has_only_simple_this_property_assignments()
4759       || this_property_assignments_count() == 0) {
4760     return false;
4761   }
4762 
4763   // If the prototype is null inline constructors cause no problems.
4764   if (!prototype->IsJSObject()) {
4765     ASSERT(prototype->IsNull());
4766     return true;
4767   }
4768 
4769   // Traverse the proposed prototype chain looking for setters for properties of
4770   // the same names as are set by the inline constructor.
4771   for (Object* obj = prototype;
4772        obj != Heap::null_value();
4773        obj = obj->GetPrototype()) {
4774     JSObject* js_object = JSObject::cast(obj);
4775     for (int i = 0; i < this_property_assignments_count(); i++) {
4776       LookupResult result;
4777       String* name = GetThisPropertyAssignmentName(i);
4778       js_object->LocalLookupRealNamedProperty(name, &result);
4779       if (result.IsProperty() && result.type() == CALLBACKS) {
4780         return false;
4781       }
4782     }
4783   }
4784 
4785   return true;
4786 }
4787 
4788 
SetThisPropertyAssignmentsInfo(bool only_simple_this_property_assignments,FixedArray * assignments)4789 void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
4790     bool only_simple_this_property_assignments,
4791     FixedArray* assignments) {
4792   set_compiler_hints(BooleanBit::set(compiler_hints(),
4793                                      kHasOnlySimpleThisPropertyAssignments,
4794                                      only_simple_this_property_assignments));
4795   set_this_property_assignments(assignments);
4796   set_this_property_assignments_count(assignments->length() / 3);
4797 }
4798 
4799 
ClearThisPropertyAssignmentsInfo()4800 void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
4801   set_compiler_hints(BooleanBit::set(compiler_hints(),
4802                                      kHasOnlySimpleThisPropertyAssignments,
4803                                      false));
4804   set_this_property_assignments(Heap::undefined_value());
4805   set_this_property_assignments_count(0);
4806 }
4807 
4808 
GetThisPropertyAssignmentName(int index)4809 String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
4810   Object* obj = this_property_assignments();
4811   ASSERT(obj->IsFixedArray());
4812   ASSERT(index < this_property_assignments_count());
4813   obj = FixedArray::cast(obj)->get(index * 3);
4814   ASSERT(obj->IsString());
4815   return String::cast(obj);
4816 }
4817 
4818 
IsThisPropertyAssignmentArgument(int index)4819 bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
4820   Object* obj = this_property_assignments();
4821   ASSERT(obj->IsFixedArray());
4822   ASSERT(index < this_property_assignments_count());
4823   obj = FixedArray::cast(obj)->get(index * 3 + 1);
4824   return Smi::cast(obj)->value() != -1;
4825 }
4826 
4827 
GetThisPropertyAssignmentArgument(int index)4828 int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
4829   ASSERT(IsThisPropertyAssignmentArgument(index));
4830   Object* obj =
4831       FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
4832   return Smi::cast(obj)->value();
4833 }
4834 
4835 
GetThisPropertyAssignmentConstant(int index)4836 Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
4837   ASSERT(!IsThisPropertyAssignmentArgument(index));
4838   Object* obj =
4839       FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
4840   return obj;
4841 }
4842 
4843 
4844 // Support function for printing the source code to a StringStream
4845 // without any allocation in the heap.
SourceCodePrint(StringStream * accumulator,int max_length)4846 void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
4847                                          int max_length) {
4848   // For some native functions there is no source.
4849   if (script()->IsUndefined() ||
4850       Script::cast(script())->source()->IsUndefined()) {
4851     accumulator->Add("<No Source>");
4852     return;
4853   }
4854 
4855   // Get the source for the script which this function came from.
4856   // Don't use String::cast because we don't want more assertion errors while
4857   // we are already creating a stack dump.
4858   String* script_source =
4859       reinterpret_cast<String*>(Script::cast(script())->source());
4860 
4861   if (!script_source->LooksValid()) {
4862     accumulator->Add("<Invalid Source>");
4863     return;
4864   }
4865 
4866   if (!is_toplevel()) {
4867     accumulator->Add("function ");
4868     Object* name = this->name();
4869     if (name->IsString() && String::cast(name)->length() > 0) {
4870       accumulator->PrintName(name);
4871     }
4872   }
4873 
4874   int len = end_position() - start_position();
4875   if (len > max_length) {
4876     accumulator->Put(script_source,
4877                      start_position(),
4878                      start_position() + max_length);
4879     accumulator->Add("...\n");
4880   } else {
4881     accumulator->Put(script_source, start_position(), end_position());
4882   }
4883 }
4884 
4885 
SharedFunctionInfoIterateBody(ObjectVisitor * v)4886 void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
4887   IteratePointers(v, kNameOffset, kConstructStubOffset + kPointerSize);
4888   IteratePointers(v, kInstanceClassNameOffset, kScriptOffset + kPointerSize);
4889   IteratePointers(v, kDebugInfoOffset, kInferredNameOffset + kPointerSize);
4890   IteratePointers(v, kThisPropertyAssignmentsOffset,
4891       kThisPropertyAssignmentsOffset + kPointerSize);
4892 }
4893 
4894 
VisitCodeTarget(RelocInfo * rinfo)4895 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
4896   ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
4897   Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
4898   Object* old_target = target;
4899   VisitPointer(&target);
4900   CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
4901 }
4902 
4903 
VisitDebugTarget(RelocInfo * rinfo)4904 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
4905   ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
4906          rinfo->IsPatchedReturnSequence());
4907   Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
4908   Object* old_target = target;
4909   VisitPointer(&target);
4910   CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
4911 }
4912 
4913 
CodeIterateBody(ObjectVisitor * v)4914 void Code::CodeIterateBody(ObjectVisitor* v) {
4915   int mode_mask = RelocInfo::kCodeTargetMask |
4916                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
4917                   RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
4918                   RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
4919                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
4920 
4921   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
4922     RelocInfo::Mode rmode = it.rinfo()->rmode();
4923     if (rmode == RelocInfo::EMBEDDED_OBJECT) {
4924       v->VisitPointer(it.rinfo()->target_object_address());
4925     } else if (RelocInfo::IsCodeTarget(rmode)) {
4926       v->VisitCodeTarget(it.rinfo());
4927     } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
4928       v->VisitExternalReference(it.rinfo()->target_reference_address());
4929 #ifdef ENABLE_DEBUGGER_SUPPORT
4930     } else if (Debug::has_break_points() &&
4931                RelocInfo::IsJSReturn(rmode) &&
4932                it.rinfo()->IsPatchedReturnSequence()) {
4933       v->VisitDebugTarget(it.rinfo());
4934 #endif
4935     } else if (rmode == RelocInfo::RUNTIME_ENTRY) {
4936       v->VisitRuntimeEntry(it.rinfo());
4937     }
4938   }
4939 
4940   ScopeInfo<>::IterateScopeInfo(this, v);
4941 }
4942 
4943 
Relocate(intptr_t delta)4944 void Code::Relocate(intptr_t delta) {
4945   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
4946     it.rinfo()->apply(delta);
4947   }
4948   CPU::FlushICache(instruction_start(), instruction_size());
4949 }
4950 
4951 
CopyFrom(const CodeDesc & desc)4952 void Code::CopyFrom(const CodeDesc& desc) {
4953   // copy code
4954   memmove(instruction_start(), desc.buffer, desc.instr_size);
4955 
4956   // fill gap with zero bytes
4957   { byte* p = instruction_start() + desc.instr_size;
4958     byte* q = relocation_start();
4959     while (p < q) {
4960       *p++ = 0;
4961     }
4962   }
4963 
4964   // copy reloc info
4965   memmove(relocation_start(),
4966           desc.buffer + desc.buffer_size - desc.reloc_size,
4967           desc.reloc_size);
4968 
4969   // unbox handles and relocate
4970   intptr_t delta = instruction_start() - desc.buffer;
4971   int mode_mask = RelocInfo::kCodeTargetMask |
4972                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
4973                   RelocInfo::kApplyMask;
4974   Assembler* origin = desc.origin;  // Needed to find target_object on X64.
4975   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
4976     RelocInfo::Mode mode = it.rinfo()->rmode();
4977     if (mode == RelocInfo::EMBEDDED_OBJECT) {
4978       Handle<Object> p = it.rinfo()->target_object_handle(origin);
4979       it.rinfo()->set_target_object(*p);
4980     } else if (RelocInfo::IsCodeTarget(mode)) {
4981       // rewrite code handles in inline cache targets to direct
4982       // pointers to the first instruction in the code object
4983       Handle<Object> p = it.rinfo()->target_object_handle(origin);
4984       Code* code = Code::cast(*p);
4985       it.rinfo()->set_target_address(code->instruction_start());
4986     } else {
4987       it.rinfo()->apply(delta);
4988     }
4989   }
4990   CPU::FlushICache(instruction_start(), instruction_size());
4991 }
4992 
4993 
4994 // Locate the source position which is closest to the address in the code. This
4995 // is using the source position information embedded in the relocation info.
4996 // The position returned is relative to the beginning of the script where the
4997 // source for this function is found.
SourcePosition(Address pc)4998 int Code::SourcePosition(Address pc) {
4999   int distance = kMaxInt;
5000   int position = RelocInfo::kNoPosition;  // Initially no position found.
5001   // Run through all the relocation info to find the best matching source
5002   // position. All the code needs to be considered as the sequence of the
5003   // instructions in the code does not necessarily follow the same order as the
5004   // source.
5005   RelocIterator it(this, RelocInfo::kPositionMask);
5006   while (!it.done()) {
5007     // Only look at positions after the current pc.
5008     if (it.rinfo()->pc() < pc) {
5009       // Get position and distance.
5010 
5011       int dist = static_cast<int>(pc - it.rinfo()->pc());
5012       int pos = static_cast<int>(it.rinfo()->data());
5013       // If this position is closer than the current candidate or if it has the
5014       // same distance as the current candidate and the position is higher then
5015       // this position is the new candidate.
5016       if ((dist < distance) ||
5017           (dist == distance && pos > position)) {
5018         position = pos;
5019         distance = dist;
5020       }
5021     }
5022     it.next();
5023   }
5024   return position;
5025 }
5026 
5027 
5028 // Same as Code::SourcePosition above except it only looks for statement
5029 // positions.
SourceStatementPosition(Address pc)5030 int Code::SourceStatementPosition(Address pc) {
5031   // First find the position as close as possible using all position
5032   // information.
5033   int position = SourcePosition(pc);
5034   // Now find the closest statement position before the position.
5035   int statement_position = 0;
5036   RelocIterator it(this, RelocInfo::kPositionMask);
5037   while (!it.done()) {
5038     if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
5039       int p = static_cast<int>(it.rinfo()->data());
5040       if (statement_position < p && p <= position) {
5041         statement_position = p;
5042       }
5043     }
5044     it.next();
5045   }
5046   return statement_position;
5047 }
5048 
5049 
5050 #ifdef ENABLE_DISASSEMBLER
5051 // Identify kind of code.
Kind2String(Kind kind)5052 const char* Code::Kind2String(Kind kind) {
5053   switch (kind) {
5054     case FUNCTION: return "FUNCTION";
5055     case STUB: return "STUB";
5056     case BUILTIN: return "BUILTIN";
5057     case LOAD_IC: return "LOAD_IC";
5058     case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
5059     case STORE_IC: return "STORE_IC";
5060     case KEYED_STORE_IC: return "KEYED_STORE_IC";
5061     case CALL_IC: return "CALL_IC";
5062   }
5063   UNREACHABLE();
5064   return NULL;
5065 }
5066 
5067 
ICState2String(InlineCacheState state)5068 const char* Code::ICState2String(InlineCacheState state) {
5069   switch (state) {
5070     case UNINITIALIZED: return "UNINITIALIZED";
5071     case PREMONOMORPHIC: return "PREMONOMORPHIC";
5072     case MONOMORPHIC: return "MONOMORPHIC";
5073     case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
5074     case MEGAMORPHIC: return "MEGAMORPHIC";
5075     case DEBUG_BREAK: return "DEBUG_BREAK";
5076     case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
5077   }
5078   UNREACHABLE();
5079   return NULL;
5080 }
5081 
5082 
PropertyType2String(PropertyType type)5083 const char* Code::PropertyType2String(PropertyType type) {
5084   switch (type) {
5085     case NORMAL: return "NORMAL";
5086     case FIELD: return "FIELD";
5087     case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
5088     case CALLBACKS: return "CALLBACKS";
5089     case INTERCEPTOR: return "INTERCEPTOR";
5090     case MAP_TRANSITION: return "MAP_TRANSITION";
5091     case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
5092     case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
5093   }
5094   UNREACHABLE();
5095   return NULL;
5096 }
5097 
Disassemble(const char * name)5098 void Code::Disassemble(const char* name) {
5099   PrintF("kind = %s\n", Kind2String(kind()));
5100   if (is_inline_cache_stub()) {
5101     PrintF("ic_state = %s\n", ICState2String(ic_state()));
5102     PrintF("ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
5103     if (ic_state() == MONOMORPHIC) {
5104       PrintF("type = %s\n", PropertyType2String(type()));
5105     }
5106   }
5107   if ((name != NULL) && (name[0] != '\0')) {
5108     PrintF("name = %s\n", name);
5109   }
5110 
5111   PrintF("Instructions (size = %d)\n", instruction_size());
5112   Disassembler::Decode(NULL, this);
5113   PrintF("\n");
5114 
5115   PrintF("RelocInfo (size = %d)\n", relocation_size());
5116   for (RelocIterator it(this); !it.done(); it.next())
5117     it.rinfo()->Print();
5118   PrintF("\n");
5119 }
5120 #endif  // ENABLE_DISASSEMBLER
5121 
5122 
SetFastElements(FixedArray * elems)5123 void JSObject::SetFastElements(FixedArray* elems) {
5124   // We should never end in here with a pixel or external array.
5125   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
5126 #ifdef DEBUG
5127   // Check the provided array is filled with the_hole.
5128   uint32_t len = static_cast<uint32_t>(elems->length());
5129   for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole());
5130 #endif
5131   AssertNoAllocation no_gc;
5132   WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
5133   switch (GetElementsKind()) {
5134     case FAST_ELEMENTS: {
5135       FixedArray* old_elements = FixedArray::cast(elements());
5136       uint32_t old_length = static_cast<uint32_t>(old_elements->length());
5137       // Fill out the new array with this content and array holes.
5138       for (uint32_t i = 0; i < old_length; i++) {
5139         elems->set(i, old_elements->get(i), mode);
5140       }
5141       break;
5142     }
5143     case DICTIONARY_ELEMENTS: {
5144       NumberDictionary* dictionary = NumberDictionary::cast(elements());
5145       for (int i = 0; i < dictionary->Capacity(); i++) {
5146         Object* key = dictionary->KeyAt(i);
5147         if (key->IsNumber()) {
5148           uint32_t entry = static_cast<uint32_t>(key->Number());
5149           elems->set(entry, dictionary->ValueAt(i), mode);
5150         }
5151       }
5152       break;
5153     }
5154     default:
5155       UNREACHABLE();
5156       break;
5157   }
5158   set_elements(elems);
5159 }
5160 
5161 
SetSlowElements(Object * len)5162 Object* JSObject::SetSlowElements(Object* len) {
5163   // We should never end in here with a pixel or external array.
5164   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
5165 
5166   uint32_t new_length = static_cast<uint32_t>(len->Number());
5167 
5168   switch (GetElementsKind()) {
5169     case FAST_ELEMENTS: {
5170       // Make sure we never try to shrink dense arrays into sparse arrays.
5171       ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
5172                                    new_length);
5173       Object* obj = NormalizeElements();
5174       if (obj->IsFailure()) return obj;
5175 
5176       // Update length for JSArrays.
5177       if (IsJSArray()) JSArray::cast(this)->set_length(len);
5178       break;
5179     }
5180     case DICTIONARY_ELEMENTS: {
5181       if (IsJSArray()) {
5182         uint32_t old_length =
5183         static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
5184         element_dictionary()->RemoveNumberEntries(new_length, old_length),
5185         JSArray::cast(this)->set_length(len);
5186       }
5187       break;
5188     }
5189     default:
5190       UNREACHABLE();
5191       break;
5192   }
5193   return this;
5194 }
5195 
5196 
Initialize(int capacity)5197 Object* JSArray::Initialize(int capacity) {
5198   ASSERT(capacity >= 0);
5199   set_length(Smi::FromInt(0));
5200   FixedArray* new_elements;
5201   if (capacity == 0) {
5202     new_elements = Heap::empty_fixed_array();
5203   } else {
5204     Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
5205     if (obj->IsFailure()) return obj;
5206     new_elements = FixedArray::cast(obj);
5207   }
5208   set_elements(new_elements);
5209   return this;
5210 }
5211 
5212 
Expand(int required_size)5213 void JSArray::Expand(int required_size) {
5214   Handle<JSArray> self(this);
5215   Handle<FixedArray> old_backing(FixedArray::cast(elements()));
5216   int old_size = old_backing->length();
5217   int new_size = required_size > old_size ? required_size : old_size;
5218   Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size);
5219   // Can't use this any more now because we may have had a GC!
5220   for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
5221   self->SetContent(*new_backing);
5222 }
5223 
5224 
5225 // Computes the new capacity when expanding the elements of a JSObject.
NewElementsCapacity(int old_capacity)5226 static int NewElementsCapacity(int old_capacity) {
5227   // (old_capacity + 50%) + 16
5228   return old_capacity + (old_capacity >> 1) + 16;
5229 }
5230 
5231 
ArrayLengthRangeError()5232 static Object* ArrayLengthRangeError() {
5233   HandleScope scope;
5234   return Top::Throw(*Factory::NewRangeError("invalid_array_length",
5235                                             HandleVector<Object>(NULL, 0)));
5236 }
5237 
5238 
SetElementsLength(Object * len)5239 Object* JSObject::SetElementsLength(Object* len) {
5240   // We should never end in here with a pixel or external array.
5241   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
5242 
5243   Object* smi_length = len->ToSmi();
5244   if (smi_length->IsSmi()) {
5245     int value = Smi::cast(smi_length)->value();
5246     if (value < 0) return ArrayLengthRangeError();
5247     switch (GetElementsKind()) {
5248       case FAST_ELEMENTS: {
5249         int old_capacity = FixedArray::cast(elements())->length();
5250         if (value <= old_capacity) {
5251           if (IsJSArray()) {
5252             int old_length = FastD2I(JSArray::cast(this)->length()->Number());
5253             // NOTE: We may be able to optimize this by removing the
5254             // last part of the elements backing storage array and
5255             // setting the capacity to the new size.
5256             for (int i = value; i < old_length; i++) {
5257               FixedArray::cast(elements())->set_the_hole(i);
5258             }
5259             JSArray::cast(this)->set_length(Smi::cast(smi_length));
5260           }
5261           return this;
5262         }
5263         int min = NewElementsCapacity(old_capacity);
5264         int new_capacity = value > min ? value : min;
5265         if (new_capacity <= kMaxFastElementsLength ||
5266             !ShouldConvertToSlowElements(new_capacity)) {
5267           Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
5268           if (obj->IsFailure()) return obj;
5269           if (IsJSArray()) {
5270             JSArray::cast(this)->set_length(Smi::cast(smi_length));
5271           }
5272           SetFastElements(FixedArray::cast(obj));
5273           return this;
5274         }
5275         break;
5276       }
5277       case DICTIONARY_ELEMENTS: {
5278         if (IsJSArray()) {
5279           if (value == 0) {
5280             // If the length of a slow array is reset to zero, we clear
5281             // the array and flush backing storage. This has the added
5282             // benefit that the array returns to fast mode.
5283             initialize_elements();
5284           } else {
5285             // Remove deleted elements.
5286             uint32_t old_length =
5287             static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
5288             element_dictionary()->RemoveNumberEntries(value, old_length);
5289           }
5290           JSArray::cast(this)->set_length(Smi::cast(smi_length));
5291         }
5292         return this;
5293       }
5294       default:
5295         UNREACHABLE();
5296         break;
5297     }
5298   }
5299 
5300   // General slow case.
5301   if (len->IsNumber()) {
5302     uint32_t length;
5303     if (Array::IndexFromObject(len, &length)) {
5304       return SetSlowElements(len);
5305     } else {
5306       return ArrayLengthRangeError();
5307     }
5308   }
5309 
5310   // len is not a number so make the array size one and
5311   // set only element to len.
5312   Object* obj = Heap::AllocateFixedArray(1);
5313   if (obj->IsFailure()) return obj;
5314   FixedArray::cast(obj)->set(0, len);
5315   if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
5316   set_elements(FixedArray::cast(obj));
5317   return this;
5318 }
5319 
5320 
SetPrototype(Object * value,bool skip_hidden_prototypes)5321 Object* JSObject::SetPrototype(Object* value,
5322                                bool skip_hidden_prototypes) {
5323   // Silently ignore the change if value is not a JSObject or null.
5324   // SpiderMonkey behaves this way.
5325   if (!value->IsJSObject() && !value->IsNull()) return value;
5326 
5327   // Before we can set the prototype we need to be sure
5328   // prototype cycles are prevented.
5329   // It is sufficient to validate that the receiver is not in the new prototype
5330   // chain.
5331   for (Object* pt = value; pt != Heap::null_value(); pt = pt->GetPrototype()) {
5332     if (JSObject::cast(pt) == this) {
5333       // Cycle detected.
5334       HandleScope scope;
5335       return Top::Throw(*Factory::NewError("cyclic_proto",
5336                                            HandleVector<Object>(NULL, 0)));
5337     }
5338   }
5339 
5340   JSObject* real_receiver = this;
5341 
5342   if (skip_hidden_prototypes) {
5343     // Find the first object in the chain whose prototype object is not
5344     // hidden and set the new prototype on that object.
5345     Object* current_proto = real_receiver->GetPrototype();
5346     while (current_proto->IsJSObject() &&
5347           JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
5348       real_receiver = JSObject::cast(current_proto);
5349       current_proto = current_proto->GetPrototype();
5350     }
5351   }
5352 
5353   // Set the new prototype of the object.
5354   Object* new_map = real_receiver->map()->CopyDropTransitions();
5355   if (new_map->IsFailure()) return new_map;
5356   Map::cast(new_map)->set_prototype(value);
5357   real_receiver->set_map(Map::cast(new_map));
5358 
5359   return value;
5360 }
5361 
5362 
HasElementPostInterceptor(JSObject * receiver,uint32_t index)5363 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
5364   switch (GetElementsKind()) {
5365     case FAST_ELEMENTS: {
5366       uint32_t length = IsJSArray() ?
5367           static_cast<uint32_t>
5368               (Smi::cast(JSArray::cast(this)->length())->value()) :
5369           static_cast<uint32_t>(FixedArray::cast(elements())->length());
5370       if ((index < length) &&
5371           !FixedArray::cast(elements())->get(index)->IsTheHole()) {
5372         return true;
5373       }
5374       break;
5375     }
5376     case PIXEL_ELEMENTS: {
5377       // TODO(iposva): Add testcase.
5378       PixelArray* pixels = PixelArray::cast(elements());
5379       if (index < static_cast<uint32_t>(pixels->length())) {
5380         return true;
5381       }
5382       break;
5383     }
5384     case EXTERNAL_BYTE_ELEMENTS:
5385     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5386     case EXTERNAL_SHORT_ELEMENTS:
5387     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5388     case EXTERNAL_INT_ELEMENTS:
5389     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5390     case EXTERNAL_FLOAT_ELEMENTS: {
5391       // TODO(kbr): Add testcase.
5392       ExternalArray* array = ExternalArray::cast(elements());
5393       if (index < static_cast<uint32_t>(array->length())) {
5394         return true;
5395       }
5396       break;
5397     }
5398     case DICTIONARY_ELEMENTS: {
5399       if (element_dictionary()->FindEntry(index)
5400           != NumberDictionary::kNotFound) {
5401         return true;
5402       }
5403       break;
5404     }
5405     default:
5406       UNREACHABLE();
5407       break;
5408   }
5409 
5410   // Handle [] on String objects.
5411   if (this->IsStringObjectWithCharacterAt(index)) return true;
5412 
5413   Object* pt = GetPrototype();
5414   if (pt == Heap::null_value()) return false;
5415   return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
5416 }
5417 
5418 
HasElementWithInterceptor(JSObject * receiver,uint32_t index)5419 bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
5420   // Make sure that the top context does not change when doing
5421   // callbacks or interceptor calls.
5422   AssertNoContextChange ncc;
5423   HandleScope scope;
5424   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
5425   Handle<JSObject> receiver_handle(receiver);
5426   Handle<JSObject> holder_handle(this);
5427   CustomArguments args(interceptor->data(), receiver, this);
5428   v8::AccessorInfo info(args.end());
5429   if (!interceptor->query()->IsUndefined()) {
5430     v8::IndexedPropertyQuery query =
5431         v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
5432     LOG(ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
5433     v8::Handle<v8::Boolean> result;
5434     {
5435       // Leaving JavaScript.
5436       VMState state(EXTERNAL);
5437       result = query(index, info);
5438     }
5439     if (!result.IsEmpty()) return result->IsTrue();
5440   } else if (!interceptor->getter()->IsUndefined()) {
5441     v8::IndexedPropertyGetter getter =
5442         v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
5443     LOG(ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
5444     v8::Handle<v8::Value> result;
5445     {
5446       // Leaving JavaScript.
5447       VMState state(EXTERNAL);
5448       result = getter(index, info);
5449     }
5450     if (!result.IsEmpty()) return true;
5451   }
5452   return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
5453 }
5454 
5455 
HasLocalElement(uint32_t index)5456 bool JSObject::HasLocalElement(uint32_t index) {
5457   // Check access rights if needed.
5458   if (IsAccessCheckNeeded() &&
5459       !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
5460     Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
5461     return false;
5462   }
5463 
5464   // Check for lookup interceptor
5465   if (HasIndexedInterceptor()) {
5466     return HasElementWithInterceptor(this, index);
5467   }
5468 
5469   // Handle [] on String objects.
5470   if (this->IsStringObjectWithCharacterAt(index)) return true;
5471 
5472   switch (GetElementsKind()) {
5473     case FAST_ELEMENTS: {
5474       uint32_t length = IsJSArray() ?
5475           static_cast<uint32_t>
5476               (Smi::cast(JSArray::cast(this)->length())->value()) :
5477           static_cast<uint32_t>(FixedArray::cast(elements())->length());
5478       return (index < length) &&
5479           !FixedArray::cast(elements())->get(index)->IsTheHole();
5480     }
5481     case PIXEL_ELEMENTS: {
5482       PixelArray* pixels = PixelArray::cast(elements());
5483       return (index < static_cast<uint32_t>(pixels->length()));
5484     }
5485     case EXTERNAL_BYTE_ELEMENTS:
5486     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5487     case EXTERNAL_SHORT_ELEMENTS:
5488     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5489     case EXTERNAL_INT_ELEMENTS:
5490     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5491     case EXTERNAL_FLOAT_ELEMENTS: {
5492       ExternalArray* array = ExternalArray::cast(elements());
5493       return (index < static_cast<uint32_t>(array->length()));
5494     }
5495     case DICTIONARY_ELEMENTS: {
5496       return element_dictionary()->FindEntry(index)
5497           != NumberDictionary::kNotFound;
5498     }
5499     default:
5500       UNREACHABLE();
5501       break;
5502   }
5503   UNREACHABLE();
5504   return Heap::null_value();
5505 }
5506 
5507 
HasElementWithReceiver(JSObject * receiver,uint32_t index)5508 bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
5509   // Check access rights if needed.
5510   if (IsAccessCheckNeeded() &&
5511       !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
5512     Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
5513     return false;
5514   }
5515 
5516   // Check for lookup interceptor
5517   if (HasIndexedInterceptor()) {
5518     return HasElementWithInterceptor(receiver, index);
5519   }
5520 
5521   switch (GetElementsKind()) {
5522     case FAST_ELEMENTS: {
5523       uint32_t length = IsJSArray() ?
5524           static_cast<uint32_t>
5525               (Smi::cast(JSArray::cast(this)->length())->value()) :
5526           static_cast<uint32_t>(FixedArray::cast(elements())->length());
5527       if ((index < length) &&
5528           !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
5529       break;
5530     }
5531     case PIXEL_ELEMENTS: {
5532       PixelArray* pixels = PixelArray::cast(elements());
5533       if (index < static_cast<uint32_t>(pixels->length())) {
5534         return true;
5535       }
5536       break;
5537     }
5538     case EXTERNAL_BYTE_ELEMENTS:
5539     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5540     case EXTERNAL_SHORT_ELEMENTS:
5541     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5542     case EXTERNAL_INT_ELEMENTS:
5543     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5544     case EXTERNAL_FLOAT_ELEMENTS: {
5545       ExternalArray* array = ExternalArray::cast(elements());
5546       if (index < static_cast<uint32_t>(array->length())) {
5547         return true;
5548       }
5549       break;
5550     }
5551     case DICTIONARY_ELEMENTS: {
5552       if (element_dictionary()->FindEntry(index)
5553           != NumberDictionary::kNotFound) {
5554         return true;
5555       }
5556       break;
5557     }
5558     default:
5559       UNREACHABLE();
5560       break;
5561   }
5562 
5563   // Handle [] on String objects.
5564   if (this->IsStringObjectWithCharacterAt(index)) return true;
5565 
5566   Object* pt = GetPrototype();
5567   if (pt == Heap::null_value()) return false;
5568   return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
5569 }
5570 
5571 
SetElementWithInterceptor(uint32_t index,Object * value)5572 Object* JSObject::SetElementWithInterceptor(uint32_t index, Object* value) {
5573   // Make sure that the top context does not change when doing
5574   // callbacks or interceptor calls.
5575   AssertNoContextChange ncc;
5576   HandleScope scope;
5577   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
5578   Handle<JSObject> this_handle(this);
5579   Handle<Object> value_handle(value);
5580   if (!interceptor->setter()->IsUndefined()) {
5581     v8::IndexedPropertySetter setter =
5582         v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
5583     LOG(ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
5584     CustomArguments args(interceptor->data(), this, this);
5585     v8::AccessorInfo info(args.end());
5586     v8::Handle<v8::Value> result;
5587     {
5588       // Leaving JavaScript.
5589       VMState state(EXTERNAL);
5590       result = setter(index, v8::Utils::ToLocal(value_handle), info);
5591     }
5592     RETURN_IF_SCHEDULED_EXCEPTION();
5593     if (!result.IsEmpty()) return *value_handle;
5594   }
5595   Object* raw_result =
5596       this_handle->SetElementWithoutInterceptor(index, *value_handle);
5597   RETURN_IF_SCHEDULED_EXCEPTION();
5598   return raw_result;
5599 }
5600 
5601 
5602 // Adding n elements in fast case is O(n*n).
5603 // Note: revisit design to have dual undefined values to capture absent
5604 // elements.
SetFastElement(uint32_t index,Object * value)5605 Object* JSObject::SetFastElement(uint32_t index, Object* value) {
5606   ASSERT(HasFastElements());
5607 
5608   FixedArray* elms = FixedArray::cast(elements());
5609   uint32_t elms_length = static_cast<uint32_t>(elms->length());
5610 
5611   if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) {
5612     Object* setter = LookupCallbackSetterInPrototypes(index);
5613     if (setter->IsJSFunction()) {
5614       return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
5615     }
5616   }
5617 
5618   // Check whether there is extra space in fixed array..
5619   if (index < elms_length) {
5620     elms->set(index, value);
5621     if (IsJSArray()) {
5622       // Update the length of the array if needed.
5623       uint32_t array_length = 0;
5624       CHECK(Array::IndexFromObject(JSArray::cast(this)->length(),
5625                                    &array_length));
5626       if (index >= array_length) {
5627         JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
5628       }
5629     }
5630     return value;
5631   }
5632 
5633   // Allow gap in fast case.
5634   if ((index - elms_length) < kMaxGap) {
5635     // Try allocating extra space.
5636     int new_capacity = NewElementsCapacity(index+1);
5637     if (new_capacity <= kMaxFastElementsLength ||
5638         !ShouldConvertToSlowElements(new_capacity)) {
5639       ASSERT(static_cast<uint32_t>(new_capacity) > index);
5640       Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
5641       if (obj->IsFailure()) return obj;
5642       SetFastElements(FixedArray::cast(obj));
5643       if (IsJSArray()) {
5644         JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
5645       }
5646       FixedArray::cast(elements())->set(index, value);
5647       return value;
5648     }
5649   }
5650 
5651   // Otherwise default to slow case.
5652   Object* obj = NormalizeElements();
5653   if (obj->IsFailure()) return obj;
5654   ASSERT(HasDictionaryElements());
5655   return SetElement(index, value);
5656 }
5657 
SetElement(uint32_t index,Object * value)5658 Object* JSObject::SetElement(uint32_t index, Object* value) {
5659   // Check access rights if needed.
5660   if (IsAccessCheckNeeded() &&
5661       !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) {
5662     Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
5663     return value;
5664   }
5665 
5666   if (IsJSGlobalProxy()) {
5667     Object* proto = GetPrototype();
5668     if (proto->IsNull()) return value;
5669     ASSERT(proto->IsJSGlobalObject());
5670     return JSObject::cast(proto)->SetElement(index, value);
5671   }
5672 
5673   // Check for lookup interceptor
5674   if (HasIndexedInterceptor()) {
5675     return SetElementWithInterceptor(index, value);
5676   }
5677 
5678   return SetElementWithoutInterceptor(index, value);
5679 }
5680 
5681 
SetElementWithoutInterceptor(uint32_t index,Object * value)5682 Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) {
5683   switch (GetElementsKind()) {
5684     case FAST_ELEMENTS:
5685       // Fast case.
5686       return SetFastElement(index, value);
5687     case PIXEL_ELEMENTS: {
5688       PixelArray* pixels = PixelArray::cast(elements());
5689       return pixels->SetValue(index, value);
5690     }
5691     case EXTERNAL_BYTE_ELEMENTS: {
5692       ExternalByteArray* array = ExternalByteArray::cast(elements());
5693       return array->SetValue(index, value);
5694     }
5695     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
5696       ExternalUnsignedByteArray* array =
5697           ExternalUnsignedByteArray::cast(elements());
5698       return array->SetValue(index, value);
5699     }
5700     case EXTERNAL_SHORT_ELEMENTS: {
5701       ExternalShortArray* array = ExternalShortArray::cast(elements());
5702       return array->SetValue(index, value);
5703     }
5704     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
5705       ExternalUnsignedShortArray* array =
5706           ExternalUnsignedShortArray::cast(elements());
5707       return array->SetValue(index, value);
5708     }
5709     case EXTERNAL_INT_ELEMENTS: {
5710       ExternalIntArray* array = ExternalIntArray::cast(elements());
5711       return array->SetValue(index, value);
5712     }
5713     case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
5714       ExternalUnsignedIntArray* array =
5715           ExternalUnsignedIntArray::cast(elements());
5716       return array->SetValue(index, value);
5717     }
5718     case EXTERNAL_FLOAT_ELEMENTS: {
5719       ExternalFloatArray* array = ExternalFloatArray::cast(elements());
5720       return array->SetValue(index, value);
5721     }
5722     case DICTIONARY_ELEMENTS: {
5723       // Insert element in the dictionary.
5724       FixedArray* elms = FixedArray::cast(elements());
5725       NumberDictionary* dictionary = NumberDictionary::cast(elms);
5726 
5727       int entry = dictionary->FindEntry(index);
5728       if (entry != NumberDictionary::kNotFound) {
5729         Object* element = dictionary->ValueAt(entry);
5730         PropertyDetails details = dictionary->DetailsAt(entry);
5731         if (details.type() == CALLBACKS) {
5732           // Only accessors allowed as elements.
5733           FixedArray* structure = FixedArray::cast(element);
5734           if (structure->get(kSetterIndex)->IsJSFunction()) {
5735             JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex));
5736             return SetPropertyWithDefinedSetter(setter, value);
5737           } else {
5738             Handle<Object> self(this);
5739             Handle<Object> key(Factory::NewNumberFromUint(index));
5740             Handle<Object> args[2] = { key, self };
5741             return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
5742                                                      HandleVector(args, 2)));
5743           }
5744         } else {
5745           dictionary->UpdateMaxNumberKey(index);
5746           dictionary->ValueAtPut(entry, value);
5747         }
5748       } else {
5749         // Index not already used. Look for an accessor in the prototype chain.
5750         if (!IsJSArray()) {
5751           Object* setter = LookupCallbackSetterInPrototypes(index);
5752           if (setter->IsJSFunction()) {
5753             return SetPropertyWithDefinedSetter(JSFunction::cast(setter),
5754                                                 value);
5755           }
5756         }
5757         Object* result = dictionary->AtNumberPut(index, value);
5758         if (result->IsFailure()) return result;
5759         if (elms != FixedArray::cast(result)) {
5760           set_elements(FixedArray::cast(result));
5761         }
5762       }
5763 
5764       // Update the array length if this JSObject is an array.
5765       if (IsJSArray()) {
5766         JSArray* array = JSArray::cast(this);
5767         Object* return_value = array->JSArrayUpdateLengthFromIndex(index,
5768                                                                    value);
5769         if (return_value->IsFailure()) return return_value;
5770       }
5771 
5772       // Attempt to put this object back in fast case.
5773       if (ShouldConvertToFastElements()) {
5774         uint32_t new_length = 0;
5775         if (IsJSArray()) {
5776           CHECK(Array::IndexFromObject(JSArray::cast(this)->length(),
5777                                        &new_length));
5778           JSArray::cast(this)->set_length(Smi::FromInt(new_length));
5779         } else {
5780           new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
5781         }
5782         Object* obj = Heap::AllocateFixedArrayWithHoles(new_length);
5783         if (obj->IsFailure()) return obj;
5784         SetFastElements(FixedArray::cast(obj));
5785 #ifdef DEBUG
5786         if (FLAG_trace_normalization) {
5787           PrintF("Object elements are fast case again:\n");
5788           Print();
5789         }
5790 #endif
5791       }
5792 
5793       return value;
5794     }
5795     default:
5796       UNREACHABLE();
5797       break;
5798   }
5799   // All possible cases have been handled above. Add a return to avoid the
5800   // complaints from the compiler.
5801   UNREACHABLE();
5802   return Heap::null_value();
5803 }
5804 
5805 
JSArrayUpdateLengthFromIndex(uint32_t index,Object * value)5806 Object* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) {
5807   uint32_t old_len = 0;
5808   CHECK(Array::IndexFromObject(length(), &old_len));
5809   // Check to see if we need to update the length. For now, we make
5810   // sure that the length stays within 32-bits (unsigned).
5811   if (index >= old_len && index != 0xffffffff) {
5812     Object* len =
5813         Heap::NumberFromDouble(static_cast<double>(index) + 1);
5814     if (len->IsFailure()) return len;
5815     set_length(len);
5816   }
5817   return value;
5818 }
5819 
5820 
GetElementPostInterceptor(JSObject * receiver,uint32_t index)5821 Object* JSObject::GetElementPostInterceptor(JSObject* receiver,
5822                                             uint32_t index) {
5823   // Get element works for both JSObject and JSArray since
5824   // JSArray::length cannot change.
5825   switch (GetElementsKind()) {
5826     case FAST_ELEMENTS: {
5827       FixedArray* elms = FixedArray::cast(elements());
5828       if (index < static_cast<uint32_t>(elms->length())) {
5829         Object* value = elms->get(index);
5830         if (!value->IsTheHole()) return value;
5831       }
5832       break;
5833     }
5834     case PIXEL_ELEMENTS: {
5835       // TODO(iposva): Add testcase and implement.
5836       UNIMPLEMENTED();
5837       break;
5838     }
5839     case EXTERNAL_BYTE_ELEMENTS:
5840     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5841     case EXTERNAL_SHORT_ELEMENTS:
5842     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5843     case EXTERNAL_INT_ELEMENTS:
5844     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5845     case EXTERNAL_FLOAT_ELEMENTS: {
5846       // TODO(kbr): Add testcase and implement.
5847       UNIMPLEMENTED();
5848       break;
5849     }
5850     case DICTIONARY_ELEMENTS: {
5851       NumberDictionary* dictionary = element_dictionary();
5852       int entry = dictionary->FindEntry(index);
5853       if (entry != NumberDictionary::kNotFound) {
5854         Object* element = dictionary->ValueAt(entry);
5855         PropertyDetails details = dictionary->DetailsAt(entry);
5856         if (details.type() == CALLBACKS) {
5857           // Only accessors allowed as elements.
5858           FixedArray* structure = FixedArray::cast(element);
5859           Object* getter = structure->get(kGetterIndex);
5860           if (getter->IsJSFunction()) {
5861             return GetPropertyWithDefinedGetter(receiver,
5862                                                 JSFunction::cast(getter));
5863           } else {
5864             // Getter is not a function.
5865             return Heap::undefined_value();
5866           }
5867         }
5868         return element;
5869       }
5870       break;
5871     }
5872     default:
5873       UNREACHABLE();
5874       break;
5875   }
5876 
5877   // Continue searching via the prototype chain.
5878   Object* pt = GetPrototype();
5879   if (pt == Heap::null_value()) return Heap::undefined_value();
5880   return pt->GetElementWithReceiver(receiver, index);
5881 }
5882 
5883 
GetElementWithInterceptor(JSObject * receiver,uint32_t index)5884 Object* JSObject::GetElementWithInterceptor(JSObject* receiver,
5885                                             uint32_t index) {
5886   // Make sure that the top context does not change when doing
5887   // callbacks or interceptor calls.
5888   AssertNoContextChange ncc;
5889   HandleScope scope;
5890   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
5891   Handle<JSObject> this_handle(receiver);
5892   Handle<JSObject> holder_handle(this);
5893 
5894   if (!interceptor->getter()->IsUndefined()) {
5895     v8::IndexedPropertyGetter getter =
5896         v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
5897     LOG(ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
5898     CustomArguments args(interceptor->data(), receiver, this);
5899     v8::AccessorInfo info(args.end());
5900     v8::Handle<v8::Value> result;
5901     {
5902       // Leaving JavaScript.
5903       VMState state(EXTERNAL);
5904       result = getter(index, info);
5905     }
5906     RETURN_IF_SCHEDULED_EXCEPTION();
5907     if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5908   }
5909 
5910   Object* raw_result =
5911       holder_handle->GetElementPostInterceptor(*this_handle, index);
5912   RETURN_IF_SCHEDULED_EXCEPTION();
5913   return raw_result;
5914 }
5915 
5916 
GetElementWithReceiver(JSObject * receiver,uint32_t index)5917 Object* JSObject::GetElementWithReceiver(JSObject* receiver, uint32_t index) {
5918   // Check access rights if needed.
5919   if (IsAccessCheckNeeded() &&
5920       !Top::MayIndexedAccess(this, index, v8::ACCESS_GET)) {
5921     Top::ReportFailedAccessCheck(this, v8::ACCESS_GET);
5922     return Heap::undefined_value();
5923   }
5924 
5925   if (HasIndexedInterceptor()) {
5926     return GetElementWithInterceptor(receiver, index);
5927   }
5928 
5929   // Get element works for both JSObject and JSArray since
5930   // JSArray::length cannot change.
5931   switch (GetElementsKind()) {
5932     case FAST_ELEMENTS: {
5933       FixedArray* elms = FixedArray::cast(elements());
5934       if (index < static_cast<uint32_t>(elms->length())) {
5935         Object* value = elms->get(index);
5936         if (!value->IsTheHole()) return value;
5937       }
5938       break;
5939     }
5940     case PIXEL_ELEMENTS: {
5941       PixelArray* pixels = PixelArray::cast(elements());
5942       if (index < static_cast<uint32_t>(pixels->length())) {
5943         uint8_t value = pixels->get(index);
5944         return Smi::FromInt(value);
5945       }
5946       break;
5947     }
5948     case EXTERNAL_BYTE_ELEMENTS: {
5949       ExternalByteArray* array = ExternalByteArray::cast(elements());
5950       if (index < static_cast<uint32_t>(array->length())) {
5951         int8_t value = array->get(index);
5952         return Smi::FromInt(value);
5953       }
5954       break;
5955     }
5956     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
5957       ExternalUnsignedByteArray* array =
5958           ExternalUnsignedByteArray::cast(elements());
5959       if (index < static_cast<uint32_t>(array->length())) {
5960         uint8_t value = array->get(index);
5961         return Smi::FromInt(value);
5962       }
5963       break;
5964     }
5965     case EXTERNAL_SHORT_ELEMENTS: {
5966       ExternalShortArray* array = ExternalShortArray::cast(elements());
5967       if (index < static_cast<uint32_t>(array->length())) {
5968         int16_t value = array->get(index);
5969         return Smi::FromInt(value);
5970       }
5971       break;
5972     }
5973     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
5974       ExternalUnsignedShortArray* array =
5975           ExternalUnsignedShortArray::cast(elements());
5976       if (index < static_cast<uint32_t>(array->length())) {
5977         uint16_t value = array->get(index);
5978         return Smi::FromInt(value);
5979       }
5980       break;
5981     }
5982     case EXTERNAL_INT_ELEMENTS: {
5983       ExternalIntArray* array = ExternalIntArray::cast(elements());
5984       if (index < static_cast<uint32_t>(array->length())) {
5985         int32_t value = array->get(index);
5986         return Heap::NumberFromInt32(value);
5987       }
5988       break;
5989     }
5990     case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
5991       ExternalUnsignedIntArray* array =
5992           ExternalUnsignedIntArray::cast(elements());
5993       if (index < static_cast<uint32_t>(array->length())) {
5994         uint32_t value = array->get(index);
5995         return Heap::NumberFromUint32(value);
5996       }
5997       break;
5998     }
5999     case EXTERNAL_FLOAT_ELEMENTS: {
6000       ExternalFloatArray* array = ExternalFloatArray::cast(elements());
6001       if (index < static_cast<uint32_t>(array->length())) {
6002         float value = array->get(index);
6003         return Heap::AllocateHeapNumber(value);
6004       }
6005       break;
6006     }
6007     case DICTIONARY_ELEMENTS: {
6008       NumberDictionary* dictionary = element_dictionary();
6009       int entry = dictionary->FindEntry(index);
6010       if (entry != NumberDictionary::kNotFound) {
6011         Object* element = dictionary->ValueAt(entry);
6012         PropertyDetails details = dictionary->DetailsAt(entry);
6013         if (details.type() == CALLBACKS) {
6014           // Only accessors allowed as elements.
6015           FixedArray* structure = FixedArray::cast(element);
6016           Object* getter = structure->get(kGetterIndex);
6017           if (getter->IsJSFunction()) {
6018             return GetPropertyWithDefinedGetter(receiver,
6019                                                 JSFunction::cast(getter));
6020           } else {
6021             // Getter is not a function.
6022             return Heap::undefined_value();
6023           }
6024         }
6025         return element;
6026       }
6027       break;
6028     }
6029   }
6030 
6031   Object* pt = GetPrototype();
6032   if (pt == Heap::null_value()) return Heap::undefined_value();
6033   return pt->GetElementWithReceiver(receiver, index);
6034 }
6035 
6036 
HasDenseElements()6037 bool JSObject::HasDenseElements() {
6038   int capacity = 0;
6039   int number_of_elements = 0;
6040 
6041   switch (GetElementsKind()) {
6042     case FAST_ELEMENTS: {
6043       FixedArray* elms = FixedArray::cast(elements());
6044       capacity = elms->length();
6045       for (int i = 0; i < capacity; i++) {
6046         if (!elms->get(i)->IsTheHole()) number_of_elements++;
6047       }
6048       break;
6049     }
6050     case PIXEL_ELEMENTS:
6051     case EXTERNAL_BYTE_ELEMENTS:
6052     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6053     case EXTERNAL_SHORT_ELEMENTS:
6054     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6055     case EXTERNAL_INT_ELEMENTS:
6056     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6057     case EXTERNAL_FLOAT_ELEMENTS: {
6058       return true;
6059     }
6060     case DICTIONARY_ELEMENTS: {
6061       NumberDictionary* dictionary = NumberDictionary::cast(elements());
6062       capacity = dictionary->Capacity();
6063       number_of_elements = dictionary->NumberOfElements();
6064       break;
6065     }
6066     default:
6067       UNREACHABLE();
6068       break;
6069   }
6070 
6071   if (capacity == 0) return true;
6072   return (number_of_elements > (capacity / 2));
6073 }
6074 
6075 
ShouldConvertToSlowElements(int new_capacity)6076 bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
6077   ASSERT(HasFastElements());
6078   // Keep the array in fast case if the current backing storage is
6079   // almost filled and if the new capacity is no more than twice the
6080   // old capacity.
6081   int elements_length = FixedArray::cast(elements())->length();
6082   return !HasDenseElements() || ((new_capacity / 2) > elements_length);
6083 }
6084 
6085 
ShouldConvertToFastElements()6086 bool JSObject::ShouldConvertToFastElements() {
6087   ASSERT(HasDictionaryElements());
6088   NumberDictionary* dictionary = NumberDictionary::cast(elements());
6089   // If the elements are sparse, we should not go back to fast case.
6090   if (!HasDenseElements()) return false;
6091   // If an element has been added at a very high index in the elements
6092   // dictionary, we cannot go back to fast case.
6093   if (dictionary->requires_slow_elements()) return false;
6094   // An object requiring access checks is never allowed to have fast
6095   // elements.  If it had fast elements we would skip security checks.
6096   if (IsAccessCheckNeeded()) return false;
6097   // If the dictionary backing storage takes up roughly half as much
6098   // space as a fast-case backing storage would the array should have
6099   // fast elements.
6100   uint32_t length = 0;
6101   if (IsJSArray()) {
6102     CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &length));
6103   } else {
6104     length = dictionary->max_number_key();
6105   }
6106   return static_cast<uint32_t>(dictionary->Capacity()) >=
6107       (length / (2 * NumberDictionary::kEntrySize));
6108 }
6109 
6110 
6111 // Certain compilers request function template instantiation when they
6112 // see the definition of the other template functions in the
6113 // class. This requires us to have the template functions put
6114 // together, so even though this function belongs in objects-debug.cc,
6115 // we keep it here instead to satisfy certain compilers.
6116 #ifdef DEBUG
6117 template<typename Shape, typename Key>
Print()6118 void Dictionary<Shape, Key>::Print() {
6119   int capacity = HashTable<Shape, Key>::Capacity();
6120   for (int i = 0; i < capacity; i++) {
6121     Object* k = HashTable<Shape, Key>::KeyAt(i);
6122     if (HashTable<Shape, Key>::IsKey(k)) {
6123       PrintF(" ");
6124       if (k->IsString()) {
6125         String::cast(k)->StringPrint();
6126       } else {
6127         k->ShortPrint();
6128       }
6129       PrintF(": ");
6130       ValueAt(i)->ShortPrint();
6131       PrintF("\n");
6132     }
6133   }
6134 }
6135 #endif
6136 
6137 
6138 template<typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)6139 void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
6140   int pos = 0;
6141   int capacity = HashTable<Shape, Key>::Capacity();
6142   AssertNoAllocation no_gc;
6143   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
6144   for (int i = 0; i < capacity; i++) {
6145     Object* k =  Dictionary<Shape, Key>::KeyAt(i);
6146     if (Dictionary<Shape, Key>::IsKey(k)) {
6147       elements->set(pos++, ValueAt(i), mode);
6148     }
6149   }
6150   ASSERT(pos == elements->length());
6151 }
6152 
6153 
GetNamedInterceptor()6154 InterceptorInfo* JSObject::GetNamedInterceptor() {
6155   ASSERT(map()->has_named_interceptor());
6156   JSFunction* constructor = JSFunction::cast(map()->constructor());
6157   Object* template_info = constructor->shared()->function_data();
6158   Object* result =
6159       FunctionTemplateInfo::cast(template_info)->named_property_handler();
6160   return InterceptorInfo::cast(result);
6161 }
6162 
6163 
GetIndexedInterceptor()6164 InterceptorInfo* JSObject::GetIndexedInterceptor() {
6165   ASSERT(map()->has_indexed_interceptor());
6166   JSFunction* constructor = JSFunction::cast(map()->constructor());
6167   Object* template_info = constructor->shared()->function_data();
6168   Object* result =
6169       FunctionTemplateInfo::cast(template_info)->indexed_property_handler();
6170   return InterceptorInfo::cast(result);
6171 }
6172 
6173 
GetPropertyPostInterceptor(JSObject * receiver,String * name,PropertyAttributes * attributes)6174 Object* JSObject::GetPropertyPostInterceptor(JSObject* receiver,
6175                                              String* name,
6176                                              PropertyAttributes* attributes) {
6177   // Check local property in holder, ignore interceptor.
6178   LookupResult result;
6179   LocalLookupRealNamedProperty(name, &result);
6180   if (result.IsProperty()) {
6181     return GetProperty(receiver, &result, name, attributes);
6182   }
6183   // Continue searching via the prototype chain.
6184   Object* pt = GetPrototype();
6185   *attributes = ABSENT;
6186   if (pt == Heap::null_value()) return Heap::undefined_value();
6187   return pt->GetPropertyWithReceiver(receiver, name, attributes);
6188 }
6189 
6190 
GetLocalPropertyPostInterceptor(JSObject * receiver,String * name,PropertyAttributes * attributes)6191 Object* JSObject::GetLocalPropertyPostInterceptor(
6192     JSObject* receiver,
6193     String* name,
6194     PropertyAttributes* attributes) {
6195   // Check local property in holder, ignore interceptor.
6196   LookupResult result;
6197   LocalLookupRealNamedProperty(name, &result);
6198   if (result.IsProperty()) {
6199     return GetProperty(receiver, &result, name, attributes);
6200   }
6201   return Heap::undefined_value();
6202 }
6203 
6204 
GetPropertyWithInterceptor(JSObject * receiver,String * name,PropertyAttributes * attributes)6205 Object* JSObject::GetPropertyWithInterceptor(
6206     JSObject* receiver,
6207     String* name,
6208     PropertyAttributes* attributes) {
6209   InterceptorInfo* interceptor = GetNamedInterceptor();
6210   HandleScope scope;
6211   Handle<JSObject> receiver_handle(receiver);
6212   Handle<JSObject> holder_handle(this);
6213   Handle<String> name_handle(name);
6214 
6215   if (!interceptor->getter()->IsUndefined()) {
6216     v8::NamedPropertyGetter getter =
6217         v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
6218     LOG(ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
6219     CustomArguments args(interceptor->data(), receiver, this);
6220     v8::AccessorInfo info(args.end());
6221     v8::Handle<v8::Value> result;
6222     {
6223       // Leaving JavaScript.
6224       VMState state(EXTERNAL);
6225       result = getter(v8::Utils::ToLocal(name_handle), info);
6226     }
6227     RETURN_IF_SCHEDULED_EXCEPTION();
6228     if (!result.IsEmpty()) {
6229       *attributes = NONE;
6230       return *v8::Utils::OpenHandle(*result);
6231     }
6232   }
6233 
6234   Object* result = holder_handle->GetPropertyPostInterceptor(
6235       *receiver_handle,
6236       *name_handle,
6237       attributes);
6238   RETURN_IF_SCHEDULED_EXCEPTION();
6239   return result;
6240 }
6241 
6242 
HasRealNamedProperty(String * key)6243 bool JSObject::HasRealNamedProperty(String* key) {
6244   // Check access rights if needed.
6245   if (IsAccessCheckNeeded() &&
6246       !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
6247     Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
6248     return false;
6249   }
6250 
6251   LookupResult result;
6252   LocalLookupRealNamedProperty(key, &result);
6253   return result.IsProperty() && (result.type() != INTERCEPTOR);
6254 }
6255 
6256 
HasRealElementProperty(uint32_t index)6257 bool JSObject::HasRealElementProperty(uint32_t index) {
6258   // Check access rights if needed.
6259   if (IsAccessCheckNeeded() &&
6260       !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
6261     Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
6262     return false;
6263   }
6264 
6265   // Handle [] on String objects.
6266   if (this->IsStringObjectWithCharacterAt(index)) return true;
6267 
6268   switch (GetElementsKind()) {
6269     case FAST_ELEMENTS: {
6270       uint32_t length = IsJSArray() ?
6271           static_cast<uint32_t>(
6272               Smi::cast(JSArray::cast(this)->length())->value()) :
6273           static_cast<uint32_t>(FixedArray::cast(elements())->length());
6274       return (index < length) &&
6275           !FixedArray::cast(elements())->get(index)->IsTheHole();
6276     }
6277     case PIXEL_ELEMENTS: {
6278       PixelArray* pixels = PixelArray::cast(elements());
6279       return index < static_cast<uint32_t>(pixels->length());
6280     }
6281     case EXTERNAL_BYTE_ELEMENTS:
6282     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6283     case EXTERNAL_SHORT_ELEMENTS:
6284     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6285     case EXTERNAL_INT_ELEMENTS:
6286     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6287     case EXTERNAL_FLOAT_ELEMENTS: {
6288       ExternalArray* array = ExternalArray::cast(elements());
6289       return index < static_cast<uint32_t>(array->length());
6290     }
6291     case DICTIONARY_ELEMENTS: {
6292       return element_dictionary()->FindEntry(index)
6293           != NumberDictionary::kNotFound;
6294     }
6295     default:
6296       UNREACHABLE();
6297       break;
6298   }
6299   // All possibilities have been handled above already.
6300   UNREACHABLE();
6301   return Heap::null_value();
6302 }
6303 
6304 
HasRealNamedCallbackProperty(String * key)6305 bool JSObject::HasRealNamedCallbackProperty(String* key) {
6306   // Check access rights if needed.
6307   if (IsAccessCheckNeeded() &&
6308       !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) {
6309     Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
6310     return false;
6311   }
6312 
6313   LookupResult result;
6314   LocalLookupRealNamedProperty(key, &result);
6315   return result.IsProperty() && (result.type() == CALLBACKS);
6316 }
6317 
6318 
NumberOfLocalProperties(PropertyAttributes filter)6319 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
6320   if (HasFastProperties()) {
6321     DescriptorArray* descs = map()->instance_descriptors();
6322     int result = 0;
6323     for (int i = 0; i < descs->number_of_descriptors(); i++) {
6324       PropertyDetails details = descs->GetDetails(i);
6325       if (details.IsProperty() && (details.attributes() & filter) == 0) {
6326         result++;
6327       }
6328     }
6329     return result;
6330   } else {
6331     return property_dictionary()->NumberOfElementsFilterAttributes(filter);
6332   }
6333 }
6334 
6335 
NumberOfEnumProperties()6336 int JSObject::NumberOfEnumProperties() {
6337   return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
6338 }
6339 
6340 
SwapPairs(FixedArray * numbers,int i,int j)6341 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
6342   Object* temp = get(i);
6343   set(i, get(j));
6344   set(j, temp);
6345   if (this != numbers) {
6346     temp = numbers->get(i);
6347     numbers->set(i, numbers->get(j));
6348     numbers->set(j, temp);
6349   }
6350 }
6351 
6352 
InsertionSortPairs(FixedArray * content,FixedArray * numbers,int len)6353 static void InsertionSortPairs(FixedArray* content,
6354                                FixedArray* numbers,
6355                                int len) {
6356   for (int i = 1; i < len; i++) {
6357     int j = i;
6358     while (j > 0 &&
6359            (NumberToUint32(numbers->get(j - 1)) >
6360             NumberToUint32(numbers->get(j)))) {
6361       content->SwapPairs(numbers, j - 1, j);
6362       j--;
6363     }
6364   }
6365 }
6366 
6367 
HeapSortPairs(FixedArray * content,FixedArray * numbers,int len)6368 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
6369   // In-place heap sort.
6370   ASSERT(content->length() == numbers->length());
6371 
6372   // Bottom-up max-heap construction.
6373   for (int i = 1; i < len; ++i) {
6374     int child_index = i;
6375     while (child_index > 0) {
6376       int parent_index = ((child_index + 1) >> 1) - 1;
6377       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
6378       uint32_t child_value = NumberToUint32(numbers->get(child_index));
6379       if (parent_value < child_value) {
6380         content->SwapPairs(numbers, parent_index, child_index);
6381       } else {
6382         break;
6383       }
6384       child_index = parent_index;
6385     }
6386   }
6387 
6388   // Extract elements and create sorted array.
6389   for (int i = len - 1; i > 0; --i) {
6390     // Put max element at the back of the array.
6391     content->SwapPairs(numbers, 0, i);
6392     // Sift down the new top element.
6393     int parent_index = 0;
6394     while (true) {
6395       int child_index = ((parent_index + 1) << 1) - 1;
6396       if (child_index >= i) break;
6397       uint32_t child1_value = NumberToUint32(numbers->get(child_index));
6398       uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
6399       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
6400       if (child_index + 1 >= i || child1_value > child2_value) {
6401         if (parent_value > child1_value) break;
6402         content->SwapPairs(numbers, parent_index, child_index);
6403         parent_index = child_index;
6404       } else {
6405         if (parent_value > child2_value) break;
6406         content->SwapPairs(numbers, parent_index, child_index + 1);
6407         parent_index = child_index + 1;
6408       }
6409     }
6410   }
6411 }
6412 
6413 
6414 // Sort this array and the numbers as pairs wrt. the (distinct) numbers.
SortPairs(FixedArray * numbers,uint32_t len)6415 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
6416   ASSERT(this->length() == numbers->length());
6417   // For small arrays, simply use insertion sort.
6418   if (len <= 10) {
6419     InsertionSortPairs(this, numbers, len);
6420     return;
6421   }
6422   // Check the range of indices.
6423   uint32_t min_index = NumberToUint32(numbers->get(0));
6424   uint32_t max_index = min_index;
6425   uint32_t i;
6426   for (i = 1; i < len; i++) {
6427     if (NumberToUint32(numbers->get(i)) < min_index) {
6428       min_index = NumberToUint32(numbers->get(i));
6429     } else if (NumberToUint32(numbers->get(i)) > max_index) {
6430       max_index = NumberToUint32(numbers->get(i));
6431     }
6432   }
6433   if (max_index - min_index + 1 == len) {
6434     // Indices form a contiguous range, unless there are duplicates.
6435     // Do an in-place linear time sort assuming distinct numbers, but
6436     // avoid hanging in case they are not.
6437     for (i = 0; i < len; i++) {
6438       uint32_t p;
6439       uint32_t j = 0;
6440       // While the current element at i is not at its correct position p,
6441       // swap the elements at these two positions.
6442       while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
6443              j++ < len) {
6444         SwapPairs(numbers, i, p);
6445       }
6446     }
6447   } else {
6448     HeapSortPairs(this, numbers, len);
6449     return;
6450   }
6451 }
6452 
6453 
6454 // Fill in the names of local properties into the supplied storage. The main
6455 // purpose of this function is to provide reflection information for the object
6456 // mirrors.
GetLocalPropertyNames(FixedArray * storage,int index)6457 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
6458   ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
6459   if (HasFastProperties()) {
6460     DescriptorArray* descs = map()->instance_descriptors();
6461     for (int i = 0; i < descs->number_of_descriptors(); i++) {
6462       if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
6463     }
6464     ASSERT(storage->length() >= index);
6465   } else {
6466     property_dictionary()->CopyKeysTo(storage);
6467   }
6468 }
6469 
6470 
NumberOfLocalElements(PropertyAttributes filter)6471 int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
6472   return GetLocalElementKeys(NULL, filter);
6473 }
6474 
6475 
NumberOfEnumElements()6476 int JSObject::NumberOfEnumElements() {
6477   // Fast case for objects with no elements.
6478   if (!IsJSValue() && HasFastElements()) {
6479     uint32_t length = IsJSArray() ?
6480         static_cast<uint32_t>(
6481             Smi::cast(JSArray::cast(this)->length())->value()) :
6482         static_cast<uint32_t>(FixedArray::cast(elements())->length());
6483     if (length == 0) return 0;
6484   }
6485   // Compute the number of enumerable elements.
6486   return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
6487 }
6488 
6489 
GetLocalElementKeys(FixedArray * storage,PropertyAttributes filter)6490 int JSObject::GetLocalElementKeys(FixedArray* storage,
6491                                   PropertyAttributes filter) {
6492   int counter = 0;
6493   switch (GetElementsKind()) {
6494     case FAST_ELEMENTS: {
6495       int length = IsJSArray() ?
6496           Smi::cast(JSArray::cast(this)->length())->value() :
6497           FixedArray::cast(elements())->length();
6498       for (int i = 0; i < length; i++) {
6499         if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
6500           if (storage != NULL) {
6501             storage->set(counter, Smi::FromInt(i));
6502           }
6503           counter++;
6504         }
6505       }
6506       ASSERT(!storage || storage->length() >= counter);
6507       break;
6508     }
6509     case PIXEL_ELEMENTS: {
6510       int length = PixelArray::cast(elements())->length();
6511       while (counter < length) {
6512         if (storage != NULL) {
6513           storage->set(counter, Smi::FromInt(counter));
6514         }
6515         counter++;
6516       }
6517       ASSERT(!storage || storage->length() >= counter);
6518       break;
6519     }
6520     case EXTERNAL_BYTE_ELEMENTS:
6521     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6522     case EXTERNAL_SHORT_ELEMENTS:
6523     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6524     case EXTERNAL_INT_ELEMENTS:
6525     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6526     case EXTERNAL_FLOAT_ELEMENTS: {
6527       int length = ExternalArray::cast(elements())->length();
6528       while (counter < length) {
6529         if (storage != NULL) {
6530           storage->set(counter, Smi::FromInt(counter));
6531         }
6532         counter++;
6533       }
6534       ASSERT(!storage || storage->length() >= counter);
6535       break;
6536     }
6537     case DICTIONARY_ELEMENTS: {
6538       if (storage != NULL) {
6539         element_dictionary()->CopyKeysTo(storage, filter);
6540       }
6541       counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
6542       break;
6543     }
6544     default:
6545       UNREACHABLE();
6546       break;
6547   }
6548 
6549   if (this->IsJSValue()) {
6550     Object* val = JSValue::cast(this)->value();
6551     if (val->IsString()) {
6552       String* str = String::cast(val);
6553       if (storage) {
6554         for (int i = 0; i < str->length(); i++) {
6555           storage->set(counter + i, Smi::FromInt(i));
6556         }
6557       }
6558       counter += str->length();
6559     }
6560   }
6561   ASSERT(!storage || storage->length() == counter);
6562   return counter;
6563 }
6564 
6565 
GetEnumElementKeys(FixedArray * storage)6566 int JSObject::GetEnumElementKeys(FixedArray* storage) {
6567   return GetLocalElementKeys(storage,
6568                              static_cast<PropertyAttributes>(DONT_ENUM));
6569 }
6570 
6571 
IsMatch(uint32_t key,Object * other)6572 bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) {
6573   ASSERT(other->IsNumber());
6574   return key == static_cast<uint32_t>(other->Number());
6575 }
6576 
6577 
Hash(uint32_t key)6578 uint32_t NumberDictionaryShape::Hash(uint32_t key) {
6579   return ComputeIntegerHash(key);
6580 }
6581 
6582 
HashForObject(uint32_t key,Object * other)6583 uint32_t NumberDictionaryShape::HashForObject(uint32_t key, Object* other) {
6584   ASSERT(other->IsNumber());
6585   return ComputeIntegerHash(static_cast<uint32_t>(other->Number()));
6586 }
6587 
6588 
AsObject(uint32_t key)6589 Object* NumberDictionaryShape::AsObject(uint32_t key) {
6590   return Heap::NumberFromUint32(key);
6591 }
6592 
6593 
IsMatch(String * key,Object * other)6594 bool StringDictionaryShape::IsMatch(String* key, Object* other) {
6595   // We know that all entries in a hash table had their hash keys created.
6596   // Use that knowledge to have fast failure.
6597   if (key->Hash() != String::cast(other)->Hash()) return false;
6598   return key->Equals(String::cast(other));
6599 }
6600 
6601 
Hash(String * key)6602 uint32_t StringDictionaryShape::Hash(String* key) {
6603   return key->Hash();
6604 }
6605 
6606 
HashForObject(String * key,Object * other)6607 uint32_t StringDictionaryShape::HashForObject(String* key, Object* other) {
6608   return String::cast(other)->Hash();
6609 }
6610 
6611 
AsObject(String * key)6612 Object* StringDictionaryShape::AsObject(String* key) {
6613   return key;
6614 }
6615 
6616 
6617 // StringKey simply carries a string object as key.
6618 class StringKey : public HashTableKey {
6619  public:
StringKey(String * string)6620   explicit StringKey(String* string) :
6621       string_(string),
6622       hash_(HashForObject(string)) { }
6623 
IsMatch(Object * string)6624   bool IsMatch(Object* string) {
6625     // We know that all entries in a hash table had their hash keys created.
6626     // Use that knowledge to have fast failure.
6627     if (hash_ != HashForObject(string)) {
6628       return false;
6629     }
6630     return string_->Equals(String::cast(string));
6631   }
6632 
Hash()6633   uint32_t Hash() { return hash_; }
6634 
HashForObject(Object * other)6635   uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
6636 
AsObject()6637   Object* AsObject() { return string_; }
6638 
6639   String* string_;
6640   uint32_t hash_;
6641 };
6642 
6643 
6644 // StringSharedKeys are used as keys in the eval cache.
6645 class StringSharedKey : public HashTableKey {
6646  public:
StringSharedKey(String * source,SharedFunctionInfo * shared)6647   StringSharedKey(String* source, SharedFunctionInfo* shared)
6648       : source_(source), shared_(shared) { }
6649 
IsMatch(Object * other)6650   bool IsMatch(Object* other) {
6651     if (!other->IsFixedArray()) return false;
6652     FixedArray* pair = FixedArray::cast(other);
6653     SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
6654     if (shared != shared_) return false;
6655     String* source = String::cast(pair->get(1));
6656     return source->Equals(source_);
6657   }
6658 
StringSharedHashHelper(String * source,SharedFunctionInfo * shared)6659   static uint32_t StringSharedHashHelper(String* source,
6660                                          SharedFunctionInfo* shared) {
6661     uint32_t hash = source->Hash();
6662     if (shared->HasSourceCode()) {
6663       // Instead of using the SharedFunctionInfo pointer in the hash
6664       // code computation, we use a combination of the hash of the
6665       // script source code and the start and end positions.  We do
6666       // this to ensure that the cache entries can survive garbage
6667       // collection.
6668       Script* script = Script::cast(shared->script());
6669       hash ^= String::cast(script->source())->Hash();
6670       hash += shared->start_position();
6671     }
6672     return hash;
6673   }
6674 
Hash()6675   uint32_t Hash() {
6676     return StringSharedHashHelper(source_, shared_);
6677   }
6678 
HashForObject(Object * obj)6679   uint32_t HashForObject(Object* obj) {
6680     FixedArray* pair = FixedArray::cast(obj);
6681     SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
6682     String* source = String::cast(pair->get(1));
6683     return StringSharedHashHelper(source, shared);
6684   }
6685 
AsObject()6686   Object* AsObject() {
6687     Object* obj = Heap::AllocateFixedArray(2);
6688     if (obj->IsFailure()) return obj;
6689     FixedArray* pair = FixedArray::cast(obj);
6690     pair->set(0, shared_);
6691     pair->set(1, source_);
6692     return pair;
6693   }
6694 
6695  private:
6696   String* source_;
6697   SharedFunctionInfo* shared_;
6698 };
6699 
6700 
6701 // RegExpKey carries the source and flags of a regular expression as key.
6702 class RegExpKey : public HashTableKey {
6703  public:
RegExpKey(String * string,JSRegExp::Flags flags)6704   RegExpKey(String* string, JSRegExp::Flags flags)
6705       : string_(string),
6706         flags_(Smi::FromInt(flags.value())) { }
6707 
6708   // Rather than storing the key in the hash table, a pointer to the
6709   // stored value is stored where the key should be.  IsMatch then
6710   // compares the search key to the found object, rather than comparing
6711   // a key to a key.
IsMatch(Object * obj)6712   bool IsMatch(Object* obj) {
6713     FixedArray* val = FixedArray::cast(obj);
6714     return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
6715         && (flags_ == val->get(JSRegExp::kFlagsIndex));
6716   }
6717 
Hash()6718   uint32_t Hash() { return RegExpHash(string_, flags_); }
6719 
AsObject()6720   Object* AsObject() {
6721     // Plain hash maps, which is where regexp keys are used, don't
6722     // use this function.
6723     UNREACHABLE();
6724     return NULL;
6725   }
6726 
HashForObject(Object * obj)6727   uint32_t HashForObject(Object* obj) {
6728     FixedArray* val = FixedArray::cast(obj);
6729     return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
6730                       Smi::cast(val->get(JSRegExp::kFlagsIndex)));
6731   }
6732 
RegExpHash(String * string,Smi * flags)6733   static uint32_t RegExpHash(String* string, Smi* flags) {
6734     return string->Hash() + flags->value();
6735   }
6736 
6737   String* string_;
6738   Smi* flags_;
6739 };
6740 
6741 // Utf8SymbolKey carries a vector of chars as key.
6742 class Utf8SymbolKey : public HashTableKey {
6743  public:
Utf8SymbolKey(Vector<const char> string)6744   explicit Utf8SymbolKey(Vector<const char> string)
6745       : string_(string), hash_field_(0) { }
6746 
IsMatch(Object * string)6747   bool IsMatch(Object* string) {
6748     return String::cast(string)->IsEqualTo(string_);
6749   }
6750 
Hash()6751   uint32_t Hash() {
6752     if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
6753     unibrow::Utf8InputBuffer<> buffer(string_.start(),
6754                                       static_cast<unsigned>(string_.length()));
6755     chars_ = buffer.Length();
6756     hash_field_ = String::ComputeHashField(&buffer, chars_);
6757     uint32_t result = hash_field_ >> String::kHashShift;
6758     ASSERT(result != 0);  // Ensure that the hash value of 0 is never computed.
6759     return result;
6760   }
6761 
HashForObject(Object * other)6762   uint32_t HashForObject(Object* other) {
6763     return String::cast(other)->Hash();
6764   }
6765 
AsObject()6766   Object* AsObject() {
6767     if (hash_field_ == 0) Hash();
6768     return Heap::AllocateSymbol(string_, chars_, hash_field_);
6769   }
6770 
6771   Vector<const char> string_;
6772   uint32_t hash_field_;
6773   int chars_;  // Caches the number of characters when computing the hash code.
6774 };
6775 
6776 
6777 // SymbolKey carries a string/symbol object as key.
6778 class SymbolKey : public HashTableKey {
6779  public:
SymbolKey(String * string)6780   explicit SymbolKey(String* string) : string_(string) { }
6781 
IsMatch(Object * string)6782   bool IsMatch(Object* string) {
6783     return String::cast(string)->Equals(string_);
6784   }
6785 
Hash()6786   uint32_t Hash() { return string_->Hash(); }
6787 
HashForObject(Object * other)6788   uint32_t HashForObject(Object* other) {
6789     return String::cast(other)->Hash();
6790   }
6791 
AsObject()6792   Object* AsObject() {
6793     // If the string is a cons string, attempt to flatten it so that
6794     // symbols will most often be flat strings.
6795     if (StringShape(string_).IsCons()) {
6796       ConsString* cons_string = ConsString::cast(string_);
6797       cons_string->TryFlatten();
6798       if (cons_string->second()->length() == 0) {
6799         string_ = cons_string->first();
6800       }
6801     }
6802     // Transform string to symbol if possible.
6803     Map* map = Heap::SymbolMapForString(string_);
6804     if (map != NULL) {
6805       string_->set_map(map);
6806       ASSERT(string_->IsSymbol());
6807       return string_;
6808     }
6809     // Otherwise allocate a new symbol.
6810     StringInputBuffer buffer(string_);
6811     return Heap::AllocateInternalSymbol(&buffer,
6812                                         string_->length(),
6813                                         string_->hash_field());
6814   }
6815 
StringHash(Object * obj)6816   static uint32_t StringHash(Object* obj) {
6817     return String::cast(obj)->Hash();
6818   }
6819 
6820   String* string_;
6821 };
6822 
6823 
6824 template<typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)6825 void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
6826   IteratePointers(v, 0, kElementsStartOffset);
6827 }
6828 
6829 
6830 template<typename Shape, typename Key>
IterateElements(ObjectVisitor * v)6831 void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
6832   IteratePointers(v,
6833                   kElementsStartOffset,
6834                   kHeaderSize + length() * kPointerSize);
6835 }
6836 
6837 
6838 template<typename Shape, typename Key>
Allocate(int at_least_space_for)6839 Object* HashTable<Shape, Key>::Allocate(int at_least_space_for) {
6840   int capacity = RoundUpToPowerOf2(at_least_space_for);
6841   if (capacity < 4) {
6842     capacity = 4;  // Guarantee min capacity.
6843   } else if (capacity > HashTable::kMaxCapacity) {
6844     return Failure::OutOfMemoryException();
6845   }
6846 
6847   Object* obj = Heap::AllocateHashTable(EntryToIndex(capacity));
6848   if (!obj->IsFailure()) {
6849     HashTable::cast(obj)->SetNumberOfElements(0);
6850     HashTable::cast(obj)->SetNumberOfDeletedElements(0);
6851     HashTable::cast(obj)->SetCapacity(capacity);
6852   }
6853   return obj;
6854 }
6855 
6856 
6857 // Find entry for key otherwise return kNotFound.
6858 template<typename Shape, typename Key>
FindEntry(Key key)6859 int HashTable<Shape, Key>::FindEntry(Key key) {
6860   uint32_t capacity = Capacity();
6861   uint32_t entry = FirstProbe(Shape::Hash(key), capacity);
6862   uint32_t count = 1;
6863   // EnsureCapacity will guarantee the hash table is never full.
6864   while (true) {
6865     Object* element = KeyAt(entry);
6866     if (element->IsUndefined()) break;  // Empty entry.
6867     if (!element->IsNull() && Shape::IsMatch(key, element)) return entry;
6868     entry = NextProbe(entry, count++, capacity);
6869   }
6870   return kNotFound;
6871 }
6872 
6873 
6874 template<typename Shape, typename Key>
EnsureCapacity(int n,Key key)6875 Object* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
6876   int capacity = Capacity();
6877   int nof = NumberOfElements() + n;
6878   int nod = NumberOfDeletedElements();
6879   // Return if:
6880   //   50% is still free after adding n elements and
6881   //   at most 50% of the free elements are deleted elements.
6882   if ((nof + (nof >> 1) <= capacity) &&
6883       (nod <= (capacity - nof) >> 1)) return this;
6884 
6885   Object* obj = Allocate(nof * 2);
6886   if (obj->IsFailure()) return obj;
6887 
6888   AssertNoAllocation no_gc;
6889   HashTable* table = HashTable::cast(obj);
6890   WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
6891 
6892   // Copy prefix to new array.
6893   for (int i = kPrefixStartIndex;
6894        i < kPrefixStartIndex + Shape::kPrefixSize;
6895        i++) {
6896     table->set(i, get(i), mode);
6897   }
6898   // Rehash the elements.
6899   for (int i = 0; i < capacity; i++) {
6900     uint32_t from_index = EntryToIndex(i);
6901     Object* k = get(from_index);
6902     if (IsKey(k)) {
6903       uint32_t hash = Shape::HashForObject(key, k);
6904       uint32_t insertion_index =
6905           EntryToIndex(table->FindInsertionEntry(hash));
6906       for (int j = 0; j < Shape::kEntrySize; j++) {
6907         table->set(insertion_index + j, get(from_index + j), mode);
6908       }
6909     }
6910   }
6911   table->SetNumberOfElements(NumberOfElements());
6912   table->SetNumberOfDeletedElements(0);
6913   return table;
6914 }
6915 
6916 
6917 
6918 template<typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)6919 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
6920   uint32_t capacity = Capacity();
6921   uint32_t entry = FirstProbe(hash, capacity);
6922   uint32_t count = 1;
6923   // EnsureCapacity will guarantee the hash table is never full.
6924   while (true) {
6925     Object* element = KeyAt(entry);
6926     if (element->IsUndefined() || element->IsNull()) break;
6927     entry = NextProbe(entry, count++, capacity);
6928   }
6929   return entry;
6930 }
6931 
6932 // Force instantiation of template instances class.
6933 // Please note this list is compiler dependent.
6934 
6935 template class HashTable<SymbolTableShape, HashTableKey*>;
6936 
6937 template class HashTable<CompilationCacheShape, HashTableKey*>;
6938 
6939 template class HashTable<MapCacheShape, HashTableKey*>;
6940 
6941 template class Dictionary<StringDictionaryShape, String*>;
6942 
6943 template class Dictionary<NumberDictionaryShape, uint32_t>;
6944 
6945 template Object* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
6946     int);
6947 
6948 template Object* Dictionary<StringDictionaryShape, String*>::Allocate(
6949     int);
6950 
6951 template Object* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
6952     uint32_t, Object*);
6953 
6954 template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
6955     Object*);
6956 
6957 template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
6958     Object*);
6959 
6960 template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
6961     FixedArray*, PropertyAttributes);
6962 
6963 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
6964     int, JSObject::DeleteMode);
6965 
6966 template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
6967     int, JSObject::DeleteMode);
6968 
6969 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
6970     FixedArray*);
6971 
6972 template int
6973 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
6974     PropertyAttributes);
6975 
6976 template Object* Dictionary<StringDictionaryShape, String*>::Add(
6977     String*, Object*, PropertyDetails);
6978 
6979 template Object*
6980 Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
6981 
6982 template int
6983 Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
6984     PropertyAttributes);
6985 
6986 template Object* Dictionary<NumberDictionaryShape, uint32_t>::Add(
6987     uint32_t, Object*, PropertyDetails);
6988 
6989 template Object* Dictionary<NumberDictionaryShape, uint32_t>::EnsureCapacity(
6990     int, uint32_t);
6991 
6992 template Object* Dictionary<StringDictionaryShape, String*>::EnsureCapacity(
6993     int, String*);
6994 
6995 template Object* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
6996     uint32_t, Object*, PropertyDetails, uint32_t);
6997 
6998 template Object* Dictionary<StringDictionaryShape, String*>::AddEntry(
6999     String*, Object*, PropertyDetails, uint32_t);
7000 
7001 template
7002 int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
7003 
7004 template
7005 int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
7006 
7007 template
7008 int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
7009 
7010 
7011 // Collates undefined and unexisting elements below limit from position
7012 // zero of the elements. The object stays in Dictionary mode.
PrepareSlowElementsForSort(uint32_t limit)7013 Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
7014   ASSERT(HasDictionaryElements());
7015   // Must stay in dictionary mode, either because of requires_slow_elements,
7016   // or because we are not going to sort (and therefore compact) all of the
7017   // elements.
7018   NumberDictionary* dict = element_dictionary();
7019   HeapNumber* result_double = NULL;
7020   if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
7021     // Allocate space for result before we start mutating the object.
7022     Object* new_double = Heap::AllocateHeapNumber(0.0);
7023     if (new_double->IsFailure()) return new_double;
7024     result_double = HeapNumber::cast(new_double);
7025   }
7026 
7027   int capacity = dict->Capacity();
7028   Object* obj = NumberDictionary::Allocate(dict->Capacity());
7029   if (obj->IsFailure()) return obj;
7030   NumberDictionary* new_dict = NumberDictionary::cast(obj);
7031 
7032   AssertNoAllocation no_alloc;
7033 
7034   uint32_t pos = 0;
7035   uint32_t undefs = 0;
7036   for (int i = 0; i < capacity; i++) {
7037     Object* k = dict->KeyAt(i);
7038     if (dict->IsKey(k)) {
7039       ASSERT(k->IsNumber());
7040       ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
7041       ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
7042       ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
7043       Object* value = dict->ValueAt(i);
7044       PropertyDetails details = dict->DetailsAt(i);
7045       if (details.type() == CALLBACKS) {
7046         // Bail out and do the sorting of undefineds and array holes in JS.
7047         return Smi::FromInt(-1);
7048       }
7049       uint32_t key = NumberToUint32(k);
7050       if (key < limit) {
7051         if (value->IsUndefined()) {
7052           undefs++;
7053         } else {
7054           new_dict->AddNumberEntry(pos, value, details);
7055           pos++;
7056         }
7057       } else {
7058         new_dict->AddNumberEntry(key, value, details);
7059       }
7060     }
7061   }
7062 
7063   uint32_t result = pos;
7064   PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
7065   while (undefs > 0) {
7066     new_dict->AddNumberEntry(pos, Heap::undefined_value(), no_details);
7067     pos++;
7068     undefs--;
7069   }
7070 
7071   set_elements(new_dict);
7072 
7073   if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
7074     return Smi::FromInt(static_cast<int>(result));
7075   }
7076 
7077   ASSERT_NE(NULL, result_double);
7078   result_double->set_value(static_cast<double>(result));
7079   return result_double;
7080 }
7081 
7082 
7083 // Collects all defined (non-hole) and non-undefined (array) elements at
7084 // the start of the elements array.
7085 // If the object is in dictionary mode, it is converted to fast elements
7086 // mode.
PrepareElementsForSort(uint32_t limit)7087 Object* JSObject::PrepareElementsForSort(uint32_t limit) {
7088   ASSERT(!HasPixelElements() && !HasExternalArrayElements());
7089 
7090   if (HasDictionaryElements()) {
7091     // Convert to fast elements containing only the existing properties.
7092     // Ordering is irrelevant, since we are going to sort anyway.
7093     NumberDictionary* dict = element_dictionary();
7094     if (IsJSArray() || dict->requires_slow_elements() ||
7095         dict->max_number_key() >= limit) {
7096       return PrepareSlowElementsForSort(limit);
7097     }
7098     // Convert to fast elements.
7099 
7100     PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED;
7101     Object* new_array =
7102         Heap::AllocateFixedArray(dict->NumberOfElements(), tenure);
7103     if (new_array->IsFailure()) {
7104       return new_array;
7105     }
7106     FixedArray* fast_elements = FixedArray::cast(new_array);
7107     dict->CopyValuesTo(fast_elements);
7108     set_elements(fast_elements);
7109   }
7110   ASSERT(HasFastElements());
7111 
7112   // Collect holes at the end, undefined before that and the rest at the
7113   // start, and return the number of non-hole, non-undefined values.
7114 
7115   FixedArray* elements = FixedArray::cast(this->elements());
7116   uint32_t elements_length = static_cast<uint32_t>(elements->length());
7117   if (limit > elements_length) {
7118     limit = elements_length ;
7119   }
7120   if (limit == 0) {
7121     return Smi::FromInt(0);
7122   }
7123 
7124   HeapNumber* result_double = NULL;
7125   if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
7126     // Pessimistically allocate space for return value before
7127     // we start mutating the array.
7128     Object* new_double = Heap::AllocateHeapNumber(0.0);
7129     if (new_double->IsFailure()) return new_double;
7130     result_double = HeapNumber::cast(new_double);
7131   }
7132 
7133   AssertNoAllocation no_alloc;
7134 
7135   // Split elements into defined, undefined and the_hole, in that order.
7136   // Only count locations for undefined and the hole, and fill them afterwards.
7137   WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
7138   unsigned int undefs = limit;
7139   unsigned int holes = limit;
7140   // Assume most arrays contain no holes and undefined values, so minimize the
7141   // number of stores of non-undefined, non-the-hole values.
7142   for (unsigned int i = 0; i < undefs; i++) {
7143     Object* current = elements->get(i);
7144     if (current->IsTheHole()) {
7145       holes--;
7146       undefs--;
7147     } else if (current->IsUndefined()) {
7148       undefs--;
7149     } else {
7150       continue;
7151     }
7152     // Position i needs to be filled.
7153     while (undefs > i) {
7154       current = elements->get(undefs);
7155       if (current->IsTheHole()) {
7156         holes--;
7157         undefs--;
7158       } else if (current->IsUndefined()) {
7159         undefs--;
7160       } else {
7161         elements->set(i, current, write_barrier);
7162         break;
7163       }
7164     }
7165   }
7166   uint32_t result = undefs;
7167   while (undefs < holes) {
7168     elements->set_undefined(undefs);
7169     undefs++;
7170   }
7171   while (holes < limit) {
7172     elements->set_the_hole(holes);
7173     holes++;
7174   }
7175 
7176   if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
7177     return Smi::FromInt(static_cast<int>(result));
7178   }
7179   ASSERT_NE(NULL, result_double);
7180   result_double->set_value(static_cast<double>(result));
7181   return result_double;
7182 }
7183 
7184 
SetValue(uint32_t index,Object * value)7185 Object* PixelArray::SetValue(uint32_t index, Object* value) {
7186   uint8_t clamped_value = 0;
7187   if (index < static_cast<uint32_t>(length())) {
7188     if (value->IsSmi()) {
7189       int int_value = Smi::cast(value)->value();
7190       if (int_value < 0) {
7191         clamped_value = 0;
7192       } else if (int_value > 255) {
7193         clamped_value = 255;
7194       } else {
7195         clamped_value = static_cast<uint8_t>(int_value);
7196       }
7197     } else if (value->IsHeapNumber()) {
7198       double double_value = HeapNumber::cast(value)->value();
7199       if (!(double_value > 0)) {
7200         // NaN and less than zero clamp to zero.
7201         clamped_value = 0;
7202       } else if (double_value > 255) {
7203         // Greater than 255 clamp to 255.
7204         clamped_value = 255;
7205       } else {
7206         // Other doubles are rounded to the nearest integer.
7207         clamped_value = static_cast<uint8_t>(double_value + 0.5);
7208       }
7209     } else {
7210       // Clamp undefined to zero (default). All other types have been
7211       // converted to a number type further up in the call chain.
7212       ASSERT(value->IsUndefined());
7213     }
7214     set(index, clamped_value);
7215   }
7216   return Smi::FromInt(clamped_value);
7217 }
7218 
7219 
7220 template<typename ExternalArrayClass, typename ValueType>
ExternalArrayIntSetter(ExternalArrayClass * receiver,uint32_t index,Object * value)7221 static Object* ExternalArrayIntSetter(ExternalArrayClass* receiver,
7222                                       uint32_t index,
7223                                       Object* value) {
7224   ValueType cast_value = 0;
7225   if (index < static_cast<uint32_t>(receiver->length())) {
7226     if (value->IsSmi()) {
7227       int int_value = Smi::cast(value)->value();
7228       cast_value = static_cast<ValueType>(int_value);
7229     } else if (value->IsHeapNumber()) {
7230       double double_value = HeapNumber::cast(value)->value();
7231       cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
7232     } else {
7233       // Clamp undefined to zero (default). All other types have been
7234       // converted to a number type further up in the call chain.
7235       ASSERT(value->IsUndefined());
7236     }
7237     receiver->set(index, cast_value);
7238   }
7239   return Heap::NumberFromInt32(cast_value);
7240 }
7241 
7242 
SetValue(uint32_t index,Object * value)7243 Object* ExternalByteArray::SetValue(uint32_t index, Object* value) {
7244   return ExternalArrayIntSetter<ExternalByteArray, int8_t>
7245       (this, index, value);
7246 }
7247 
7248 
SetValue(uint32_t index,Object * value)7249 Object* ExternalUnsignedByteArray::SetValue(uint32_t index, Object* value) {
7250   return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
7251       (this, index, value);
7252 }
7253 
7254 
SetValue(uint32_t index,Object * value)7255 Object* ExternalShortArray::SetValue(uint32_t index, Object* value) {
7256   return ExternalArrayIntSetter<ExternalShortArray, int16_t>
7257       (this, index, value);
7258 }
7259 
7260 
SetValue(uint32_t index,Object * value)7261 Object* ExternalUnsignedShortArray::SetValue(uint32_t index, Object* value) {
7262   return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
7263       (this, index, value);
7264 }
7265 
7266 
SetValue(uint32_t index,Object * value)7267 Object* ExternalIntArray::SetValue(uint32_t index, Object* value) {
7268   return ExternalArrayIntSetter<ExternalIntArray, int32_t>
7269       (this, index, value);
7270 }
7271 
7272 
SetValue(uint32_t index,Object * value)7273 Object* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
7274   uint32_t cast_value = 0;
7275   if (index < static_cast<uint32_t>(length())) {
7276     if (value->IsSmi()) {
7277       int int_value = Smi::cast(value)->value();
7278       cast_value = static_cast<uint32_t>(int_value);
7279     } else if (value->IsHeapNumber()) {
7280       double double_value = HeapNumber::cast(value)->value();
7281       cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
7282     } else {
7283       // Clamp undefined to zero (default). All other types have been
7284       // converted to a number type further up in the call chain.
7285       ASSERT(value->IsUndefined());
7286     }
7287     set(index, cast_value);
7288   }
7289   return Heap::NumberFromUint32(cast_value);
7290 }
7291 
7292 
SetValue(uint32_t index,Object * value)7293 Object* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
7294   float cast_value = 0;
7295   if (index < static_cast<uint32_t>(length())) {
7296     if (value->IsSmi()) {
7297       int int_value = Smi::cast(value)->value();
7298       cast_value = static_cast<float>(int_value);
7299     } else if (value->IsHeapNumber()) {
7300       double double_value = HeapNumber::cast(value)->value();
7301       cast_value = static_cast<float>(double_value);
7302     } else {
7303       // Clamp undefined to zero (default). All other types have been
7304       // converted to a number type further up in the call chain.
7305       ASSERT(value->IsUndefined());
7306     }
7307     set(index, cast_value);
7308   }
7309   return Heap::AllocateHeapNumber(cast_value);
7310 }
7311 
7312 
GetPropertyCell(LookupResult * result)7313 Object* GlobalObject::GetPropertyCell(LookupResult* result) {
7314   ASSERT(!HasFastProperties());
7315   Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
7316   ASSERT(value->IsJSGlobalPropertyCell());
7317   return value;
7318 }
7319 
7320 
EnsurePropertyCell(String * name)7321 Object* GlobalObject::EnsurePropertyCell(String* name) {
7322   ASSERT(!HasFastProperties());
7323   int entry = property_dictionary()->FindEntry(name);
7324   if (entry == StringDictionary::kNotFound) {
7325     Object* cell = Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value());
7326     if (cell->IsFailure()) return cell;
7327     PropertyDetails details(NONE, NORMAL);
7328     details = details.AsDeleted();
7329     Object* dictionary = property_dictionary()->Add(name, cell, details);
7330     if (dictionary->IsFailure()) return dictionary;
7331     set_properties(StringDictionary::cast(dictionary));
7332     return cell;
7333   } else {
7334     Object* value = property_dictionary()->ValueAt(entry);
7335     ASSERT(value->IsJSGlobalPropertyCell());
7336     return value;
7337   }
7338 }
7339 
7340 
LookupString(String * string,Object ** s)7341 Object* SymbolTable::LookupString(String* string, Object** s) {
7342   SymbolKey key(string);
7343   return LookupKey(&key, s);
7344 }
7345 
7346 
7347 // This class is used for looking up two character strings in the symbol table.
7348 // If we don't have a hit we don't want to waste much time so we unroll the
7349 // string hash calculation loop here for speed.  Doesn't work if the two
7350 // characters form a decimal integer, since such strings have a different hash
7351 // algorithm.
7352 class TwoCharHashTableKey : public HashTableKey {
7353  public:
TwoCharHashTableKey(uint32_t c1,uint32_t c2)7354   TwoCharHashTableKey(uint32_t c1, uint32_t c2)
7355     : c1_(c1), c2_(c2) {
7356     // Char 1.
7357     uint32_t hash = c1 + (c1 << 10);
7358     hash ^= hash >> 6;
7359     // Char 2.
7360     hash += c2;
7361     hash += hash << 10;
7362     hash ^= hash >> 6;
7363     // GetHash.
7364     hash += hash << 3;
7365     hash ^= hash >> 11;
7366     hash += hash << 15;
7367     if (hash == 0) hash = 27;
7368 #ifdef DEBUG
7369     StringHasher hasher(2);
7370     hasher.AddCharacter(c1);
7371     hasher.AddCharacter(c2);
7372     // If this assert fails then we failed to reproduce the two-character
7373     // version of the string hashing algorithm above.  One reason could be
7374     // that we were passed two digits as characters, since the hash
7375     // algorithm is different in that case.
7376     ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
7377 #endif
7378     hash_ = hash;
7379   }
7380 
IsMatch(Object * o)7381   bool IsMatch(Object* o) {
7382     if (!o->IsString()) return false;
7383     String* other = String::cast(o);
7384     if (other->length() != 2) return false;
7385     if (other->Get(0) != c1_) return false;
7386     return other->Get(1) == c2_;
7387   }
7388 
Hash()7389   uint32_t Hash() { return hash_; }
HashForObject(Object * key)7390   uint32_t HashForObject(Object* key) {
7391     if (!key->IsString()) return 0;
7392     return String::cast(key)->Hash();
7393   }
7394 
AsObject()7395   Object* AsObject() {
7396     // The TwoCharHashTableKey is only used for looking in the symbol
7397     // table, not for adding to it.
7398     UNREACHABLE();
7399     return NULL;
7400   }
7401  private:
7402   uint32_t c1_;
7403   uint32_t c2_;
7404   uint32_t hash_;
7405 };
7406 
7407 
LookupSymbolIfExists(String * string,String ** symbol)7408 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
7409   SymbolKey key(string);
7410   int entry = FindEntry(&key);
7411   if (entry == kNotFound) {
7412     return false;
7413   } else {
7414     String* result = String::cast(KeyAt(entry));
7415     ASSERT(StringShape(result).IsSymbol());
7416     *symbol = result;
7417     return true;
7418   }
7419 }
7420 
7421 
LookupTwoCharsSymbolIfExists(uint32_t c1,uint32_t c2,String ** symbol)7422 bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
7423                                                uint32_t c2,
7424                                                String** symbol) {
7425   TwoCharHashTableKey key(c1, c2);
7426   int entry = FindEntry(&key);
7427   if (entry == kNotFound) {
7428     return false;
7429   } else {
7430     String* result = String::cast(KeyAt(entry));
7431     ASSERT(StringShape(result).IsSymbol());
7432     *symbol = result;
7433     return true;
7434   }
7435 }
7436 
7437 
LookupSymbol(Vector<const char> str,Object ** s)7438 Object* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
7439   Utf8SymbolKey key(str);
7440   return LookupKey(&key, s);
7441 }
7442 
7443 
LookupKey(HashTableKey * key,Object ** s)7444 Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
7445   int entry = FindEntry(key);
7446 
7447   // Symbol already in table.
7448   if (entry != kNotFound) {
7449     *s = KeyAt(entry);
7450     return this;
7451   }
7452 
7453   // Adding new symbol. Grow table if needed.
7454   Object* obj = EnsureCapacity(1, key);
7455   if (obj->IsFailure()) return obj;
7456 
7457   // Create symbol object.
7458   Object* symbol = key->AsObject();
7459   if (symbol->IsFailure()) return symbol;
7460 
7461   // If the symbol table grew as part of EnsureCapacity, obj is not
7462   // the current symbol table and therefore we cannot use
7463   // SymbolTable::cast here.
7464   SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
7465 
7466   // Add the new symbol and return it along with the symbol table.
7467   entry = table->FindInsertionEntry(key->Hash());
7468   table->set(EntryToIndex(entry), symbol);
7469   table->ElementAdded();
7470   *s = symbol;
7471   return table;
7472 }
7473 
7474 
Lookup(String * src)7475 Object* CompilationCacheTable::Lookup(String* src) {
7476   StringKey key(src);
7477   int entry = FindEntry(&key);
7478   if (entry == kNotFound) return Heap::undefined_value();
7479   return get(EntryToIndex(entry) + 1);
7480 }
7481 
7482 
LookupEval(String * src,Context * context)7483 Object* CompilationCacheTable::LookupEval(String* src, Context* context) {
7484   StringSharedKey key(src, context->closure()->shared());
7485   int entry = FindEntry(&key);
7486   if (entry == kNotFound) return Heap::undefined_value();
7487   return get(EntryToIndex(entry) + 1);
7488 }
7489 
7490 
LookupRegExp(String * src,JSRegExp::Flags flags)7491 Object* CompilationCacheTable::LookupRegExp(String* src,
7492                                             JSRegExp::Flags flags) {
7493   RegExpKey key(src, flags);
7494   int entry = FindEntry(&key);
7495   if (entry == kNotFound) return Heap::undefined_value();
7496   return get(EntryToIndex(entry) + 1);
7497 }
7498 
7499 
Put(String * src,Object * value)7500 Object* CompilationCacheTable::Put(String* src, Object* value) {
7501   StringKey key(src);
7502   Object* obj = EnsureCapacity(1, &key);
7503   if (obj->IsFailure()) return obj;
7504 
7505   CompilationCacheTable* cache =
7506       reinterpret_cast<CompilationCacheTable*>(obj);
7507   int entry = cache->FindInsertionEntry(key.Hash());
7508   cache->set(EntryToIndex(entry), src);
7509   cache->set(EntryToIndex(entry) + 1, value);
7510   cache->ElementAdded();
7511   return cache;
7512 }
7513 
7514 
PutEval(String * src,Context * context,Object * value)7515 Object* CompilationCacheTable::PutEval(String* src,
7516                                        Context* context,
7517                                        Object* value) {
7518   StringSharedKey key(src, context->closure()->shared());
7519   Object* obj = EnsureCapacity(1, &key);
7520   if (obj->IsFailure()) return obj;
7521 
7522   CompilationCacheTable* cache =
7523       reinterpret_cast<CompilationCacheTable*>(obj);
7524   int entry = cache->FindInsertionEntry(key.Hash());
7525 
7526   Object* k = key.AsObject();
7527   if (k->IsFailure()) return k;
7528 
7529   cache->set(EntryToIndex(entry), k);
7530   cache->set(EntryToIndex(entry) + 1, value);
7531   cache->ElementAdded();
7532   return cache;
7533 }
7534 
7535 
PutRegExp(String * src,JSRegExp::Flags flags,FixedArray * value)7536 Object* CompilationCacheTable::PutRegExp(String* src,
7537                                          JSRegExp::Flags flags,
7538                                          FixedArray* value) {
7539   RegExpKey key(src, flags);
7540   Object* obj = EnsureCapacity(1, &key);
7541   if (obj->IsFailure()) return obj;
7542 
7543   CompilationCacheTable* cache =
7544       reinterpret_cast<CompilationCacheTable*>(obj);
7545   int entry = cache->FindInsertionEntry(key.Hash());
7546   // We store the value in the key slot, and compare the search key
7547   // to the stored value with a custon IsMatch function during lookups.
7548   cache->set(EntryToIndex(entry), value);
7549   cache->set(EntryToIndex(entry) + 1, value);
7550   cache->ElementAdded();
7551   return cache;
7552 }
7553 
7554 
7555 // SymbolsKey used for HashTable where key is array of symbols.
7556 class SymbolsKey : public HashTableKey {
7557  public:
SymbolsKey(FixedArray * symbols)7558   explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
7559 
IsMatch(Object * symbols)7560   bool IsMatch(Object* symbols) {
7561     FixedArray* o = FixedArray::cast(symbols);
7562     int len = symbols_->length();
7563     if (o->length() != len) return false;
7564     for (int i = 0; i < len; i++) {
7565       if (o->get(i) != symbols_->get(i)) return false;
7566     }
7567     return true;
7568   }
7569 
Hash()7570   uint32_t Hash() { return HashForObject(symbols_); }
7571 
HashForObject(Object * obj)7572   uint32_t HashForObject(Object* obj) {
7573     FixedArray* symbols = FixedArray::cast(obj);
7574     int len = symbols->length();
7575     uint32_t hash = 0;
7576     for (int i = 0; i < len; i++) {
7577       hash ^= String::cast(symbols->get(i))->Hash();
7578     }
7579     return hash;
7580   }
7581 
AsObject()7582   Object* AsObject() { return symbols_; }
7583 
7584  private:
7585   FixedArray* symbols_;
7586 };
7587 
7588 
Lookup(FixedArray * array)7589 Object* MapCache::Lookup(FixedArray* array) {
7590   SymbolsKey key(array);
7591   int entry = FindEntry(&key);
7592   if (entry == kNotFound) return Heap::undefined_value();
7593   return get(EntryToIndex(entry) + 1);
7594 }
7595 
7596 
Put(FixedArray * array,Map * value)7597 Object* MapCache::Put(FixedArray* array, Map* value) {
7598   SymbolsKey key(array);
7599   Object* obj = EnsureCapacity(1, &key);
7600   if (obj->IsFailure()) return obj;
7601 
7602   MapCache* cache = reinterpret_cast<MapCache*>(obj);
7603   int entry = cache->FindInsertionEntry(key.Hash());
7604   cache->set(EntryToIndex(entry), array);
7605   cache->set(EntryToIndex(entry) + 1, value);
7606   cache->ElementAdded();
7607   return cache;
7608 }
7609 
7610 
7611 template<typename Shape, typename Key>
Allocate(int at_least_space_for)7612 Object* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
7613   Object* obj = HashTable<Shape, Key>::Allocate(at_least_space_for);
7614   // Initialize the next enumeration index.
7615   if (!obj->IsFailure()) {
7616     Dictionary<Shape, Key>::cast(obj)->
7617         SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
7618   }
7619   return obj;
7620 }
7621 
7622 
7623 template<typename Shape, typename Key>
GenerateNewEnumerationIndices()7624 Object* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
7625   int length = HashTable<Shape, Key>::NumberOfElements();
7626 
7627   // Allocate and initialize iteration order array.
7628   Object* obj = Heap::AllocateFixedArray(length);
7629   if (obj->IsFailure()) return obj;
7630   FixedArray* iteration_order = FixedArray::cast(obj);
7631   for (int i = 0; i < length; i++) {
7632     iteration_order->set(i, Smi::FromInt(i));
7633   }
7634 
7635   // Allocate array with enumeration order.
7636   obj = Heap::AllocateFixedArray(length);
7637   if (obj->IsFailure()) return obj;
7638   FixedArray* enumeration_order = FixedArray::cast(obj);
7639 
7640   // Fill the enumeration order array with property details.
7641   int capacity = HashTable<Shape, Key>::Capacity();
7642   int pos = 0;
7643   for (int i = 0; i < capacity; i++) {
7644     if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
7645       enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
7646     }
7647   }
7648 
7649   // Sort the arrays wrt. enumeration order.
7650   iteration_order->SortPairs(enumeration_order, enumeration_order->length());
7651 
7652   // Overwrite the enumeration_order with the enumeration indices.
7653   for (int i = 0; i < length; i++) {
7654     int index = Smi::cast(iteration_order->get(i))->value();
7655     int enum_index = PropertyDetails::kInitialIndex + i;
7656     enumeration_order->set(index, Smi::FromInt(enum_index));
7657   }
7658 
7659   // Update the dictionary with new indices.
7660   capacity = HashTable<Shape, Key>::Capacity();
7661   pos = 0;
7662   for (int i = 0; i < capacity; i++) {
7663     if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
7664       int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
7665       PropertyDetails details = DetailsAt(i);
7666       PropertyDetails new_details =
7667           PropertyDetails(details.attributes(), details.type(), enum_index);
7668       DetailsAtPut(i, new_details);
7669     }
7670   }
7671 
7672   // Set the next enumeration index.
7673   SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
7674   return this;
7675 }
7676 
7677 template<typename Shape, typename Key>
EnsureCapacity(int n,Key key)7678 Object* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
7679   // Check whether there are enough enumeration indices to add n elements.
7680   if (Shape::kIsEnumerable &&
7681       !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
7682     // If not, we generate new indices for the properties.
7683     Object* result = GenerateNewEnumerationIndices();
7684     if (result->IsFailure()) return result;
7685   }
7686   return HashTable<Shape, Key>::EnsureCapacity(n, key);
7687 }
7688 
7689 
RemoveNumberEntries(uint32_t from,uint32_t to)7690 void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
7691   // Do nothing if the interval [from, to) is empty.
7692   if (from >= to) return;
7693 
7694   int removed_entries = 0;
7695   Object* sentinel = Heap::null_value();
7696   int capacity = Capacity();
7697   for (int i = 0; i < capacity; i++) {
7698     Object* key = KeyAt(i);
7699     if (key->IsNumber()) {
7700       uint32_t number = static_cast<uint32_t>(key->Number());
7701       if (from <= number && number < to) {
7702         SetEntry(i, sentinel, sentinel, Smi::FromInt(0));
7703         removed_entries++;
7704       }
7705     }
7706   }
7707 
7708   // Update the number of elements.
7709   ElementsRemoved(removed_entries);
7710 }
7711 
7712 
7713 template<typename Shape, typename Key>
DeleteProperty(int entry,JSObject::DeleteMode mode)7714 Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
7715                                                JSObject::DeleteMode mode) {
7716   PropertyDetails details = DetailsAt(entry);
7717   // Ignore attributes if forcing a deletion.
7718   if (details.IsDontDelete() && mode == JSObject::NORMAL_DELETION) {
7719     return Heap::false_value();
7720   }
7721   SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0));
7722   HashTable<Shape, Key>::ElementRemoved();
7723   return Heap::true_value();
7724 }
7725 
7726 
7727 template<typename Shape, typename Key>
AtPut(Key key,Object * value)7728 Object* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
7729   int entry = FindEntry(key);
7730 
7731   // If the entry is present set the value;
7732   if (entry != Dictionary<Shape, Key>::kNotFound) {
7733     ValueAtPut(entry, value);
7734     return this;
7735   }
7736 
7737   // Check whether the dictionary should be extended.
7738   Object* obj = EnsureCapacity(1, key);
7739   if (obj->IsFailure()) return obj;
7740 
7741   Object* k = Shape::AsObject(key);
7742   if (k->IsFailure()) return k;
7743   PropertyDetails details = PropertyDetails(NONE, NORMAL);
7744   return Dictionary<Shape, Key>::cast(obj)->
7745       AddEntry(key, value, details, Shape::Hash(key));
7746 }
7747 
7748 
7749 template<typename Shape, typename Key>
Add(Key key,Object * value,PropertyDetails details)7750 Object* Dictionary<Shape, Key>::Add(Key key,
7751                                     Object* value,
7752                                     PropertyDetails details) {
7753   // Valdate key is absent.
7754   SLOW_ASSERT((FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
7755   // Check whether the dictionary should be extended.
7756   Object* obj = EnsureCapacity(1, key);
7757   if (obj->IsFailure()) return obj;
7758   return Dictionary<Shape, Key>::cast(obj)->
7759       AddEntry(key, value, details, Shape::Hash(key));
7760 }
7761 
7762 
7763 // Add a key, value pair to the dictionary.
7764 template<typename Shape, typename Key>
AddEntry(Key key,Object * value,PropertyDetails details,uint32_t hash)7765 Object* Dictionary<Shape, Key>::AddEntry(Key key,
7766                                          Object* value,
7767                                          PropertyDetails details,
7768                                          uint32_t hash) {
7769   // Compute the key object.
7770   Object* k = Shape::AsObject(key);
7771   if (k->IsFailure()) return k;
7772 
7773   uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
7774   // Insert element at empty or deleted entry
7775   if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
7776     // Assign an enumeration index to the property and update
7777     // SetNextEnumerationIndex.
7778     int index = NextEnumerationIndex();
7779     details = PropertyDetails(details.attributes(), details.type(), index);
7780     SetNextEnumerationIndex(index + 1);
7781   }
7782   SetEntry(entry, k, value, details);
7783   ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
7784           || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
7785   HashTable<Shape, Key>::ElementAdded();
7786   return this;
7787 }
7788 
7789 
UpdateMaxNumberKey(uint32_t key)7790 void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
7791   // If the dictionary requires slow elements an element has already
7792   // been added at a high index.
7793   if (requires_slow_elements()) return;
7794   // Check if this index is high enough that we should require slow
7795   // elements.
7796   if (key > kRequiresSlowElementsLimit) {
7797     set_requires_slow_elements();
7798     return;
7799   }
7800   // Update max key value.
7801   Object* max_index_object = get(kMaxNumberKeyIndex);
7802   if (!max_index_object->IsSmi() || max_number_key() < key) {
7803     FixedArray::set(kMaxNumberKeyIndex,
7804                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
7805   }
7806 }
7807 
7808 
AddNumberEntry(uint32_t key,Object * value,PropertyDetails details)7809 Object* NumberDictionary::AddNumberEntry(uint32_t key,
7810                                          Object* value,
7811                                          PropertyDetails details) {
7812   UpdateMaxNumberKey(key);
7813   SLOW_ASSERT(FindEntry(key) == kNotFound);
7814   return Add(key, value, details);
7815 }
7816 
7817 
AtNumberPut(uint32_t key,Object * value)7818 Object* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
7819   UpdateMaxNumberKey(key);
7820   return AtPut(key, value);
7821 }
7822 
7823 
Set(uint32_t key,Object * value,PropertyDetails details)7824 Object* NumberDictionary::Set(uint32_t key,
7825                               Object* value,
7826                               PropertyDetails details) {
7827   int entry = FindEntry(key);
7828   if (entry == kNotFound) return AddNumberEntry(key, value, details);
7829   // Preserve enumeration index.
7830   details = PropertyDetails(details.attributes(),
7831                             details.type(),
7832                             DetailsAt(entry).index());
7833   SetEntry(entry, NumberDictionaryShape::AsObject(key), value, details);
7834   return this;
7835 }
7836 
7837 
7838 
7839 template<typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyAttributes filter)7840 int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
7841     PropertyAttributes filter) {
7842   int capacity = HashTable<Shape, Key>::Capacity();
7843   int result = 0;
7844   for (int i = 0; i < capacity; i++) {
7845     Object* k = HashTable<Shape, Key>::KeyAt(i);
7846     if (HashTable<Shape, Key>::IsKey(k)) {
7847       PropertyDetails details = DetailsAt(i);
7848       if (details.IsDeleted()) continue;
7849       PropertyAttributes attr = details.attributes();
7850       if ((attr & filter) == 0) result++;
7851     }
7852   }
7853   return result;
7854 }
7855 
7856 
7857 template<typename Shape, typename Key>
NumberOfEnumElements()7858 int Dictionary<Shape, Key>::NumberOfEnumElements() {
7859   return NumberOfElementsFilterAttributes(
7860       static_cast<PropertyAttributes>(DONT_ENUM));
7861 }
7862 
7863 
7864 template<typename Shape, typename Key>
CopyKeysTo(FixedArray * storage,PropertyAttributes filter)7865 void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
7866                                         PropertyAttributes filter) {
7867   ASSERT(storage->length() >= NumberOfEnumElements());
7868   int capacity = HashTable<Shape, Key>::Capacity();
7869   int index = 0;
7870   for (int i = 0; i < capacity; i++) {
7871      Object* k = HashTable<Shape, Key>::KeyAt(i);
7872      if (HashTable<Shape, Key>::IsKey(k)) {
7873        PropertyDetails details = DetailsAt(i);
7874        if (details.IsDeleted()) continue;
7875        PropertyAttributes attr = details.attributes();
7876        if ((attr & filter) == 0) storage->set(index++, k);
7877      }
7878   }
7879   storage->SortPairs(storage, index);
7880   ASSERT(storage->length() >= index);
7881 }
7882 
7883 
CopyEnumKeysTo(FixedArray * storage,FixedArray * sort_array)7884 void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
7885                                       FixedArray* sort_array) {
7886   ASSERT(storage->length() >= NumberOfEnumElements());
7887   int capacity = Capacity();
7888   int index = 0;
7889   for (int i = 0; i < capacity; i++) {
7890      Object* k = KeyAt(i);
7891      if (IsKey(k)) {
7892        PropertyDetails details = DetailsAt(i);
7893        if (details.IsDeleted() || details.IsDontEnum()) continue;
7894        storage->set(index, k);
7895        sort_array->set(index, Smi::FromInt(details.index()));
7896        index++;
7897      }
7898   }
7899   storage->SortPairs(sort_array, sort_array->length());
7900   ASSERT(storage->length() >= index);
7901 }
7902 
7903 
7904 template<typename Shape, typename Key>
CopyKeysTo(FixedArray * storage)7905 void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
7906   ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
7907       static_cast<PropertyAttributes>(NONE)));
7908   int capacity = HashTable<Shape, Key>::Capacity();
7909   int index = 0;
7910   for (int i = 0; i < capacity; i++) {
7911     Object* k = HashTable<Shape, Key>::KeyAt(i);
7912     if (HashTable<Shape, Key>::IsKey(k)) {
7913       PropertyDetails details = DetailsAt(i);
7914       if (details.IsDeleted()) continue;
7915       storage->set(index++, k);
7916     }
7917   }
7918   ASSERT(storage->length() >= index);
7919 }
7920 
7921 
7922 // Backwards lookup (slow).
7923 template<typename Shape, typename Key>
SlowReverseLookup(Object * value)7924 Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
7925   int capacity = HashTable<Shape, Key>::Capacity();
7926   for (int i = 0; i < capacity; i++) {
7927     Object* k =  HashTable<Shape, Key>::KeyAt(i);
7928     if (Dictionary<Shape, Key>::IsKey(k)) {
7929       Object* e = ValueAt(i);
7930       if (e->IsJSGlobalPropertyCell()) {
7931         e = JSGlobalPropertyCell::cast(e)->value();
7932       }
7933       if (e == value) return k;
7934     }
7935   }
7936   return Heap::undefined_value();
7937 }
7938 
7939 
TransformPropertiesToFastFor(JSObject * obj,int unused_property_fields)7940 Object* StringDictionary::TransformPropertiesToFastFor(
7941     JSObject* obj, int unused_property_fields) {
7942   // Make sure we preserve dictionary representation if there are too many
7943   // descriptors.
7944   if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
7945 
7946   // Figure out if it is necessary to generate new enumeration indices.
7947   int max_enumeration_index =
7948       NextEnumerationIndex() +
7949           (DescriptorArray::kMaxNumberOfDescriptors -
7950            NumberOfElements());
7951   if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
7952     Object* result = GenerateNewEnumerationIndices();
7953     if (result->IsFailure()) return result;
7954   }
7955 
7956   int instance_descriptor_length = 0;
7957   int number_of_fields = 0;
7958 
7959   // Compute the length of the instance descriptor.
7960   int capacity = Capacity();
7961   for (int i = 0; i < capacity; i++) {
7962     Object* k = KeyAt(i);
7963     if (IsKey(k)) {
7964       Object* value = ValueAt(i);
7965       PropertyType type = DetailsAt(i).type();
7966       ASSERT(type != FIELD);
7967       instance_descriptor_length++;
7968       if (type == NORMAL &&
7969           (!value->IsJSFunction() || Heap::InNewSpace(value))) {
7970         number_of_fields += 1;
7971       }
7972     }
7973   }
7974 
7975   // Allocate the instance descriptor.
7976   Object* descriptors_unchecked =
7977       DescriptorArray::Allocate(instance_descriptor_length);
7978   if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
7979   DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
7980 
7981   int inobject_props = obj->map()->inobject_properties();
7982   int number_of_allocated_fields =
7983       number_of_fields + unused_property_fields - inobject_props;
7984 
7985   // Allocate the fixed array for the fields.
7986   Object* fields = Heap::AllocateFixedArray(number_of_allocated_fields);
7987   if (fields->IsFailure()) return fields;
7988 
7989   // Fill in the instance descriptor and the fields.
7990   int next_descriptor = 0;
7991   int current_offset = 0;
7992   for (int i = 0; i < capacity; i++) {
7993     Object* k = KeyAt(i);
7994     if (IsKey(k)) {
7995       Object* value = ValueAt(i);
7996       // Ensure the key is a symbol before writing into the instance descriptor.
7997       Object* key = Heap::LookupSymbol(String::cast(k));
7998       if (key->IsFailure()) return key;
7999       PropertyDetails details = DetailsAt(i);
8000       PropertyType type = details.type();
8001 
8002       if (value->IsJSFunction() && !Heap::InNewSpace(value)) {
8003         ConstantFunctionDescriptor d(String::cast(key),
8004                                      JSFunction::cast(value),
8005                                      details.attributes(),
8006                                      details.index());
8007         descriptors->Set(next_descriptor++, &d);
8008       } else if (type == NORMAL) {
8009         if (current_offset < inobject_props) {
8010           obj->InObjectPropertyAtPut(current_offset,
8011                                      value,
8012                                      UPDATE_WRITE_BARRIER);
8013         } else {
8014           int offset = current_offset - inobject_props;
8015           FixedArray::cast(fields)->set(offset, value);
8016         }
8017         FieldDescriptor d(String::cast(key),
8018                           current_offset++,
8019                           details.attributes(),
8020                           details.index());
8021         descriptors->Set(next_descriptor++, &d);
8022       } else if (type == CALLBACKS) {
8023         CallbacksDescriptor d(String::cast(key),
8024                               value,
8025                               details.attributes(),
8026                               details.index());
8027         descriptors->Set(next_descriptor++, &d);
8028       } else {
8029         UNREACHABLE();
8030       }
8031     }
8032   }
8033   ASSERT(current_offset == number_of_fields);
8034 
8035   descriptors->Sort();
8036   // Allocate new map.
8037   Object* new_map = obj->map()->CopyDropDescriptors();
8038   if (new_map->IsFailure()) return new_map;
8039 
8040   // Transform the object.
8041   obj->set_map(Map::cast(new_map));
8042   obj->map()->set_instance_descriptors(descriptors);
8043   obj->map()->set_unused_property_fields(unused_property_fields);
8044 
8045   obj->set_properties(FixedArray::cast(fields));
8046   ASSERT(obj->IsJSObject());
8047 
8048   descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
8049   // Check that it really works.
8050   ASSERT(obj->HasFastProperties());
8051 
8052   return obj;
8053 }
8054 
8055 
8056 #ifdef ENABLE_DEBUGGER_SUPPORT
8057 // Check if there is a break point at this code position.
HasBreakPoint(int code_position)8058 bool DebugInfo::HasBreakPoint(int code_position) {
8059   // Get the break point info object for this code position.
8060   Object* break_point_info = GetBreakPointInfo(code_position);
8061 
8062   // If there is no break point info object or no break points in the break
8063   // point info object there is no break point at this code position.
8064   if (break_point_info->IsUndefined()) return false;
8065   return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
8066 }
8067 
8068 
8069 // Get the break point info object for this code position.
GetBreakPointInfo(int code_position)8070 Object* DebugInfo::GetBreakPointInfo(int code_position) {
8071   // Find the index of the break point info object for this code position.
8072   int index = GetBreakPointInfoIndex(code_position);
8073 
8074   // Return the break point info object if any.
8075   if (index == kNoBreakPointInfo) return Heap::undefined_value();
8076   return BreakPointInfo::cast(break_points()->get(index));
8077 }
8078 
8079 
8080 // Clear a break point at the specified code position.
ClearBreakPoint(Handle<DebugInfo> debug_info,int code_position,Handle<Object> break_point_object)8081 void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
8082                                 int code_position,
8083                                 Handle<Object> break_point_object) {
8084   Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
8085   if (break_point_info->IsUndefined()) return;
8086   BreakPointInfo::ClearBreakPoint(
8087       Handle<BreakPointInfo>::cast(break_point_info),
8088       break_point_object);
8089 }
8090 
8091 
SetBreakPoint(Handle<DebugInfo> debug_info,int code_position,int source_position,int statement_position,Handle<Object> break_point_object)8092 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
8093                               int code_position,
8094                               int source_position,
8095                               int statement_position,
8096                               Handle<Object> break_point_object) {
8097   Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
8098   if (!break_point_info->IsUndefined()) {
8099     BreakPointInfo::SetBreakPoint(
8100         Handle<BreakPointInfo>::cast(break_point_info),
8101         break_point_object);
8102     return;
8103   }
8104 
8105   // Adding a new break point for a code position which did not have any
8106   // break points before. Try to find a free slot.
8107   int index = kNoBreakPointInfo;
8108   for (int i = 0; i < debug_info->break_points()->length(); i++) {
8109     if (debug_info->break_points()->get(i)->IsUndefined()) {
8110       index = i;
8111       break;
8112     }
8113   }
8114   if (index == kNoBreakPointInfo) {
8115     // No free slot - extend break point info array.
8116     Handle<FixedArray> old_break_points =
8117         Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
8118     debug_info->set_break_points(*Factory::NewFixedArray(
8119         old_break_points->length() +
8120             Debug::kEstimatedNofBreakPointsInFunction));
8121     Handle<FixedArray> new_break_points =
8122         Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
8123     for (int i = 0; i < old_break_points->length(); i++) {
8124       new_break_points->set(i, old_break_points->get(i));
8125     }
8126     index = old_break_points->length();
8127   }
8128   ASSERT(index != kNoBreakPointInfo);
8129 
8130   // Allocate new BreakPointInfo object and set the break point.
8131   Handle<BreakPointInfo> new_break_point_info =
8132       Handle<BreakPointInfo>::cast(Factory::NewStruct(BREAK_POINT_INFO_TYPE));
8133   new_break_point_info->set_code_position(Smi::FromInt(code_position));
8134   new_break_point_info->set_source_position(Smi::FromInt(source_position));
8135   new_break_point_info->
8136       set_statement_position(Smi::FromInt(statement_position));
8137   new_break_point_info->set_break_point_objects(Heap::undefined_value());
8138   BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
8139   debug_info->break_points()->set(index, *new_break_point_info);
8140 }
8141 
8142 
8143 // Get the break point objects for a code position.
GetBreakPointObjects(int code_position)8144 Object* DebugInfo::GetBreakPointObjects(int code_position) {
8145   Object* break_point_info = GetBreakPointInfo(code_position);
8146   if (break_point_info->IsUndefined()) {
8147     return Heap::undefined_value();
8148   }
8149   return BreakPointInfo::cast(break_point_info)->break_point_objects();
8150 }
8151 
8152 
8153 // Get the total number of break points.
GetBreakPointCount()8154 int DebugInfo::GetBreakPointCount() {
8155   if (break_points()->IsUndefined()) return 0;
8156   int count = 0;
8157   for (int i = 0; i < break_points()->length(); i++) {
8158     if (!break_points()->get(i)->IsUndefined()) {
8159       BreakPointInfo* break_point_info =
8160           BreakPointInfo::cast(break_points()->get(i));
8161       count += break_point_info->GetBreakPointCount();
8162     }
8163   }
8164   return count;
8165 }
8166 
8167 
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)8168 Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
8169                                       Handle<Object> break_point_object) {
8170   if (debug_info->break_points()->IsUndefined()) return Heap::undefined_value();
8171   for (int i = 0; i < debug_info->break_points()->length(); i++) {
8172     if (!debug_info->break_points()->get(i)->IsUndefined()) {
8173       Handle<BreakPointInfo> break_point_info =
8174           Handle<BreakPointInfo>(BreakPointInfo::cast(
8175               debug_info->break_points()->get(i)));
8176       if (BreakPointInfo::HasBreakPointObject(break_point_info,
8177                                               break_point_object)) {
8178         return *break_point_info;
8179       }
8180     }
8181   }
8182   return Heap::undefined_value();
8183 }
8184 
8185 
8186 // Find the index of the break point info object for the specified code
8187 // position.
GetBreakPointInfoIndex(int code_position)8188 int DebugInfo::GetBreakPointInfoIndex(int code_position) {
8189   if (break_points()->IsUndefined()) return kNoBreakPointInfo;
8190   for (int i = 0; i < break_points()->length(); i++) {
8191     if (!break_points()->get(i)->IsUndefined()) {
8192       BreakPointInfo* break_point_info =
8193           BreakPointInfo::cast(break_points()->get(i));
8194       if (break_point_info->code_position()->value() == code_position) {
8195         return i;
8196       }
8197     }
8198   }
8199   return kNoBreakPointInfo;
8200 }
8201 
8202 
8203 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)8204 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
8205                                      Handle<Object> break_point_object) {
8206   // If there are no break points just ignore.
8207   if (break_point_info->break_point_objects()->IsUndefined()) return;
8208   // If there is a single break point clear it if it is the same.
8209   if (!break_point_info->break_point_objects()->IsFixedArray()) {
8210     if (break_point_info->break_point_objects() == *break_point_object) {
8211       break_point_info->set_break_point_objects(Heap::undefined_value());
8212     }
8213     return;
8214   }
8215   // If there are multiple break points shrink the array
8216   ASSERT(break_point_info->break_point_objects()->IsFixedArray());
8217   Handle<FixedArray> old_array =
8218       Handle<FixedArray>(
8219           FixedArray::cast(break_point_info->break_point_objects()));
8220   Handle<FixedArray> new_array =
8221       Factory::NewFixedArray(old_array->length() - 1);
8222   int found_count = 0;
8223   for (int i = 0; i < old_array->length(); i++) {
8224     if (old_array->get(i) == *break_point_object) {
8225       ASSERT(found_count == 0);
8226       found_count++;
8227     } else {
8228       new_array->set(i - found_count, old_array->get(i));
8229     }
8230   }
8231   // If the break point was found in the list change it.
8232   if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
8233 }
8234 
8235 
8236 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)8237 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
8238                                    Handle<Object> break_point_object) {
8239   // If there was no break point objects before just set it.
8240   if (break_point_info->break_point_objects()->IsUndefined()) {
8241     break_point_info->set_break_point_objects(*break_point_object);
8242     return;
8243   }
8244   // If the break point object is the same as before just ignore.
8245   if (break_point_info->break_point_objects() == *break_point_object) return;
8246   // If there was one break point object before replace with array.
8247   if (!break_point_info->break_point_objects()->IsFixedArray()) {
8248     Handle<FixedArray> array = Factory::NewFixedArray(2);
8249     array->set(0, break_point_info->break_point_objects());
8250     array->set(1, *break_point_object);
8251     break_point_info->set_break_point_objects(*array);
8252     return;
8253   }
8254   // If there was more than one break point before extend array.
8255   Handle<FixedArray> old_array =
8256       Handle<FixedArray>(
8257           FixedArray::cast(break_point_info->break_point_objects()));
8258   Handle<FixedArray> new_array =
8259       Factory::NewFixedArray(old_array->length() + 1);
8260   for (int i = 0; i < old_array->length(); i++) {
8261     // If the break point was there before just ignore.
8262     if (old_array->get(i) == *break_point_object) return;
8263     new_array->set(i, old_array->get(i));
8264   }
8265   // Add the new break point.
8266   new_array->set(old_array->length(), *break_point_object);
8267   break_point_info->set_break_point_objects(*new_array);
8268 }
8269 
8270 
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)8271 bool BreakPointInfo::HasBreakPointObject(
8272     Handle<BreakPointInfo> break_point_info,
8273     Handle<Object> break_point_object) {
8274   // No break point.
8275   if (break_point_info->break_point_objects()->IsUndefined()) return false;
8276   // Single beak point.
8277   if (!break_point_info->break_point_objects()->IsFixedArray()) {
8278     return break_point_info->break_point_objects() == *break_point_object;
8279   }
8280   // Multiple break points.
8281   FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
8282   for (int i = 0; i < array->length(); i++) {
8283     if (array->get(i) == *break_point_object) {
8284       return true;
8285     }
8286   }
8287   return false;
8288 }
8289 
8290 
8291 // Get the number of break points.
GetBreakPointCount()8292 int BreakPointInfo::GetBreakPointCount() {
8293   // No break point.
8294   if (break_point_objects()->IsUndefined()) return 0;
8295   // Single beak point.
8296   if (!break_point_objects()->IsFixedArray()) return 1;
8297   // Multiple break points.
8298   return FixedArray::cast(break_point_objects())->length();
8299 }
8300 #endif
8301 
8302 
8303 } }  // namespace v8::internal
8304