1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #include "api.h"
31 #include "arguments.h"
32 #include "bootstrapper.h"
33 #include "codegen.h"
34 #include "debug.h"
35 #include "deoptimizer.h"
36 #include "date.h"
37 #include "elements.h"
38 #include "execution.h"
39 #include "full-codegen.h"
40 #include "hydrogen.h"
41 #include "objects-inl.h"
42 #include "objects-visiting.h"
43 #include "objects-visiting-inl.h"
44 #include "macro-assembler.h"
45 #include "mark-compact.h"
46 #include "safepoint-table.h"
47 #include "string-stream.h"
48 #include "utils.h"
49 #include "vm-state-inl.h"
50
51 #ifdef ENABLE_DISASSEMBLER
52 #include "disasm.h"
53 #include "disassembler.h"
54 #endif
55
56 namespace v8 {
57 namespace internal {
58
PrintElementsKind(FILE * out,ElementsKind kind)59 void PrintElementsKind(FILE* out, ElementsKind kind) {
60 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
61 PrintF(out, "%s", accessor->name());
62 }
63
64
CreateJSValue(JSFunction * constructor,Object * value)65 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
66 Object* value) {
67 Object* result;
68 { MaybeObject* maybe_result =
69 constructor->GetHeap()->AllocateJSObject(constructor);
70 if (!maybe_result->ToObject(&result)) return maybe_result;
71 }
72 JSValue::cast(result)->set_value(value);
73 return result;
74 }
75
76
ToObject(Context * global_context)77 MaybeObject* Object::ToObject(Context* global_context) {
78 if (IsNumber()) {
79 return CreateJSValue(global_context->number_function(), this);
80 } else if (IsBoolean()) {
81 return CreateJSValue(global_context->boolean_function(), this);
82 } else if (IsString()) {
83 return CreateJSValue(global_context->string_function(), this);
84 }
85 ASSERT(IsJSObject());
86 return this;
87 }
88
89
ToObject()90 MaybeObject* Object::ToObject() {
91 if (IsJSReceiver()) {
92 return this;
93 } else if (IsNumber()) {
94 Isolate* isolate = Isolate::Current();
95 Context* global_context = isolate->context()->global_context();
96 return CreateJSValue(global_context->number_function(), this);
97 } else if (IsBoolean()) {
98 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
99 Context* global_context = isolate->context()->global_context();
100 return CreateJSValue(global_context->boolean_function(), this);
101 } else if (IsString()) {
102 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
103 Context* global_context = isolate->context()->global_context();
104 return CreateJSValue(global_context->string_function(), this);
105 }
106
107 // Throw a type error.
108 return Failure::InternalError();
109 }
110
111
ToBoolean()112 Object* Object::ToBoolean() {
113 if (IsTrue()) return this;
114 if (IsFalse()) return this;
115 if (IsSmi()) {
116 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
117 }
118 HeapObject* heap_object = HeapObject::cast(this);
119 if (heap_object->IsUndefined() || heap_object->IsNull()) {
120 return heap_object->GetHeap()->false_value();
121 }
122 // Undetectable object is false
123 if (heap_object->IsUndetectableObject()) {
124 return heap_object->GetHeap()->false_value();
125 }
126 if (heap_object->IsString()) {
127 return heap_object->GetHeap()->ToBoolean(
128 String::cast(this)->length() != 0);
129 }
130 if (heap_object->IsHeapNumber()) {
131 return HeapNumber::cast(this)->HeapNumberToBoolean();
132 }
133 return heap_object->GetHeap()->true_value();
134 }
135
136
Lookup(String * name,LookupResult * result)137 void Object::Lookup(String* name, LookupResult* result) {
138 Object* holder = NULL;
139 if (IsJSReceiver()) {
140 holder = this;
141 } else {
142 Context* global_context = Isolate::Current()->context()->global_context();
143 if (IsNumber()) {
144 holder = global_context->number_function()->instance_prototype();
145 } else if (IsString()) {
146 holder = global_context->string_function()->instance_prototype();
147 } else if (IsBoolean()) {
148 holder = global_context->boolean_function()->instance_prototype();
149 }
150 }
151 ASSERT(holder != NULL); // Cannot handle null or undefined.
152 JSReceiver::cast(holder)->Lookup(name, result);
153 }
154
155
GetPropertyWithReceiver(Object * receiver,String * name,PropertyAttributes * attributes)156 MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
157 String* name,
158 PropertyAttributes* attributes) {
159 LookupResult result(name->GetIsolate());
160 Lookup(name, &result);
161 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
162 ASSERT(*attributes <= ABSENT);
163 return value;
164 }
165
166
GetPropertyWithCallback(Object * receiver,Object * structure,String * name)167 MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
168 Object* structure,
169 String* name) {
170 Isolate* isolate = name->GetIsolate();
171 // To accommodate both the old and the new api we switch on the
172 // data structure used to store the callbacks. Eventually foreign
173 // callbacks should be phased out.
174 if (structure->IsForeign()) {
175 AccessorDescriptor* callback =
176 reinterpret_cast<AccessorDescriptor*>(
177 Foreign::cast(structure)->foreign_address());
178 MaybeObject* value = (callback->getter)(receiver, callback->data);
179 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
180 return value;
181 }
182
183 // api style callbacks.
184 if (structure->IsAccessorInfo()) {
185 AccessorInfo* data = AccessorInfo::cast(structure);
186 Object* fun_obj = data->getter();
187 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
188 HandleScope scope(isolate);
189 JSObject* self = JSObject::cast(receiver);
190 Handle<String> key(name);
191 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
192 CustomArguments args(isolate, data->data(), self, this);
193 v8::AccessorInfo info(args.end());
194 v8::Handle<v8::Value> result;
195 {
196 // Leaving JavaScript.
197 VMState state(isolate, EXTERNAL);
198 result = call_fun(v8::Utils::ToLocal(key), info);
199 }
200 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
201 if (result.IsEmpty()) {
202 return isolate->heap()->undefined_value();
203 }
204 return *v8::Utils::OpenHandle(*result);
205 }
206
207 // __defineGetter__ callback
208 if (structure->IsAccessorPair()) {
209 Object* getter = AccessorPair::cast(structure)->getter();
210 if (getter->IsSpecFunction()) {
211 // TODO(rossberg): nicer would be to cast to some JSCallable here...
212 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
213 }
214 // Getter is not a function.
215 return isolate->heap()->undefined_value();
216 }
217
218 UNREACHABLE();
219 return NULL;
220 }
221
222
GetPropertyWithHandler(Object * receiver_raw,String * name_raw)223 MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
224 String* name_raw) {
225 Isolate* isolate = GetIsolate();
226 HandleScope scope(isolate);
227 Handle<Object> receiver(receiver_raw);
228 Handle<Object> name(name_raw);
229
230 Handle<Object> args[] = { receiver, name };
231 Handle<Object> result = CallTrap(
232 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
233 if (isolate->has_pending_exception()) return Failure::Exception();
234
235 return *result;
236 }
237
238
GetElement(Handle<Object> object,uint32_t index)239 Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
240 Isolate* isolate = object->IsHeapObject()
241 ? Handle<HeapObject>::cast(object)->GetIsolate()
242 : Isolate::Current();
243 CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
244 }
245
246
GetElementWithHandler(Object * receiver,uint32_t index)247 MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
248 uint32_t index) {
249 String* name;
250 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
251 if (!maybe->To<String>(&name)) return maybe;
252 return GetPropertyWithHandler(receiver, name);
253 }
254
255
SetElementWithHandler(uint32_t index,Object * value,StrictModeFlag strict_mode)256 MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
257 Object* value,
258 StrictModeFlag strict_mode) {
259 String* name;
260 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
261 if (!maybe->To<String>(&name)) return maybe;
262 return SetPropertyWithHandler(name, value, NONE, strict_mode);
263 }
264
265
HasElementWithHandler(uint32_t index)266 bool JSProxy::HasElementWithHandler(uint32_t index) {
267 String* name;
268 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
269 if (!maybe->To<String>(&name)) return maybe;
270 return HasPropertyWithHandler(name);
271 }
272
273
GetPropertyWithDefinedGetter(Object * receiver,JSReceiver * getter)274 MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
275 JSReceiver* getter) {
276 HandleScope scope;
277 Handle<JSReceiver> fun(getter);
278 Handle<Object> self(receiver);
279 #ifdef ENABLE_DEBUGGER_SUPPORT
280 Debug* debug = fun->GetHeap()->isolate()->debug();
281 // Handle stepping into a getter if step into is active.
282 // TODO(rossberg): should this apply to getters that are function proxies?
283 if (debug->StepInActive() && fun->IsJSFunction()) {
284 debug->HandleStepIn(
285 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
286 }
287 #endif
288
289 bool has_pending_exception;
290 Handle<Object> result =
291 Execution::Call(fun, self, 0, NULL, &has_pending_exception, true);
292 // Check for pending exception and return the result.
293 if (has_pending_exception) return Failure::Exception();
294 return *result;
295 }
296
297
298 // Only deal with CALLBACKS and INTERCEPTOR
GetPropertyWithFailedAccessCheck(Object * receiver,LookupResult * result,String * name,PropertyAttributes * attributes)299 MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
300 Object* receiver,
301 LookupResult* result,
302 String* name,
303 PropertyAttributes* attributes) {
304 if (result->IsProperty()) {
305 switch (result->type()) {
306 case CALLBACKS: {
307 // Only allow API accessors.
308 Object* obj = result->GetCallbackObject();
309 if (obj->IsAccessorInfo()) {
310 AccessorInfo* info = AccessorInfo::cast(obj);
311 if (info->all_can_read()) {
312 *attributes = result->GetAttributes();
313 return result->holder()->GetPropertyWithCallback(
314 receiver, result->GetCallbackObject(), name);
315 }
316 }
317 break;
318 }
319 case NORMAL:
320 case FIELD:
321 case CONSTANT_FUNCTION: {
322 // Search ALL_CAN_READ accessors in prototype chain.
323 LookupResult r(GetIsolate());
324 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
325 if (r.IsProperty()) {
326 return GetPropertyWithFailedAccessCheck(receiver,
327 &r,
328 name,
329 attributes);
330 }
331 break;
332 }
333 case INTERCEPTOR: {
334 // If the object has an interceptor, try real named properties.
335 // No access check in GetPropertyAttributeWithInterceptor.
336 LookupResult r(GetIsolate());
337 result->holder()->LookupRealNamedProperty(name, &r);
338 if (r.IsProperty()) {
339 return GetPropertyWithFailedAccessCheck(receiver,
340 &r,
341 name,
342 attributes);
343 }
344 break;
345 }
346 default:
347 UNREACHABLE();
348 }
349 }
350
351 // No accessible property found.
352 *attributes = ABSENT;
353 Heap* heap = name->GetHeap();
354 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
355 return heap->undefined_value();
356 }
357
358
GetPropertyAttributeWithFailedAccessCheck(Object * receiver,LookupResult * result,String * name,bool continue_search)359 PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
360 Object* receiver,
361 LookupResult* result,
362 String* name,
363 bool continue_search) {
364 if (result->IsProperty()) {
365 switch (result->type()) {
366 case CALLBACKS: {
367 // Only allow API accessors.
368 Object* obj = result->GetCallbackObject();
369 if (obj->IsAccessorInfo()) {
370 AccessorInfo* info = AccessorInfo::cast(obj);
371 if (info->all_can_read()) {
372 return result->GetAttributes();
373 }
374 }
375 break;
376 }
377
378 case NORMAL:
379 case FIELD:
380 case CONSTANT_FUNCTION: {
381 if (!continue_search) break;
382 // Search ALL_CAN_READ accessors in prototype chain.
383 LookupResult r(GetIsolate());
384 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
385 if (r.IsProperty()) {
386 return GetPropertyAttributeWithFailedAccessCheck(receiver,
387 &r,
388 name,
389 continue_search);
390 }
391 break;
392 }
393
394 case INTERCEPTOR: {
395 // If the object has an interceptor, try real named properties.
396 // No access check in GetPropertyAttributeWithInterceptor.
397 LookupResult r(GetIsolate());
398 if (continue_search) {
399 result->holder()->LookupRealNamedProperty(name, &r);
400 } else {
401 result->holder()->LocalLookupRealNamedProperty(name, &r);
402 }
403 if (r.IsProperty()) {
404 return GetPropertyAttributeWithFailedAccessCheck(receiver,
405 &r,
406 name,
407 continue_search);
408 }
409 break;
410 }
411
412 default:
413 UNREACHABLE();
414 }
415 }
416
417 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
418 return ABSENT;
419 }
420
421
GetNormalizedProperty(LookupResult * result)422 Object* JSObject::GetNormalizedProperty(LookupResult* result) {
423 ASSERT(!HasFastProperties());
424 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
425 if (IsGlobalObject()) {
426 value = JSGlobalPropertyCell::cast(value)->value();
427 }
428 ASSERT(!value->IsJSGlobalPropertyCell());
429 return value;
430 }
431
432
SetNormalizedProperty(LookupResult * result,Object * value)433 Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
434 ASSERT(!HasFastProperties());
435 if (IsGlobalObject()) {
436 JSGlobalPropertyCell* cell =
437 JSGlobalPropertyCell::cast(
438 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
439 cell->set_value(value);
440 } else {
441 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
442 }
443 return value;
444 }
445
446
SetNormalizedProperty(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyDetails details)447 Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
448 Handle<String> key,
449 Handle<Object> value,
450 PropertyDetails details) {
451 CALL_HEAP_FUNCTION(object->GetIsolate(),
452 object->SetNormalizedProperty(*key, *value, details),
453 Object);
454 }
455
456
SetNormalizedProperty(String * name,Object * value,PropertyDetails details)457 MaybeObject* JSObject::SetNormalizedProperty(String* name,
458 Object* value,
459 PropertyDetails details) {
460 ASSERT(!HasFastProperties());
461 int entry = property_dictionary()->FindEntry(name);
462 if (entry == StringDictionary::kNotFound) {
463 Object* store_value = value;
464 if (IsGlobalObject()) {
465 Heap* heap = name->GetHeap();
466 MaybeObject* maybe_store_value =
467 heap->AllocateJSGlobalPropertyCell(value);
468 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
469 }
470 Object* dict;
471 { MaybeObject* maybe_dict =
472 property_dictionary()->Add(name, store_value, details);
473 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
474 }
475 set_properties(StringDictionary::cast(dict));
476 return value;
477 }
478 // Preserve enumeration index.
479 details = PropertyDetails(details.attributes(),
480 details.type(),
481 property_dictionary()->DetailsAt(entry).index());
482 if (IsGlobalObject()) {
483 JSGlobalPropertyCell* cell =
484 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
485 cell->set_value(value);
486 // Please note we have to update the property details.
487 property_dictionary()->DetailsAtPut(entry, details);
488 } else {
489 property_dictionary()->SetEntry(entry, name, value, details);
490 }
491 return value;
492 }
493
494
DeleteNormalizedProperty(String * name,DeleteMode mode)495 MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
496 ASSERT(!HasFastProperties());
497 StringDictionary* dictionary = property_dictionary();
498 int entry = dictionary->FindEntry(name);
499 if (entry != StringDictionary::kNotFound) {
500 // If we have a global object set the cell to the hole.
501 if (IsGlobalObject()) {
502 PropertyDetails details = dictionary->DetailsAt(entry);
503 if (details.IsDontDelete()) {
504 if (mode != FORCE_DELETION) return GetHeap()->false_value();
505 // When forced to delete global properties, we have to make a
506 // map change to invalidate any ICs that think they can load
507 // from the DontDelete cell without checking if it contains
508 // the hole value.
509 Object* new_map;
510 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
511 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
512 }
513 set_map(Map::cast(new_map));
514 }
515 JSGlobalPropertyCell* cell =
516 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
517 cell->set_value(cell->GetHeap()->the_hole_value());
518 dictionary->DetailsAtPut(entry, details.AsDeleted());
519 } else {
520 Object* deleted = dictionary->DeleteProperty(entry, mode);
521 if (deleted == GetHeap()->true_value()) {
522 FixedArray* new_properties = NULL;
523 MaybeObject* maybe_properties = dictionary->Shrink(name);
524 if (!maybe_properties->To(&new_properties)) {
525 return maybe_properties;
526 }
527 set_properties(new_properties);
528 }
529 return deleted;
530 }
531 }
532 return GetHeap()->true_value();
533 }
534
535
IsDirty()536 bool JSObject::IsDirty() {
537 Object* cons_obj = map()->constructor();
538 if (!cons_obj->IsJSFunction())
539 return true;
540 JSFunction* fun = JSFunction::cast(cons_obj);
541 if (!fun->shared()->IsApiFunction())
542 return true;
543 // If the object is fully fast case and has the same map it was
544 // created with then no changes can have been made to it.
545 return map() != fun->initial_map()
546 || !HasFastElements()
547 || !HasFastProperties();
548 }
549
550
GetProperty(Handle<Object> object,Handle<Object> receiver,LookupResult * result,Handle<String> key,PropertyAttributes * attributes)551 Handle<Object> Object::GetProperty(Handle<Object> object,
552 Handle<Object> receiver,
553 LookupResult* result,
554 Handle<String> key,
555 PropertyAttributes* attributes) {
556 Isolate* isolate = object->IsHeapObject()
557 ? Handle<HeapObject>::cast(object)->GetIsolate()
558 : Isolate::Current();
559 CALL_HEAP_FUNCTION(
560 isolate,
561 object->GetProperty(*receiver, result, *key, attributes),
562 Object);
563 }
564
565
GetProperty(Object * receiver,LookupResult * result,String * name,PropertyAttributes * attributes)566 MaybeObject* Object::GetProperty(Object* receiver,
567 LookupResult* result,
568 String* name,
569 PropertyAttributes* attributes) {
570 // Make sure that the top context does not change when doing
571 // callbacks or interceptor calls.
572 AssertNoContextChange ncc;
573 Heap* heap = name->GetHeap();
574
575 // Traverse the prototype chain from the current object (this) to
576 // the holder and check for access rights. This avoids traversing the
577 // objects more than once in case of interceptors, because the
578 // holder will always be the interceptor holder and the search may
579 // only continue with a current object just after the interceptor
580 // holder in the prototype chain.
581 // Proxy handlers do not use the proxy's prototype, so we can skip this.
582 if (!result->IsHandler()) {
583 Object* last = result->IsProperty()
584 ? result->holder()
585 : Object::cast(heap->null_value());
586 ASSERT(this != this->GetPrototype());
587 for (Object* current = this; true; current = current->GetPrototype()) {
588 if (current->IsAccessCheckNeeded()) {
589 // Check if we're allowed to read from the current object. Note
590 // that even though we may not actually end up loading the named
591 // property from the current object, we still check that we have
592 // access to it.
593 JSObject* checked = JSObject::cast(current);
594 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
595 return checked->GetPropertyWithFailedAccessCheck(receiver,
596 result,
597 name,
598 attributes);
599 }
600 }
601 // Stop traversing the chain once we reach the last object in the
602 // chain; either the holder of the result or null in case of an
603 // absent property.
604 if (current == last) break;
605 }
606 }
607
608 if (!result->IsProperty()) {
609 *attributes = ABSENT;
610 return heap->undefined_value();
611 }
612 *attributes = result->GetAttributes();
613 Object* value;
614 switch (result->type()) {
615 case NORMAL:
616 value = result->holder()->GetNormalizedProperty(result);
617 ASSERT(!value->IsTheHole() || result->IsReadOnly());
618 return value->IsTheHole() ? heap->undefined_value() : value;
619 case FIELD:
620 value = result->holder()->FastPropertyAt(result->GetFieldIndex());
621 ASSERT(!value->IsTheHole() || result->IsReadOnly());
622 return value->IsTheHole() ? heap->undefined_value() : value;
623 case CONSTANT_FUNCTION:
624 return result->GetConstantFunction();
625 case CALLBACKS:
626 return result->holder()->GetPropertyWithCallback(
627 receiver, result->GetCallbackObject(), name);
628 case HANDLER:
629 return result->proxy()->GetPropertyWithHandler(receiver, name);
630 case INTERCEPTOR: {
631 JSObject* recvr = JSObject::cast(receiver);
632 return result->holder()->GetPropertyWithInterceptor(
633 recvr, name, attributes);
634 }
635 case MAP_TRANSITION:
636 case ELEMENTS_TRANSITION:
637 case CONSTANT_TRANSITION:
638 case NULL_DESCRIPTOR:
639 break;
640 }
641 UNREACHABLE();
642 return NULL;
643 }
644
645
GetElementWithReceiver(Object * receiver,uint32_t index)646 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
647 Heap* heap = IsSmi()
648 ? Isolate::Current()->heap()
649 : HeapObject::cast(this)->GetHeap();
650 Object* holder = this;
651
652 // Iterate up the prototype chain until an element is found or the null
653 // prototype is encountered.
654 for (holder = this;
655 holder != heap->null_value();
656 holder = holder->GetPrototype()) {
657 if (!holder->IsJSObject()) {
658 Isolate* isolate = heap->isolate();
659 Context* global_context = isolate->context()->global_context();
660 if (holder->IsNumber()) {
661 holder = global_context->number_function()->instance_prototype();
662 } else if (holder->IsString()) {
663 holder = global_context->string_function()->instance_prototype();
664 } else if (holder->IsBoolean()) {
665 holder = global_context->boolean_function()->instance_prototype();
666 } else if (holder->IsJSProxy()) {
667 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
668 } else {
669 // Undefined and null have no indexed properties.
670 ASSERT(holder->IsUndefined() || holder->IsNull());
671 return heap->undefined_value();
672 }
673 }
674
675 // Inline the case for JSObjects. Doing so significantly improves the
676 // performance of fetching elements where checking the prototype chain is
677 // necessary.
678 JSObject* js_object = JSObject::cast(holder);
679
680 // Check access rights if needed.
681 if (js_object->IsAccessCheckNeeded()) {
682 Isolate* isolate = heap->isolate();
683 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
684 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
685 return heap->undefined_value();
686 }
687 }
688
689 if (js_object->HasIndexedInterceptor()) {
690 return js_object->GetElementWithInterceptor(receiver, index);
691 }
692
693 if (js_object->elements() != heap->empty_fixed_array()) {
694 MaybeObject* result = js_object->GetElementsAccessor()->Get(
695 receiver, js_object, index);
696 if (result != heap->the_hole_value()) return result;
697 }
698 }
699
700 return heap->undefined_value();
701 }
702
703
GetPrototype()704 Object* Object::GetPrototype() {
705 if (IsSmi()) {
706 Heap* heap = Isolate::Current()->heap();
707 Context* context = heap->isolate()->context()->global_context();
708 return context->number_function()->instance_prototype();
709 }
710
711 HeapObject* heap_object = HeapObject::cast(this);
712
713 // The object is either a number, a string, a boolean,
714 // a real JS object, or a Harmony proxy.
715 if (heap_object->IsJSReceiver()) {
716 return heap_object->map()->prototype();
717 }
718 Heap* heap = heap_object->GetHeap();
719 Context* context = heap->isolate()->context()->global_context();
720
721 if (heap_object->IsHeapNumber()) {
722 return context->number_function()->instance_prototype();
723 }
724 if (heap_object->IsString()) {
725 return context->string_function()->instance_prototype();
726 }
727 if (heap_object->IsBoolean()) {
728 return context->boolean_function()->instance_prototype();
729 } else {
730 return heap->null_value();
731 }
732 }
733
734
GetHash(CreationFlag flag)735 MaybeObject* Object::GetHash(CreationFlag flag) {
736 // The object is either a number, a string, an odd-ball,
737 // a real JS object, or a Harmony proxy.
738 if (IsNumber()) {
739 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
740 return Smi::FromInt(hash & Smi::kMaxValue);
741 }
742 if (IsString()) {
743 uint32_t hash = String::cast(this)->Hash();
744 return Smi::FromInt(hash);
745 }
746 if (IsOddball()) {
747 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
748 return Smi::FromInt(hash);
749 }
750 if (IsJSReceiver()) {
751 return JSReceiver::cast(this)->GetIdentityHash(flag);
752 }
753
754 UNREACHABLE();
755 return Smi::FromInt(0);
756 }
757
758
SameValue(Object * other)759 bool Object::SameValue(Object* other) {
760 if (other == this) return true;
761 if (!IsHeapObject() || !other->IsHeapObject()) return false;
762
763 // The object is either a number, a string, an odd-ball,
764 // a real JS object, or a Harmony proxy.
765 if (IsNumber() && other->IsNumber()) {
766 double this_value = Number();
767 double other_value = other->Number();
768 return (this_value == other_value) ||
769 (isnan(this_value) && isnan(other_value));
770 }
771 if (IsString() && other->IsString()) {
772 return String::cast(this)->Equals(String::cast(other));
773 }
774 return false;
775 }
776
777
ShortPrint(FILE * out)778 void Object::ShortPrint(FILE* out) {
779 HeapStringAllocator allocator;
780 StringStream accumulator(&allocator);
781 ShortPrint(&accumulator);
782 accumulator.OutputToFile(out);
783 }
784
785
ShortPrint(StringStream * accumulator)786 void Object::ShortPrint(StringStream* accumulator) {
787 if (IsSmi()) {
788 Smi::cast(this)->SmiPrint(accumulator);
789 } else if (IsFailure()) {
790 Failure::cast(this)->FailurePrint(accumulator);
791 } else {
792 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
793 }
794 }
795
796
SmiPrint(FILE * out)797 void Smi::SmiPrint(FILE* out) {
798 PrintF(out, "%d", value());
799 }
800
801
SmiPrint(StringStream * accumulator)802 void Smi::SmiPrint(StringStream* accumulator) {
803 accumulator->Add("%d", value());
804 }
805
806
FailurePrint(StringStream * accumulator)807 void Failure::FailurePrint(StringStream* accumulator) {
808 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
809 }
810
811
FailurePrint(FILE * out)812 void Failure::FailurePrint(FILE* out) {
813 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
814 }
815
816
817 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
818 // English? Returns false for non-ASCII or words that don't start with
819 // a capital letter. The a/an rule follows pronunciation in English.
820 // We don't use the BBC's overcorrect "an historic occasion" though if
821 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)822 static bool AnWord(String* str) {
823 if (str->length() == 0) return false; // A nothing.
824 int c0 = str->Get(0);
825 int c1 = str->length() > 1 ? str->Get(1) : 0;
826 if (c0 == 'U') {
827 if (c1 > 'Z') {
828 return true; // An Umpire, but a UTF8String, a U.
829 }
830 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
831 return true; // An Ape, an ABCBook.
832 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
833 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
834 c0 == 'S' || c0 == 'X')) {
835 return true; // An MP3File, an M.
836 }
837 return false;
838 }
839
840
SlowTryFlatten(PretenureFlag pretenure)841 MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
842 #ifdef DEBUG
843 // Do not attempt to flatten in debug mode when allocation is not
844 // allowed. This is to avoid an assertion failure when allocating.
845 // Flattening strings is the only case where we always allow
846 // allocation because no GC is performed if the allocation fails.
847 if (!HEAP->IsAllocationAllowed()) return this;
848 #endif
849
850 Heap* heap = GetHeap();
851 switch (StringShape(this).representation_tag()) {
852 case kConsStringTag: {
853 ConsString* cs = ConsString::cast(this);
854 if (cs->second()->length() == 0) {
855 return cs->first();
856 }
857 // There's little point in putting the flat string in new space if the
858 // cons string is in old space. It can never get GCed until there is
859 // an old space GC.
860 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
861 int len = length();
862 Object* object;
863 String* result;
864 if (IsAsciiRepresentation()) {
865 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
866 if (!maybe_object->ToObject(&object)) return maybe_object;
867 }
868 result = String::cast(object);
869 String* first = cs->first();
870 int first_length = first->length();
871 char* dest = SeqAsciiString::cast(result)->GetChars();
872 WriteToFlat(first, dest, 0, first_length);
873 String* second = cs->second();
874 WriteToFlat(second,
875 dest + first_length,
876 0,
877 len - first_length);
878 } else {
879 { MaybeObject* maybe_object =
880 heap->AllocateRawTwoByteString(len, tenure);
881 if (!maybe_object->ToObject(&object)) return maybe_object;
882 }
883 result = String::cast(object);
884 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
885 String* first = cs->first();
886 int first_length = first->length();
887 WriteToFlat(first, dest, 0, first_length);
888 String* second = cs->second();
889 WriteToFlat(second,
890 dest + first_length,
891 0,
892 len - first_length);
893 }
894 cs->set_first(result);
895 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
896 return result;
897 }
898 default:
899 return this;
900 }
901 }
902
903
MakeExternal(v8::String::ExternalStringResource * resource)904 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
905 // Externalizing twice leaks the external resource, so it's
906 // prohibited by the API.
907 ASSERT(!this->IsExternalString());
908 #ifdef DEBUG
909 if (FLAG_enable_slow_asserts) {
910 // Assert that the resource and the string are equivalent.
911 ASSERT(static_cast<size_t>(this->length()) == resource->length());
912 ScopedVector<uc16> smart_chars(this->length());
913 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
914 ASSERT(memcmp(smart_chars.start(),
915 resource->data(),
916 resource->length() * sizeof(smart_chars[0])) == 0);
917 }
918 #endif // DEBUG
919 Heap* heap = GetHeap();
920 int size = this->Size(); // Byte size of the original string.
921 if (size < ExternalString::kShortSize) {
922 return false;
923 }
924 bool is_ascii = this->IsAsciiRepresentation();
925 bool is_symbol = this->IsSymbol();
926
927 // Morph the object to an external string by adjusting the map and
928 // reinitializing the fields.
929 if (size >= ExternalString::kSize) {
930 this->set_map_no_write_barrier(
931 is_symbol
932 ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
933 : heap->external_symbol_map())
934 : (is_ascii ? heap->external_string_with_ascii_data_map()
935 : heap->external_string_map()));
936 } else {
937 this->set_map_no_write_barrier(
938 is_symbol
939 ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
940 : heap->short_external_symbol_map())
941 : (is_ascii ? heap->short_external_string_with_ascii_data_map()
942 : heap->short_external_string_map()));
943 }
944 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
945 self->set_resource(resource);
946 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
947
948 // Fill the remainder of the string with dead wood.
949 int new_size = this->Size(); // Byte size of the external String object.
950 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
951 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
952 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
953 new_size - size);
954 }
955 return true;
956 }
957
958
MakeExternal(v8::String::ExternalAsciiStringResource * resource)959 bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
960 #ifdef DEBUG
961 if (FLAG_enable_slow_asserts) {
962 // Assert that the resource and the string are equivalent.
963 ASSERT(static_cast<size_t>(this->length()) == resource->length());
964 ScopedVector<char> smart_chars(this->length());
965 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
966 ASSERT(memcmp(smart_chars.start(),
967 resource->data(),
968 resource->length() * sizeof(smart_chars[0])) == 0);
969 }
970 #endif // DEBUG
971 Heap* heap = GetHeap();
972 int size = this->Size(); // Byte size of the original string.
973 if (size < ExternalString::kShortSize) {
974 return false;
975 }
976 bool is_symbol = this->IsSymbol();
977
978 // Morph the object to an external string by adjusting the map and
979 // reinitializing the fields. Use short version if space is limited.
980 if (size >= ExternalString::kSize) {
981 this->set_map_no_write_barrier(
982 is_symbol ? heap->external_ascii_symbol_map()
983 : heap->external_ascii_string_map());
984 } else {
985 this->set_map_no_write_barrier(
986 is_symbol ? heap->short_external_ascii_symbol_map()
987 : heap->short_external_ascii_string_map());
988 }
989 ExternalAsciiString* self = ExternalAsciiString::cast(this);
990 self->set_resource(resource);
991 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
992
993 // Fill the remainder of the string with dead wood.
994 int new_size = this->Size(); // Byte size of the external String object.
995 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
996 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
997 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
998 new_size - size);
999 }
1000 return true;
1001 }
1002
1003
StringShortPrint(StringStream * accumulator)1004 void String::StringShortPrint(StringStream* accumulator) {
1005 int len = length();
1006 if (len > kMaxShortPrintLength) {
1007 accumulator->Add("<Very long string[%u]>", len);
1008 return;
1009 }
1010
1011 if (!LooksValid()) {
1012 accumulator->Add("<Invalid String>");
1013 return;
1014 }
1015
1016 StringInputBuffer buf(this);
1017
1018 bool truncated = false;
1019 if (len > kMaxShortPrintLength) {
1020 len = kMaxShortPrintLength;
1021 truncated = true;
1022 }
1023 bool ascii = true;
1024 for (int i = 0; i < len; i++) {
1025 int c = buf.GetNext();
1026
1027 if (c < 32 || c >= 127) {
1028 ascii = false;
1029 }
1030 }
1031 buf.Reset(this);
1032 if (ascii) {
1033 accumulator->Add("<String[%u]: ", length());
1034 for (int i = 0; i < len; i++) {
1035 accumulator->Put(buf.GetNext());
1036 }
1037 accumulator->Put('>');
1038 } else {
1039 // Backslash indicates that the string contains control
1040 // characters and that backslashes are therefore escaped.
1041 accumulator->Add("<String[%u]\\: ", length());
1042 for (int i = 0; i < len; i++) {
1043 int c = buf.GetNext();
1044 if (c == '\n') {
1045 accumulator->Add("\\n");
1046 } else if (c == '\r') {
1047 accumulator->Add("\\r");
1048 } else if (c == '\\') {
1049 accumulator->Add("\\\\");
1050 } else if (c < 32 || c > 126) {
1051 accumulator->Add("\\x%02x", c);
1052 } else {
1053 accumulator->Put(c);
1054 }
1055 }
1056 if (truncated) {
1057 accumulator->Put('.');
1058 accumulator->Put('.');
1059 accumulator->Put('.');
1060 }
1061 accumulator->Put('>');
1062 }
1063 return;
1064 }
1065
1066
JSObjectShortPrint(StringStream * accumulator)1067 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1068 switch (map()->instance_type()) {
1069 case JS_ARRAY_TYPE: {
1070 double length = JSArray::cast(this)->length()->Number();
1071 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
1072 break;
1073 }
1074 case JS_WEAK_MAP_TYPE: {
1075 accumulator->Add("<JS WeakMap>");
1076 break;
1077 }
1078 case JS_REGEXP_TYPE: {
1079 accumulator->Add("<JS RegExp>");
1080 break;
1081 }
1082 case JS_FUNCTION_TYPE: {
1083 Object* fun_name = JSFunction::cast(this)->shared()->name();
1084 bool printed = false;
1085 if (fun_name->IsString()) {
1086 String* str = String::cast(fun_name);
1087 if (str->length() > 0) {
1088 accumulator->Add("<JS Function ");
1089 accumulator->Put(str);
1090 accumulator->Put('>');
1091 printed = true;
1092 }
1093 }
1094 if (!printed) {
1095 accumulator->Add("<JS Function>");
1096 }
1097 break;
1098 }
1099 // All other JSObjects are rather similar to each other (JSObject,
1100 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1101 default: {
1102 Map* map_of_this = map();
1103 Heap* heap = GetHeap();
1104 Object* constructor = map_of_this->constructor();
1105 bool printed = false;
1106 if (constructor->IsHeapObject() &&
1107 !heap->Contains(HeapObject::cast(constructor))) {
1108 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1109 } else {
1110 bool global_object = IsJSGlobalProxy();
1111 if (constructor->IsJSFunction()) {
1112 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
1113 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1114 } else {
1115 Object* constructor_name =
1116 JSFunction::cast(constructor)->shared()->name();
1117 if (constructor_name->IsString()) {
1118 String* str = String::cast(constructor_name);
1119 if (str->length() > 0) {
1120 bool vowel = AnWord(str);
1121 accumulator->Add("<%sa%s ",
1122 global_object ? "Global Object: " : "",
1123 vowel ? "n" : "");
1124 accumulator->Put(str);
1125 printed = true;
1126 }
1127 }
1128 }
1129 }
1130 if (!printed) {
1131 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1132 }
1133 }
1134 if (IsJSValue()) {
1135 accumulator->Add(" value = ");
1136 JSValue::cast(this)->value()->ShortPrint(accumulator);
1137 }
1138 accumulator->Put('>');
1139 break;
1140 }
1141 }
1142 }
1143
1144
PrintElementsTransition(FILE * file,ElementsKind from_kind,FixedArrayBase * from_elements,ElementsKind to_kind,FixedArrayBase * to_elements)1145 void JSObject::PrintElementsTransition(
1146 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1147 ElementsKind to_kind, FixedArrayBase* to_elements) {
1148 if (from_kind != to_kind) {
1149 PrintF(file, "elements transition [");
1150 PrintElementsKind(file, from_kind);
1151 PrintF(file, " -> ");
1152 PrintElementsKind(file, to_kind);
1153 PrintF(file, "] in ");
1154 JavaScriptFrame::PrintTop(file, false, true);
1155 PrintF(file, " for ");
1156 ShortPrint(file);
1157 PrintF(file, " from ");
1158 from_elements->ShortPrint(file);
1159 PrintF(file, " to ");
1160 to_elements->ShortPrint(file);
1161 PrintF(file, "\n");
1162 }
1163 }
1164
1165
HeapObjectShortPrint(StringStream * accumulator)1166 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
1167 Heap* heap = GetHeap();
1168 if (!heap->Contains(this)) {
1169 accumulator->Add("!!!INVALID POINTER!!!");
1170 return;
1171 }
1172 if (!heap->Contains(map())) {
1173 accumulator->Add("!!!INVALID MAP!!!");
1174 return;
1175 }
1176
1177 accumulator->Add("%p ", this);
1178
1179 if (IsString()) {
1180 String::cast(this)->StringShortPrint(accumulator);
1181 return;
1182 }
1183 if (IsJSObject()) {
1184 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1185 return;
1186 }
1187 switch (map()->instance_type()) {
1188 case MAP_TYPE:
1189 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
1190 break;
1191 case FIXED_ARRAY_TYPE:
1192 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1193 break;
1194 case FIXED_DOUBLE_ARRAY_TYPE:
1195 accumulator->Add("<FixedDoubleArray[%u]>",
1196 FixedDoubleArray::cast(this)->length());
1197 break;
1198 case BYTE_ARRAY_TYPE:
1199 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1200 break;
1201 case FREE_SPACE_TYPE:
1202 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1203 break;
1204 case EXTERNAL_PIXEL_ARRAY_TYPE:
1205 accumulator->Add("<ExternalPixelArray[%u]>",
1206 ExternalPixelArray::cast(this)->length());
1207 break;
1208 case EXTERNAL_BYTE_ARRAY_TYPE:
1209 accumulator->Add("<ExternalByteArray[%u]>",
1210 ExternalByteArray::cast(this)->length());
1211 break;
1212 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1213 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1214 ExternalUnsignedByteArray::cast(this)->length());
1215 break;
1216 case EXTERNAL_SHORT_ARRAY_TYPE:
1217 accumulator->Add("<ExternalShortArray[%u]>",
1218 ExternalShortArray::cast(this)->length());
1219 break;
1220 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1221 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1222 ExternalUnsignedShortArray::cast(this)->length());
1223 break;
1224 case EXTERNAL_INT_ARRAY_TYPE:
1225 accumulator->Add("<ExternalIntArray[%u]>",
1226 ExternalIntArray::cast(this)->length());
1227 break;
1228 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1229 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1230 ExternalUnsignedIntArray::cast(this)->length());
1231 break;
1232 case EXTERNAL_FLOAT_ARRAY_TYPE:
1233 accumulator->Add("<ExternalFloatArray[%u]>",
1234 ExternalFloatArray::cast(this)->length());
1235 break;
1236 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1237 accumulator->Add("<ExternalDoubleArray[%u]>",
1238 ExternalDoubleArray::cast(this)->length());
1239 break;
1240 case SHARED_FUNCTION_INFO_TYPE:
1241 accumulator->Add("<SharedFunctionInfo>");
1242 break;
1243 case JS_MESSAGE_OBJECT_TYPE:
1244 accumulator->Add("<JSMessageObject>");
1245 break;
1246 #define MAKE_STRUCT_CASE(NAME, Name, name) \
1247 case NAME##_TYPE: \
1248 accumulator->Put('<'); \
1249 accumulator->Add(#Name); \
1250 accumulator->Put('>'); \
1251 break;
1252 STRUCT_LIST(MAKE_STRUCT_CASE)
1253 #undef MAKE_STRUCT_CASE
1254 case CODE_TYPE:
1255 accumulator->Add("<Code>");
1256 break;
1257 case ODDBALL_TYPE: {
1258 if (IsUndefined())
1259 accumulator->Add("<undefined>");
1260 else if (IsTheHole())
1261 accumulator->Add("<the hole>");
1262 else if (IsNull())
1263 accumulator->Add("<null>");
1264 else if (IsTrue())
1265 accumulator->Add("<true>");
1266 else if (IsFalse())
1267 accumulator->Add("<false>");
1268 else
1269 accumulator->Add("<Odd Oddball>");
1270 break;
1271 }
1272 case HEAP_NUMBER_TYPE:
1273 accumulator->Add("<Number: ");
1274 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1275 accumulator->Put('>');
1276 break;
1277 case JS_PROXY_TYPE:
1278 accumulator->Add("<JSProxy>");
1279 break;
1280 case JS_FUNCTION_PROXY_TYPE:
1281 accumulator->Add("<JSFunctionProxy>");
1282 break;
1283 case FOREIGN_TYPE:
1284 accumulator->Add("<Foreign>");
1285 break;
1286 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1287 accumulator->Add("Cell for ");
1288 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1289 break;
1290 default:
1291 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1292 break;
1293 }
1294 }
1295
1296
Iterate(ObjectVisitor * v)1297 void HeapObject::Iterate(ObjectVisitor* v) {
1298 // Handle header
1299 IteratePointer(v, kMapOffset);
1300 // Handle object body
1301 Map* m = map();
1302 IterateBody(m->instance_type(), SizeFromMap(m), v);
1303 }
1304
1305
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)1306 void HeapObject::IterateBody(InstanceType type, int object_size,
1307 ObjectVisitor* v) {
1308 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1309 // During GC, the map pointer field is encoded.
1310 if (type < FIRST_NONSTRING_TYPE) {
1311 switch (type & kStringRepresentationMask) {
1312 case kSeqStringTag:
1313 break;
1314 case kConsStringTag:
1315 ConsString::BodyDescriptor::IterateBody(this, v);
1316 break;
1317 case kSlicedStringTag:
1318 SlicedString::BodyDescriptor::IterateBody(this, v);
1319 break;
1320 case kExternalStringTag:
1321 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1322 reinterpret_cast<ExternalAsciiString*>(this)->
1323 ExternalAsciiStringIterateBody(v);
1324 } else {
1325 reinterpret_cast<ExternalTwoByteString*>(this)->
1326 ExternalTwoByteStringIterateBody(v);
1327 }
1328 break;
1329 }
1330 return;
1331 }
1332
1333 switch (type) {
1334 case FIXED_ARRAY_TYPE:
1335 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
1336 break;
1337 case FIXED_DOUBLE_ARRAY_TYPE:
1338 break;
1339 case JS_OBJECT_TYPE:
1340 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1341 case JS_VALUE_TYPE:
1342 case JS_DATE_TYPE:
1343 case JS_ARRAY_TYPE:
1344 case JS_SET_TYPE:
1345 case JS_MAP_TYPE:
1346 case JS_WEAK_MAP_TYPE:
1347 case JS_REGEXP_TYPE:
1348 case JS_GLOBAL_PROXY_TYPE:
1349 case JS_GLOBAL_OBJECT_TYPE:
1350 case JS_BUILTINS_OBJECT_TYPE:
1351 case JS_MESSAGE_OBJECT_TYPE:
1352 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
1353 break;
1354 case JS_FUNCTION_TYPE:
1355 reinterpret_cast<JSFunction*>(this)
1356 ->JSFunctionIterateBody(object_size, v);
1357 break;
1358 case ODDBALL_TYPE:
1359 Oddball::BodyDescriptor::IterateBody(this, v);
1360 break;
1361 case JS_PROXY_TYPE:
1362 JSProxy::BodyDescriptor::IterateBody(this, v);
1363 break;
1364 case JS_FUNCTION_PROXY_TYPE:
1365 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1366 break;
1367 case FOREIGN_TYPE:
1368 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
1369 break;
1370 case MAP_TYPE:
1371 Map::BodyDescriptor::IterateBody(this, v);
1372 break;
1373 case CODE_TYPE:
1374 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1375 break;
1376 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1377 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
1378 break;
1379 case HEAP_NUMBER_TYPE:
1380 case FILLER_TYPE:
1381 case BYTE_ARRAY_TYPE:
1382 case FREE_SPACE_TYPE:
1383 case EXTERNAL_PIXEL_ARRAY_TYPE:
1384 case EXTERNAL_BYTE_ARRAY_TYPE:
1385 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1386 case EXTERNAL_SHORT_ARRAY_TYPE:
1387 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1388 case EXTERNAL_INT_ARRAY_TYPE:
1389 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1390 case EXTERNAL_FLOAT_ARRAY_TYPE:
1391 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1392 break;
1393 case SHARED_FUNCTION_INFO_TYPE: {
1394 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
1395 shared->SharedFunctionInfoIterateBody(v);
1396 break;
1397 }
1398
1399 #define MAKE_STRUCT_CASE(NAME, Name, name) \
1400 case NAME##_TYPE:
1401 STRUCT_LIST(MAKE_STRUCT_CASE)
1402 #undef MAKE_STRUCT_CASE
1403 StructBodyDescriptor::IterateBody(this, object_size, v);
1404 break;
1405 default:
1406 PrintF("Unknown type: %d\n", type);
1407 UNREACHABLE();
1408 }
1409 }
1410
1411
HeapNumberToBoolean()1412 Object* HeapNumber::HeapNumberToBoolean() {
1413 // NaN, +0, and -0 should return the false object
1414 #if __BYTE_ORDER == __LITTLE_ENDIAN
1415 union IeeeDoubleLittleEndianArchType u;
1416 #elif __BYTE_ORDER == __BIG_ENDIAN
1417 union IeeeDoubleBigEndianArchType u;
1418 #endif
1419 u.d = value();
1420 if (u.bits.exp == 2047) {
1421 // Detect NaN for IEEE double precision floating point.
1422 if ((u.bits.man_low | u.bits.man_high) != 0)
1423 return GetHeap()->false_value();
1424 }
1425 if (u.bits.exp == 0) {
1426 // Detect +0, and -0 for IEEE double precision floating point.
1427 if ((u.bits.man_low | u.bits.man_high) == 0)
1428 return GetHeap()->false_value();
1429 }
1430 return GetHeap()->true_value();
1431 }
1432
1433
HeapNumberPrint(FILE * out)1434 void HeapNumber::HeapNumberPrint(FILE* out) {
1435 PrintF(out, "%.16g", Number());
1436 }
1437
1438
HeapNumberPrint(StringStream * accumulator)1439 void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1440 // The Windows version of vsnprintf can allocate when printing a %g string
1441 // into a buffer that may not be big enough. We don't want random memory
1442 // allocation when producing post-crash stack traces, so we print into a
1443 // buffer that is plenty big enough for any floating point number, then
1444 // print that using vsnprintf (which may truncate but never allocate if
1445 // there is no more space in the buffer).
1446 EmbeddedVector<char, 100> buffer;
1447 OS::SNPrintF(buffer, "%.16g", Number());
1448 accumulator->Add("%s", buffer.start());
1449 }
1450
1451
class_name()1452 String* JSReceiver::class_name() {
1453 if (IsJSFunction() && IsJSFunctionProxy()) {
1454 return GetHeap()->function_class_symbol();
1455 }
1456 if (map()->constructor()->IsJSFunction()) {
1457 JSFunction* constructor = JSFunction::cast(map()->constructor());
1458 return String::cast(constructor->shared()->instance_class_name());
1459 }
1460 // If the constructor is not present, return "Object".
1461 return GetHeap()->Object_symbol();
1462 }
1463
1464
constructor_name()1465 String* JSReceiver::constructor_name() {
1466 if (map()->constructor()->IsJSFunction()) {
1467 JSFunction* constructor = JSFunction::cast(map()->constructor());
1468 String* name = String::cast(constructor->shared()->name());
1469 if (name->length() > 0) return name;
1470 String* inferred_name = constructor->shared()->inferred_name();
1471 if (inferred_name->length() > 0) return inferred_name;
1472 Object* proto = GetPrototype();
1473 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
1474 }
1475 // TODO(rossberg): what about proxies?
1476 // If the constructor is not present, return "Object".
1477 return GetHeap()->Object_symbol();
1478 }
1479
1480
AddFastPropertyUsingMap(Map * new_map,String * name,Object * value)1481 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1482 String* name,
1483 Object* value) {
1484 int index = new_map->PropertyIndexFor(name);
1485 if (map()->unused_property_fields() == 0) {
1486 ASSERT(map()->unused_property_fields() == 0);
1487 int new_unused = new_map->unused_property_fields();
1488 Object* values;
1489 { MaybeObject* maybe_values =
1490 properties()->CopySize(properties()->length() + new_unused + 1);
1491 if (!maybe_values->ToObject(&values)) return maybe_values;
1492 }
1493 set_properties(FixedArray::cast(values));
1494 }
1495 set_map(new_map);
1496 return FastPropertyAtPut(index, value);
1497 }
1498
1499
IsIdentifier(UnicodeCache * cache,unibrow::CharacterStream * buffer)1500 static bool IsIdentifier(UnicodeCache* cache,
1501 unibrow::CharacterStream* buffer) {
1502 // Checks whether the buffer contains an identifier (no escape).
1503 if (!buffer->has_more()) return false;
1504 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1505 return false;
1506 }
1507 while (buffer->has_more()) {
1508 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1509 return false;
1510 }
1511 }
1512 return true;
1513 }
1514
1515
AddFastProperty(String * name,Object * value,PropertyAttributes attributes)1516 MaybeObject* JSObject::AddFastProperty(String* name,
1517 Object* value,
1518 PropertyAttributes attributes) {
1519 ASSERT(!IsJSGlobalProxy());
1520
1521 // Normalize the object if the name is an actual string (not the
1522 // hidden symbols) and is not a real identifier.
1523 Isolate* isolate = GetHeap()->isolate();
1524 StringInputBuffer buffer(name);
1525 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
1526 && name != isolate->heap()->hidden_symbol()) {
1527 Object* obj;
1528 { MaybeObject* maybe_obj =
1529 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1530 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1531 }
1532 return AddSlowProperty(name, value, attributes);
1533 }
1534
1535 DescriptorArray* old_descriptors = map()->instance_descriptors();
1536 // Compute the new index for new field.
1537 int index = map()->NextFreePropertyIndex();
1538
1539 // Allocate new instance descriptors with (name, index) added
1540 FieldDescriptor new_field(name, index, attributes);
1541 Object* new_descriptors;
1542 { MaybeObject* maybe_new_descriptors =
1543 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1544 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1545 return maybe_new_descriptors;
1546 }
1547 }
1548
1549 // Only allow map transition if the object isn't the global object and there
1550 // is not a transition for the name, or there's a transition for the name but
1551 // it's unrelated to properties.
1552 int descriptor_index = old_descriptors->Search(name);
1553
1554 // Element transitions are stored in the descriptor for property "", which is
1555 // not a identifier and should have forced a switch to slow properties above.
1556 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1557 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
1558 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1559 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
1560 bool allow_map_transition =
1561 can_insert_transition &&
1562 (isolate->context()->global_context()->object_function()->map() != map());
1563
1564 ASSERT(index < map()->inobject_properties() ||
1565 (index - map()->inobject_properties()) < properties()->length() ||
1566 map()->unused_property_fields() == 0);
1567 // Allocate a new map for the object.
1568 Object* r;
1569 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1570 if (!maybe_r->ToObject(&r)) return maybe_r;
1571 }
1572 Map* new_map = Map::cast(r);
1573 if (allow_map_transition) {
1574 // Allocate new instance descriptors for the old map with map transition.
1575 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
1576 Object* r;
1577 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1578 if (!maybe_r->ToObject(&r)) return maybe_r;
1579 }
1580 old_descriptors = DescriptorArray::cast(r);
1581 }
1582
1583 if (map()->unused_property_fields() == 0) {
1584 if (properties()->length() > MaxFastProperties()) {
1585 Object* obj;
1586 { MaybeObject* maybe_obj =
1587 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1588 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1589 }
1590 return AddSlowProperty(name, value, attributes);
1591 }
1592 // Make room for the new value
1593 Object* values;
1594 { MaybeObject* maybe_values =
1595 properties()->CopySize(properties()->length() + kFieldsAdded);
1596 if (!maybe_values->ToObject(&values)) return maybe_values;
1597 }
1598 set_properties(FixedArray::cast(values));
1599 new_map->set_unused_property_fields(kFieldsAdded - 1);
1600 } else {
1601 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1602 }
1603 // We have now allocated all the necessary objects.
1604 // All the changes can be applied at once, so they are atomic.
1605 map()->set_instance_descriptors(old_descriptors);
1606 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1607 set_map(new_map);
1608 return FastPropertyAtPut(index, value);
1609 }
1610
1611
AddConstantFunctionProperty(String * name,JSFunction * function,PropertyAttributes attributes)1612 MaybeObject* JSObject::AddConstantFunctionProperty(
1613 String* name,
1614 JSFunction* function,
1615 PropertyAttributes attributes) {
1616 // Allocate new instance descriptors with (name, function) added
1617 ConstantFunctionDescriptor d(name, function, attributes);
1618 Object* new_descriptors;
1619 { MaybeObject* maybe_new_descriptors =
1620 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1621 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1622 return maybe_new_descriptors;
1623 }
1624 }
1625
1626 // Allocate a new map for the object.
1627 Object* new_map;
1628 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1629 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1630 }
1631
1632 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1633 Map::cast(new_map)->set_instance_descriptors(descriptors);
1634 Map* old_map = map();
1635 set_map(Map::cast(new_map));
1636
1637 // If the old map is the global object map (from new Object()),
1638 // then transitions are not added to it, so we are done.
1639 Heap* heap = GetHeap();
1640 if (old_map == heap->isolate()->context()->global_context()->
1641 object_function()->map()) {
1642 return function;
1643 }
1644
1645 // Do not add CONSTANT_TRANSITIONS to global objects
1646 if (IsGlobalObject()) {
1647 return function;
1648 }
1649
1650 // Add a CONSTANT_TRANSITION descriptor to the old map,
1651 // so future assignments to this property on other objects
1652 // of the same type will create a normal field, not a constant function.
1653 // Don't do this for special properties, with non-trival attributes.
1654 if (attributes != NONE) {
1655 return function;
1656 }
1657 ConstTransitionDescriptor mark(name, Map::cast(new_map));
1658 { MaybeObject* maybe_new_descriptors =
1659 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1660 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1661 // We have accomplished the main goal, so return success.
1662 return function;
1663 }
1664 }
1665 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1666
1667 return function;
1668 }
1669
1670
1671 // Add property in slow mode
AddSlowProperty(String * name,Object * value,PropertyAttributes attributes)1672 MaybeObject* JSObject::AddSlowProperty(String* name,
1673 Object* value,
1674 PropertyAttributes attributes) {
1675 ASSERT(!HasFastProperties());
1676 StringDictionary* dict = property_dictionary();
1677 Object* store_value = value;
1678 if (IsGlobalObject()) {
1679 // In case name is an orphaned property reuse the cell.
1680 int entry = dict->FindEntry(name);
1681 if (entry != StringDictionary::kNotFound) {
1682 store_value = dict->ValueAt(entry);
1683 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1684 // Assign an enumeration index to the property and update
1685 // SetNextEnumerationIndex.
1686 int index = dict->NextEnumerationIndex();
1687 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1688 dict->SetNextEnumerationIndex(index + 1);
1689 dict->SetEntry(entry, name, store_value, details);
1690 return value;
1691 }
1692 Heap* heap = GetHeap();
1693 { MaybeObject* maybe_store_value =
1694 heap->AllocateJSGlobalPropertyCell(value);
1695 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1696 }
1697 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1698 }
1699 PropertyDetails details = PropertyDetails(attributes, NORMAL);
1700 Object* result;
1701 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1702 if (!maybe_result->ToObject(&result)) return maybe_result;
1703 }
1704 if (dict != result) set_properties(StringDictionary::cast(result));
1705 return value;
1706 }
1707
1708
AddProperty(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1709 MaybeObject* JSObject::AddProperty(String* name,
1710 Object* value,
1711 PropertyAttributes attributes,
1712 StrictModeFlag strict_mode) {
1713 ASSERT(!IsJSGlobalProxy());
1714 Map* map_of_this = map();
1715 Heap* heap = GetHeap();
1716 if (!map_of_this->is_extensible()) {
1717 if (strict_mode == kNonStrictMode) {
1718 return value;
1719 } else {
1720 Handle<Object> args[1] = {Handle<String>(name)};
1721 return heap->isolate()->Throw(
1722 *FACTORY->NewTypeError("object_not_extensible",
1723 HandleVector(args, 1)));
1724 }
1725 }
1726 if (HasFastProperties()) {
1727 // Ensure the descriptor array does not get too big.
1728 if (map_of_this->instance_descriptors()->number_of_descriptors() <
1729 DescriptorArray::kMaxNumberOfDescriptors) {
1730 if (value->IsJSFunction()) {
1731 return AddConstantFunctionProperty(name,
1732 JSFunction::cast(value),
1733 attributes);
1734 } else {
1735 return AddFastProperty(name, value, attributes);
1736 }
1737 } else {
1738 // Normalize the object to prevent very large instance descriptors.
1739 // This eliminates unwanted N^2 allocation and lookup behavior.
1740 Object* obj;
1741 { MaybeObject* maybe_obj =
1742 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1743 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1744 }
1745 }
1746 }
1747 return AddSlowProperty(name, value, attributes);
1748 }
1749
1750
SetPropertyPostInterceptor(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1751 MaybeObject* JSObject::SetPropertyPostInterceptor(
1752 String* name,
1753 Object* value,
1754 PropertyAttributes attributes,
1755 StrictModeFlag strict_mode) {
1756 // Check local property, ignore interceptor.
1757 LookupResult result(GetIsolate());
1758 LocalLookupRealNamedProperty(name, &result);
1759 if (result.IsFound()) {
1760 // An existing property, a map transition or a null descriptor was
1761 // found. Use set property to handle all these cases.
1762 return SetProperty(&result, name, value, attributes, strict_mode);
1763 }
1764 bool found = false;
1765 MaybeObject* result_object;
1766 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1767 value,
1768 attributes,
1769 &found,
1770 strict_mode);
1771 if (found) return result_object;
1772 // Add a new real property.
1773 return AddProperty(name, value, attributes, strict_mode);
1774 }
1775
1776
ReplaceSlowProperty(String * name,Object * value,PropertyAttributes attributes)1777 MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1778 Object* value,
1779 PropertyAttributes attributes) {
1780 StringDictionary* dictionary = property_dictionary();
1781 int old_index = dictionary->FindEntry(name);
1782 int new_enumeration_index = 0; // 0 means "Use the next available index."
1783 if (old_index != -1) {
1784 // All calls to ReplaceSlowProperty have had all transitions removed.
1785 ASSERT(!dictionary->ContainsTransition(old_index));
1786 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1787 }
1788
1789 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1790 return SetNormalizedProperty(name, value, new_details);
1791 }
1792
1793
ConvertDescriptorToFieldAndMapTransition(String * name,Object * new_value,PropertyAttributes attributes)1794 MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
1795 String* name,
1796 Object* new_value,
1797 PropertyAttributes attributes) {
1798 Map* old_map = map();
1799 Object* result;
1800 { MaybeObject* maybe_result =
1801 ConvertDescriptorToField(name, new_value, attributes);
1802 if (!maybe_result->ToObject(&result)) return maybe_result;
1803 }
1804 // If we get to this point we have succeeded - do not return failure
1805 // after this point. Later stuff is optional.
1806 if (!HasFastProperties()) {
1807 return result;
1808 }
1809 // Do not add transitions to the map of "new Object()".
1810 if (map() == GetIsolate()->context()->global_context()->
1811 object_function()->map()) {
1812 return result;
1813 }
1814
1815 MapTransitionDescriptor transition(name,
1816 map(),
1817 attributes);
1818 Object* new_descriptors;
1819 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1820 CopyInsert(&transition, KEEP_TRANSITIONS);
1821 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1822 return result; // Yes, return _result_.
1823 }
1824 }
1825 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1826 return result;
1827 }
1828
1829
ConvertDescriptorToField(String * name,Object * new_value,PropertyAttributes attributes)1830 MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1831 Object* new_value,
1832 PropertyAttributes attributes) {
1833 if (map()->unused_property_fields() == 0 &&
1834 properties()->length() > MaxFastProperties()) {
1835 Object* obj;
1836 { MaybeObject* maybe_obj =
1837 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1838 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1839 }
1840 return ReplaceSlowProperty(name, new_value, attributes);
1841 }
1842
1843 int index = map()->NextFreePropertyIndex();
1844 FieldDescriptor new_field(name, index, attributes);
1845 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
1846 Object* descriptors_unchecked;
1847 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1848 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1849 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1850 return maybe_descriptors_unchecked;
1851 }
1852 }
1853 DescriptorArray* new_descriptors =
1854 DescriptorArray::cast(descriptors_unchecked);
1855
1856 // Make a new map for the object.
1857 Object* new_map_unchecked;
1858 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1859 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1860 return maybe_new_map_unchecked;
1861 }
1862 }
1863 Map* new_map = Map::cast(new_map_unchecked);
1864 new_map->set_instance_descriptors(new_descriptors);
1865
1866 // Make new properties array if necessary.
1867 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1868 int new_unused_property_fields = map()->unused_property_fields() - 1;
1869 if (map()->unused_property_fields() == 0) {
1870 new_unused_property_fields = kFieldsAdded - 1;
1871 Object* new_properties_object;
1872 { MaybeObject* maybe_new_properties_object =
1873 properties()->CopySize(properties()->length() + kFieldsAdded);
1874 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1875 return maybe_new_properties_object;
1876 }
1877 }
1878 new_properties = FixedArray::cast(new_properties_object);
1879 }
1880
1881 // Update pointers to commit changes.
1882 // Object points to the new map.
1883 new_map->set_unused_property_fields(new_unused_property_fields);
1884 set_map(new_map);
1885 if (new_properties) {
1886 set_properties(FixedArray::cast(new_properties));
1887 }
1888 return FastPropertyAtPut(index, new_value);
1889 }
1890
1891
1892
SetPropertyWithInterceptor(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1893 MaybeObject* JSObject::SetPropertyWithInterceptor(
1894 String* name,
1895 Object* value,
1896 PropertyAttributes attributes,
1897 StrictModeFlag strict_mode) {
1898 Isolate* isolate = GetIsolate();
1899 HandleScope scope(isolate);
1900 Handle<JSObject> this_handle(this);
1901 Handle<String> name_handle(name);
1902 Handle<Object> value_handle(value, isolate);
1903 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1904 if (!interceptor->setter()->IsUndefined()) {
1905 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1906 CustomArguments args(isolate, interceptor->data(), this, this);
1907 v8::AccessorInfo info(args.end());
1908 v8::NamedPropertySetter setter =
1909 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1910 v8::Handle<v8::Value> result;
1911 {
1912 // Leaving JavaScript.
1913 VMState state(isolate, EXTERNAL);
1914 Handle<Object> value_unhole(value->IsTheHole() ?
1915 isolate->heap()->undefined_value() :
1916 value,
1917 isolate);
1918 result = setter(v8::Utils::ToLocal(name_handle),
1919 v8::Utils::ToLocal(value_unhole),
1920 info);
1921 }
1922 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1923 if (!result.IsEmpty()) return *value_handle;
1924 }
1925 MaybeObject* raw_result =
1926 this_handle->SetPropertyPostInterceptor(*name_handle,
1927 *value_handle,
1928 attributes,
1929 strict_mode);
1930 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1931 return raw_result;
1932 }
1933
1934
SetProperty(Handle<JSReceiver> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes,StrictModeFlag strict_mode)1935 Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1936 Handle<String> key,
1937 Handle<Object> value,
1938 PropertyAttributes attributes,
1939 StrictModeFlag strict_mode) {
1940 CALL_HEAP_FUNCTION(object->GetIsolate(),
1941 object->SetProperty(*key, *value, attributes, strict_mode),
1942 Object);
1943 }
1944
1945
SetProperty(String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)1946 MaybeObject* JSReceiver::SetProperty(String* name,
1947 Object* value,
1948 PropertyAttributes attributes,
1949 StrictModeFlag strict_mode) {
1950 LookupResult result(GetIsolate());
1951 LocalLookup(name, &result);
1952 return SetProperty(&result, name, value, attributes, strict_mode);
1953 }
1954
1955
SetPropertyWithCallback(Object * structure,String * name,Object * value,JSObject * holder,StrictModeFlag strict_mode)1956 MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1957 String* name,
1958 Object* value,
1959 JSObject* holder,
1960 StrictModeFlag strict_mode) {
1961 Isolate* isolate = GetIsolate();
1962 HandleScope scope(isolate);
1963
1964 // We should never get here to initialize a const with the hole
1965 // value since a const declaration would conflict with the setter.
1966 ASSERT(!value->IsTheHole());
1967 Handle<Object> value_handle(value, isolate);
1968
1969 // To accommodate both the old and the new api we switch on the
1970 // data structure used to store the callbacks. Eventually foreign
1971 // callbacks should be phased out.
1972 if (structure->IsForeign()) {
1973 AccessorDescriptor* callback =
1974 reinterpret_cast<AccessorDescriptor*>(
1975 Foreign::cast(structure)->foreign_address());
1976 MaybeObject* obj = (callback->setter)(this, value, callback->data);
1977 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1978 if (obj->IsFailure()) return obj;
1979 return *value_handle;
1980 }
1981
1982 if (structure->IsAccessorInfo()) {
1983 // api style callbacks
1984 AccessorInfo* data = AccessorInfo::cast(structure);
1985 Object* call_obj = data->setter();
1986 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1987 if (call_fun == NULL) return value;
1988 Handle<String> key(name);
1989 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1990 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
1991 v8::AccessorInfo info(args.end());
1992 {
1993 // Leaving JavaScript.
1994 VMState state(isolate, EXTERNAL);
1995 call_fun(v8::Utils::ToLocal(key),
1996 v8::Utils::ToLocal(value_handle),
1997 info);
1998 }
1999 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
2000 return *value_handle;
2001 }
2002
2003 if (structure->IsAccessorPair()) {
2004 Object* setter = AccessorPair::cast(structure)->setter();
2005 if (setter->IsSpecFunction()) {
2006 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2007 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
2008 } else {
2009 if (strict_mode == kNonStrictMode) {
2010 return value;
2011 }
2012 Handle<String> key(name);
2013 Handle<Object> holder_handle(holder, isolate);
2014 Handle<Object> args[2] = { key, holder_handle };
2015 return isolate->Throw(
2016 *isolate->factory()->NewTypeError("no_setter_in_callback",
2017 HandleVector(args, 2)));
2018 }
2019 }
2020
2021 UNREACHABLE();
2022 return NULL;
2023 }
2024
2025
SetPropertyWithDefinedSetter(JSReceiver * setter,Object * value)2026 MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2027 Object* value) {
2028 Isolate* isolate = GetIsolate();
2029 Handle<Object> value_handle(value, isolate);
2030 Handle<JSReceiver> fun(setter, isolate);
2031 Handle<JSReceiver> self(this, isolate);
2032 #ifdef ENABLE_DEBUGGER_SUPPORT
2033 Debug* debug = isolate->debug();
2034 // Handle stepping into a setter if step into is active.
2035 // TODO(rossberg): should this apply to getters that are function proxies?
2036 if (debug->StepInActive() && fun->IsJSFunction()) {
2037 debug->HandleStepIn(
2038 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
2039 }
2040 #endif
2041 bool has_pending_exception;
2042 Handle<Object> argv[] = { value_handle };
2043 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
2044 // Check for pending exception and return the result.
2045 if (has_pending_exception) return Failure::Exception();
2046 return *value_handle;
2047 }
2048
2049
LookupCallbackSetterInPrototypes(String * name,LookupResult * result)2050 void JSObject::LookupCallbackSetterInPrototypes(String* name,
2051 LookupResult* result) {
2052 Heap* heap = GetHeap();
2053 for (Object* pt = GetPrototype();
2054 pt != heap->null_value();
2055 pt = pt->GetPrototype()) {
2056 if (pt->IsJSProxy()) {
2057 return result->HandlerResult(JSProxy::cast(pt));
2058 }
2059 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
2060 if (result->IsProperty()) {
2061 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2062 // Found non-callback or read-only callback, stop looking.
2063 break;
2064 }
2065 }
2066 result->NotFound();
2067 }
2068
2069
SetElementWithCallbackSetterInPrototypes(uint32_t index,Object * value,bool * found,StrictModeFlag strict_mode)2070 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2071 uint32_t index,
2072 Object* value,
2073 bool* found,
2074 StrictModeFlag strict_mode) {
2075 Heap* heap = GetHeap();
2076 for (Object* pt = GetPrototype();
2077 pt != heap->null_value();
2078 pt = pt->GetPrototype()) {
2079 if (pt->IsJSProxy()) {
2080 String* name;
2081 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2082 if (!maybe->To<String>(&name)) {
2083 *found = true; // Force abort
2084 return maybe;
2085 }
2086 return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2087 name, value, NONE, strict_mode, found);
2088 }
2089 if (!JSObject::cast(pt)->HasDictionaryElements()) {
2090 continue;
2091 }
2092 SeededNumberDictionary* dictionary =
2093 JSObject::cast(pt)->element_dictionary();
2094 int entry = dictionary->FindEntry(index);
2095 if (entry != SeededNumberDictionary::kNotFound) {
2096 PropertyDetails details = dictionary->DetailsAt(entry);
2097 if (details.type() == CALLBACKS) {
2098 *found = true;
2099 return SetElementWithCallback(dictionary->ValueAt(entry),
2100 index,
2101 value,
2102 JSObject::cast(pt),
2103 strict_mode);
2104 }
2105 }
2106 }
2107 *found = false;
2108 return heap->the_hole_value();
2109 }
2110
SetPropertyWithCallbackSetterInPrototypes(String * name,Object * value,PropertyAttributes attributes,bool * found,StrictModeFlag strict_mode)2111 MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2112 String* name,
2113 Object* value,
2114 PropertyAttributes attributes,
2115 bool* found,
2116 StrictModeFlag strict_mode) {
2117 Heap* heap = GetHeap();
2118 // We could not find a local property so let's check whether there is an
2119 // accessor that wants to handle the property.
2120 LookupResult accessor_result(heap->isolate());
2121 LookupCallbackSetterInPrototypes(name, &accessor_result);
2122 if (accessor_result.IsFound()) {
2123 *found = true;
2124 if (accessor_result.type() == CALLBACKS) {
2125 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2126 name,
2127 value,
2128 accessor_result.holder(),
2129 strict_mode);
2130 } else if (accessor_result.type() == HANDLER) {
2131 // There is a proxy in the prototype chain. Invoke its
2132 // getPropertyDescriptor trap.
2133 bool found = false;
2134 // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2135 // make sure to use the handlified references after calling
2136 // the function.
2137 Handle<JSObject> self(this);
2138 Handle<String> hname(name);
2139 Handle<Object> hvalue(value);
2140 MaybeObject* result =
2141 accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2142 name, value, attributes, strict_mode, &found);
2143 if (found) return result;
2144 // The proxy does not define the property as an accessor.
2145 // Consequently, it has no effect on setting the receiver.
2146 return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
2147 }
2148 }
2149 *found = false;
2150 return heap->the_hole_value();
2151 }
2152
2153
LookupInDescriptor(String * name,LookupResult * result)2154 void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2155 DescriptorArray* descriptors = map()->instance_descriptors();
2156 int number = descriptors->SearchWithCache(name);
2157 if (number != DescriptorArray::kNotFound) {
2158 result->DescriptorResult(this, descriptors->GetDetails(number), number);
2159 } else {
2160 result->NotFound();
2161 }
2162 }
2163
2164
LookupInDescriptors(JSObject * holder,String * name,LookupResult * result)2165 void Map::LookupInDescriptors(JSObject* holder,
2166 String* name,
2167 LookupResult* result) {
2168 DescriptorArray* descriptors = instance_descriptors();
2169 DescriptorLookupCache* cache =
2170 GetHeap()->isolate()->descriptor_lookup_cache();
2171 int number = cache->Lookup(descriptors, name);
2172 if (number == DescriptorLookupCache::kAbsent) {
2173 number = descriptors->Search(name);
2174 cache->Update(descriptors, name, number);
2175 }
2176 if (number != DescriptorArray::kNotFound) {
2177 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2178 } else {
2179 result->NotFound();
2180 }
2181 }
2182
2183
ContainsMap(MapHandleList * maps,Handle<Map> map)2184 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2185 ASSERT(!map.is_null());
2186 for (int i = 0; i < maps->length(); ++i) {
2187 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2188 }
2189 return false;
2190 }
2191
2192
2193 template <class T>
MaybeNull(T * p)2194 static Handle<T> MaybeNull(T* p) {
2195 if (p == NULL) return Handle<T>::null();
2196 return Handle<T>(p);
2197 }
2198
2199
FindTransitionedMap(MapHandleList * candidates)2200 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2201 ElementsKind elms_kind = elements_kind();
2202 if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2203 bool dummy = true;
2204 Handle<Map> fast_map =
2205 MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2206 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2207 return fast_map;
2208 }
2209 return Handle<Map>::null();
2210 }
2211 if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2212 bool dummy = true;
2213 Handle<Map> double_map =
2214 MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2215 // In the current implementation, if the DOUBLE map doesn't exist, the
2216 // FAST map can't exist either.
2217 if (double_map.is_null()) return Handle<Map>::null();
2218 Handle<Map> fast_map =
2219 MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2220 &dummy));
2221 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2222 return fast_map;
2223 }
2224 if (ContainsMap(candidates, double_map)) return double_map;
2225 }
2226 return Handle<Map>::null();
2227 }
2228
GetElementsTransitionMapFromDescriptor(Object * descriptor_contents,ElementsKind elements_kind)2229 static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2230 ElementsKind elements_kind) {
2231 if (descriptor_contents->IsMap()) {
2232 Map* map = Map::cast(descriptor_contents);
2233 if (map->elements_kind() == elements_kind) {
2234 return map;
2235 }
2236 return NULL;
2237 }
2238
2239 FixedArray* map_array = FixedArray::cast(descriptor_contents);
2240 for (int i = 0; i < map_array->length(); ++i) {
2241 Object* current = map_array->get(i);
2242 // Skip undefined slots, they are sentinels for reclaimed maps.
2243 if (!current->IsUndefined()) {
2244 Map* current_map = Map::cast(map_array->get(i));
2245 if (current_map->elements_kind() == elements_kind) {
2246 return current_map;
2247 }
2248 }
2249 }
2250
2251 return NULL;
2252 }
2253
2254
AddElementsTransitionMapToDescriptor(Object * descriptor_contents,Map * new_map)2255 static MaybeObject* AddElementsTransitionMapToDescriptor(
2256 Object* descriptor_contents,
2257 Map* new_map) {
2258 // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2259 // simply add the map.
2260 if (descriptor_contents == NULL) {
2261 return new_map;
2262 }
2263
2264 // There was already a map in the descriptor, create a 2-element FixedArray
2265 // to contain the existing map plus the new one.
2266 FixedArray* new_array;
2267 Heap* heap = new_map->GetHeap();
2268 if (descriptor_contents->IsMap()) {
2269 // Must tenure, DescriptorArray expects no new-space objects.
2270 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2271 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2272 return maybe_new_array;
2273 }
2274 new_array->set(0, descriptor_contents);
2275 new_array->set(1, new_map);
2276 return new_array;
2277 }
2278
2279 // The descriptor already contained a list of maps for different ElementKinds
2280 // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2281 // slot, and if that's not available, create a FixedArray to hold the existing
2282 // maps plus the new one and fill it in.
2283 FixedArray* array = FixedArray::cast(descriptor_contents);
2284 for (int i = 0; i < array->length(); ++i) {
2285 if (array->get(i)->IsUndefined()) {
2286 array->set(i, new_map);
2287 return array;
2288 }
2289 }
2290
2291 // Must tenure, DescriptorArray expects no new-space objects.
2292 MaybeObject* maybe_new_array =
2293 heap->AllocateFixedArray(array->length() + 1, TENURED);
2294 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2295 return maybe_new_array;
2296 }
2297 int i = 0;
2298 while (i < array->length()) {
2299 new_array->set(i, array->get(i));
2300 ++i;
2301 }
2302 new_array->set(i, new_map);
2303 return new_array;
2304 }
2305
2306
elements_transition_sentinel_name()2307 String* Map::elements_transition_sentinel_name() {
2308 return GetHeap()->empty_symbol();
2309 }
2310
2311
GetDescriptorContents(String * sentinel_name,bool * safe_to_add_transition)2312 Object* Map::GetDescriptorContents(String* sentinel_name,
2313 bool* safe_to_add_transition) {
2314 // Get the cached index for the descriptors lookup, or find and cache it.
2315 DescriptorArray* descriptors = instance_descriptors();
2316 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2317 int index = cache->Lookup(descriptors, sentinel_name);
2318 if (index == DescriptorLookupCache::kAbsent) {
2319 index = descriptors->Search(sentinel_name);
2320 cache->Update(descriptors, sentinel_name, index);
2321 }
2322 // If the transition already exists, return its descriptor.
2323 if (index != DescriptorArray::kNotFound) {
2324 PropertyDetails details(descriptors->GetDetails(index));
2325 if (details.type() == ELEMENTS_TRANSITION) {
2326 return descriptors->GetValue(index);
2327 } else {
2328 if (safe_to_add_transition != NULL) {
2329 *safe_to_add_transition = false;
2330 }
2331 }
2332 }
2333 return NULL;
2334 }
2335
2336
LookupElementsTransitionMap(ElementsKind elements_kind,bool * safe_to_add_transition)2337 Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2338 bool* safe_to_add_transition) {
2339 // Special case: indirect SMI->FAST transition (cf. comment in
2340 // AddElementsTransition()).
2341 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2342 elements_kind == FAST_ELEMENTS) {
2343 Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2344 safe_to_add_transition);
2345 if (double_map == NULL) return double_map;
2346 return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2347 safe_to_add_transition);
2348 }
2349 Object* descriptor_contents = GetDescriptorContents(
2350 elements_transition_sentinel_name(), safe_to_add_transition);
2351 if (descriptor_contents != NULL) {
2352 Map* maybe_transition_map =
2353 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2354 elements_kind);
2355 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2356 return maybe_transition_map;
2357 }
2358 return NULL;
2359 }
2360
2361
AddElementsTransition(ElementsKind elements_kind,Map * transitioned_map)2362 MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2363 Map* transitioned_map) {
2364 // The map transition graph should be a tree, therefore the transition
2365 // from SMI to FAST elements is not done directly, but by going through
2366 // DOUBLE elements first.
2367 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2368 elements_kind == FAST_ELEMENTS) {
2369 bool safe_to_add = true;
2370 Map* double_map = this->LookupElementsTransitionMap(
2371 FAST_DOUBLE_ELEMENTS, &safe_to_add);
2372 // This method is only called when safe_to_add_transition has been found
2373 // to be true earlier.
2374 ASSERT(safe_to_add);
2375
2376 if (double_map == NULL) {
2377 MaybeObject* maybe_map = this->CopyDropTransitions();
2378 if (!maybe_map->To(&double_map)) return maybe_map;
2379 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2380 MaybeObject* maybe_double_transition = this->AddElementsTransition(
2381 FAST_DOUBLE_ELEMENTS, double_map);
2382 if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2383 }
2384 return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2385 }
2386
2387 bool safe_to_add_transition = true;
2388 Object* descriptor_contents = GetDescriptorContents(
2389 elements_transition_sentinel_name(), &safe_to_add_transition);
2390 // This method is only called when safe_to_add_transition has been found
2391 // to be true earlier.
2392 ASSERT(safe_to_add_transition);
2393 MaybeObject* maybe_new_contents =
2394 AddElementsTransitionMapToDescriptor(descriptor_contents,
2395 transitioned_map);
2396 Object* new_contents;
2397 if (!maybe_new_contents->ToObject(&new_contents)) {
2398 return maybe_new_contents;
2399 }
2400
2401 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2402 new_contents);
2403 Object* new_descriptors;
2404 MaybeObject* maybe_new_descriptors =
2405 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2406 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2407 return maybe_new_descriptors;
2408 }
2409 set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2410 return this;
2411 }
2412
2413
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)2414 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2415 ElementsKind to_kind) {
2416 Isolate* isolate = object->GetIsolate();
2417 CALL_HEAP_FUNCTION(isolate,
2418 object->GetElementsTransitionMap(isolate, to_kind),
2419 Map);
2420 }
2421
2422
GetElementsTransitionMapSlow(ElementsKind to_kind)2423 MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
2424 Map* current_map = map();
2425 ElementsKind from_kind = current_map->elements_kind();
2426
2427 if (from_kind == to_kind) return current_map;
2428
2429 // Only objects with FastProperties can have DescriptorArrays and can track
2430 // element-related maps. Also don't add descriptors to maps that are shared.
2431 bool safe_to_add_transition = HasFastProperties() &&
2432 !current_map->IsUndefined() &&
2433 !current_map->is_shared();
2434
2435 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2436 // with elements that switch back and forth between dictionary and fast
2437 // element mode.
2438 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2439 safe_to_add_transition = false;
2440 }
2441
2442 if (safe_to_add_transition) {
2443 // It's only safe to manipulate the descriptor array if it would be
2444 // safe to add a transition.
2445 Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2446 to_kind, &safe_to_add_transition);
2447 if (maybe_transition_map != NULL) {
2448 return maybe_transition_map;
2449 }
2450 }
2451
2452 Map* new_map = NULL;
2453
2454 // No transition to an existing map for the given ElementsKind. Make a new
2455 // one.
2456 { MaybeObject* maybe_map = current_map->CopyDropTransitions();
2457 if (!maybe_map->To(&new_map)) return maybe_map;
2458 }
2459
2460 new_map->set_elements_kind(to_kind);
2461
2462 // Only remember the map transition if the object's map is NOT equal to the
2463 // global object_function's map and there is not an already existing
2464 // non-matching element transition.
2465 Context* global_context = GetIsolate()->context()->global_context();
2466 bool allow_map_transition = safe_to_add_transition &&
2467 (global_context->object_function()->map() != map());
2468 if (allow_map_transition) {
2469 MaybeObject* maybe_transition =
2470 current_map->AddElementsTransition(to_kind, new_map);
2471 if (maybe_transition->IsFailure()) return maybe_transition;
2472 }
2473 return new_map;
2474 }
2475
2476
LocalLookupRealNamedProperty(String * name,LookupResult * result)2477 void JSObject::LocalLookupRealNamedProperty(String* name,
2478 LookupResult* result) {
2479 if (IsJSGlobalProxy()) {
2480 Object* proto = GetPrototype();
2481 if (proto->IsNull()) return result->NotFound();
2482 ASSERT(proto->IsJSGlobalObject());
2483 // A GlobalProxy's prototype should always be a proper JSObject.
2484 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2485 }
2486
2487 if (HasFastProperties()) {
2488 LookupInDescriptor(name, result);
2489 if (result->IsFound()) {
2490 // A property, a map transition or a null descriptor was found.
2491 // We return all of these result types because
2492 // LocalLookupRealNamedProperty is used when setting properties
2493 // where map transitions and null descriptors are handled.
2494 ASSERT(result->holder() == this && result->type() != NORMAL);
2495 // Disallow caching for uninitialized constants. These can only
2496 // occur as fields.
2497 if (result->IsReadOnly() && result->type() == FIELD &&
2498 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2499 result->DisallowCaching();
2500 }
2501 return;
2502 }
2503 } else {
2504 int entry = property_dictionary()->FindEntry(name);
2505 if (entry != StringDictionary::kNotFound) {
2506 Object* value = property_dictionary()->ValueAt(entry);
2507 if (IsGlobalObject()) {
2508 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2509 if (d.IsDeleted()) {
2510 result->NotFound();
2511 return;
2512 }
2513 value = JSGlobalPropertyCell::cast(value)->value();
2514 }
2515 // Make sure to disallow caching for uninitialized constants
2516 // found in the dictionary-mode objects.
2517 if (value->IsTheHole()) result->DisallowCaching();
2518 result->DictionaryResult(this, entry);
2519 return;
2520 }
2521 }
2522 result->NotFound();
2523 }
2524
2525
LookupRealNamedProperty(String * name,LookupResult * result)2526 void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2527 LocalLookupRealNamedProperty(name, result);
2528 if (result->IsProperty()) return;
2529
2530 LookupRealNamedPropertyInPrototypes(name, result);
2531 }
2532
2533
LookupRealNamedPropertyInPrototypes(String * name,LookupResult * result)2534 void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2535 LookupResult* result) {
2536 Heap* heap = GetHeap();
2537 for (Object* pt = GetPrototype();
2538 pt != heap->null_value();
2539 pt = JSObject::cast(pt)->GetPrototype()) {
2540 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
2541 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
2542 }
2543 result->NotFound();
2544 }
2545
2546
2547 // We only need to deal with CALLBACKS and INTERCEPTORS
SetPropertyWithFailedAccessCheck(LookupResult * result,String * name,Object * value,bool check_prototype,StrictModeFlag strict_mode)2548 MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2549 LookupResult* result,
2550 String* name,
2551 Object* value,
2552 bool check_prototype,
2553 StrictModeFlag strict_mode) {
2554 if (check_prototype && !result->IsProperty()) {
2555 LookupCallbackSetterInPrototypes(name, result);
2556 }
2557
2558 if (result->IsProperty()) {
2559 if (!result->IsReadOnly()) {
2560 switch (result->type()) {
2561 case CALLBACKS: {
2562 Object* obj = result->GetCallbackObject();
2563 if (obj->IsAccessorInfo()) {
2564 AccessorInfo* info = AccessorInfo::cast(obj);
2565 if (info->all_can_write()) {
2566 return SetPropertyWithCallback(result->GetCallbackObject(),
2567 name,
2568 value,
2569 result->holder(),
2570 strict_mode);
2571 }
2572 }
2573 break;
2574 }
2575 case INTERCEPTOR: {
2576 // Try lookup real named properties. Note that only property can be
2577 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2578 LookupResult r(GetIsolate());
2579 LookupRealNamedProperty(name, &r);
2580 if (r.IsProperty()) {
2581 return SetPropertyWithFailedAccessCheck(&r,
2582 name,
2583 value,
2584 check_prototype,
2585 strict_mode);
2586 }
2587 break;
2588 }
2589 default: {
2590 break;
2591 }
2592 }
2593 }
2594 }
2595
2596 Isolate* isolate = GetIsolate();
2597 HandleScope scope(isolate);
2598 Handle<Object> value_handle(value);
2599 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
2600 return *value_handle;
2601 }
2602
2603
SetProperty(LookupResult * result,String * key,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)2604 MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2605 String* key,
2606 Object* value,
2607 PropertyAttributes attributes,
2608 StrictModeFlag strict_mode) {
2609 if (result->IsFound() && result->type() == HANDLER) {
2610 return result->proxy()->SetPropertyWithHandler(
2611 key, value, attributes, strict_mode);
2612 } else {
2613 return JSObject::cast(this)->SetPropertyForResult(
2614 result, key, value, attributes, strict_mode);
2615 }
2616 }
2617
2618
HasPropertyWithHandler(String * name_raw)2619 bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2620 Isolate* isolate = GetIsolate();
2621 HandleScope scope(isolate);
2622 Handle<Object> receiver(this);
2623 Handle<Object> name(name_raw);
2624
2625 Handle<Object> args[] = { name };
2626 Handle<Object> result = CallTrap(
2627 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
2628 if (isolate->has_pending_exception()) return Failure::Exception();
2629
2630 return result->ToBoolean()->IsTrue();
2631 }
2632
2633
SetPropertyWithHandler(String * name_raw,Object * value_raw,PropertyAttributes attributes,StrictModeFlag strict_mode)2634 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2635 String* name_raw,
2636 Object* value_raw,
2637 PropertyAttributes attributes,
2638 StrictModeFlag strict_mode) {
2639 Isolate* isolate = GetIsolate();
2640 HandleScope scope(isolate);
2641 Handle<Object> receiver(this);
2642 Handle<Object> name(name_raw);
2643 Handle<Object> value(value_raw);
2644
2645 Handle<Object> args[] = { receiver, name, value };
2646 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
2647 if (isolate->has_pending_exception()) return Failure::Exception();
2648
2649 return *value;
2650 }
2651
2652
SetPropertyWithHandlerIfDefiningSetter(String * name_raw,Object * value_raw,PropertyAttributes attributes,StrictModeFlag strict_mode,bool * found)2653 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2654 String* name_raw,
2655 Object* value_raw,
2656 PropertyAttributes attributes,
2657 StrictModeFlag strict_mode,
2658 bool* found) {
2659 *found = true; // except where defined otherwise...
2660 Isolate* isolate = GetHeap()->isolate();
2661 Handle<JSProxy> proxy(this);
2662 Handle<Object> handler(this->handler()); // Trap might morph proxy.
2663 Handle<String> name(name_raw);
2664 Handle<Object> value(value_raw);
2665 Handle<Object> args[] = { name };
2666 Handle<Object> result = proxy->CallTrap(
2667 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2668 if (isolate->has_pending_exception()) return Failure::Exception();
2669
2670 if (!result->IsUndefined()) {
2671 // The proxy handler cares about this property.
2672 // Check whether it is virtualized as an accessor.
2673 // Emulate [[GetProperty]] semantics for proxies.
2674 bool has_pending_exception;
2675 Handle<Object> argv[] = { result };
2676 Handle<Object> desc =
2677 Execution::Call(isolate->to_complete_property_descriptor(), result,
2678 ARRAY_SIZE(argv), argv, &has_pending_exception);
2679 if (has_pending_exception) return Failure::Exception();
2680
2681 Handle<String> conf_name =
2682 isolate->factory()->LookupAsciiSymbol("configurable_");
2683 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2684 ASSERT(!isolate->has_pending_exception());
2685 if (configurable->IsFalse()) {
2686 Handle<String> trap =
2687 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2688 Handle<Object> args[] = { handler, trap, name };
2689 Handle<Object> error = isolate->factory()->NewTypeError(
2690 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2691 return isolate->Throw(*error);
2692 }
2693 ASSERT(configurable->IsTrue());
2694
2695 // Check for AccessorDescriptor.
2696 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2697 Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2698 ASSERT(!isolate->has_pending_exception());
2699 if (!setter->IsUndefined()) {
2700 // We have a setter -- invoke it.
2701 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2702 return proxy->SetPropertyWithDefinedSetter(
2703 JSReceiver::cast(*setter), *value);
2704 } else {
2705 Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2706 Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2707 ASSERT(!isolate->has_pending_exception());
2708 if (!getter->IsUndefined()) {
2709 // We have a getter but no setter -- the property may not be
2710 // written. In strict mode, throw an error.
2711 if (strict_mode == kNonStrictMode) return *value;
2712 Handle<Object> args[] = { name, proxy };
2713 Handle<Object> error = isolate->factory()->NewTypeError(
2714 "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2715 return isolate->Throw(*error);
2716 }
2717 }
2718 // Fall-through.
2719 }
2720
2721 // The proxy does not define the property as an accessor.
2722 *found = false;
2723 return *value;
2724 }
2725
2726
DeletePropertyWithHandler(String * name_raw,DeleteMode mode)2727 MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2728 String* name_raw, DeleteMode mode) {
2729 Isolate* isolate = GetIsolate();
2730 HandleScope scope(isolate);
2731 Handle<Object> receiver(this);
2732 Handle<Object> name(name_raw);
2733
2734 Handle<Object> args[] = { name };
2735 Handle<Object> result = CallTrap(
2736 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
2737 if (isolate->has_pending_exception()) return Failure::Exception();
2738
2739 Object* bool_result = result->ToBoolean();
2740 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2741 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2742 Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
2743 Handle<Object> error = isolate->factory()->NewTypeError(
2744 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2745 isolate->Throw(*error);
2746 return Failure::Exception();
2747 }
2748 return bool_result;
2749 }
2750
2751
DeleteElementWithHandler(uint32_t index,DeleteMode mode)2752 MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2753 uint32_t index,
2754 DeleteMode mode) {
2755 Isolate* isolate = GetIsolate();
2756 HandleScope scope(isolate);
2757 Handle<String> name = isolate->factory()->Uint32ToString(index);
2758 return JSProxy::DeletePropertyWithHandler(*name, mode);
2759 }
2760
2761
GetPropertyAttributeWithHandler(JSReceiver * receiver_raw,String * name_raw)2762 MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2763 JSReceiver* receiver_raw,
2764 String* name_raw) {
2765 Isolate* isolate = GetIsolate();
2766 HandleScope scope(isolate);
2767 Handle<JSProxy> proxy(this);
2768 Handle<Object> handler(this->handler()); // Trap might morph proxy.
2769 Handle<JSReceiver> receiver(receiver_raw);
2770 Handle<Object> name(name_raw);
2771
2772 Handle<Object> args[] = { name };
2773 Handle<Object> result = CallTrap(
2774 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2775 if (isolate->has_pending_exception()) return NONE;
2776
2777 if (result->IsUndefined()) return ABSENT;
2778
2779 bool has_pending_exception;
2780 Handle<Object> argv[] = { result };
2781 Handle<Object> desc =
2782 Execution::Call(isolate->to_complete_property_descriptor(), result,
2783 ARRAY_SIZE(argv), argv, &has_pending_exception);
2784 if (has_pending_exception) return NONE;
2785
2786 // Convert result to PropertyAttributes.
2787 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2788 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2789 if (isolate->has_pending_exception()) return NONE;
2790 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2791 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2792 if (isolate->has_pending_exception()) return NONE;
2793 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2794 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2795 if (isolate->has_pending_exception()) return NONE;
2796
2797 if (configurable->IsFalse()) {
2798 Handle<String> trap =
2799 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2800 Handle<Object> args[] = { handler, trap, name };
2801 Handle<Object> error = isolate->factory()->NewTypeError(
2802 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2803 isolate->Throw(*error);
2804 return NONE;
2805 }
2806
2807 int attributes = NONE;
2808 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2809 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2810 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2811 return static_cast<PropertyAttributes>(attributes);
2812 }
2813
2814
GetElementAttributeWithHandler(JSReceiver * receiver,uint32_t index)2815 MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2816 JSReceiver* receiver,
2817 uint32_t index) {
2818 Isolate* isolate = GetIsolate();
2819 HandleScope scope(isolate);
2820 Handle<String> name = isolate->factory()->Uint32ToString(index);
2821 return GetPropertyAttributeWithHandler(receiver, *name);
2822 }
2823
2824
Fix()2825 void JSProxy::Fix() {
2826 Isolate* isolate = GetIsolate();
2827 HandleScope scope(isolate);
2828 Handle<JSProxy> self(this);
2829
2830 // Save identity hash.
2831 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2832
2833 if (IsJSFunctionProxy()) {
2834 isolate->factory()->BecomeJSFunction(self);
2835 // Code will be set on the JavaScript side.
2836 } else {
2837 isolate->factory()->BecomeJSObject(self);
2838 }
2839 ASSERT(self->IsJSObject());
2840
2841 // Inherit identity, if it was present.
2842 Object* hash;
2843 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2844 Handle<JSObject> new_self(JSObject::cast(*self));
2845 isolate->factory()->SetIdentityHash(new_self, hash);
2846 }
2847 }
2848
2849
CallTrap(const char * name,Handle<Object> derived,int argc,Handle<Object> argv[])2850 MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2851 Handle<Object> derived,
2852 int argc,
2853 Handle<Object> argv[]) {
2854 Isolate* isolate = GetIsolate();
2855 Handle<Object> handler(this->handler());
2856
2857 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2858 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2859 if (isolate->has_pending_exception()) return trap;
2860
2861 if (trap->IsUndefined()) {
2862 if (derived.is_null()) {
2863 Handle<Object> args[] = { handler, trap_name };
2864 Handle<Object> error = isolate->factory()->NewTypeError(
2865 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2866 isolate->Throw(*error);
2867 return Handle<Object>();
2868 }
2869 trap = Handle<Object>(derived);
2870 }
2871
2872 bool threw;
2873 return Execution::Call(trap, handler, argc, argv, &threw);
2874 }
2875
2876
SetPropertyForResult(LookupResult * result,String * name,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode)2877 MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2878 String* name,
2879 Object* value,
2880 PropertyAttributes attributes,
2881 StrictModeFlag strict_mode) {
2882 Heap* heap = GetHeap();
2883 // Make sure that the top context does not change when doing callbacks or
2884 // interceptor calls.
2885 AssertNoContextChange ncc;
2886
2887 // Optimization for 2-byte strings often used as keys in a decompression
2888 // dictionary. We make these short keys into symbols to avoid constantly
2889 // reallocating them.
2890 if (!name->IsSymbol() && name->length() <= 2) {
2891 Object* symbol_version;
2892 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
2893 if (maybe_symbol_version->ToObject(&symbol_version)) {
2894 name = String::cast(symbol_version);
2895 }
2896 }
2897 }
2898
2899 // Check access rights if needed.
2900 if (IsAccessCheckNeeded()) {
2901 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2902 return SetPropertyWithFailedAccessCheck(
2903 result, name, value, true, strict_mode);
2904 }
2905 }
2906
2907 if (IsJSGlobalProxy()) {
2908 Object* proto = GetPrototype();
2909 if (proto->IsNull()) return value;
2910 ASSERT(proto->IsJSGlobalObject());
2911 return JSObject::cast(proto)->SetPropertyForResult(
2912 result, name, value, attributes, strict_mode);
2913 }
2914
2915 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2916 bool found = false;
2917 MaybeObject* result_object;
2918 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2919 value,
2920 attributes,
2921 &found,
2922 strict_mode);
2923 if (found) return result_object;
2924 }
2925
2926 // At this point, no GC should have happened, as this would invalidate
2927 // 'result', which we cannot handlify!
2928
2929 if (!result->IsFound()) {
2930 // Neither properties nor transitions found.
2931 return AddProperty(name, value, attributes, strict_mode);
2932 }
2933 if (result->IsReadOnly() && result->IsProperty()) {
2934 if (strict_mode == kStrictMode) {
2935 Handle<JSObject> self(this);
2936 Handle<String> hname(name);
2937 Handle<Object> args[] = { hname, self };
2938 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2939 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
2940 } else {
2941 return value;
2942 }
2943 }
2944 // This is a real property that is not read-only, or it is a
2945 // transition or null descriptor and there are no setters in the prototypes.
2946 switch (result->type()) {
2947 case NORMAL:
2948 return SetNormalizedProperty(result, value);
2949 case FIELD:
2950 return FastPropertyAtPut(result->GetFieldIndex(), value);
2951 case MAP_TRANSITION:
2952 if (attributes == result->GetAttributes()) {
2953 // Only use map transition if the attributes match.
2954 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2955 name,
2956 value);
2957 }
2958 return ConvertDescriptorToField(name, value, attributes);
2959 case CONSTANT_FUNCTION:
2960 // Only replace the function if necessary.
2961 if (value == result->GetConstantFunction()) return value;
2962 // Preserve the attributes of this existing property.
2963 attributes = result->GetAttributes();
2964 return ConvertDescriptorToField(name, value, attributes);
2965 case CALLBACKS:
2966 return SetPropertyWithCallback(result->GetCallbackObject(),
2967 name,
2968 value,
2969 result->holder(),
2970 strict_mode);
2971 case INTERCEPTOR:
2972 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
2973 case CONSTANT_TRANSITION: {
2974 // If the same constant function is being added we can simply
2975 // transition to the target map.
2976 Map* target_map = result->GetTransitionMap();
2977 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2978 int number = target_descriptors->SearchWithCache(name);
2979 ASSERT(number != DescriptorArray::kNotFound);
2980 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2981 JSFunction* function =
2982 JSFunction::cast(target_descriptors->GetValue(number));
2983 if (value == function) {
2984 set_map(target_map);
2985 return value;
2986 }
2987 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2988 // FIELD, even if the value is a constant function.
2989 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2990 }
2991 case NULL_DESCRIPTOR:
2992 case ELEMENTS_TRANSITION:
2993 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2994 case HANDLER:
2995 UNREACHABLE();
2996 return value;
2997 }
2998 UNREACHABLE(); // keep the compiler happy
2999 return value;
3000 }
3001
3002
3003 // Set a real local property, even if it is READ_ONLY. If the property is not
3004 // present, add it with attributes NONE. This code is an exact clone of
3005 // SetProperty, with the check for IsReadOnly and the check for a
3006 // callback setter removed. The two lines looking up the LookupResult
3007 // result are also added. If one of the functions is changed, the other
3008 // should be.
3009 // Note that this method cannot be used to set the prototype of a function
3010 // because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3011 // doesn't handle function prototypes correctly.
SetLocalPropertyIgnoreAttributes(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes)3012 Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3013 Handle<JSObject> object,
3014 Handle<String> key,
3015 Handle<Object> value,
3016 PropertyAttributes attributes) {
3017 CALL_HEAP_FUNCTION(
3018 object->GetIsolate(),
3019 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3020 Object);
3021 }
3022
3023
SetLocalPropertyIgnoreAttributes(String * name,Object * value,PropertyAttributes attributes)3024 MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
3025 String* name,
3026 Object* value,
3027 PropertyAttributes attributes) {
3028
3029 // Make sure that the top context does not change when doing callbacks or
3030 // interceptor calls.
3031 AssertNoContextChange ncc;
3032 Isolate* isolate = GetIsolate();
3033 LookupResult result(isolate);
3034 LocalLookup(name, &result);
3035 // Check access rights if needed.
3036 if (IsAccessCheckNeeded()) {
3037 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3038 return SetPropertyWithFailedAccessCheck(&result,
3039 name,
3040 value,
3041 false,
3042 kNonStrictMode);
3043 }
3044 }
3045
3046 if (IsJSGlobalProxy()) {
3047 Object* proto = GetPrototype();
3048 if (proto->IsNull()) return value;
3049 ASSERT(proto->IsJSGlobalObject());
3050 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
3051 name,
3052 value,
3053 attributes);
3054 }
3055
3056 // Check for accessor in prototype chain removed here in clone.
3057 if (!result.IsFound()) {
3058 // Neither properties nor transitions found.
3059 return AddProperty(name, value, attributes, kNonStrictMode);
3060 }
3061
3062 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3063
3064 // Check of IsReadOnly removed from here in clone.
3065 switch (result.type()) {
3066 case NORMAL:
3067 return SetNormalizedProperty(name, value, details);
3068 case FIELD:
3069 return FastPropertyAtPut(result.GetFieldIndex(), value);
3070 case MAP_TRANSITION:
3071 if (attributes == result.GetAttributes()) {
3072 // Only use map transition if the attributes match.
3073 return AddFastPropertyUsingMap(result.GetTransitionMap(),
3074 name,
3075 value);
3076 }
3077 return ConvertDescriptorToField(name, value, attributes);
3078 case CONSTANT_FUNCTION:
3079 // Only replace the function if necessary.
3080 if (value == result.GetConstantFunction()) return value;
3081 // Preserve the attributes of this existing property.
3082 attributes = result.GetAttributes();
3083 return ConvertDescriptorToField(name, value, attributes);
3084 case CALLBACKS:
3085 case INTERCEPTOR:
3086 // Override callback in clone
3087 return ConvertDescriptorToField(name, value, attributes);
3088 case CONSTANT_TRANSITION:
3089 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3090 // if the value is a function.
3091 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3092 case NULL_DESCRIPTOR:
3093 case ELEMENTS_TRANSITION:
3094 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3095 case HANDLER:
3096 UNREACHABLE();
3097 return value;
3098 }
3099 UNREACHABLE(); // keep the compiler happy
3100 return value;
3101 }
3102
3103
GetPropertyAttributePostInterceptor(JSObject * receiver,String * name,bool continue_search)3104 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3105 JSObject* receiver,
3106 String* name,
3107 bool continue_search) {
3108 // Check local property, ignore interceptor.
3109 LookupResult result(GetIsolate());
3110 LocalLookupRealNamedProperty(name, &result);
3111 if (result.IsProperty()) return result.GetAttributes();
3112
3113 if (continue_search) {
3114 // Continue searching via the prototype chain.
3115 Object* pt = GetPrototype();
3116 if (!pt->IsNull()) {
3117 return JSObject::cast(pt)->
3118 GetPropertyAttributeWithReceiver(receiver, name);
3119 }
3120 }
3121 return ABSENT;
3122 }
3123
3124
GetPropertyAttributeWithInterceptor(JSObject * receiver,String * name,bool continue_search)3125 PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3126 JSObject* receiver,
3127 String* name,
3128 bool continue_search) {
3129 Isolate* isolate = GetIsolate();
3130
3131 // Make sure that the top context does not change when doing
3132 // callbacks or interceptor calls.
3133 AssertNoContextChange ncc;
3134
3135 HandleScope scope(isolate);
3136 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3137 Handle<JSObject> receiver_handle(receiver);
3138 Handle<JSObject> holder_handle(this);
3139 Handle<String> name_handle(name);
3140 CustomArguments args(isolate, interceptor->data(), receiver, this);
3141 v8::AccessorInfo info(args.end());
3142 if (!interceptor->query()->IsUndefined()) {
3143 v8::NamedPropertyQuery query =
3144 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
3145 LOG(isolate,
3146 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
3147 v8::Handle<v8::Integer> result;
3148 {
3149 // Leaving JavaScript.
3150 VMState state(isolate, EXTERNAL);
3151 result = query(v8::Utils::ToLocal(name_handle), info);
3152 }
3153 if (!result.IsEmpty()) {
3154 ASSERT(result->IsInt32());
3155 return static_cast<PropertyAttributes>(result->Int32Value());
3156 }
3157 } else if (!interceptor->getter()->IsUndefined()) {
3158 v8::NamedPropertyGetter getter =
3159 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
3160 LOG(isolate,
3161 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
3162 v8::Handle<v8::Value> result;
3163 {
3164 // Leaving JavaScript.
3165 VMState state(isolate, EXTERNAL);
3166 result = getter(v8::Utils::ToLocal(name_handle), info);
3167 }
3168 if (!result.IsEmpty()) return DONT_ENUM;
3169 }
3170 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3171 *name_handle,
3172 continue_search);
3173 }
3174
3175
GetPropertyAttributeWithReceiver(JSReceiver * receiver,String * key)3176 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3177 JSReceiver* receiver,
3178 String* key) {
3179 uint32_t index = 0;
3180 if (IsJSObject() && key->AsArrayIndex(&index)) {
3181 return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3182 ? NONE : ABSENT;
3183 }
3184 // Named property.
3185 LookupResult result(GetIsolate());
3186 Lookup(key, &result);
3187 return GetPropertyAttribute(receiver, &result, key, true);
3188 }
3189
3190
GetPropertyAttribute(JSReceiver * receiver,LookupResult * result,String * name,bool continue_search)3191 PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3192 LookupResult* result,
3193 String* name,
3194 bool continue_search) {
3195 // Check access rights if needed.
3196 if (IsAccessCheckNeeded()) {
3197 JSObject* this_obj = JSObject::cast(this);
3198 Heap* heap = GetHeap();
3199 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3200 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3201 receiver, result, name, continue_search);
3202 }
3203 }
3204 if (result->IsProperty()) {
3205 switch (result->type()) {
3206 case NORMAL: // fall through
3207 case FIELD:
3208 case CONSTANT_FUNCTION:
3209 case CALLBACKS:
3210 return result->GetAttributes();
3211 case HANDLER: {
3212 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3213 receiver, name);
3214 }
3215 case INTERCEPTOR:
3216 return result->holder()->GetPropertyAttributeWithInterceptor(
3217 JSObject::cast(receiver), name, continue_search);
3218 default:
3219 UNREACHABLE();
3220 }
3221 }
3222 return ABSENT;
3223 }
3224
3225
GetLocalPropertyAttribute(String * name)3226 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
3227 // Check whether the name is an array index.
3228 uint32_t index = 0;
3229 if (IsJSObject() && name->AsArrayIndex(&index)) {
3230 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
3231 return ABSENT;
3232 }
3233 // Named property.
3234 LookupResult result(GetIsolate());
3235 LocalLookup(name, &result);
3236 return GetPropertyAttribute(this, &result, name, false);
3237 }
3238
3239
Get(JSObject * obj,PropertyNormalizationMode mode)3240 MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3241 PropertyNormalizationMode mode) {
3242 Isolate* isolate = obj->GetIsolate();
3243 Map* fast = obj->map();
3244 int index = fast->Hash() % kEntries;
3245 Object* result = get(index);
3246 if (result->IsMap() &&
3247 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
3248 #ifdef DEBUG
3249 if (FLAG_verify_heap) {
3250 Map::cast(result)->SharedMapVerify();
3251 }
3252 if (FLAG_enable_slow_asserts) {
3253 // The cached map should match newly created normalized map bit-by-bit.
3254 Object* fresh;
3255 { MaybeObject* maybe_fresh =
3256 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3257 if (maybe_fresh->ToObject(&fresh)) {
3258 ASSERT(memcmp(Map::cast(fresh)->address(),
3259 Map::cast(result)->address(),
3260 Map::kSize) == 0);
3261 }
3262 }
3263 }
3264 #endif
3265 return result;
3266 }
3267
3268 { MaybeObject* maybe_result =
3269 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3270 if (!maybe_result->ToObject(&result)) return maybe_result;
3271 }
3272 set(index, result);
3273 isolate->counters()->normalized_maps()->Increment();
3274
3275 return result;
3276 }
3277
3278
Clear()3279 void NormalizedMapCache::Clear() {
3280 int entries = length();
3281 for (int i = 0; i != entries; i++) {
3282 set_undefined(i);
3283 }
3284 }
3285
3286
UpdateMapCodeCache(Handle<JSObject> object,Handle<String> name,Handle<Code> code)3287 void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3288 Handle<String> name,
3289 Handle<Code> code) {
3290 Isolate* isolate = object->GetIsolate();
3291 CALL_HEAP_FUNCTION_VOID(isolate,
3292 object->UpdateMapCodeCache(*name, *code));
3293 }
3294
3295
UpdateMapCodeCache(String * name,Code * code)3296 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
3297 if (map()->is_shared()) {
3298 // Fast case maps are never marked as shared.
3299 ASSERT(!HasFastProperties());
3300 // Replace the map with an identical copy that can be safely modified.
3301 Object* obj;
3302 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3303 UNIQUE_NORMALIZED_MAP);
3304 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3305 }
3306 GetIsolate()->counters()->normalized_maps()->Increment();
3307
3308 set_map(Map::cast(obj));
3309 }
3310 return map()->UpdateCodeCache(name, code);
3311 }
3312
3313
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties)3314 void JSObject::NormalizeProperties(Handle<JSObject> object,
3315 PropertyNormalizationMode mode,
3316 int expected_additional_properties) {
3317 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3318 object->NormalizeProperties(
3319 mode, expected_additional_properties));
3320 }
3321
3322
NormalizeProperties(PropertyNormalizationMode mode,int expected_additional_properties)3323 MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3324 int expected_additional_properties) {
3325 if (!HasFastProperties()) return this;
3326
3327 // The global object is always normalized.
3328 ASSERT(!IsGlobalObject());
3329 // JSGlobalProxy must never be normalized
3330 ASSERT(!IsJSGlobalProxy());
3331
3332 Map* map_of_this = map();
3333
3334 // Allocate new content.
3335 int property_count = map_of_this->NumberOfDescribedProperties();
3336 if (expected_additional_properties > 0) {
3337 property_count += expected_additional_properties;
3338 } else {
3339 property_count += 2; // Make space for two more properties.
3340 }
3341 StringDictionary* dictionary;
3342 { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count);
3343 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3344 }
3345
3346 DescriptorArray* descs = map_of_this->instance_descriptors();
3347 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3348 PropertyDetails details(descs->GetDetails(i));
3349 switch (details.type()) {
3350 case CONSTANT_FUNCTION: {
3351 PropertyDetails d =
3352 PropertyDetails(details.attributes(), NORMAL, details.index());
3353 Object* value = descs->GetConstantFunction(i);
3354 MaybeObject* maybe_dictionary =
3355 dictionary->Add(descs->GetKey(i), value, d);
3356 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3357 break;
3358 }
3359 case FIELD: {
3360 PropertyDetails d =
3361 PropertyDetails(details.attributes(), NORMAL, details.index());
3362 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
3363 MaybeObject* maybe_dictionary =
3364 dictionary->Add(descs->GetKey(i), value, d);
3365 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3366 break;
3367 }
3368 case CALLBACKS: {
3369 if (!descs->IsProperty(i)) break;
3370 Object* value = descs->GetCallbacksObject(i);
3371 if (value->IsAccessorPair()) {
3372 MaybeObject* maybe_copy =
3373 AccessorPair::cast(value)->CopyWithoutTransitions();
3374 if (!maybe_copy->To(&value)) return maybe_copy;
3375 }
3376 MaybeObject* maybe_dictionary =
3377 dictionary->Add(descs->GetKey(i), value, details);
3378 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
3379 break;
3380 }
3381 case MAP_TRANSITION:
3382 case CONSTANT_TRANSITION:
3383 case NULL_DESCRIPTOR:
3384 case INTERCEPTOR:
3385 case ELEMENTS_TRANSITION:
3386 break;
3387 case HANDLER:
3388 case NORMAL:
3389 UNREACHABLE();
3390 break;
3391 }
3392 }
3393
3394 Heap* current_heap = GetHeap();
3395
3396 // Copy the next enumeration index from instance descriptor.
3397 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
3398 dictionary->SetNextEnumerationIndex(index);
3399
3400 Map* new_map;
3401 { MaybeObject* maybe_map =
3402 current_heap->isolate()->context()->global_context()->
3403 normalized_map_cache()->Get(this, mode);
3404 if (!maybe_map->To(&new_map)) return maybe_map;
3405 }
3406
3407 // We have now successfully allocated all the necessary objects.
3408 // Changes can now be made with the guarantee that all of them take effect.
3409
3410 // Resize the object in the heap if necessary.
3411 int new_instance_size = new_map->instance_size();
3412 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
3413 ASSERT(instance_size_delta >= 0);
3414 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3415 instance_size_delta);
3416 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
3417 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3418 -instance_size_delta);
3419 }
3420
3421
3422 set_map(new_map);
3423 new_map->clear_instance_descriptors();
3424
3425 set_properties(dictionary);
3426
3427 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
3428
3429 #ifdef DEBUG
3430 if (FLAG_trace_normalization) {
3431 PrintF("Object properties have been normalized:\n");
3432 Print();
3433 }
3434 #endif
3435 return this;
3436 }
3437
3438
TransformToFastProperties(Handle<JSObject> object,int unused_property_fields)3439 void JSObject::TransformToFastProperties(Handle<JSObject> object,
3440 int unused_property_fields) {
3441 CALL_HEAP_FUNCTION_VOID(
3442 object->GetIsolate(),
3443 object->TransformToFastProperties(unused_property_fields));
3444 }
3445
3446
TransformToFastProperties(int unused_property_fields)3447 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
3448 if (HasFastProperties()) return this;
3449 ASSERT(!IsGlobalObject());
3450 return property_dictionary()->
3451 TransformPropertiesToFastFor(this, unused_property_fields);
3452 }
3453
3454
NormalizeElements(Handle<JSObject> object)3455 Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3456 Handle<JSObject> object) {
3457 CALL_HEAP_FUNCTION(object->GetIsolate(),
3458 object->NormalizeElements(),
3459 SeededNumberDictionary);
3460 }
3461
3462
NormalizeElements()3463 MaybeObject* JSObject::NormalizeElements() {
3464 ASSERT(!HasExternalArrayElements());
3465
3466 // Find the backing store.
3467 FixedArrayBase* array = FixedArrayBase::cast(elements());
3468 Map* old_map = array->map();
3469 bool is_arguments =
3470 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
3471 if (is_arguments) {
3472 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
3473 }
3474 if (array->IsDictionary()) return array;
3475
3476 ASSERT(HasFastElements() ||
3477 HasFastSmiOnlyElements() ||
3478 HasFastDoubleElements() ||
3479 HasFastArgumentsElements());
3480 // Compute the effective length and allocate a new backing store.
3481 int length = IsJSArray()
3482 ? Smi::cast(JSArray::cast(this)->length())->value()
3483 : array->length();
3484 int old_capacity = 0;
3485 int used_elements = 0;
3486 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
3487 SeededNumberDictionary* dictionary = NULL;
3488 { Object* object;
3489 MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
3490 if (!maybe->ToObject(&object)) return maybe;
3491 dictionary = SeededNumberDictionary::cast(object);
3492 }
3493
3494 // Copy the elements to the new backing store.
3495 bool has_double_elements = array->IsFixedDoubleArray();
3496 for (int i = 0; i < length; i++) {
3497 Object* value = NULL;
3498 if (has_double_elements) {
3499 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3500 if (double_array->is_the_hole(i)) {
3501 value = GetIsolate()->heap()->the_hole_value();
3502 } else {
3503 // Objects must be allocated in the old object space, since the
3504 // overall number of HeapNumbers needed for the conversion might
3505 // exceed the capacity of new space, and we would fail repeatedly
3506 // trying to convert the FixedDoubleArray.
3507 MaybeObject* maybe_value_object =
3508 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
3509 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
3510 }
3511 } else {
3512 ASSERT(old_map->has_fast_elements() ||
3513 old_map->has_fast_smi_only_elements());
3514 value = FixedArray::cast(array)->get(i);
3515 }
3516 PropertyDetails details = PropertyDetails(NONE, NORMAL);
3517 if (!value->IsTheHole()) {
3518 Object* result;
3519 MaybeObject* maybe_result =
3520 dictionary->AddNumberEntry(i, value, details);
3521 if (!maybe_result->ToObject(&result)) return maybe_result;
3522 dictionary = SeededNumberDictionary::cast(result);
3523 }
3524 }
3525
3526 // Switch to using the dictionary as the backing storage for elements.
3527 if (is_arguments) {
3528 FixedArray::cast(elements())->set(1, dictionary);
3529 } else {
3530 // Set the new map first to satify the elements type assert in
3531 // set_elements().
3532 Object* new_map;
3533 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
3534 DICTIONARY_ELEMENTS);
3535 if (!maybe->ToObject(&new_map)) return maybe;
3536 set_map(Map::cast(new_map));
3537 set_elements(dictionary);
3538 }
3539
3540 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3541 Increment();
3542
3543 #ifdef DEBUG
3544 if (FLAG_trace_normalization) {
3545 PrintF("Object elements have been normalized:\n");
3546 Print();
3547 }
3548 #endif
3549
3550 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3551 return dictionary;
3552 }
3553
3554
GenerateIdentityHash()3555 Smi* JSReceiver::GenerateIdentityHash() {
3556 Isolate* isolate = GetIsolate();
3557
3558 int hash_value;
3559 int attempts = 0;
3560 do {
3561 // Generate a random 32-bit hash value but limit range to fit
3562 // within a smi.
3563 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
3564 attempts++;
3565 } while (hash_value == 0 && attempts < 30);
3566 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3567
3568 return Smi::FromInt(hash_value);
3569 }
3570
3571
SetIdentityHash(Object * hash,CreationFlag flag)3572 MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3573 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3574 hash);
3575 if (maybe->IsFailure()) return maybe;
3576 return this;
3577 }
3578
3579
GetIdentityHash(Handle<JSObject> obj)3580 int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3581 CALL_AND_RETRY(obj->GetIsolate(),
3582 obj->GetIdentityHash(ALLOW_CREATION),
3583 return Smi::cast(__object__)->value(),
3584 return 0);
3585 }
3586
3587
GetIdentityHash(CreationFlag flag)3588 MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3589 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3590 if (stored_value->IsSmi()) return stored_value;
3591
3592 // Do not generate permanent identity hash code if not requested.
3593 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3594
3595 Smi* hash = GenerateIdentityHash();
3596 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3597 hash);
3598 if (result->IsFailure()) return result;
3599 if (result->ToObjectUnchecked()->IsUndefined()) {
3600 // Trying to get hash of detached proxy.
3601 return Smi::FromInt(0);
3602 }
3603 return hash;
3604 }
3605
3606
GetIdentityHash(CreationFlag flag)3607 MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3608 Object* hash = this->hash();
3609 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3610 hash = GenerateIdentityHash();
3611 set_hash(hash);
3612 }
3613 return hash;
3614 }
3615
3616
GetHiddenProperty(String * key)3617 Object* JSObject::GetHiddenProperty(String* key) {
3618 if (IsJSGlobalProxy()) {
3619 // For a proxy, use the prototype as target object.
3620 Object* proxy_parent = GetPrototype();
3621 // If the proxy is detached, return undefined.
3622 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3623 ASSERT(proxy_parent->IsJSGlobalObject());
3624 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3625 }
3626 ASSERT(!IsJSGlobalProxy());
3627 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3628 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3629 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3630 return GetHeap()->undefined_value();
3631 }
3632 StringDictionary* dictionary =
3633 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3634 int entry = dictionary->FindEntry(key);
3635 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3636 return dictionary->ValueAt(entry);
3637 }
3638
3639
SetHiddenProperty(Handle<JSObject> obj,Handle<String> key,Handle<Object> value)3640 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3641 Handle<String> key,
3642 Handle<Object> value) {
3643 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3644 obj->SetHiddenProperty(*key, *value),
3645 Object);
3646 }
3647
3648
SetHiddenProperty(String * key,Object * value)3649 MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3650 if (IsJSGlobalProxy()) {
3651 // For a proxy, use the prototype as target object.
3652 Object* proxy_parent = GetPrototype();
3653 // If the proxy is detached, return undefined.
3654 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3655 ASSERT(proxy_parent->IsJSGlobalObject());
3656 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3657 }
3658 ASSERT(!IsJSGlobalProxy());
3659 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3660 StringDictionary* dictionary;
3661 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3662
3663 // If it was found, check if the key is already in the dictionary.
3664 int entry = dictionary->FindEntry(key);
3665 if (entry != StringDictionary::kNotFound) {
3666 // If key was found, just update the value.
3667 dictionary->ValueAtPut(entry, value);
3668 return this;
3669 }
3670 // Key was not already in the dictionary, so add the entry.
3671 MaybeObject* insert_result = dictionary->Add(key,
3672 value,
3673 PropertyDetails(NONE, NORMAL));
3674 StringDictionary* new_dict;
3675 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3676 if (new_dict != dictionary) {
3677 // If adding the key expanded the dictionary (i.e., Add returned a new
3678 // dictionary), store it back to the object.
3679 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3680 if (store_result->IsFailure()) return store_result;
3681 }
3682 // Return this to mark success.
3683 return this;
3684 }
3685
3686
DeleteHiddenProperty(String * key)3687 void JSObject::DeleteHiddenProperty(String* key) {
3688 if (IsJSGlobalProxy()) {
3689 // For a proxy, use the prototype as target object.
3690 Object* proxy_parent = GetPrototype();
3691 // If the proxy is detached, return immediately.
3692 if (proxy_parent->IsNull()) return;
3693 ASSERT(proxy_parent->IsJSGlobalObject());
3694 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3695 return;
3696 }
3697 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3698 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3699 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3700 StringDictionary* dictionary =
3701 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3702 int entry = dictionary->FindEntry(key);
3703 if (entry == StringDictionary::kNotFound) {
3704 // Key wasn't in dictionary. Deletion is a success.
3705 return;
3706 }
3707 // Key was in the dictionary. Remove it.
3708 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3709 }
3710
3711
HasHiddenProperties()3712 bool JSObject::HasHiddenProperties() {
3713 return GetPropertyAttributePostInterceptor(this,
3714 GetHeap()->hidden_symbol(),
3715 false) != ABSENT;
3716 }
3717
3718
GetHiddenPropertiesDictionary(bool create_if_absent)3719 MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3720 ASSERT(!IsJSGlobalProxy());
3721 if (HasFastProperties()) {
3722 // If the object has fast properties, check whether the first slot
3723 // in the descriptor array matches the hidden symbol. Since the
3724 // hidden symbols hash code is zero (and no other string has hash
3725 // code zero) it will always occupy the first entry if present.
3726 DescriptorArray* descriptors = this->map()->instance_descriptors();
3727 if ((descriptors->number_of_descriptors() > 0) &&
3728 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3729 if (descriptors->GetType(0) == FIELD) {
3730 Object* hidden_store =
3731 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3732 return StringDictionary::cast(hidden_store);
3733 } else {
3734 ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3735 descriptors->GetType(0) == MAP_TRANSITION);
3736 }
3737 }
3738 } else {
3739 PropertyAttributes attributes;
3740 // You can't install a getter on a property indexed by the hidden symbol,
3741 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3742 // object.
3743 Object* lookup =
3744 GetLocalPropertyPostInterceptor(this,
3745 GetHeap()->hidden_symbol(),
3746 &attributes)->ToObjectUnchecked();
3747 if (!lookup->IsUndefined()) {
3748 return StringDictionary::cast(lookup);
3749 }
3750 }
3751 if (!create_if_absent) return GetHeap()->undefined_value();
3752 const int kInitialSize = 5;
3753 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3754 StringDictionary* dictionary;
3755 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3756 MaybeObject* store_result =
3757 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3758 dictionary,
3759 DONT_ENUM,
3760 kNonStrictMode);
3761 if (store_result->IsFailure()) return store_result;
3762 return dictionary;
3763 }
3764
3765
SetHiddenPropertiesDictionary(StringDictionary * dictionary)3766 MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3767 StringDictionary* dictionary) {
3768 ASSERT(!IsJSGlobalProxy());
3769 ASSERT(HasHiddenProperties());
3770 if (HasFastProperties()) {
3771 // If the object has fast properties, check whether the first slot
3772 // in the descriptor array matches the hidden symbol. Since the
3773 // hidden symbols hash code is zero (and no other string has hash
3774 // code zero) it will always occupy the first entry if present.
3775 DescriptorArray* descriptors = this->map()->instance_descriptors();
3776 if ((descriptors->number_of_descriptors() > 0) &&
3777 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3778 if (descriptors->GetType(0) == FIELD) {
3779 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3780 return this;
3781 } else {
3782 ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3783 descriptors->GetType(0) == MAP_TRANSITION);
3784 }
3785 }
3786 }
3787 MaybeObject* store_result =
3788 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3789 dictionary,
3790 DONT_ENUM,
3791 kNonStrictMode);
3792 if (store_result->IsFailure()) return store_result;
3793 return this;
3794 }
3795
3796
DeletePropertyPostInterceptor(String * name,DeleteMode mode)3797 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3798 DeleteMode mode) {
3799 // Check local property, ignore interceptor.
3800 LookupResult result(GetIsolate());
3801 LocalLookupRealNamedProperty(name, &result);
3802 if (!result.IsProperty()) return GetHeap()->true_value();
3803
3804 // Normalize object if needed.
3805 Object* obj;
3806 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3807 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3808 }
3809
3810 return DeleteNormalizedProperty(name, mode);
3811 }
3812
3813
DeletePropertyWithInterceptor(String * name)3814 MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
3815 Isolate* isolate = GetIsolate();
3816 HandleScope scope(isolate);
3817 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3818 Handle<String> name_handle(name);
3819 Handle<JSObject> this_handle(this);
3820 if (!interceptor->deleter()->IsUndefined()) {
3821 v8::NamedPropertyDeleter deleter =
3822 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
3823 LOG(isolate,
3824 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3825 CustomArguments args(isolate, interceptor->data(), this, this);
3826 v8::AccessorInfo info(args.end());
3827 v8::Handle<v8::Boolean> result;
3828 {
3829 // Leaving JavaScript.
3830 VMState state(isolate, EXTERNAL);
3831 result = deleter(v8::Utils::ToLocal(name_handle), info);
3832 }
3833 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3834 if (!result.IsEmpty()) {
3835 ASSERT(result->IsBoolean());
3836 return *v8::Utils::OpenHandle(*result);
3837 }
3838 }
3839 MaybeObject* raw_result =
3840 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
3841 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3842 return raw_result;
3843 }
3844
3845
DeleteElementWithInterceptor(uint32_t index)3846 MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
3847 Isolate* isolate = GetIsolate();
3848 Heap* heap = isolate->heap();
3849 // Make sure that the top context does not change when doing
3850 // callbacks or interceptor calls.
3851 AssertNoContextChange ncc;
3852 HandleScope scope(isolate);
3853 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
3854 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
3855 v8::IndexedPropertyDeleter deleter =
3856 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3857 Handle<JSObject> this_handle(this);
3858 LOG(isolate,
3859 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3860 CustomArguments args(isolate, interceptor->data(), this, this);
3861 v8::AccessorInfo info(args.end());
3862 v8::Handle<v8::Boolean> result;
3863 {
3864 // Leaving JavaScript.
3865 VMState state(isolate, EXTERNAL);
3866 result = deleter(index, info);
3867 }
3868 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3869 if (!result.IsEmpty()) {
3870 ASSERT(result->IsBoolean());
3871 return *v8::Utils::OpenHandle(*result);
3872 }
3873 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3874 *this_handle,
3875 index,
3876 NORMAL_DELETION);
3877 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
3878 return raw_result;
3879 }
3880
3881
DeleteElement(Handle<JSObject> obj,uint32_t index)3882 Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3883 uint32_t index) {
3884 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3885 obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3886 Object);
3887 }
3888
3889
DeleteElement(uint32_t index,DeleteMode mode)3890 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
3891 Isolate* isolate = GetIsolate();
3892 // Check access rights if needed.
3893 if (IsAccessCheckNeeded() &&
3894 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3895 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3896 return isolate->heap()->false_value();
3897 }
3898
3899 if (IsJSGlobalProxy()) {
3900 Object* proto = GetPrototype();
3901 if (proto->IsNull()) return isolate->heap()->false_value();
3902 ASSERT(proto->IsJSGlobalObject());
3903 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3904 }
3905
3906 if (HasIndexedInterceptor()) {
3907 // Skip interceptor if forcing deletion.
3908 if (mode != FORCE_DELETION) {
3909 return DeleteElementWithInterceptor(index);
3910 }
3911 mode = JSReceiver::FORCE_DELETION;
3912 }
3913
3914 return GetElementsAccessor()->Delete(this, index, mode);
3915 }
3916
3917
DeleteProperty(Handle<JSObject> obj,Handle<String> prop)3918 Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3919 Handle<String> prop) {
3920 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3921 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3922 Object);
3923 }
3924
3925
DeleteProperty(String * name,DeleteMode mode)3926 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
3927 Isolate* isolate = GetIsolate();
3928 // ECMA-262, 3rd, 8.6.2.5
3929 ASSERT(name->IsString());
3930
3931 // Check access rights if needed.
3932 if (IsAccessCheckNeeded() &&
3933 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3934 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3935 return isolate->heap()->false_value();
3936 }
3937
3938 if (IsJSGlobalProxy()) {
3939 Object* proto = GetPrototype();
3940 if (proto->IsNull()) return isolate->heap()->false_value();
3941 ASSERT(proto->IsJSGlobalObject());
3942 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3943 }
3944
3945 uint32_t index = 0;
3946 if (name->AsArrayIndex(&index)) {
3947 return DeleteElement(index, mode);
3948 } else {
3949 LookupResult result(isolate);
3950 LocalLookup(name, &result);
3951 if (!result.IsProperty()) return isolate->heap()->true_value();
3952 // Ignore attributes if forcing a deletion.
3953 if (result.IsDontDelete() && mode != FORCE_DELETION) {
3954 if (mode == STRICT_DELETION) {
3955 // Deleting a non-configurable property in strict mode.
3956 HandleScope scope(isolate);
3957 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
3958 return isolate->Throw(*isolate->factory()->NewTypeError(
3959 "strict_delete_property", HandleVector(args, 2)));
3960 }
3961 return isolate->heap()->false_value();
3962 }
3963 // Check for interceptor.
3964 if (result.type() == INTERCEPTOR) {
3965 // Skip interceptor if forcing a deletion.
3966 if (mode == FORCE_DELETION) {
3967 return DeletePropertyPostInterceptor(name, mode);
3968 }
3969 return DeletePropertyWithInterceptor(name);
3970 }
3971 // Normalize object if needed.
3972 Object* obj;
3973 { MaybeObject* maybe_obj =
3974 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3975 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3976 }
3977 // Make sure the properties are normalized before removing the entry.
3978 return DeleteNormalizedProperty(name, mode);
3979 }
3980 }
3981
3982
DeleteElement(uint32_t index,DeleteMode mode)3983 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
3984 if (IsJSProxy()) {
3985 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
3986 }
3987 return JSObject::cast(this)->DeleteElement(index, mode);
3988 }
3989
3990
DeleteProperty(String * name,DeleteMode mode)3991 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3992 if (IsJSProxy()) {
3993 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3994 }
3995 return JSObject::cast(this)->DeleteProperty(name, mode);
3996 }
3997
3998
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)3999 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
4000 ElementsKind kind,
4001 Object* object) {
4002 ASSERT(kind == FAST_ELEMENTS ||
4003 kind == DICTIONARY_ELEMENTS);
4004 if (kind == FAST_ELEMENTS) {
4005 int length = IsJSArray()
4006 ? Smi::cast(JSArray::cast(this)->length())->value()
4007 : elements->length();
4008 for (int i = 0; i < length; ++i) {
4009 Object* element = elements->get(i);
4010 if (!element->IsTheHole() && element == object) return true;
4011 }
4012 } else {
4013 Object* key =
4014 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
4015 if (!key->IsUndefined()) return true;
4016 }
4017 return false;
4018 }
4019
4020
4021 // Check whether this object references another object.
ReferencesObject(Object * obj)4022 bool JSObject::ReferencesObject(Object* obj) {
4023 Map* map_of_this = map();
4024 Heap* heap = GetHeap();
4025 AssertNoAllocation no_alloc;
4026
4027 // Is the object the constructor for this object?
4028 if (map_of_this->constructor() == obj) {
4029 return true;
4030 }
4031
4032 // Is the object the prototype for this object?
4033 if (map_of_this->prototype() == obj) {
4034 return true;
4035 }
4036
4037 // Check if the object is among the named properties.
4038 Object* key = SlowReverseLookup(obj);
4039 if (!key->IsUndefined()) {
4040 return true;
4041 }
4042
4043 // Check if the object is among the indexed properties.
4044 ElementsKind kind = GetElementsKind();
4045 switch (kind) {
4046 case EXTERNAL_PIXEL_ELEMENTS:
4047 case EXTERNAL_BYTE_ELEMENTS:
4048 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4049 case EXTERNAL_SHORT_ELEMENTS:
4050 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4051 case EXTERNAL_INT_ELEMENTS:
4052 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4053 case EXTERNAL_FLOAT_ELEMENTS:
4054 case EXTERNAL_DOUBLE_ELEMENTS:
4055 case FAST_DOUBLE_ELEMENTS:
4056 // Raw pixels and external arrays do not reference other
4057 // objects.
4058 break;
4059 case FAST_SMI_ONLY_ELEMENTS:
4060 break;
4061 case FAST_ELEMENTS:
4062 case DICTIONARY_ELEMENTS: {
4063 FixedArray* elements = FixedArray::cast(this->elements());
4064 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
4065 break;
4066 }
4067 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4068 FixedArray* parameter_map = FixedArray::cast(elements());
4069 // Check the mapped parameters.
4070 int length = parameter_map->length();
4071 for (int i = 2; i < length; ++i) {
4072 Object* value = parameter_map->get(i);
4073 if (!value->IsTheHole() && value == obj) return true;
4074 }
4075 // Check the arguments.
4076 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4077 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4078 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
4079 break;
4080 }
4081 }
4082
4083 // For functions check the context.
4084 if (IsJSFunction()) {
4085 // Get the constructor function for arguments array.
4086 JSObject* arguments_boilerplate =
4087 heap->isolate()->context()->global_context()->
4088 arguments_boilerplate();
4089 JSFunction* arguments_function =
4090 JSFunction::cast(arguments_boilerplate->map()->constructor());
4091
4092 // Get the context and don't check if it is the global context.
4093 JSFunction* f = JSFunction::cast(this);
4094 Context* context = f->context();
4095 if (context->IsGlobalContext()) {
4096 return false;
4097 }
4098
4099 // Check the non-special context slots.
4100 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4101 // Only check JS objects.
4102 if (context->get(i)->IsJSObject()) {
4103 JSObject* ctxobj = JSObject::cast(context->get(i));
4104 // If it is an arguments array check the content.
4105 if (ctxobj->map()->constructor() == arguments_function) {
4106 if (ctxobj->ReferencesObject(obj)) {
4107 return true;
4108 }
4109 } else if (ctxobj == obj) {
4110 return true;
4111 }
4112 }
4113 }
4114
4115 // Check the context extension (if any) if it can have references.
4116 if (context->has_extension() && !context->IsCatchContext()) {
4117 return JSObject::cast(context->extension())->ReferencesObject(obj);
4118 }
4119 }
4120
4121 // No references to object.
4122 return false;
4123 }
4124
4125
PreventExtensions(Handle<JSObject> object)4126 Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
4127 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
4128 }
4129
4130
PreventExtensions()4131 MaybeObject* JSObject::PreventExtensions() {
4132 Isolate* isolate = GetIsolate();
4133 if (IsAccessCheckNeeded() &&
4134 !isolate->MayNamedAccess(this,
4135 isolate->heap()->undefined_value(),
4136 v8::ACCESS_KEYS)) {
4137 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4138 return isolate->heap()->false_value();
4139 }
4140
4141 if (IsJSGlobalProxy()) {
4142 Object* proto = GetPrototype();
4143 if (proto->IsNull()) return this;
4144 ASSERT(proto->IsJSGlobalObject());
4145 return JSObject::cast(proto)->PreventExtensions();
4146 }
4147
4148 // It's not possible to seal objects with external array elements
4149 if (HasExternalArrayElements()) {
4150 HandleScope scope(isolate);
4151 Handle<Object> object(this);
4152 Handle<Object> error =
4153 isolate->factory()->NewTypeError(
4154 "cant_prevent_ext_external_array_elements",
4155 HandleVector(&object, 1));
4156 return isolate->Throw(*error);
4157 }
4158
4159 // If there are fast elements we normalize.
4160 SeededNumberDictionary* dictionary = NULL;
4161 { MaybeObject* maybe = NormalizeElements();
4162 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
4163 }
4164 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4165 // Make sure that we never go back to fast case.
4166 dictionary->set_requires_slow_elements();
4167
4168 // Do a map transition, other objects with this map may still
4169 // be extensible.
4170 Map* new_map;
4171 { MaybeObject* maybe = map()->CopyDropTransitions();
4172 if (!maybe->To<Map>(&new_map)) return maybe;
4173 }
4174 new_map->set_is_extensible(false);
4175 set_map(new_map);
4176 ASSERT(!map()->is_extensible());
4177 return new_map;
4178 }
4179
4180
4181 // Tests for the fast common case for property enumeration:
4182 // - This object and all prototypes has an enum cache (which means that
4183 // it is no proxy, has no interceptors and needs no access checks).
4184 // - This object has no elements.
4185 // - No prototype has enumerable properties/elements.
IsSimpleEnum()4186 bool JSReceiver::IsSimpleEnum() {
4187 Heap* heap = GetHeap();
4188 for (Object* o = this;
4189 o != heap->null_value();
4190 o = JSObject::cast(o)->GetPrototype()) {
4191 if (!o->IsJSObject()) return false;
4192 JSObject* curr = JSObject::cast(o);
4193 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
4194 ASSERT(!curr->HasNamedInterceptor());
4195 ASSERT(!curr->HasIndexedInterceptor());
4196 ASSERT(!curr->IsAccessCheckNeeded());
4197 if (curr->NumberOfEnumElements() > 0) return false;
4198 if (curr != this) {
4199 FixedArray* curr_fixed_array =
4200 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
4201 if (curr_fixed_array->length() > 0) return false;
4202 }
4203 }
4204 return true;
4205 }
4206
4207
NumberOfDescribedProperties(PropertyAttributes filter)4208 int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
4209 int result = 0;
4210 DescriptorArray* descs = instance_descriptors();
4211 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4212 PropertyDetails details(descs->GetDetails(i));
4213 if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
4214 result++;
4215 }
4216 }
4217 return result;
4218 }
4219
4220
PropertyIndexFor(String * name)4221 int Map::PropertyIndexFor(String* name) {
4222 DescriptorArray* descs = instance_descriptors();
4223 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4224 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4225 return descs->GetFieldIndex(i);
4226 }
4227 }
4228 return -1;
4229 }
4230
4231
NextFreePropertyIndex()4232 int Map::NextFreePropertyIndex() {
4233 int max_index = -1;
4234 DescriptorArray* descs = instance_descriptors();
4235 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4236 if (descs->GetType(i) == FIELD) {
4237 int current_index = descs->GetFieldIndex(i);
4238 if (current_index > max_index) max_index = current_index;
4239 }
4240 }
4241 return max_index + 1;
4242 }
4243
4244
FindAccessor(String * name)4245 AccessorDescriptor* Map::FindAccessor(String* name) {
4246 DescriptorArray* descs = instance_descriptors();
4247 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4248 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4249 return descs->GetCallbacks(i);
4250 }
4251 }
4252 return NULL;
4253 }
4254
4255
LocalLookup(String * name,LookupResult * result)4256 void JSReceiver::LocalLookup(String* name, LookupResult* result) {
4257 ASSERT(name->IsString());
4258
4259 Heap* heap = GetHeap();
4260
4261 if (IsJSGlobalProxy()) {
4262 Object* proto = GetPrototype();
4263 if (proto->IsNull()) return result->NotFound();
4264 ASSERT(proto->IsJSGlobalObject());
4265 return JSReceiver::cast(proto)->LocalLookup(name, result);
4266 }
4267
4268 if (IsJSProxy()) {
4269 result->HandlerResult(JSProxy::cast(this));
4270 return;
4271 }
4272
4273 // Do not use inline caching if the object is a non-global object
4274 // that requires access checks.
4275 if (IsAccessCheckNeeded()) {
4276 result->DisallowCaching();
4277 }
4278
4279 JSObject* js_object = JSObject::cast(this);
4280
4281 // Check __proto__ before interceptor.
4282 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
4283 result->ConstantResult(js_object);
4284 return;
4285 }
4286
4287 // Check for lookup interceptor except when bootstrapping.
4288 if (js_object->HasNamedInterceptor() &&
4289 !heap->isolate()->bootstrapper()->IsActive()) {
4290 result->InterceptorResult(js_object);
4291 return;
4292 }
4293
4294 js_object->LocalLookupRealNamedProperty(name, result);
4295 }
4296
4297
Lookup(String * name,LookupResult * result)4298 void JSReceiver::Lookup(String* name, LookupResult* result) {
4299 // Ecma-262 3rd 8.6.2.4
4300 Heap* heap = GetHeap();
4301 for (Object* current = this;
4302 current != heap->null_value();
4303 current = JSObject::cast(current)->GetPrototype()) {
4304 JSReceiver::cast(current)->LocalLookup(name, result);
4305 if (result->IsProperty()) return;
4306 }
4307 result->NotFound();
4308 }
4309
4310
4311 // Search object and it's prototype chain for callback properties.
LookupCallback(String * name,LookupResult * result)4312 void JSObject::LookupCallback(String* name, LookupResult* result) {
4313 Heap* heap = GetHeap();
4314 for (Object* current = this;
4315 current != heap->null_value() && current->IsJSObject();
4316 current = JSObject::cast(current)->GetPrototype()) {
4317 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
4318 if (result->IsFound() && result->type() == CALLBACKS) return;
4319 }
4320 result->NotFound();
4321 }
4322
4323
4324 // Try to update an accessor in an elements dictionary. Return true if the
4325 // update succeeded, and false otherwise.
UpdateGetterSetterInDictionary(SeededNumberDictionary * dictionary,uint32_t index,Object * getter,Object * setter,PropertyAttributes attributes)4326 static bool UpdateGetterSetterInDictionary(
4327 SeededNumberDictionary* dictionary,
4328 uint32_t index,
4329 Object* getter,
4330 Object* setter,
4331 PropertyAttributes attributes) {
4332 int entry = dictionary->FindEntry(index);
4333 if (entry != SeededNumberDictionary::kNotFound) {
4334 Object* result = dictionary->ValueAt(entry);
4335 PropertyDetails details = dictionary->DetailsAt(entry);
4336 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
4337 ASSERT(!details.IsDontDelete());
4338 if (details.attributes() != attributes) {
4339 dictionary->DetailsAtPut(entry,
4340 PropertyDetails(attributes, CALLBACKS, index));
4341 }
4342 AccessorPair::cast(result)->SetComponents(getter, setter);
4343 return true;
4344 }
4345 }
4346 return false;
4347 }
4348
4349
DefineElementAccessor(uint32_t index,Object * getter,Object * setter,PropertyAttributes attributes)4350 MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
4351 Object* getter,
4352 Object* setter,
4353 PropertyAttributes attributes) {
4354 switch (GetElementsKind()) {
4355 case FAST_SMI_ONLY_ELEMENTS:
4356 case FAST_ELEMENTS:
4357 case FAST_DOUBLE_ELEMENTS:
4358 break;
4359 case EXTERNAL_PIXEL_ELEMENTS:
4360 case EXTERNAL_BYTE_ELEMENTS:
4361 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4362 case EXTERNAL_SHORT_ELEMENTS:
4363 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4364 case EXTERNAL_INT_ELEMENTS:
4365 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4366 case EXTERNAL_FLOAT_ELEMENTS:
4367 case EXTERNAL_DOUBLE_ELEMENTS:
4368 // Ignore getters and setters on pixel and external array elements.
4369 return GetHeap()->undefined_value();
4370 case DICTIONARY_ELEMENTS:
4371 if (UpdateGetterSetterInDictionary(element_dictionary(),
4372 index,
4373 getter,
4374 setter,
4375 attributes)) {
4376 return GetHeap()->undefined_value();
4377 }
4378 break;
4379 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4380 // Ascertain whether we have read-only properties or an existing
4381 // getter/setter pair in an arguments elements dictionary backing
4382 // store.
4383 FixedArray* parameter_map = FixedArray::cast(elements());
4384 uint32_t length = parameter_map->length();
4385 Object* probe =
4386 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4387 if (probe == NULL || probe->IsTheHole()) {
4388 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4389 if (arguments->IsDictionary()) {
4390 SeededNumberDictionary* dictionary =
4391 SeededNumberDictionary::cast(arguments);
4392 if (UpdateGetterSetterInDictionary(dictionary,
4393 index,
4394 getter,
4395 setter,
4396 attributes)) {
4397 return GetHeap()->undefined_value();
4398 }
4399 }
4400 }
4401 break;
4402 }
4403 }
4404
4405 AccessorPair* accessors;
4406 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4407 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4408 }
4409 accessors->SetComponents(getter, setter);
4410
4411 return SetElementCallback(index, accessors, attributes);
4412 }
4413
4414
DefinePropertyAccessor(String * name,Object * getter,Object * setter,PropertyAttributes attributes)4415 MaybeObject* JSObject::DefinePropertyAccessor(String* name,
4416 Object* getter,
4417 Object* setter,
4418 PropertyAttributes attributes) {
4419 // Lookup the name.
4420 LookupResult result(GetHeap()->isolate());
4421 LocalLookupRealNamedProperty(name, &result);
4422 if (result.IsFound()) {
4423 if (result.type() == CALLBACKS) {
4424 ASSERT(!result.IsDontDelete());
4425 Object* obj = result.GetCallbackObject();
4426 // Need to preserve old getters/setters.
4427 if (obj->IsAccessorPair()) {
4428 AccessorPair* copy;
4429 { MaybeObject* maybe_copy =
4430 AccessorPair::cast(obj)->CopyWithoutTransitions();
4431 if (!maybe_copy->To(©)) return maybe_copy;
4432 }
4433 copy->SetComponents(getter, setter);
4434 // Use set to update attributes.
4435 return SetPropertyCallback(name, copy, attributes);
4436 }
4437 }
4438 }
4439
4440 AccessorPair* accessors;
4441 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4442 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4443 }
4444 accessors->SetComponents(getter, setter);
4445
4446 return SetPropertyCallback(name, accessors, attributes);
4447 }
4448
4449
CanSetCallback(String * name)4450 bool JSObject::CanSetCallback(String* name) {
4451 ASSERT(!IsAccessCheckNeeded() ||
4452 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
4453
4454 // Check if there is an API defined callback object which prohibits
4455 // callback overwriting in this object or it's prototype chain.
4456 // This mechanism is needed for instance in a browser setting, where
4457 // certain accessors such as window.location should not be allowed
4458 // to be overwritten because allowing overwriting could potentially
4459 // cause security problems.
4460 LookupResult callback_result(GetIsolate());
4461 LookupCallback(name, &callback_result);
4462 if (callback_result.IsProperty()) {
4463 Object* obj = callback_result.GetCallbackObject();
4464 if (obj->IsAccessorInfo() &&
4465 AccessorInfo::cast(obj)->prohibits_overwriting()) {
4466 return false;
4467 }
4468 }
4469
4470 return true;
4471 }
4472
4473
SetElementCallback(uint32_t index,Object * structure,PropertyAttributes attributes)4474 MaybeObject* JSObject::SetElementCallback(uint32_t index,
4475 Object* structure,
4476 PropertyAttributes attributes) {
4477 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4478
4479 // Normalize elements to make this operation simple.
4480 SeededNumberDictionary* dictionary;
4481 { MaybeObject* maybe_dictionary = NormalizeElements();
4482 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
4483 }
4484 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4485
4486 // Update the dictionary with the new CALLBACKS property.
4487 { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
4488 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
4489 }
4490
4491 dictionary->set_requires_slow_elements();
4492 // Update the dictionary backing store on the object.
4493 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4494 // Also delete any parameter alias.
4495 //
4496 // TODO(kmillikin): when deleting the last parameter alias we could
4497 // switch to a direct backing store without the parameter map. This
4498 // would allow GC of the context.
4499 FixedArray* parameter_map = FixedArray::cast(elements());
4500 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
4501 parameter_map->set(index + 2, GetHeap()->the_hole_value());
4502 }
4503 parameter_map->set(1, dictionary);
4504 } else {
4505 set_elements(dictionary);
4506 }
4507
4508 return GetHeap()->undefined_value();
4509 }
4510
4511
SetPropertyCallback(String * name,Object * structure,PropertyAttributes attributes)4512 MaybeObject* JSObject::SetPropertyCallback(String* name,
4513 Object* structure,
4514 PropertyAttributes attributes) {
4515 // Normalize object to make this operation simple.
4516 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4517 if (maybe_ok->IsFailure()) return maybe_ok;
4518 }
4519
4520 // For the global object allocate a new map to invalidate the global inline
4521 // caches which have a global property cell reference directly in the code.
4522 if (IsGlobalObject()) {
4523 Map* new_map;
4524 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
4525 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
4526 }
4527 set_map(new_map);
4528 // When running crankshaft, changing the map is not enough. We
4529 // need to deoptimize all functions that rely on this global
4530 // object.
4531 Deoptimizer::DeoptimizeGlobalObject(this);
4532 }
4533
4534 // Update the dictionary with the new CALLBACKS property.
4535 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4536 { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details);
4537 if (maybe_ok->IsFailure()) return maybe_ok;
4538 }
4539
4540 return GetHeap()->undefined_value();
4541 }
4542
4543
DefineAccessor(Handle<JSObject> object,Handle<String> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)4544 void JSObject::DefineAccessor(Handle<JSObject> object,
4545 Handle<String> name,
4546 Handle<Object> getter,
4547 Handle<Object> setter,
4548 PropertyAttributes attributes) {
4549 CALL_HEAP_FUNCTION_VOID(
4550 object->GetIsolate(),
4551 object->DefineAccessor(*name, *getter, *setter, attributes));
4552 }
4553
DefineAccessor(String * name,Object * getter,Object * setter,PropertyAttributes attributes)4554 MaybeObject* JSObject::DefineAccessor(String* name,
4555 Object* getter,
4556 Object* setter,
4557 PropertyAttributes attributes) {
4558 Isolate* isolate = GetIsolate();
4559 // Check access rights if needed.
4560 if (IsAccessCheckNeeded() &&
4561 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4562 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4563 return isolate->heap()->undefined_value();
4564 }
4565
4566 if (IsJSGlobalProxy()) {
4567 Object* proto = GetPrototype();
4568 if (proto->IsNull()) return this;
4569 ASSERT(proto->IsJSGlobalObject());
4570 return JSObject::cast(proto)->DefineAccessor(
4571 name, getter, setter, attributes);
4572 }
4573
4574 // Make sure that the top context does not change when doing callbacks or
4575 // interceptor calls.
4576 AssertNoContextChange ncc;
4577
4578 // Try to flatten before operating on the string.
4579 name->TryFlatten();
4580
4581 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4582
4583 uint32_t index = 0;
4584 return name->AsArrayIndex(&index) ?
4585 DefineElementAccessor(index, getter, setter, attributes) :
4586 DefinePropertyAccessor(name, getter, setter, attributes);
4587 }
4588
4589
DefineAccessor(AccessorInfo * info)4590 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
4591 Isolate* isolate = GetIsolate();
4592 String* name = String::cast(info->name());
4593 // Check access rights if needed.
4594 if (IsAccessCheckNeeded() &&
4595 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4596 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4597 return isolate->heap()->undefined_value();
4598 }
4599
4600 if (IsJSGlobalProxy()) {
4601 Object* proto = GetPrototype();
4602 if (proto->IsNull()) return this;
4603 ASSERT(proto->IsJSGlobalObject());
4604 return JSObject::cast(proto)->DefineAccessor(info);
4605 }
4606
4607 // Make sure that the top context does not change when doing callbacks or
4608 // interceptor calls.
4609 AssertNoContextChange ncc;
4610
4611 // Try to flatten before operating on the string.
4612 name->TryFlatten();
4613
4614 if (!CanSetCallback(name)) {
4615 return isolate->heap()->undefined_value();
4616 }
4617
4618 uint32_t index = 0;
4619 bool is_element = name->AsArrayIndex(&index);
4620
4621 if (is_element) {
4622 if (IsJSArray()) return isolate->heap()->undefined_value();
4623
4624 // Accessors overwrite previous callbacks (cf. with getters/setters).
4625 switch (GetElementsKind()) {
4626 case FAST_SMI_ONLY_ELEMENTS:
4627 case FAST_ELEMENTS:
4628 case FAST_DOUBLE_ELEMENTS:
4629 break;
4630 case EXTERNAL_PIXEL_ELEMENTS:
4631 case EXTERNAL_BYTE_ELEMENTS:
4632 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4633 case EXTERNAL_SHORT_ELEMENTS:
4634 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4635 case EXTERNAL_INT_ELEMENTS:
4636 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4637 case EXTERNAL_FLOAT_ELEMENTS:
4638 case EXTERNAL_DOUBLE_ELEMENTS:
4639 // Ignore getters and setters on pixel and external array
4640 // elements.
4641 return isolate->heap()->undefined_value();
4642 case DICTIONARY_ELEMENTS:
4643 break;
4644 case NON_STRICT_ARGUMENTS_ELEMENTS:
4645 UNIMPLEMENTED();
4646 break;
4647 }
4648
4649 { MaybeObject* maybe_ok =
4650 SetElementCallback(index, info, info->property_attributes());
4651 if (maybe_ok->IsFailure()) return maybe_ok;
4652 }
4653 } else {
4654 // Lookup the name.
4655 LookupResult result(isolate);
4656 LocalLookup(name, &result);
4657 // ES5 forbids turning a property into an accessor if it's not
4658 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4659 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
4660 return isolate->heap()->undefined_value();
4661 }
4662 { MaybeObject* maybe_ok =
4663 SetPropertyCallback(name, info, info->property_attributes());
4664 if (maybe_ok->IsFailure()) return maybe_ok;
4665 }
4666 }
4667
4668 return this;
4669 }
4670
4671
LookupAccessor(String * name,AccessorComponent component)4672 Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
4673 Heap* heap = GetHeap();
4674
4675 // Make sure that the top context does not change when doing callbacks or
4676 // interceptor calls.
4677 AssertNoContextChange ncc;
4678
4679 // Check access rights if needed.
4680 if (IsAccessCheckNeeded() &&
4681 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4682 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4683 return heap->undefined_value();
4684 }
4685
4686 // Make the lookup and include prototypes.
4687 uint32_t index = 0;
4688 if (name->AsArrayIndex(&index)) {
4689 for (Object* obj = this;
4690 obj != heap->null_value();
4691 obj = JSObject::cast(obj)->GetPrototype()) {
4692 JSObject* js_object = JSObject::cast(obj);
4693 if (js_object->HasDictionaryElements()) {
4694 SeededNumberDictionary* dictionary = js_object->element_dictionary();
4695 int entry = dictionary->FindEntry(index);
4696 if (entry != SeededNumberDictionary::kNotFound) {
4697 Object* element = dictionary->ValueAt(entry);
4698 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
4699 element->IsAccessorPair()) {
4700 return AccessorPair::cast(element)->GetComponent(component);
4701 }
4702 }
4703 }
4704 }
4705 } else {
4706 for (Object* obj = this;
4707 obj != heap->null_value();
4708 obj = JSObject::cast(obj)->GetPrototype()) {
4709 LookupResult result(heap->isolate());
4710 JSObject::cast(obj)->LocalLookup(name, &result);
4711 if (result.IsProperty()) {
4712 if (result.IsReadOnly()) return heap->undefined_value();
4713 if (result.type() == CALLBACKS) {
4714 Object* obj = result.GetCallbackObject();
4715 if (obj->IsAccessorPair()) {
4716 return AccessorPair::cast(obj)->GetComponent(component);
4717 }
4718 }
4719 }
4720 }
4721 }
4722 return heap->undefined_value();
4723 }
4724
4725
SlowReverseLookup(Object * value)4726 Object* JSObject::SlowReverseLookup(Object* value) {
4727 if (HasFastProperties()) {
4728 DescriptorArray* descs = map()->instance_descriptors();
4729 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4730 if (descs->GetType(i) == FIELD) {
4731 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4732 return descs->GetKey(i);
4733 }
4734 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4735 if (descs->GetConstantFunction(i) == value) {
4736 return descs->GetKey(i);
4737 }
4738 }
4739 }
4740 return GetHeap()->undefined_value();
4741 } else {
4742 return property_dictionary()->SlowReverseLookup(value);
4743 }
4744 }
4745
4746
CopyDropDescriptors()4747 MaybeObject* Map::CopyDropDescriptors() {
4748 Heap* heap = GetHeap();
4749 Object* result;
4750 { MaybeObject* maybe_result =
4751 heap->AllocateMap(instance_type(), instance_size());
4752 if (!maybe_result->ToObject(&result)) return maybe_result;
4753 }
4754 Map::cast(result)->set_prototype(prototype());
4755 Map::cast(result)->set_constructor(constructor());
4756 // Don't copy descriptors, so map transitions always remain a forest.
4757 // If we retained the same descriptors we would have two maps
4758 // pointing to the same transition which is bad because the garbage
4759 // collector relies on being able to reverse pointers from transitions
4760 // to maps. If properties need to be retained use CopyDropTransitions.
4761 Map::cast(result)->clear_instance_descriptors();
4762 // Please note instance_type and instance_size are set when allocated.
4763 Map::cast(result)->set_inobject_properties(inobject_properties());
4764 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4765
4766 // If the map has pre-allocated properties always start out with a descriptor
4767 // array describing these properties.
4768 if (pre_allocated_property_fields() > 0) {
4769 ASSERT(constructor()->IsJSFunction());
4770 JSFunction* ctor = JSFunction::cast(constructor());
4771 Object* descriptors;
4772 { MaybeObject* maybe_descriptors =
4773 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4774 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4775 }
4776 Map::cast(result)->set_instance_descriptors(
4777 DescriptorArray::cast(descriptors));
4778 Map::cast(result)->set_pre_allocated_property_fields(
4779 pre_allocated_property_fields());
4780 }
4781 Map::cast(result)->set_bit_field(bit_field());
4782 Map::cast(result)->set_bit_field2(bit_field2());
4783 Map::cast(result)->set_bit_field3(bit_field3());
4784 Map::cast(result)->set_is_shared(false);
4785 Map::cast(result)->ClearCodeCache(heap);
4786 return result;
4787 }
4788
4789
CopyNormalized(PropertyNormalizationMode mode,NormalizedMapSharingMode sharing)4790 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4791 NormalizedMapSharingMode sharing) {
4792 int new_instance_size = instance_size();
4793 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4794 new_instance_size -= inobject_properties() * kPointerSize;
4795 }
4796
4797 Object* result;
4798 { MaybeObject* maybe_result =
4799 GetHeap()->AllocateMap(instance_type(), new_instance_size);
4800 if (!maybe_result->ToObject(&result)) return maybe_result;
4801 }
4802
4803 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4804 Map::cast(result)->set_inobject_properties(inobject_properties());
4805 }
4806
4807 Map::cast(result)->set_prototype(prototype());
4808 Map::cast(result)->set_constructor(constructor());
4809
4810 Map::cast(result)->set_bit_field(bit_field());
4811 Map::cast(result)->set_bit_field2(bit_field2());
4812 Map::cast(result)->set_bit_field3(bit_field3());
4813
4814 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4815
4816 #ifdef DEBUG
4817 if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
4818 Map::cast(result)->SharedMapVerify();
4819 }
4820 #endif
4821
4822 return result;
4823 }
4824
4825
CopyDropTransitions()4826 MaybeObject* Map::CopyDropTransitions() {
4827 Object* new_map;
4828 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4829 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4830 }
4831 Object* descriptors;
4832 { MaybeObject* maybe_descriptors =
4833 instance_descriptors()->RemoveTransitions();
4834 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4835 }
4836 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
4837 return new_map;
4838 }
4839
UpdateCodeCache(Handle<Map> map,Handle<String> name,Handle<Code> code)4840 void Map::UpdateCodeCache(Handle<Map> map,
4841 Handle<String> name,
4842 Handle<Code> code) {
4843 Isolate* isolate = map->GetIsolate();
4844 CALL_HEAP_FUNCTION_VOID(isolate,
4845 map->UpdateCodeCache(*name, *code));
4846 }
4847
UpdateCodeCache(String * name,Code * code)4848 MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
4849 // Allocate the code cache if not present.
4850 if (code_cache()->IsFixedArray()) {
4851 Object* result;
4852 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
4853 if (!maybe_result->ToObject(&result)) return maybe_result;
4854 }
4855 set_code_cache(result);
4856 }
4857
4858 // Update the code cache.
4859 return CodeCache::cast(code_cache())->Update(name, code);
4860 }
4861
4862
FindInCodeCache(String * name,Code::Flags flags)4863 Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4864 // Do a lookup if a code cache exists.
4865 if (!code_cache()->IsFixedArray()) {
4866 return CodeCache::cast(code_cache())->Lookup(name, flags);
4867 } else {
4868 return GetHeap()->undefined_value();
4869 }
4870 }
4871
4872
IndexInCodeCache(Object * name,Code * code)4873 int Map::IndexInCodeCache(Object* name, Code* code) {
4874 // Get the internal index if a code cache exists.
4875 if (!code_cache()->IsFixedArray()) {
4876 return CodeCache::cast(code_cache())->GetIndex(name, code);
4877 }
4878 return -1;
4879 }
4880
4881
RemoveFromCodeCache(String * name,Code * code,int index)4882 void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4883 // No GC is supposed to happen between a call to IndexInCodeCache and
4884 // RemoveFromCodeCache so the code cache must be there.
4885 ASSERT(!code_cache()->IsFixedArray());
4886 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4887 }
4888
4889
4890 // An iterator over all map transitions in an descriptor array, reusing the map
4891 // field of the contens array while it is running.
4892 class IntrusiveMapTransitionIterator {
4893 public:
IntrusiveMapTransitionIterator(DescriptorArray * descriptor_array)4894 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
4895 : descriptor_array_(descriptor_array) { }
4896
Start()4897 void Start() {
4898 ASSERT(!IsIterating());
4899 if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
4900 }
4901
IsIterating()4902 bool IsIterating() {
4903 return HasContentArray() && (*ContentHeader())->IsSmi();
4904 }
4905
Next()4906 Map* Next() {
4907 ASSERT(IsIterating());
4908 FixedArray* contents = ContentArray();
4909 // Attention, tricky index manipulation ahead: Every entry in the contents
4910 // array consists of a value/details pair, so the index is typically even.
4911 // An exception is made for CALLBACKS entries: An even index means we look
4912 // at its getter, and an odd index means we look at its setter.
4913 int index = Smi::cast(*ContentHeader())->value();
4914 while (index < contents->length()) {
4915 PropertyDetails details(Smi::cast(contents->get(index | 1)));
4916 switch (details.type()) {
4917 case MAP_TRANSITION:
4918 case CONSTANT_TRANSITION:
4919 case ELEMENTS_TRANSITION:
4920 // We definitely have a map transition.
4921 *ContentHeader() = Smi::FromInt(index + 2);
4922 return static_cast<Map*>(contents->get(index));
4923 case CALLBACKS: {
4924 // We might have a map transition in a getter or in a setter.
4925 AccessorPair* accessors =
4926 static_cast<AccessorPair*>(contents->get(index & ~1));
4927 Object* accessor =
4928 ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4929 index++;
4930 if (accessor->IsMap()) {
4931 *ContentHeader() = Smi::FromInt(index);
4932 return static_cast<Map*>(accessor);
4933 }
4934 break;
4935 }
4936 case NORMAL:
4937 case FIELD:
4938 case CONSTANT_FUNCTION:
4939 case HANDLER:
4940 case INTERCEPTOR:
4941 case NULL_DESCRIPTOR:
4942 // We definitely have no map transition.
4943 index += 2;
4944 break;
4945 }
4946 }
4947 *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4948 return NULL;
4949 }
4950
4951 private:
HasContentArray()4952 bool HasContentArray() {
4953 return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
4954 }
4955
ContentArray()4956 FixedArray* ContentArray() {
4957 Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
4958 return static_cast<FixedArray*>(array);
4959 }
4960
ContentHeader()4961 Object** ContentHeader() {
4962 return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
4963 }
4964
4965 DescriptorArray* descriptor_array_;
4966 };
4967
4968
4969 // An iterator over all prototype transitions, reusing the map field of the
4970 // underlying array while it is running.
4971 class IntrusivePrototypeTransitionIterator {
4972 public:
IntrusivePrototypeTransitionIterator(FixedArray * proto_trans)4973 explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
4974 : proto_trans_(proto_trans) { }
4975
Start()4976 void Start() {
4977 ASSERT(!IsIterating());
4978 if (HasTransitions()) *Header() = Smi::FromInt(0);
4979 }
4980
IsIterating()4981 bool IsIterating() {
4982 return HasTransitions() && (*Header())->IsSmi();
4983 }
4984
Next()4985 Map* Next() {
4986 ASSERT(IsIterating());
4987 int transitionNumber = Smi::cast(*Header())->value();
4988 if (transitionNumber < NumberOfTransitions()) {
4989 *Header() = Smi::FromInt(transitionNumber + 1);
4990 return GetTransition(transitionNumber);
4991 }
4992 *Header() = proto_trans_->GetHeap()->fixed_array_map();
4993 return NULL;
4994 }
4995
4996 private:
HasTransitions()4997 bool HasTransitions() {
4998 return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
4999 }
5000
Header()5001 Object** Header() {
5002 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
5003 }
5004
NumberOfTransitions()5005 int NumberOfTransitions() {
5006 Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5007 return Smi::cast(num)->value();
5008 }
5009
GetTransition(int transitionNumber)5010 Map* GetTransition(int transitionNumber) {
5011 return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5012 }
5013
IndexFor(int transitionNumber)5014 int IndexFor(int transitionNumber) {
5015 return Map::kProtoTransitionHeaderSize +
5016 Map::kProtoTransitionMapOffset +
5017 transitionNumber * Map::kProtoTransitionElementsPerEntry;
5018 }
5019
5020 FixedArray* proto_trans_;
5021 };
5022
5023
5024 // To traverse the transition tree iteratively, we have to store two kinds of
5025 // information in a map: The parent map in the traversal and which children of a
5026 // node have already been visited. To do this without additional memory, we
5027 // temporarily reuse two maps with known values:
5028 //
5029 // (1) The map of the map temporarily holds the parent, and is restored to the
5030 // meta map afterwards.
5031 //
5032 // (2) The info which children have already been visited depends on which part
5033 // of the map we currently iterate:
5034 //
5035 // (a) If we currently follow normal map transitions, we temporarily store
5036 // the current index in the map of the FixedArray of the desciptor
5037 // array's contents, and restore it to the fixed array map afterwards.
5038 // Note that a single descriptor can have 0, 1, or 2 transitions.
5039 //
5040 // (b) If we currently follow prototype transitions, we temporarily store
5041 // the current index in the map of the FixedArray holding the prototype
5042 // transitions, and restore it to the fixed array map afterwards.
5043 //
5044 // Note that the child iterator is just a concatenation of two iterators: One
5045 // iterating over map transitions and one iterating over prototype transisitons.
5046 class TraversableMap : public Map {
5047 public:
5048 // Record the parent in the traversal within this map. Note that this destroys
5049 // this map's map!
SetParent(TraversableMap * parent)5050 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5051
5052 // Reset the current map's map, returning the parent previously stored in it.
GetAndResetParent()5053 TraversableMap* GetAndResetParent() {
5054 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5055 set_map_no_write_barrier(GetHeap()->meta_map());
5056 return old_parent;
5057 }
5058
5059 // Start iterating over this map's children, possibly destroying a FixedArray
5060 // map (see explanation above).
ChildIteratorStart()5061 void ChildIteratorStart() {
5062 IntrusiveMapTransitionIterator(instance_descriptors()).Start();
5063 IntrusivePrototypeTransitionIterator(
5064 unchecked_prototype_transitions()).Start();
5065 }
5066
5067 // If we have an unvisited child map, return that one and advance. If we have
5068 // none, return NULL and reset any destroyed FixedArray maps.
ChildIteratorNext()5069 TraversableMap* ChildIteratorNext() {
5070 IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5071 if (descriptor_iterator.IsIterating()) {
5072 Map* next = descriptor_iterator.Next();
5073 if (next != NULL) return static_cast<TraversableMap*>(next);
5074 }
5075 IntrusivePrototypeTransitionIterator
5076 proto_iterator(unchecked_prototype_transitions());
5077 if (proto_iterator.IsIterating()) {
5078 Map* next = proto_iterator.Next();
5079 if (next != NULL) return static_cast<TraversableMap*>(next);
5080 }
5081 return NULL;
5082 }
5083 };
5084
5085
5086 // Traverse the transition tree in postorder without using the C++ stack by
5087 // doing pointer reversal.
TraverseTransitionTree(TraverseCallback callback,void * data)5088 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
5089 TraversableMap* current = static_cast<TraversableMap*>(this);
5090 current->ChildIteratorStart();
5091 while (true) {
5092 TraversableMap* child = current->ChildIteratorNext();
5093 if (child != NULL) {
5094 child->ChildIteratorStart();
5095 child->SetParent(current);
5096 current = child;
5097 } else {
5098 TraversableMap* parent = current->GetAndResetParent();
5099 callback(current, data);
5100 if (current == this) break;
5101 current = parent;
5102 }
5103 }
5104 }
5105
5106
Update(String * name,Code * code)5107 MaybeObject* CodeCache::Update(String* name, Code* code) {
5108 // The number of monomorphic stubs for normal load/store/call IC's can grow to
5109 // a large number and therefore they need to go into a hash table. They are
5110 // used to load global properties from cells.
5111 if (code->type() == NORMAL) {
5112 // Make sure that a hash table is allocated for the normal load code cache.
5113 if (normal_type_cache()->IsUndefined()) {
5114 Object* result;
5115 { MaybeObject* maybe_result =
5116 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
5117 if (!maybe_result->ToObject(&result)) return maybe_result;
5118 }
5119 set_normal_type_cache(result);
5120 }
5121 return UpdateNormalTypeCache(name, code);
5122 } else {
5123 ASSERT(default_cache()->IsFixedArray());
5124 return UpdateDefaultCache(name, code);
5125 }
5126 }
5127
5128
UpdateDefaultCache(String * name,Code * code)5129 MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
5130 // When updating the default code cache we disregard the type encoded in the
5131 // flags. This allows call constant stubs to overwrite call field
5132 // stubs, etc.
5133 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
5134
5135 // First check whether we can update existing code cache without
5136 // extending it.
5137 FixedArray* cache = default_cache();
5138 int length = cache->length();
5139 int deleted_index = -1;
5140 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5141 Object* key = cache->get(i);
5142 if (key->IsNull()) {
5143 if (deleted_index < 0) deleted_index = i;
5144 continue;
5145 }
5146 if (key->IsUndefined()) {
5147 if (deleted_index >= 0) i = deleted_index;
5148 cache->set(i + kCodeCacheEntryNameOffset, name);
5149 cache->set(i + kCodeCacheEntryCodeOffset, code);
5150 return this;
5151 }
5152 if (name->Equals(String::cast(key))) {
5153 Code::Flags found =
5154 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
5155 if (Code::RemoveTypeFromFlags(found) == flags) {
5156 cache->set(i + kCodeCacheEntryCodeOffset, code);
5157 return this;
5158 }
5159 }
5160 }
5161
5162 // Reached the end of the code cache. If there were deleted
5163 // elements, reuse the space for the first of them.
5164 if (deleted_index >= 0) {
5165 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
5166 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
5167 return this;
5168 }
5169
5170 // Extend the code cache with some new entries (at least one). Must be a
5171 // multiple of the entry size.
5172 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
5173 new_length = new_length - new_length % kCodeCacheEntrySize;
5174 ASSERT((new_length % kCodeCacheEntrySize) == 0);
5175 Object* result;
5176 { MaybeObject* maybe_result = cache->CopySize(new_length);
5177 if (!maybe_result->ToObject(&result)) return maybe_result;
5178 }
5179
5180 // Add the (name, code) pair to the new cache.
5181 cache = FixedArray::cast(result);
5182 cache->set(length + kCodeCacheEntryNameOffset, name);
5183 cache->set(length + kCodeCacheEntryCodeOffset, code);
5184 set_default_cache(cache);
5185 return this;
5186 }
5187
5188
UpdateNormalTypeCache(String * name,Code * code)5189 MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
5190 // Adding a new entry can cause a new cache to be allocated.
5191 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5192 Object* new_cache;
5193 { MaybeObject* maybe_new_cache = cache->Put(name, code);
5194 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5195 }
5196 set_normal_type_cache(new_cache);
5197 return this;
5198 }
5199
5200
Lookup(String * name,Code::Flags flags)5201 Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5202 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5203 return LookupNormalTypeCache(name, flags);
5204 } else {
5205 return LookupDefaultCache(name, flags);
5206 }
5207 }
5208
5209
LookupDefaultCache(String * name,Code::Flags flags)5210 Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5211 FixedArray* cache = default_cache();
5212 int length = cache->length();
5213 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5214 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
5215 // Skip deleted elements.
5216 if (key->IsNull()) continue;
5217 if (key->IsUndefined()) return key;
5218 if (name->Equals(String::cast(key))) {
5219 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5220 if (code->flags() == flags) {
5221 return code;
5222 }
5223 }
5224 }
5225 return GetHeap()->undefined_value();
5226 }
5227
5228
LookupNormalTypeCache(String * name,Code::Flags flags)5229 Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5230 if (!normal_type_cache()->IsUndefined()) {
5231 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5232 return cache->Lookup(name, flags);
5233 } else {
5234 return GetHeap()->undefined_value();
5235 }
5236 }
5237
5238
GetIndex(Object * name,Code * code)5239 int CodeCache::GetIndex(Object* name, Code* code) {
5240 if (code->type() == NORMAL) {
5241 if (normal_type_cache()->IsUndefined()) return -1;
5242 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5243 return cache->GetIndex(String::cast(name), code->flags());
5244 }
5245
5246 FixedArray* array = default_cache();
5247 int len = array->length();
5248 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5249 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
5250 }
5251 return -1;
5252 }
5253
5254
RemoveByIndex(Object * name,Code * code,int index)5255 void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
5256 if (code->type() == NORMAL) {
5257 ASSERT(!normal_type_cache()->IsUndefined());
5258 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5259 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
5260 cache->RemoveByIndex(index);
5261 } else {
5262 FixedArray* array = default_cache();
5263 ASSERT(array->length() >= index && array->get(index)->IsCode());
5264 // Use null instead of undefined for deleted elements to distinguish
5265 // deleted elements from unused elements. This distinction is used
5266 // when looking up in the cache and when updating the cache.
5267 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5268 array->set_null(index - 1); // Name.
5269 array->set_null(index); // Code.
5270 }
5271 }
5272
5273
5274 // The key in the code cache hash table consists of the property name and the
5275 // code object. The actual match is on the name and the code flags. If a key
5276 // is created using the flags and not a code object it can only be used for
5277 // lookup not to create a new entry.
5278 class CodeCacheHashTableKey : public HashTableKey {
5279 public:
CodeCacheHashTableKey(String * name,Code::Flags flags)5280 CodeCacheHashTableKey(String* name, Code::Flags flags)
5281 : name_(name), flags_(flags), code_(NULL) { }
5282
CodeCacheHashTableKey(String * name,Code * code)5283 CodeCacheHashTableKey(String* name, Code* code)
5284 : name_(name),
5285 flags_(code->flags()),
5286 code_(code) { }
5287
5288
IsMatch(Object * other)5289 bool IsMatch(Object* other) {
5290 if (!other->IsFixedArray()) return false;
5291 FixedArray* pair = FixedArray::cast(other);
5292 String* name = String::cast(pair->get(0));
5293 Code::Flags flags = Code::cast(pair->get(1))->flags();
5294 if (flags != flags_) {
5295 return false;
5296 }
5297 return name_->Equals(name);
5298 }
5299
NameFlagsHashHelper(String * name,Code::Flags flags)5300 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5301 return name->Hash() ^ flags;
5302 }
5303
Hash()5304 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5305
HashForObject(Object * obj)5306 uint32_t HashForObject(Object* obj) {
5307 FixedArray* pair = FixedArray::cast(obj);
5308 String* name = String::cast(pair->get(0));
5309 Code* code = Code::cast(pair->get(1));
5310 return NameFlagsHashHelper(name, code->flags());
5311 }
5312
AsObject()5313 MUST_USE_RESULT MaybeObject* AsObject() {
5314 ASSERT(code_ != NULL);
5315 Object* obj;
5316 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
5317 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5318 }
5319 FixedArray* pair = FixedArray::cast(obj);
5320 pair->set(0, name_);
5321 pair->set(1, code_);
5322 return pair;
5323 }
5324
5325 private:
5326 String* name_;
5327 Code::Flags flags_;
5328 // TODO(jkummerow): We should be able to get by without this.
5329 Code* code_;
5330 };
5331
5332
Lookup(String * name,Code::Flags flags)5333 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5334 CodeCacheHashTableKey key(name, flags);
5335 int entry = FindEntry(&key);
5336 if (entry == kNotFound) return GetHeap()->undefined_value();
5337 return get(EntryToIndex(entry) + 1);
5338 }
5339
5340
Put(String * name,Code * code)5341 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
5342 CodeCacheHashTableKey key(name, code);
5343 Object* obj;
5344 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5345 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5346 }
5347
5348 // Don't use |this|, as the table might have grown.
5349 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5350
5351 int entry = cache->FindInsertionEntry(key.Hash());
5352 Object* k;
5353 { MaybeObject* maybe_k = key.AsObject();
5354 if (!maybe_k->ToObject(&k)) return maybe_k;
5355 }
5356
5357 cache->set(EntryToIndex(entry), k);
5358 cache->set(EntryToIndex(entry) + 1, code);
5359 cache->ElementAdded();
5360 return cache;
5361 }
5362
5363
GetIndex(String * name,Code::Flags flags)5364 int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5365 CodeCacheHashTableKey key(name, flags);
5366 int entry = FindEntry(&key);
5367 return (entry == kNotFound) ? -1 : entry;
5368 }
5369
5370
RemoveByIndex(int index)5371 void CodeCacheHashTable::RemoveByIndex(int index) {
5372 ASSERT(index >= 0);
5373 Heap* heap = GetHeap();
5374 set(EntryToIndex(index), heap->the_hole_value());
5375 set(EntryToIndex(index) + 1, heap->the_hole_value());
5376 ElementRemoved();
5377 }
5378
5379
Update(Handle<PolymorphicCodeCache> cache,MapHandleList * maps,Code::Flags flags,Handle<Code> code)5380 void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5381 MapHandleList* maps,
5382 Code::Flags flags,
5383 Handle<Code> code) {
5384 Isolate* isolate = cache->GetIsolate();
5385 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5386 }
5387
5388
Update(MapHandleList * maps,Code::Flags flags,Code * code)5389 MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
5390 Code::Flags flags,
5391 Code* code) {
5392 // Initialize cache if necessary.
5393 if (cache()->IsUndefined()) {
5394 Object* result;
5395 { MaybeObject* maybe_result =
5396 PolymorphicCodeCacheHashTable::Allocate(
5397 PolymorphicCodeCacheHashTable::kInitialSize);
5398 if (!maybe_result->ToObject(&result)) return maybe_result;
5399 }
5400 set_cache(result);
5401 } else {
5402 // This entry shouldn't be contained in the cache yet.
5403 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5404 ->Lookup(maps, flags)->IsUndefined());
5405 }
5406 PolymorphicCodeCacheHashTable* hash_table =
5407 PolymorphicCodeCacheHashTable::cast(cache());
5408 Object* new_cache;
5409 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5410 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5411 }
5412 set_cache(new_cache);
5413 return this;
5414 }
5415
5416
Lookup(MapHandleList * maps,Code::Flags flags)5417 Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5418 Code::Flags flags) {
5419 if (!cache()->IsUndefined()) {
5420 PolymorphicCodeCacheHashTable* hash_table =
5421 PolymorphicCodeCacheHashTable::cast(cache());
5422 return Handle<Object>(hash_table->Lookup(maps, flags));
5423 } else {
5424 return GetIsolate()->factory()->undefined_value();
5425 }
5426 }
5427
5428
5429 // Despite their name, object of this class are not stored in the actual
5430 // hash table; instead they're temporarily used for lookups. It is therefore
5431 // safe to have a weak (non-owning) pointer to a MapList as a member field.
5432 class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5433 public:
5434 // Callers must ensure that |maps| outlives the newly constructed object.
PolymorphicCodeCacheHashTableKey(MapHandleList * maps,int code_flags)5435 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
5436 : maps_(maps),
5437 code_flags_(code_flags) {}
5438
IsMatch(Object * other)5439 bool IsMatch(Object* other) {
5440 MapHandleList other_maps(kDefaultListAllocationSize);
5441 int other_flags;
5442 FromObject(other, &other_flags, &other_maps);
5443 if (code_flags_ != other_flags) return false;
5444 if (maps_->length() != other_maps.length()) return false;
5445 // Compare just the hashes first because it's faster.
5446 int this_hash = MapsHashHelper(maps_, code_flags_);
5447 int other_hash = MapsHashHelper(&other_maps, other_flags);
5448 if (this_hash != other_hash) return false;
5449
5450 // Full comparison: for each map in maps_, look for an equivalent map in
5451 // other_maps. This implementation is slow, but probably good enough for
5452 // now because the lists are short (<= 4 elements currently).
5453 for (int i = 0; i < maps_->length(); ++i) {
5454 bool match_found = false;
5455 for (int j = 0; j < other_maps.length(); ++j) {
5456 if (*(maps_->at(i)) == *(other_maps.at(j))) {
5457 match_found = true;
5458 break;
5459 }
5460 }
5461 if (!match_found) return false;
5462 }
5463 return true;
5464 }
5465
MapsHashHelper(MapHandleList * maps,int code_flags)5466 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
5467 uint32_t hash = code_flags;
5468 for (int i = 0; i < maps->length(); ++i) {
5469 hash ^= maps->at(i)->Hash();
5470 }
5471 return hash;
5472 }
5473
Hash()5474 uint32_t Hash() {
5475 return MapsHashHelper(maps_, code_flags_);
5476 }
5477
HashForObject(Object * obj)5478 uint32_t HashForObject(Object* obj) {
5479 MapHandleList other_maps(kDefaultListAllocationSize);
5480 int other_flags;
5481 FromObject(obj, &other_flags, &other_maps);
5482 return MapsHashHelper(&other_maps, other_flags);
5483 }
5484
AsObject()5485 MUST_USE_RESULT MaybeObject* AsObject() {
5486 Object* obj;
5487 // The maps in |maps_| must be copied to a newly allocated FixedArray,
5488 // both because the referenced MapList is short-lived, and because C++
5489 // objects can't be stored in the heap anyway.
5490 { MaybeObject* maybe_obj =
5491 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5492 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5493 }
5494 FixedArray* list = FixedArray::cast(obj);
5495 list->set(0, Smi::FromInt(code_flags_));
5496 for (int i = 0; i < maps_->length(); ++i) {
5497 list->set(i + 1, *maps_->at(i));
5498 }
5499 return list;
5500 }
5501
5502 private:
FromObject(Object * obj,int * code_flags,MapHandleList * maps)5503 static MapHandleList* FromObject(Object* obj,
5504 int* code_flags,
5505 MapHandleList* maps) {
5506 FixedArray* list = FixedArray::cast(obj);
5507 maps->Rewind(0);
5508 *code_flags = Smi::cast(list->get(0))->value();
5509 for (int i = 1; i < list->length(); ++i) {
5510 maps->Add(Handle<Map>(Map::cast(list->get(i))));
5511 }
5512 return maps;
5513 }
5514
5515 MapHandleList* maps_; // weak.
5516 int code_flags_;
5517 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
5518 };
5519
5520
Lookup(MapHandleList * maps,int code_flags)5521 Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5522 int code_flags) {
5523 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5524 int entry = FindEntry(&key);
5525 if (entry == kNotFound) return GetHeap()->undefined_value();
5526 return get(EntryToIndex(entry) + 1);
5527 }
5528
5529
Put(MapHandleList * maps,int code_flags,Code * code)5530 MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
5531 int code_flags,
5532 Code* code) {
5533 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5534 Object* obj;
5535 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5536 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5537 }
5538 PolymorphicCodeCacheHashTable* cache =
5539 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5540 int entry = cache->FindInsertionEntry(key.Hash());
5541 { MaybeObject* maybe_obj = key.AsObject();
5542 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5543 }
5544 cache->set(EntryToIndex(entry), obj);
5545 cache->set(EntryToIndex(entry) + 1, code);
5546 cache->ElementAdded();
5547 return cache;
5548 }
5549
5550
AddKeysFromJSArray(JSArray * array)5551 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
5552 ElementsAccessor* accessor = array->GetElementsAccessor();
5553 MaybeObject* maybe_result =
5554 accessor->AddElementsToFixedArray(array, array, this);
5555 FixedArray* result;
5556 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5557 #ifdef DEBUG
5558 if (FLAG_enable_slow_asserts) {
5559 for (int i = 0; i < result->length(); i++) {
5560 Object* current = result->get(i);
5561 ASSERT(current->IsNumber() || current->IsString());
5562 }
5563 }
5564 #endif
5565 return result;
5566 }
5567
5568
UnionOfKeys(FixedArray * other)5569 MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
5570 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5571 MaybeObject* maybe_result =
5572 accessor->AddElementsToFixedArray(NULL, NULL, this, other);
5573 FixedArray* result;
5574 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5575 #ifdef DEBUG
5576 if (FLAG_enable_slow_asserts) {
5577 for (int i = 0; i < result->length(); i++) {
5578 Object* current = result->get(i);
5579 ASSERT(current->IsNumber() || current->IsString());
5580 }
5581 }
5582 #endif
5583 return result;
5584 }
5585
5586
CopySize(int new_length)5587 MaybeObject* FixedArray::CopySize(int new_length) {
5588 Heap* heap = GetHeap();
5589 if (new_length == 0) return heap->empty_fixed_array();
5590 Object* obj;
5591 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
5592 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5593 }
5594 FixedArray* result = FixedArray::cast(obj);
5595 // Copy the content
5596 AssertNoAllocation no_gc;
5597 int len = length();
5598 if (new_length < len) len = new_length;
5599 // We are taking the map from the old fixed array so the map is sure to
5600 // be an immortal immutable object.
5601 result->set_map_no_write_barrier(map());
5602 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
5603 for (int i = 0; i < len; i++) {
5604 result->set(i, get(i), mode);
5605 }
5606 return result;
5607 }
5608
5609
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)5610 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
5611 AssertNoAllocation no_gc;
5612 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
5613 for (int index = 0; index < len; index++) {
5614 dest->set(dest_pos+index, get(pos+index), mode);
5615 }
5616 }
5617
5618
5619 #ifdef DEBUG
IsEqualTo(FixedArray * other)5620 bool FixedArray::IsEqualTo(FixedArray* other) {
5621 if (length() != other->length()) return false;
5622 for (int i = 0 ; i < length(); ++i) {
5623 if (get(i) != other->get(i)) return false;
5624 }
5625 return true;
5626 }
5627 #endif
5628
5629
Allocate(int number_of_descriptors)5630 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
5631 Heap* heap = Isolate::Current()->heap();
5632 if (number_of_descriptors == 0) {
5633 return heap->empty_descriptor_array();
5634 }
5635 // Allocate the array of keys.
5636 Object* array;
5637 { MaybeObject* maybe_array =
5638 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
5639 if (!maybe_array->ToObject(&array)) return maybe_array;
5640 }
5641 // Do not use DescriptorArray::cast on incomplete object.
5642 FixedArray* result = FixedArray::cast(array);
5643
5644 // Allocate the content array and set it in the descriptor array.
5645 { MaybeObject* maybe_array =
5646 heap->AllocateFixedArray(number_of_descriptors << 1);
5647 if (!maybe_array->ToObject(&array)) return maybe_array;
5648 }
5649 result->set(kBitField3StorageIndex, Smi::FromInt(0));
5650 result->set(kContentArrayIndex, array);
5651 result->set(kEnumerationIndexIndex,
5652 Smi::FromInt(PropertyDetails::kInitialIndex));
5653 return result;
5654 }
5655
5656
SetEnumCache(FixedArray * bridge_storage,FixedArray * new_cache,Object * new_index_cache)5657 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
5658 FixedArray* new_cache,
5659 Object* new_index_cache) {
5660 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
5661 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
5662 if (HasEnumCache()) {
5663 FixedArray::cast(get(kEnumerationIndexIndex))->
5664 set(kEnumCacheBridgeCacheIndex, new_cache);
5665 FixedArray::cast(get(kEnumerationIndexIndex))->
5666 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
5667 } else {
5668 if (IsEmpty()) return; // Do nothing for empty descriptor array.
5669 FixedArray::cast(bridge_storage)->
5670 set(kEnumCacheBridgeCacheIndex, new_cache);
5671 FixedArray::cast(bridge_storage)->
5672 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
5673 NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5674 kEnumCacheBridgeEnumIndex,
5675 get(kEnumerationIndexIndex));
5676 set(kEnumerationIndexIndex, bridge_storage);
5677 }
5678 }
5679
5680
InsertionPointFound(String * key1,String * key2)5681 static bool InsertionPointFound(String* key1, String* key2) {
5682 return key1->Hash() > key2->Hash() || key1 == key2;
5683 }
5684
5685
CopyFrom(Handle<DescriptorArray> dst,int dst_index,Handle<DescriptorArray> src,int src_index,const WhitenessWitness & witness)5686 void DescriptorArray::CopyFrom(Handle<DescriptorArray> dst,
5687 int dst_index,
5688 Handle<DescriptorArray> src,
5689 int src_index,
5690 const WhitenessWitness& witness) {
5691 CALL_HEAP_FUNCTION_VOID(dst->GetIsolate(),
5692 dst->CopyFrom(dst_index, *src, src_index, witness));
5693 }
5694
5695
CopyFrom(int dst_index,DescriptorArray * src,int src_index,const WhitenessWitness & witness)5696 MaybeObject* DescriptorArray::CopyFrom(int dst_index,
5697 DescriptorArray* src,
5698 int src_index,
5699 const WhitenessWitness& witness) {
5700 Object* value = src->GetValue(src_index);
5701 PropertyDetails details(src->GetDetails(src_index));
5702 if (details.type() == CALLBACKS && value->IsAccessorPair()) {
5703 MaybeObject* maybe_copy =
5704 AccessorPair::cast(value)->CopyWithoutTransitions();
5705 if (!maybe_copy->To(&value)) return maybe_copy;
5706 }
5707 Descriptor desc(src->GetKey(src_index), value, details);
5708 Set(dst_index, &desc, witness);
5709 return this;
5710 }
5711
5712
CopyInsert(Descriptor * descriptor,TransitionFlag transition_flag)5713 MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5714 TransitionFlag transition_flag) {
5715 // Transitions are only kept when inserting another transition.
5716 // This precondition is not required by this function's implementation, but
5717 // is currently required by the semantics of maps, so we check it.
5718 // Conversely, we filter after replacing, so replacing a transition and
5719 // removing all other transitions is not supported.
5720 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
5721 ASSERT(remove_transitions == !descriptor->ContainsTransition());
5722 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
5723
5724 // Ensure the key is a symbol.
5725 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5726 if (maybe_result->IsFailure()) return maybe_result;
5727 }
5728
5729 int new_size = 0;
5730 for (int i = 0; i < number_of_descriptors(); i++) {
5731 if (IsNullDescriptor(i)) continue;
5732 if (remove_transitions && IsTransitionOnly(i)) continue;
5733 new_size++;
5734 }
5735
5736 // If key is in descriptor, we replace it in-place when filtering.
5737 // Count a null descriptor for key as inserted, not replaced.
5738 int index = Search(descriptor->GetKey());
5739 const bool replacing = (index != kNotFound);
5740 bool keep_enumeration_index = false;
5741 if (replacing) {
5742 // We are replacing an existing descriptor. We keep the enumeration
5743 // index of a visible property.
5744 PropertyType t = PropertyDetails(GetDetails(index)).type();
5745 if (t == CONSTANT_FUNCTION ||
5746 t == FIELD ||
5747 t == CALLBACKS ||
5748 t == INTERCEPTOR) {
5749 keep_enumeration_index = true;
5750 } else if (remove_transitions) {
5751 // Replaced descriptor has been counted as removed if it is
5752 // a transition that will be replaced. Adjust count in this case.
5753 ++new_size;
5754 }
5755 } else {
5756 ++new_size;
5757 }
5758
5759 DescriptorArray* new_descriptors;
5760 { MaybeObject* maybe_result = Allocate(new_size);
5761 if (!maybe_result->To(&new_descriptors)) return maybe_result;
5762 }
5763
5764 DescriptorArray::WhitenessWitness witness(new_descriptors);
5765
5766 // Set the enumeration index in the descriptors and set the enumeration index
5767 // in the result.
5768 int enumeration_index = NextEnumerationIndex();
5769 if (!descriptor->ContainsTransition()) {
5770 if (keep_enumeration_index) {
5771 descriptor->SetEnumerationIndex(
5772 PropertyDetails(GetDetails(index)).index());
5773 } else {
5774 descriptor->SetEnumerationIndex(enumeration_index);
5775 ++enumeration_index;
5776 }
5777 }
5778 new_descriptors->SetNextEnumerationIndex(enumeration_index);
5779
5780 // Copy the descriptors, filtering out transitions and null descriptors,
5781 // and inserting or replacing a descriptor.
5782 int to_index = 0;
5783 int insertion_index = -1;
5784 int from_index = 0;
5785 while (from_index < number_of_descriptors()) {
5786 if (insertion_index < 0 &&
5787 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) {
5788 insertion_index = to_index++;
5789 if (replacing) from_index++;
5790 } else {
5791 if (!(IsNullDescriptor(from_index) ||
5792 (remove_transitions && IsTransitionOnly(from_index)))) {
5793 MaybeObject* copy_result =
5794 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
5795 if (copy_result->IsFailure()) return copy_result;
5796 }
5797 from_index++;
5798 }
5799 }
5800 if (insertion_index < 0) insertion_index = to_index++;
5801 new_descriptors->Set(insertion_index, descriptor, witness);
5802
5803 ASSERT(to_index == new_descriptors->number_of_descriptors());
5804 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5805
5806 return new_descriptors;
5807 }
5808
5809
RemoveTransitions()5810 MaybeObject* DescriptorArray::RemoveTransitions() {
5811 // Allocate the new descriptor array.
5812 int new_number_of_descriptors = 0;
5813 for (int i = 0; i < number_of_descriptors(); i++) {
5814 if (IsProperty(i)) new_number_of_descriptors++;
5815 }
5816 DescriptorArray* new_descriptors;
5817 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors);
5818 if (!maybe_result->To(&new_descriptors)) return maybe_result;
5819 }
5820
5821 // Copy the content.
5822 DescriptorArray::WhitenessWitness witness(new_descriptors);
5823 int next_descriptor = 0;
5824 for (int i = 0; i < number_of_descriptors(); i++) {
5825 if (IsProperty(i)) {
5826 MaybeObject* copy_result =
5827 new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5828 if (copy_result->IsFailure()) return copy_result;
5829 }
5830 }
5831 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5832
5833 return new_descriptors;
5834 }
5835
5836
SortUnchecked(const WhitenessWitness & witness)5837 void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
5838 // In-place heap sort.
5839 int len = number_of_descriptors();
5840
5841 // Bottom-up max-heap construction.
5842 // Index of the last node with children
5843 const int max_parent_index = (len / 2) - 1;
5844 for (int i = max_parent_index; i >= 0; --i) {
5845 int parent_index = i;
5846 const uint32_t parent_hash = GetKey(i)->Hash();
5847 while (parent_index <= max_parent_index) {
5848 int child_index = 2 * parent_index + 1;
5849 uint32_t child_hash = GetKey(child_index)->Hash();
5850 if (child_index + 1 < len) {
5851 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5852 if (right_child_hash > child_hash) {
5853 child_index++;
5854 child_hash = right_child_hash;
5855 }
5856 }
5857 if (child_hash <= parent_hash) break;
5858 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
5859 // Now element at child_index could be < its children.
5860 parent_index = child_index; // parent_hash remains correct.
5861 }
5862 }
5863
5864 // Extract elements and create sorted array.
5865 for (int i = len - 1; i > 0; --i) {
5866 // Put max element at the back of the array.
5867 NoIncrementalWriteBarrierSwapDescriptors(0, i);
5868 // Shift down the new top element.
5869 int parent_index = 0;
5870 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5871 const int max_parent_index = (i / 2) - 1;
5872 while (parent_index <= max_parent_index) {
5873 int child_index = parent_index * 2 + 1;
5874 uint32_t child_hash = GetKey(child_index)->Hash();
5875 if (child_index + 1 < i) {
5876 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5877 if (right_child_hash > child_hash) {
5878 child_index++;
5879 child_hash = right_child_hash;
5880 }
5881 }
5882 if (child_hash <= parent_hash) break;
5883 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
5884 parent_index = child_index;
5885 }
5886 }
5887 }
5888
5889
Sort(const WhitenessWitness & witness)5890 void DescriptorArray::Sort(const WhitenessWitness& witness) {
5891 SortUnchecked(witness);
5892 SLOW_ASSERT(IsSortedNoDuplicates());
5893 }
5894
5895
BinarySearch(String * name,int low,int high)5896 int DescriptorArray::BinarySearch(String* name, int low, int high) {
5897 uint32_t hash = name->Hash();
5898
5899 while (low <= high) {
5900 int mid = (low + high) / 2;
5901 String* mid_name = GetKey(mid);
5902 uint32_t mid_hash = mid_name->Hash();
5903
5904 if (mid_hash > hash) {
5905 high = mid - 1;
5906 continue;
5907 }
5908 if (mid_hash < hash) {
5909 low = mid + 1;
5910 continue;
5911 }
5912 // Found an element with the same hash-code.
5913 ASSERT(hash == mid_hash);
5914 // There might be more, so we find the first one and
5915 // check them all to see if we have a match.
5916 if (name == mid_name && !is_null_descriptor(mid)) return mid;
5917 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5918 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
5919 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
5920 }
5921 break;
5922 }
5923 return kNotFound;
5924 }
5925
5926
LinearSearch(String * name,int len)5927 int DescriptorArray::LinearSearch(String* name, int len) {
5928 uint32_t hash = name->Hash();
5929 for (int number = 0; number < len; number++) {
5930 String* entry = GetKey(number);
5931 if ((entry->Hash() == hash) &&
5932 name->Equals(entry) &&
5933 !is_null_descriptor(number)) {
5934 return number;
5935 }
5936 }
5937 return kNotFound;
5938 }
5939
5940
CopyWithoutTransitions()5941 MaybeObject* AccessorPair::CopyWithoutTransitions() {
5942 Heap* heap = GetHeap();
5943 AccessorPair* copy;
5944 { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5945 if (!maybe_copy->To(©)) return maybe_copy;
5946 }
5947 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
5948 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
5949 return copy;
5950 }
5951
5952
GetComponent(AccessorComponent component)5953 Object* AccessorPair::GetComponent(AccessorComponent component) {
5954 Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter();
5955 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
5956 }
5957
5958
Allocate(int deopt_entry_count,PretenureFlag pretenure)5959 MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5960 PretenureFlag pretenure) {
5961 ASSERT(deopt_entry_count > 0);
5962 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
5963 pretenure);
5964 }
5965
5966
Allocate(int number_of_deopt_points,PretenureFlag pretenure)5967 MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5968 PretenureFlag pretenure) {
5969 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5970 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
5971 pretenure);
5972 }
5973
5974
5975 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)5976 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5977 if (IsEmpty()) return other->IsEmpty();
5978 if (other->IsEmpty()) return false;
5979 if (length() != other->length()) return false;
5980 for (int i = 0; i < length(); ++i) {
5981 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5982 }
5983 return GetContentArray()->IsEqualTo(other->GetContentArray());
5984 }
5985 #endif
5986
5987
LooksValid()5988 bool String::LooksValid() {
5989 if (!Isolate::Current()->heap()->Contains(this)) return false;
5990 return true;
5991 }
5992
5993
GetFlatContent()5994 String::FlatContent String::GetFlatContent() {
5995 int length = this->length();
5996 StringShape shape(this);
5997 String* string = this;
5998 int offset = 0;
5999 if (shape.representation_tag() == kConsStringTag) {
6000 ConsString* cons = ConsString::cast(string);
6001 if (cons->second()->length() != 0) {
6002 return FlatContent();
6003 }
6004 string = cons->first();
6005 shape = StringShape(string);
6006 }
6007 if (shape.representation_tag() == kSlicedStringTag) {
6008 SlicedString* slice = SlicedString::cast(string);
6009 offset = slice->offset();
6010 string = slice->parent();
6011 shape = StringShape(string);
6012 ASSERT(shape.representation_tag() != kConsStringTag &&
6013 shape.representation_tag() != kSlicedStringTag);
6014 }
6015 if (shape.encoding_tag() == kAsciiStringTag) {
6016 const char* start;
6017 if (shape.representation_tag() == kSeqStringTag) {
6018 start = SeqAsciiString::cast(string)->GetChars();
6019 } else {
6020 start = ExternalAsciiString::cast(string)->GetChars();
6021 }
6022 return FlatContent(Vector<const char>(start + offset, length));
6023 } else {
6024 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
6025 const uc16* start;
6026 if (shape.representation_tag() == kSeqStringTag) {
6027 start = SeqTwoByteString::cast(string)->GetChars();
6028 } else {
6029 start = ExternalTwoByteString::cast(string)->GetChars();
6030 }
6031 return FlatContent(Vector<const uc16>(start + offset, length));
6032 }
6033 }
6034
6035
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)6036 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6037 RobustnessFlag robust_flag,
6038 int offset,
6039 int length,
6040 int* length_return) {
6041 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
6042 return SmartArrayPointer<char>(NULL);
6043 }
6044 Heap* heap = GetHeap();
6045
6046 // Negative length means the to the end of the string.
6047 if (length < 0) length = kMaxInt - offset;
6048
6049 // Compute the size of the UTF-8 string. Start at the specified offset.
6050 Access<StringInputBuffer> buffer(
6051 heap->isolate()->objects_string_input_buffer());
6052 buffer->Reset(offset, this);
6053 int character_position = offset;
6054 int utf8_bytes = 0;
6055 int last = unibrow::Utf16::kNoPreviousCharacter;
6056 while (buffer->has_more() && character_position++ < offset + length) {
6057 uint16_t character = buffer->GetNext();
6058 utf8_bytes += unibrow::Utf8::Length(character, last);
6059 last = character;
6060 }
6061
6062 if (length_return) {
6063 *length_return = utf8_bytes;
6064 }
6065
6066 char* result = NewArray<char>(utf8_bytes + 1);
6067
6068 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
6069 buffer->Rewind();
6070 buffer->Seek(offset);
6071 character_position = offset;
6072 int utf8_byte_position = 0;
6073 last = unibrow::Utf16::kNoPreviousCharacter;
6074 while (buffer->has_more() && character_position++ < offset + length) {
6075 uint16_t character = buffer->GetNext();
6076 if (allow_nulls == DISALLOW_NULLS && character == 0) {
6077 character = ' ';
6078 }
6079 utf8_byte_position +=
6080 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
6081 last = character;
6082 }
6083 result[utf8_byte_position] = 0;
6084 return SmartArrayPointer<char>(result);
6085 }
6086
6087
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)6088 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6089 RobustnessFlag robust_flag,
6090 int* length_return) {
6091 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6092 }
6093
6094
GetTwoByteData()6095 const uc16* String::GetTwoByteData() {
6096 return GetTwoByteData(0);
6097 }
6098
6099
GetTwoByteData(unsigned start)6100 const uc16* String::GetTwoByteData(unsigned start) {
6101 ASSERT(!IsAsciiRepresentationUnderneath());
6102 switch (StringShape(this).representation_tag()) {
6103 case kSeqStringTag:
6104 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
6105 case kExternalStringTag:
6106 return ExternalTwoByteString::cast(this)->
6107 ExternalTwoByteStringGetData(start);
6108 case kSlicedStringTag: {
6109 SlicedString* slice = SlicedString::cast(this);
6110 return slice->parent()->GetTwoByteData(start + slice->offset());
6111 }
6112 case kConsStringTag:
6113 UNREACHABLE();
6114 return NULL;
6115 }
6116 UNREACHABLE();
6117 return NULL;
6118 }
6119
6120
ToWideCString(RobustnessFlag robust_flag)6121 SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
6122 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
6123 return SmartArrayPointer<uc16>();
6124 }
6125 Heap* heap = GetHeap();
6126
6127 Access<StringInputBuffer> buffer(
6128 heap->isolate()->objects_string_input_buffer());
6129 buffer->Reset(this);
6130
6131 uc16* result = NewArray<uc16>(length() + 1);
6132
6133 int i = 0;
6134 while (buffer->has_more()) {
6135 uint16_t character = buffer->GetNext();
6136 result[i++] = character;
6137 }
6138 result[i] = 0;
6139 return SmartArrayPointer<uc16>(result);
6140 }
6141
6142
SeqTwoByteStringGetData(unsigned start)6143 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
6144 return reinterpret_cast<uc16*>(
6145 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6146 }
6147
6148
SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6149 void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6150 unsigned* offset_ptr,
6151 unsigned max_chars) {
6152 unsigned chars_read = 0;
6153 unsigned offset = *offset_ptr;
6154 while (chars_read < max_chars) {
6155 uint16_t c = *reinterpret_cast<uint16_t*>(
6156 reinterpret_cast<char*>(this) -
6157 kHeapObjectTag + kHeaderSize + offset * kShortSize);
6158 if (c <= kMaxAsciiCharCode) {
6159 // Fast case for ASCII characters. Cursor is an input output argument.
6160 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6161 rbb->util_buffer,
6162 rbb->capacity,
6163 rbb->cursor)) {
6164 break;
6165 }
6166 } else {
6167 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6168 rbb->util_buffer,
6169 rbb->capacity,
6170 rbb->cursor)) {
6171 break;
6172 }
6173 }
6174 offset++;
6175 chars_read++;
6176 }
6177 *offset_ptr = offset;
6178 rbb->remaining += chars_read;
6179 }
6180
6181
SeqAsciiStringReadBlock(unsigned * remaining,unsigned * offset_ptr,unsigned max_chars)6182 const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6183 unsigned* remaining,
6184 unsigned* offset_ptr,
6185 unsigned max_chars) {
6186 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6187 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6188 *remaining = max_chars;
6189 *offset_ptr += max_chars;
6190 return b;
6191 }
6192
6193
6194 // This will iterate unless the block of string data spans two 'halves' of
6195 // a ConsString, in which case it will recurse. Since the block of string
6196 // data to be read has a maximum size this limits the maximum recursion
6197 // depth to something sane. Since C++ does not have tail call recursion
6198 // elimination, the iteration must be explicit. Since this is not an
6199 // -IntoBuffer method it can delegate to one of the efficient
6200 // *AsciiStringReadBlock routines.
ConsStringReadBlock(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6201 const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6202 unsigned* offset_ptr,
6203 unsigned max_chars) {
6204 ConsString* current = this;
6205 unsigned offset = *offset_ptr;
6206 int offset_correction = 0;
6207
6208 while (true) {
6209 String* left = current->first();
6210 unsigned left_length = (unsigned)left->length();
6211 if (left_length > offset &&
6212 (max_chars <= left_length - offset ||
6213 (rbb->capacity <= left_length - offset &&
6214 (max_chars = left_length - offset, true)))) { // comma operator!
6215 // Left hand side only - iterate unless we have reached the bottom of
6216 // the cons tree. The assignment on the left of the comma operator is
6217 // in order to make use of the fact that the -IntoBuffer routines can
6218 // produce at most 'capacity' characters. This enables us to postpone
6219 // the point where we switch to the -IntoBuffer routines (below) in order
6220 // to maximize the chances of delegating a big chunk of work to the
6221 // efficient *AsciiStringReadBlock routines.
6222 if (StringShape(left).IsCons()) {
6223 current = ConsString::cast(left);
6224 continue;
6225 } else {
6226 const unibrow::byte* answer =
6227 String::ReadBlock(left, rbb, &offset, max_chars);
6228 *offset_ptr = offset + offset_correction;
6229 return answer;
6230 }
6231 } else if (left_length <= offset) {
6232 // Right hand side only - iterate unless we have reached the bottom of
6233 // the cons tree.
6234 String* right = current->second();
6235 offset -= left_length;
6236 offset_correction += left_length;
6237 if (StringShape(right).IsCons()) {
6238 current = ConsString::cast(right);
6239 continue;
6240 } else {
6241 const unibrow::byte* answer =
6242 String::ReadBlock(right, rbb, &offset, max_chars);
6243 *offset_ptr = offset + offset_correction;
6244 return answer;
6245 }
6246 } else {
6247 // The block to be read spans two sides of the ConsString, so we call the
6248 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
6249 // are able to assemble data from several part strings because they use
6250 // the util_buffer to store their data and never return direct pointers
6251 // to their storage. We don't try to read more than the buffer capacity
6252 // here or we can get too much recursion.
6253 ASSERT(rbb->remaining == 0);
6254 ASSERT(rbb->cursor == 0);
6255 current->ConsStringReadBlockIntoBuffer(
6256 rbb,
6257 &offset,
6258 max_chars > rbb->capacity ? rbb->capacity : max_chars);
6259 *offset_ptr = offset + offset_correction;
6260 return rbb->util_buffer;
6261 }
6262 }
6263 }
6264
6265
ExternalAsciiStringReadBlock(unsigned * remaining,unsigned * offset_ptr,unsigned max_chars)6266 const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6267 unsigned* remaining,
6268 unsigned* offset_ptr,
6269 unsigned max_chars) {
6270 // Cast const char* to unibrow::byte* (signedness difference).
6271 const unibrow::byte* b =
6272 reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
6273 *remaining = max_chars;
6274 *offset_ptr += max_chars;
6275 return b;
6276 }
6277
6278
ExternalTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6279 void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6280 ReadBlockBuffer* rbb,
6281 unsigned* offset_ptr,
6282 unsigned max_chars) {
6283 unsigned chars_read = 0;
6284 unsigned offset = *offset_ptr;
6285 const uint16_t* data = GetChars();
6286 while (chars_read < max_chars) {
6287 uint16_t c = data[offset];
6288 if (c <= kMaxAsciiCharCode) {
6289 // Fast case for ASCII characters. Cursor is an input output argument.
6290 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6291 rbb->util_buffer,
6292 rbb->capacity,
6293 rbb->cursor))
6294 break;
6295 } else {
6296 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6297 rbb->util_buffer,
6298 rbb->capacity,
6299 rbb->cursor))
6300 break;
6301 }
6302 offset++;
6303 chars_read++;
6304 }
6305 *offset_ptr = offset;
6306 rbb->remaining += chars_read;
6307 }
6308
6309
SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6310 void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6311 unsigned* offset_ptr,
6312 unsigned max_chars) {
6313 unsigned capacity = rbb->capacity - rbb->cursor;
6314 if (max_chars > capacity) max_chars = capacity;
6315 memcpy(rbb->util_buffer + rbb->cursor,
6316 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6317 *offset_ptr * kCharSize,
6318 max_chars);
6319 rbb->remaining += max_chars;
6320 *offset_ptr += max_chars;
6321 rbb->cursor += max_chars;
6322 }
6323
6324
ExternalAsciiStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6325 void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6326 ReadBlockBuffer* rbb,
6327 unsigned* offset_ptr,
6328 unsigned max_chars) {
6329 unsigned capacity = rbb->capacity - rbb->cursor;
6330 if (max_chars > capacity) max_chars = capacity;
6331 memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
6332 rbb->remaining += max_chars;
6333 *offset_ptr += max_chars;
6334 rbb->cursor += max_chars;
6335 }
6336
6337
6338 // This method determines the type of string involved and then copies
6339 // a whole chunk of characters into a buffer, or returns a pointer to a buffer
6340 // where they can be found. The pointer is not necessarily valid across a GC
6341 // (see AsciiStringReadBlock).
ReadBlock(String * input,ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6342 const unibrow::byte* String::ReadBlock(String* input,
6343 ReadBlockBuffer* rbb,
6344 unsigned* offset_ptr,
6345 unsigned max_chars) {
6346 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6347 if (max_chars == 0) {
6348 rbb->remaining = 0;
6349 return NULL;
6350 }
6351 switch (StringShape(input).representation_tag()) {
6352 case kSeqStringTag:
6353 if (input->IsAsciiRepresentation()) {
6354 SeqAsciiString* str = SeqAsciiString::cast(input);
6355 return str->SeqAsciiStringReadBlock(&rbb->remaining,
6356 offset_ptr,
6357 max_chars);
6358 } else {
6359 SeqTwoByteString* str = SeqTwoByteString::cast(input);
6360 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6361 offset_ptr,
6362 max_chars);
6363 return rbb->util_buffer;
6364 }
6365 case kConsStringTag:
6366 return ConsString::cast(input)->ConsStringReadBlock(rbb,
6367 offset_ptr,
6368 max_chars);
6369 case kExternalStringTag:
6370 if (input->IsAsciiRepresentation()) {
6371 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6372 &rbb->remaining,
6373 offset_ptr,
6374 max_chars);
6375 } else {
6376 ExternalTwoByteString::cast(input)->
6377 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6378 offset_ptr,
6379 max_chars);
6380 return rbb->util_buffer;
6381 }
6382 case kSlicedStringTag:
6383 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6384 offset_ptr,
6385 max_chars);
6386 default:
6387 break;
6388 }
6389
6390 UNREACHABLE();
6391 return 0;
6392 }
6393
6394
PostGarbageCollectionProcessing()6395 void Relocatable::PostGarbageCollectionProcessing() {
6396 Isolate* isolate = Isolate::Current();
6397 Relocatable* current = isolate->relocatable_top();
6398 while (current != NULL) {
6399 current->PostGarbageCollection();
6400 current = current->prev_;
6401 }
6402 }
6403
6404
6405 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()6406 int Relocatable::ArchiveSpacePerThread() {
6407 return sizeof(Isolate::Current()->relocatable_top());
6408 }
6409
6410
6411 // Archive statics that are thread local.
ArchiveState(Isolate * isolate,char * to)6412 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
6413 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6414 isolate->set_relocatable_top(NULL);
6415 return to + ArchiveSpacePerThread();
6416 }
6417
6418
6419 // Restore statics that are thread local.
RestoreState(Isolate * isolate,char * from)6420 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
6421 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
6422 return from + ArchiveSpacePerThread();
6423 }
6424
6425
Iterate(ObjectVisitor * v,char * thread_storage)6426 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6427 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6428 Iterate(v, top);
6429 return thread_storage + ArchiveSpacePerThread();
6430 }
6431
6432
Iterate(ObjectVisitor * v)6433 void Relocatable::Iterate(ObjectVisitor* v) {
6434 Isolate* isolate = Isolate::Current();
6435 Iterate(v, isolate->relocatable_top());
6436 }
6437
6438
Iterate(ObjectVisitor * v,Relocatable * top)6439 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6440 Relocatable* current = top;
6441 while (current != NULL) {
6442 current->IterateInstance(v);
6443 current = current->prev_;
6444 }
6445 }
6446
6447
FlatStringReader(Isolate * isolate,Handle<String> str)6448 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6449 : Relocatable(isolate),
6450 str_(str.location()),
6451 length_(str->length()) {
6452 PostGarbageCollection();
6453 }
6454
6455
FlatStringReader(Isolate * isolate,Vector<const char> input)6456 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6457 : Relocatable(isolate),
6458 str_(0),
6459 is_ascii_(true),
6460 length_(input.length()),
6461 start_(input.start()) { }
6462
6463
PostGarbageCollection()6464 void FlatStringReader::PostGarbageCollection() {
6465 if (str_ == NULL) return;
6466 Handle<String> str(str_);
6467 ASSERT(str->IsFlat());
6468 String::FlatContent content = str->GetFlatContent();
6469 ASSERT(content.IsFlat());
6470 is_ascii_ = content.IsAscii();
6471 if (is_ascii_) {
6472 start_ = content.ToAsciiVector().start();
6473 } else {
6474 start_ = content.ToUC16Vector().start();
6475 }
6476 }
6477
6478
Seek(unsigned pos)6479 void StringInputBuffer::Seek(unsigned pos) {
6480 Reset(pos, input_);
6481 }
6482
6483
Seek(unsigned pos)6484 void SafeStringInputBuffer::Seek(unsigned pos) {
6485 Reset(pos, input_);
6486 }
6487
6488
6489 // This method determines the type of string involved and then copies
6490 // a whole chunk of characters into a buffer. It can be used with strings
6491 // that have been glued together to form a ConsString and which must cooperate
6492 // to fill up a buffer.
ReadBlockIntoBuffer(String * input,ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6493 void String::ReadBlockIntoBuffer(String* input,
6494 ReadBlockBuffer* rbb,
6495 unsigned* offset_ptr,
6496 unsigned max_chars) {
6497 ASSERT(*offset_ptr <= (unsigned)input->length());
6498 if (max_chars == 0) return;
6499
6500 switch (StringShape(input).representation_tag()) {
6501 case kSeqStringTag:
6502 if (input->IsAsciiRepresentation()) {
6503 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
6504 offset_ptr,
6505 max_chars);
6506 return;
6507 } else {
6508 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6509 offset_ptr,
6510 max_chars);
6511 return;
6512 }
6513 case kConsStringTag:
6514 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6515 offset_ptr,
6516 max_chars);
6517 return;
6518 case kExternalStringTag:
6519 if (input->IsAsciiRepresentation()) {
6520 ExternalAsciiString::cast(input)->
6521 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6522 } else {
6523 ExternalTwoByteString::cast(input)->
6524 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6525 offset_ptr,
6526 max_chars);
6527 }
6528 return;
6529 case kSlicedStringTag:
6530 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6531 offset_ptr,
6532 max_chars);
6533 return;
6534 default:
6535 break;
6536 }
6537
6538 UNREACHABLE();
6539 return;
6540 }
6541
6542
ReadBlock(String * input,unibrow::byte * util_buffer,unsigned capacity,unsigned * remaining,unsigned * offset_ptr)6543 const unibrow::byte* String::ReadBlock(String* input,
6544 unibrow::byte* util_buffer,
6545 unsigned capacity,
6546 unsigned* remaining,
6547 unsigned* offset_ptr) {
6548 ASSERT(*offset_ptr <= (unsigned)input->length());
6549 unsigned chars = input->length() - *offset_ptr;
6550 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6551 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
6552 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6553 *remaining = rbb.remaining;
6554 return answer;
6555 }
6556
6557
ReadBlock(String ** raw_input,unibrow::byte * util_buffer,unsigned capacity,unsigned * remaining,unsigned * offset_ptr)6558 const unibrow::byte* String::ReadBlock(String** raw_input,
6559 unibrow::byte* util_buffer,
6560 unsigned capacity,
6561 unsigned* remaining,
6562 unsigned* offset_ptr) {
6563 Handle<String> input(raw_input);
6564 ASSERT(*offset_ptr <= (unsigned)input->length());
6565 unsigned chars = input->length() - *offset_ptr;
6566 if (chars > capacity) chars = capacity;
6567 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6568 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
6569 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6570 *remaining = rbb.remaining;
6571 return rbb.util_buffer;
6572 }
6573
6574
6575 // This will iterate unless the block of string data spans two 'halves' of
6576 // a ConsString, in which case it will recurse. Since the block of string
6577 // data to be read has a maximum size this limits the maximum recursion
6578 // depth to something sane. Since C++ does not have tail call recursion
6579 // elimination, the iteration must be explicit.
ConsStringReadBlockIntoBuffer(ReadBlockBuffer * rbb,unsigned * offset_ptr,unsigned max_chars)6580 void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6581 unsigned* offset_ptr,
6582 unsigned max_chars) {
6583 ConsString* current = this;
6584 unsigned offset = *offset_ptr;
6585 int offset_correction = 0;
6586
6587 while (true) {
6588 String* left = current->first();
6589 unsigned left_length = (unsigned)left->length();
6590 if (left_length > offset &&
6591 max_chars <= left_length - offset) {
6592 // Left hand side only - iterate unless we have reached the bottom of
6593 // the cons tree.
6594 if (StringShape(left).IsCons()) {
6595 current = ConsString::cast(left);
6596 continue;
6597 } else {
6598 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6599 *offset_ptr = offset + offset_correction;
6600 return;
6601 }
6602 } else if (left_length <= offset) {
6603 // Right hand side only - iterate unless we have reached the bottom of
6604 // the cons tree.
6605 offset -= left_length;
6606 offset_correction += left_length;
6607 String* right = current->second();
6608 if (StringShape(right).IsCons()) {
6609 current = ConsString::cast(right);
6610 continue;
6611 } else {
6612 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6613 *offset_ptr = offset + offset_correction;
6614 return;
6615 }
6616 } else {
6617 // The block to be read spans two sides of the ConsString, so we recurse.
6618 // First recurse on the left.
6619 max_chars -= left_length - offset;
6620 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6621 // We may have reached the max or there may not have been enough space
6622 // in the buffer for the characters in the left hand side.
6623 if (offset == left_length) {
6624 // Recurse on the right.
6625 String* right = String::cast(current->second());
6626 offset -= left_length;
6627 offset_correction += left_length;
6628 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6629 }
6630 *offset_ptr = offset + offset_correction;
6631 return;
6632 }
6633 }
6634 }
6635
6636
ConsStringGet(int index)6637 uint16_t ConsString::ConsStringGet(int index) {
6638 ASSERT(index >= 0 && index < this->length());
6639
6640 // Check for a flattened cons string
6641 if (second()->length() == 0) {
6642 String* left = first();
6643 return left->Get(index);
6644 }
6645
6646 String* string = String::cast(this);
6647
6648 while (true) {
6649 if (StringShape(string).IsCons()) {
6650 ConsString* cons_string = ConsString::cast(string);
6651 String* left = cons_string->first();
6652 if (left->length() > index) {
6653 string = left;
6654 } else {
6655 index -= left->length();
6656 string = cons_string->second();
6657 }
6658 } else {
6659 return string->Get(index);
6660 }
6661 }
6662
6663 UNREACHABLE();
6664 return 0;
6665 }
6666
6667
SlicedStringGet(int index)6668 uint16_t SlicedString::SlicedStringGet(int index) {
6669 return parent()->Get(offset() + index);
6670 }
6671
6672
SlicedStringReadBlock(ReadBlockBuffer * buffer,unsigned * offset_ptr,unsigned chars)6673 const unibrow::byte* SlicedString::SlicedStringReadBlock(
6674 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6675 unsigned offset = this->offset();
6676 *offset_ptr += offset;
6677 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6678 buffer, offset_ptr, chars);
6679 *offset_ptr -= offset;
6680 return answer;
6681 }
6682
6683
SlicedStringReadBlockIntoBuffer(ReadBlockBuffer * buffer,unsigned * offset_ptr,unsigned chars)6684 void SlicedString::SlicedStringReadBlockIntoBuffer(
6685 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6686 unsigned offset = this->offset();
6687 *offset_ptr += offset;
6688 String::ReadBlockIntoBuffer(String::cast(parent()),
6689 buffer, offset_ptr, chars);
6690 *offset_ptr -= offset;
6691 }
6692
6693 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)6694 void String::WriteToFlat(String* src,
6695 sinkchar* sink,
6696 int f,
6697 int t) {
6698 String* source = src;
6699 int from = f;
6700 int to = t;
6701 while (true) {
6702 ASSERT(0 <= from && from <= to && to <= source->length());
6703 switch (StringShape(source).full_representation_tag()) {
6704 case kAsciiStringTag | kExternalStringTag: {
6705 CopyChars(sink,
6706 ExternalAsciiString::cast(source)->GetChars() + from,
6707 to - from);
6708 return;
6709 }
6710 case kTwoByteStringTag | kExternalStringTag: {
6711 const uc16* data =
6712 ExternalTwoByteString::cast(source)->GetChars();
6713 CopyChars(sink,
6714 data + from,
6715 to - from);
6716 return;
6717 }
6718 case kAsciiStringTag | kSeqStringTag: {
6719 CopyChars(sink,
6720 SeqAsciiString::cast(source)->GetChars() + from,
6721 to - from);
6722 return;
6723 }
6724 case kTwoByteStringTag | kSeqStringTag: {
6725 CopyChars(sink,
6726 SeqTwoByteString::cast(source)->GetChars() + from,
6727 to - from);
6728 return;
6729 }
6730 case kAsciiStringTag | kConsStringTag:
6731 case kTwoByteStringTag | kConsStringTag: {
6732 ConsString* cons_string = ConsString::cast(source);
6733 String* first = cons_string->first();
6734 int boundary = first->length();
6735 if (to - boundary >= boundary - from) {
6736 // Right hand side is longer. Recurse over left.
6737 if (from < boundary) {
6738 WriteToFlat(first, sink, from, boundary);
6739 sink += boundary - from;
6740 from = 0;
6741 } else {
6742 from -= boundary;
6743 }
6744 to -= boundary;
6745 source = cons_string->second();
6746 } else {
6747 // Left hand side is longer. Recurse over right.
6748 if (to > boundary) {
6749 String* second = cons_string->second();
6750 // When repeatedly appending to a string, we get a cons string that
6751 // is unbalanced to the left, a list, essentially. We inline the
6752 // common case of sequential ascii right child.
6753 if (to - boundary == 1) {
6754 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
6755 } else if (second->IsSeqAsciiString()) {
6756 CopyChars(sink + boundary - from,
6757 SeqAsciiString::cast(second)->GetChars(),
6758 to - boundary);
6759 } else {
6760 WriteToFlat(second,
6761 sink + boundary - from,
6762 0,
6763 to - boundary);
6764 }
6765 to = boundary;
6766 }
6767 source = first;
6768 }
6769 break;
6770 }
6771 case kAsciiStringTag | kSlicedStringTag:
6772 case kTwoByteStringTag | kSlicedStringTag: {
6773 SlicedString* slice = SlicedString::cast(source);
6774 unsigned offset = slice->offset();
6775 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6776 return;
6777 }
6778 }
6779 }
6780 }
6781
6782
6783 template <typename IteratorA, typename IteratorB>
CompareStringContents(IteratorA * ia,IteratorB * ib)6784 static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6785 // General slow case check. We know that the ia and ib iterators
6786 // have the same length.
6787 while (ia->has_more()) {
6788 uint32_t ca = ia->GetNext();
6789 uint32_t cb = ib->GetNext();
6790 ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6791 ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6792 if (ca != cb)
6793 return false;
6794 }
6795 return true;
6796 }
6797
6798
6799 // Compares the contents of two strings by reading and comparing
6800 // int-sized blocks of characters.
6801 template <typename Char>
CompareRawStringContents(Vector<Char> a,Vector<Char> b)6802 static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6803 int length = a.length();
6804 ASSERT_EQ(length, b.length());
6805 const Char* pa = a.start();
6806 const Char* pb = b.start();
6807 int i = 0;
6808 #ifndef V8_HOST_CAN_READ_UNALIGNED
6809 // If this architecture isn't comfortable reading unaligned ints
6810 // then we have to check that the strings are aligned before
6811 // comparing them blockwise.
6812 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
6813 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6814 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
6815 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
6816 #endif
6817 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
6818 int endpoint = length - kStepSize;
6819 // Compare blocks until we reach near the end of the string.
6820 for (; i <= endpoint; i += kStepSize) {
6821 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6822 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6823 if (wa != wb) {
6824 return false;
6825 }
6826 }
6827 #ifndef V8_HOST_CAN_READ_UNALIGNED
6828 }
6829 #endif
6830 // Compare the remaining characters that didn't fit into a block.
6831 for (; i < length; i++) {
6832 if (a[i] != b[i]) {
6833 return false;
6834 }
6835 }
6836 return true;
6837 }
6838
6839
6840 template <typename IteratorA>
CompareStringContentsPartial(Isolate * isolate,IteratorA * ia,String * b)6841 static inline bool CompareStringContentsPartial(Isolate* isolate,
6842 IteratorA* ia,
6843 String* b) {
6844 String::FlatContent content = b->GetFlatContent();
6845 if (content.IsFlat()) {
6846 if (content.IsAscii()) {
6847 VectorIterator<char> ib(content.ToAsciiVector());
6848 return CompareStringContents(ia, &ib);
6849 } else {
6850 VectorIterator<uc16> ib(content.ToUC16Vector());
6851 return CompareStringContents(ia, &ib);
6852 }
6853 } else {
6854 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6855 return CompareStringContents(ia,
6856 isolate->objects_string_compare_buffer_b());
6857 }
6858 }
6859
6860
SlowEquals(String * other)6861 bool String::SlowEquals(String* other) {
6862 // Fast check: negative check with lengths.
6863 int len = length();
6864 if (len != other->length()) return false;
6865 if (len == 0) return true;
6866
6867 // Fast check: if hash code is computed for both strings
6868 // a fast negative check can be performed.
6869 if (HasHashCode() && other->HasHashCode()) {
6870 #ifdef DEBUG
6871 if (FLAG_enable_slow_asserts) {
6872 if (Hash() != other->Hash()) {
6873 bool found_difference = false;
6874 for (int i = 0; i < len; i++) {
6875 if (Get(i) != other->Get(i)) {
6876 found_difference = true;
6877 break;
6878 }
6879 }
6880 ASSERT(found_difference);
6881 }
6882 }
6883 #endif
6884 if (Hash() != other->Hash()) return false;
6885 }
6886
6887 // We know the strings are both non-empty. Compare the first chars
6888 // before we try to flatten the strings.
6889 if (this->Get(0) != other->Get(0)) return false;
6890
6891 String* lhs = this->TryFlattenGetString();
6892 String* rhs = other->TryFlattenGetString();
6893
6894 if (StringShape(lhs).IsSequentialAscii() &&
6895 StringShape(rhs).IsSequentialAscii()) {
6896 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6897 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
6898 return CompareRawStringContents(Vector<const char>(str1, len),
6899 Vector<const char>(str2, len));
6900 }
6901
6902 Isolate* isolate = GetIsolate();
6903 String::FlatContent lhs_content = lhs->GetFlatContent();
6904 String::FlatContent rhs_content = rhs->GetFlatContent();
6905 if (lhs_content.IsFlat()) {
6906 if (lhs_content.IsAscii()) {
6907 Vector<const char> vec1 = lhs_content.ToAsciiVector();
6908 if (rhs_content.IsFlat()) {
6909 if (rhs_content.IsAscii()) {
6910 Vector<const char> vec2 = rhs_content.ToAsciiVector();
6911 return CompareRawStringContents(vec1, vec2);
6912 } else {
6913 VectorIterator<char> buf1(vec1);
6914 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
6915 return CompareStringContents(&buf1, &ib);
6916 }
6917 } else {
6918 VectorIterator<char> buf1(vec1);
6919 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6920 return CompareStringContents(&buf1,
6921 isolate->objects_string_compare_buffer_b());
6922 }
6923 } else {
6924 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6925 if (rhs_content.IsFlat()) {
6926 if (rhs_content.IsAscii()) {
6927 VectorIterator<uc16> buf1(vec1);
6928 VectorIterator<char> ib(rhs_content.ToAsciiVector());
6929 return CompareStringContents(&buf1, &ib);
6930 } else {
6931 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
6932 return CompareRawStringContents(vec1, vec2);
6933 }
6934 } else {
6935 VectorIterator<uc16> buf1(vec1);
6936 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6937 return CompareStringContents(&buf1,
6938 isolate->objects_string_compare_buffer_b());
6939 }
6940 }
6941 } else {
6942 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6943 return CompareStringContentsPartial(isolate,
6944 isolate->objects_string_compare_buffer_a(), rhs);
6945 }
6946 }
6947
6948
MarkAsUndetectable()6949 bool String::MarkAsUndetectable() {
6950 if (StringShape(this).IsSymbol()) return false;
6951
6952 Map* map = this->map();
6953 Heap* heap = GetHeap();
6954 if (map == heap->string_map()) {
6955 this->set_map(heap->undetectable_string_map());
6956 return true;
6957 } else if (map == heap->ascii_string_map()) {
6958 this->set_map(heap->undetectable_ascii_string_map());
6959 return true;
6960 }
6961 // Rest cannot be marked as undetectable
6962 return false;
6963 }
6964
6965
IsEqualTo(Vector<const char> str)6966 bool String::IsEqualTo(Vector<const char> str) {
6967 Isolate* isolate = GetIsolate();
6968 int slen = length();
6969 Access<UnicodeCache::Utf8Decoder>
6970 decoder(isolate->unicode_cache()->utf8_decoder());
6971 decoder->Reset(str.start(), str.length());
6972 int i;
6973 for (i = 0; i < slen && decoder->has_more(); i++) {
6974 uint32_t r = decoder->GetNext();
6975 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
6976 if (i > slen - 1) return false;
6977 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
6978 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
6979 } else {
6980 if (Get(i) != r) return false;
6981 }
6982 }
6983 return i == slen && !decoder->has_more();
6984 }
6985
6986
IsAsciiEqualTo(Vector<const char> str)6987 bool String::IsAsciiEqualTo(Vector<const char> str) {
6988 int slen = length();
6989 if (str.length() != slen) return false;
6990 FlatContent content = GetFlatContent();
6991 if (content.IsAscii()) {
6992 return CompareChars(content.ToAsciiVector().start(),
6993 str.start(), slen) == 0;
6994 }
6995 for (int i = 0; i < slen; i++) {
6996 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
6997 }
6998 return true;
6999 }
7000
7001
IsTwoByteEqualTo(Vector<const uc16> str)7002 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
7003 int slen = length();
7004 if (str.length() != slen) return false;
7005 FlatContent content = GetFlatContent();
7006 if (content.IsTwoByte()) {
7007 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
7008 }
7009 for (int i = 0; i < slen; i++) {
7010 if (Get(i) != str[i]) return false;
7011 }
7012 return true;
7013 }
7014
7015
ComputeAndSetHash()7016 uint32_t String::ComputeAndSetHash() {
7017 // Should only be called if hash code has not yet been computed.
7018 ASSERT(!HasHashCode());
7019
7020 const int len = length();
7021
7022 // Compute the hash code.
7023 uint32_t field = 0;
7024 if (StringShape(this).IsSequentialAscii()) {
7025 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
7026 len,
7027 GetHeap()->HashSeed());
7028 } else if (StringShape(this).IsSequentialTwoByte()) {
7029 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
7030 len,
7031 GetHeap()->HashSeed());
7032 } else {
7033 StringInputBuffer buffer(this);
7034 field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
7035 }
7036
7037 // Store the hash code in the object.
7038 set_hash_field(field);
7039
7040 // Check the hash code is there.
7041 ASSERT(HasHashCode());
7042 uint32_t result = field >> kHashShift;
7043 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
7044 return result;
7045 }
7046
7047
ComputeArrayIndex(unibrow::CharacterStream * buffer,uint32_t * index,int length)7048 bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
7049 uint32_t* index,
7050 int length) {
7051 if (length == 0 || length > kMaxArrayIndexSize) return false;
7052 uc32 ch = buffer->GetNext();
7053
7054 // If the string begins with a '0' character, it must only consist
7055 // of it to be a legal array index.
7056 if (ch == '0') {
7057 *index = 0;
7058 return length == 1;
7059 }
7060
7061 // Convert string to uint32 array index; character by character.
7062 int d = ch - '0';
7063 if (d < 0 || d > 9) return false;
7064 uint32_t result = d;
7065 while (buffer->has_more()) {
7066 d = buffer->GetNext() - '0';
7067 if (d < 0 || d > 9) return false;
7068 // Check that the new result is below the 32 bit limit.
7069 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7070 result = (result * 10) + d;
7071 }
7072
7073 *index = result;
7074 return true;
7075 }
7076
7077
SlowAsArrayIndex(uint32_t * index)7078 bool String::SlowAsArrayIndex(uint32_t* index) {
7079 if (length() <= kMaxCachedArrayIndexLength) {
7080 Hash(); // force computation of hash code
7081 uint32_t field = hash_field();
7082 if ((field & kIsNotArrayIndexMask) != 0) return false;
7083 // Isolate the array index form the full hash field.
7084 *index = (kArrayIndexHashMask & field) >> kHashShift;
7085 return true;
7086 } else {
7087 StringInputBuffer buffer(this);
7088 return ComputeArrayIndex(&buffer, index, length());
7089 }
7090 }
7091
7092
MakeArrayIndexHash(uint32_t value,int length)7093 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
7094 // For array indexes mix the length into the hash as an array index could
7095 // be zero.
7096 ASSERT(length > 0);
7097 ASSERT(length <= String::kMaxArrayIndexSize);
7098 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7099 (1 << String::kArrayIndexValueBits));
7100
7101 value <<= String::kHashShift;
7102 value |= length << String::kArrayIndexHashLengthShift;
7103
7104 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7105 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7106 (value & String::kContainsCachedArrayIndexMask) == 0);
7107 return value;
7108 }
7109
7110
AddSurrogatePair(uc32 c)7111 void StringHasher::AddSurrogatePair(uc32 c) {
7112 uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7113 AddCharacter(lead);
7114 uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7115 AddCharacter(trail);
7116 }
7117
7118
AddSurrogatePairNoIndex(uc32 c)7119 void StringHasher::AddSurrogatePairNoIndex(uc32 c) {
7120 uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7121 AddCharacterNoIndex(lead);
7122 uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7123 AddCharacterNoIndex(trail);
7124 }
7125
7126
GetHashField()7127 uint32_t StringHasher::GetHashField() {
7128 ASSERT(is_valid());
7129 if (length_ <= String::kMaxHashCalcLength) {
7130 if (is_array_index()) {
7131 return MakeArrayIndexHash(array_index(), length_);
7132 }
7133 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
7134 } else {
7135 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
7136 }
7137 }
7138
7139
ComputeHashField(unibrow::CharacterStream * buffer,int length,uint32_t seed)7140 uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
7141 int length,
7142 uint32_t seed) {
7143 StringHasher hasher(length, seed);
7144
7145 // Very long strings have a trivial hash that doesn't inspect the
7146 // string contents.
7147 if (hasher.has_trivial_hash()) {
7148 return hasher.GetHashField();
7149 }
7150
7151 // Do the iterative array index computation as long as there is a
7152 // chance this is an array index.
7153 while (buffer->has_more() && hasher.is_array_index()) {
7154 hasher.AddCharacter(buffer->GetNext());
7155 }
7156
7157 // Process the remaining characters without updating the array
7158 // index.
7159 while (buffer->has_more()) {
7160 hasher.AddCharacterNoIndex(buffer->GetNext());
7161 }
7162
7163 return hasher.GetHashField();
7164 }
7165
7166
SubString(int start,int end,PretenureFlag pretenure)7167 MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
7168 Heap* heap = GetHeap();
7169 if (start == 0 && end == length()) return this;
7170 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
7171 return result;
7172 }
7173
7174
PrintOn(FILE * file)7175 void String::PrintOn(FILE* file) {
7176 int length = this->length();
7177 for (int i = 0; i < length; i++) {
7178 fprintf(file, "%c", Get(i));
7179 }
7180 }
7181
7182
CreateOneBackPointer(Object * transition_target)7183 void Map::CreateOneBackPointer(Object* transition_target) {
7184 if (!transition_target->IsMap()) return;
7185 Map* target = Map::cast(transition_target);
7186 #ifdef DEBUG
7187 // Verify target.
7188 Object* source_prototype = prototype();
7189 Object* target_prototype = target->prototype();
7190 ASSERT(source_prototype->IsJSReceiver() ||
7191 source_prototype->IsMap() ||
7192 source_prototype->IsNull());
7193 ASSERT(target_prototype->IsJSReceiver() ||
7194 target_prototype->IsNull());
7195 ASSERT(source_prototype->IsMap() ||
7196 source_prototype == target_prototype);
7197 #endif
7198 // Point target back to source. set_prototype() will not let us set
7199 // the prototype to a map, as we do here.
7200 *RawField(target, kPrototypeOffset) = this;
7201 }
7202
7203
CreateBackPointers()7204 void Map::CreateBackPointers() {
7205 DescriptorArray* descriptors = instance_descriptors();
7206 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
7207 switch (descriptors->GetType(i)) {
7208 case MAP_TRANSITION:
7209 case CONSTANT_TRANSITION:
7210 CreateOneBackPointer(descriptors->GetValue(i));
7211 break;
7212 case ELEMENTS_TRANSITION: {
7213 Object* object = descriptors->GetValue(i);
7214 if (object->IsMap()) {
7215 CreateOneBackPointer(object);
7216 } else {
7217 FixedArray* array = FixedArray::cast(object);
7218 for (int i = 0; i < array->length(); ++i) {
7219 CreateOneBackPointer(array->get(i));
7220 }
7221 }
7222 break;
7223 }
7224 case CALLBACKS: {
7225 Object* object = descriptors->GetValue(i);
7226 if (object->IsAccessorPair()) {
7227 AccessorPair* accessors = AccessorPair::cast(object);
7228 CreateOneBackPointer(accessors->getter());
7229 CreateOneBackPointer(accessors->setter());
7230 }
7231 break;
7232 }
7233 case NORMAL:
7234 case FIELD:
7235 case CONSTANT_FUNCTION:
7236 case HANDLER:
7237 case INTERCEPTOR:
7238 case NULL_DESCRIPTOR:
7239 break;
7240 }
7241 }
7242 }
7243
7244
RestoreOneBackPointer(Object * object,Object * real_prototype,bool * keep_entry)7245 bool Map::RestoreOneBackPointer(Object* object,
7246 Object* real_prototype,
7247 bool* keep_entry) {
7248 if (!object->IsMap()) return false;
7249 Map* map = Map::cast(object);
7250 if (Marking::MarkBitFrom(map).Get()) {
7251 *keep_entry = true;
7252 return false;
7253 }
7254 ASSERT(map->prototype() == this || map->prototype() == real_prototype);
7255 // Getter prototype() is read-only, set_prototype() has side effects.
7256 *RawField(map, Map::kPrototypeOffset) = real_prototype;
7257 return true;
7258 }
7259
7260
ClearNonLiveTransitions(Heap * heap,Object * real_prototype)7261 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
7262 DescriptorArray* d = DescriptorArray::cast(
7263 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7264 if (d->IsEmpty()) return;
7265 Smi* NullDescriptorDetails =
7266 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
7267 FixedArray* contents = FixedArray::cast(
7268 d->get(DescriptorArray::kContentArrayIndex));
7269 ASSERT(contents->length() >= 2);
7270 for (int i = 0; i < contents->length(); i += 2) {
7271 // If the pair (value, details) is a map transition, check if the target is
7272 // live. If not, null the descriptor. Also drop the back pointer for that
7273 // map transition, so that this map is not reached again by following a back
7274 // pointer from a non-live object.
7275 bool keep_entry = false;
7276 PropertyDetails details(Smi::cast(contents->get(i + 1)));
7277 switch (details.type()) {
7278 case MAP_TRANSITION:
7279 case CONSTANT_TRANSITION:
7280 RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
7281 break;
7282 case ELEMENTS_TRANSITION: {
7283 Object* object = contents->get(i);
7284 if (object->IsMap()) {
7285 RestoreOneBackPointer(object, real_prototype, &keep_entry);
7286 } else {
7287 FixedArray* array = FixedArray::cast(object);
7288 for (int j = 0; j < array->length(); ++j) {
7289 if (RestoreOneBackPointer(array->get(j),
7290 real_prototype,
7291 &keep_entry)) {
7292 array->set_undefined(j);
7293 }
7294 }
7295 }
7296 break;
7297 }
7298 case CALLBACKS: {
7299 Object* object = contents->get(i);
7300 if (object->IsAccessorPair()) {
7301 AccessorPair* accessors = AccessorPair::cast(object);
7302 if (RestoreOneBackPointer(accessors->getter(),
7303 real_prototype,
7304 &keep_entry)) {
7305 accessors->set_getter(heap->the_hole_value());
7306 }
7307 if (RestoreOneBackPointer(accessors->setter(),
7308 real_prototype,
7309 &keep_entry)) {
7310 accessors->set_setter(heap->the_hole_value());
7311 }
7312 } else {
7313 keep_entry = true;
7314 }
7315 break;
7316 }
7317 case NORMAL:
7318 case FIELD:
7319 case CONSTANT_FUNCTION:
7320 case HANDLER:
7321 case INTERCEPTOR:
7322 case NULL_DESCRIPTOR:
7323 keep_entry = true;
7324 break;
7325 }
7326 // Make sure that an entry containing only dead transitions gets collected.
7327 // What we *really* want to do here is removing this entry completely, but
7328 // for technical reasons we can't do this, so we zero it out instead.
7329 if (!keep_entry) {
7330 contents->set_unchecked(i + 1, NullDescriptorDetails);
7331 contents->set_null_unchecked(heap, i);
7332 }
7333 }
7334 }
7335
7336
Hash()7337 int Map::Hash() {
7338 // For performance reasons we only hash the 3 most variable fields of a map:
7339 // constructor, prototype and bit_field2.
7340
7341 // Shift away the tag.
7342 int hash = (static_cast<uint32_t>(
7343 reinterpret_cast<uintptr_t>(constructor())) >> 2);
7344
7345 // XOR-ing the prototype and constructor directly yields too many zero bits
7346 // when the two pointers are close (which is fairly common).
7347 // To avoid this we shift the prototype 4 bits relatively to the constructor.
7348 hash ^= (static_cast<uint32_t>(
7349 reinterpret_cast<uintptr_t>(prototype())) << 2);
7350
7351 return hash ^ (hash >> 16) ^ bit_field2();
7352 }
7353
7354
EquivalentToForNormalization(Map * other,PropertyNormalizationMode mode)7355 bool Map::EquivalentToForNormalization(Map* other,
7356 PropertyNormalizationMode mode) {
7357 return
7358 constructor() == other->constructor() &&
7359 prototype() == other->prototype() &&
7360 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7361 0 :
7362 other->inobject_properties()) &&
7363 instance_type() == other->instance_type() &&
7364 bit_field() == other->bit_field() &&
7365 bit_field2() == other->bit_field2() &&
7366 (bit_field3() & ~(1<<Map::kIsShared)) ==
7367 (other->bit_field3() & ~(1<<Map::kIsShared));
7368 }
7369
7370
JSFunctionIterateBody(int object_size,ObjectVisitor * v)7371 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7372 // Iterate over all fields in the body but take care in dealing with
7373 // the code entry.
7374 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7375 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7376 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7377 }
7378
7379
MarkForLazyRecompilation()7380 void JSFunction::MarkForLazyRecompilation() {
7381 ASSERT(is_compiled() && !IsOptimized());
7382 ASSERT(shared()->allows_lazy_compilation() ||
7383 code()->optimizable());
7384 Builtins* builtins = GetIsolate()->builtins();
7385 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
7386 }
7387
7388
EnsureCompiled(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)7389 bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7390 ClearExceptionFlag flag) {
7391 return shared->is_compiled() || CompileLazy(shared, flag);
7392 }
7393
7394
CompileLazyHelper(CompilationInfo * info,ClearExceptionFlag flag)7395 static bool CompileLazyHelper(CompilationInfo* info,
7396 ClearExceptionFlag flag) {
7397 // Compile the source information to a code object.
7398 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7399 ASSERT(!info->isolate()->has_pending_exception());
7400 bool result = Compiler::CompileLazy(info);
7401 ASSERT(result != Isolate::Current()->has_pending_exception());
7402 if (!result && flag == CLEAR_EXCEPTION) {
7403 info->isolate()->clear_pending_exception();
7404 }
7405 return result;
7406 }
7407
7408
CompileLazy(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)7409 bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7410 ClearExceptionFlag flag) {
7411 CompilationInfo info(shared);
7412 return CompileLazyHelper(&info, flag);
7413 }
7414
7415
CompileLazy(Handle<JSFunction> function,ClearExceptionFlag flag)7416 bool JSFunction::CompileLazy(Handle<JSFunction> function,
7417 ClearExceptionFlag flag) {
7418 bool result = true;
7419 if (function->shared()->is_compiled()) {
7420 function->ReplaceCode(function->shared()->code());
7421 function->shared()->set_code_age(0);
7422 } else {
7423 CompilationInfo info(function);
7424 result = CompileLazyHelper(&info, flag);
7425 ASSERT(!result || function->is_compiled());
7426 }
7427 return result;
7428 }
7429
7430
CompileOptimized(Handle<JSFunction> function,int osr_ast_id,ClearExceptionFlag flag)7431 bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7432 int osr_ast_id,
7433 ClearExceptionFlag flag) {
7434 CompilationInfo info(function);
7435 info.SetOptimizing(osr_ast_id);
7436 return CompileLazyHelper(&info, flag);
7437 }
7438
7439
IsInlineable()7440 bool JSFunction::IsInlineable() {
7441 if (IsBuiltin()) return false;
7442 SharedFunctionInfo* shared_info = shared();
7443 // Check that the function has a script associated with it.
7444 if (!shared_info->script()->IsScript()) return false;
7445 if (shared_info->optimization_disabled()) return false;
7446 Code* code = shared_info->code();
7447 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7448 // If we never ran this (unlikely) then lets try to optimize it.
7449 if (code->kind() != Code::FUNCTION) return true;
7450 return code->optimizable();
7451 }
7452
7453
SetInstancePrototype(Object * value)7454 MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
7455 ASSERT(value->IsJSReceiver());
7456 Heap* heap = GetHeap();
7457 if (has_initial_map()) {
7458 // If the function has allocated the initial map
7459 // replace it with a copy containing the new prototype.
7460 Map* new_map;
7461 MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
7462 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7463 new_map->set_prototype(value);
7464 MaybeObject* maybe_object =
7465 set_initial_map_and_cache_transitions(new_map);
7466 if (maybe_object->IsFailure()) return maybe_object;
7467 } else {
7468 // Put the value in the initial map field until an initial map is
7469 // needed. At that point, a new initial map is created and the
7470 // prototype is put into the initial map where it belongs.
7471 set_prototype_or_initial_map(value);
7472 }
7473 heap->ClearInstanceofCache();
7474 return value;
7475 }
7476
7477
SetPrototype(Object * value)7478 MaybeObject* JSFunction::SetPrototype(Object* value) {
7479 ASSERT(should_have_prototype());
7480 Object* construct_prototype = value;
7481
7482 // If the value is not a JSReceiver, store the value in the map's
7483 // constructor field so it can be accessed. Also, set the prototype
7484 // used for constructing objects to the original object prototype.
7485 // See ECMA-262 13.2.2.
7486 if (!value->IsJSReceiver()) {
7487 // Copy the map so this does not affect unrelated functions.
7488 // Remove map transitions because they point to maps with a
7489 // different prototype.
7490 Map* new_map;
7491 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
7492 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7493 }
7494 Heap* heap = new_map->GetHeap();
7495 set_map(new_map);
7496 new_map->set_constructor(value);
7497 new_map->set_non_instance_prototype(true);
7498 construct_prototype =
7499 heap->isolate()->context()->global_context()->
7500 initial_object_prototype();
7501 } else {
7502 map()->set_non_instance_prototype(false);
7503 }
7504
7505 return SetInstancePrototype(construct_prototype);
7506 }
7507
7508
RemovePrototype()7509 Object* JSFunction::RemovePrototype() {
7510 Context* global_context = context()->global_context();
7511 Map* no_prototype_map = shared()->is_classic_mode()
7512 ? global_context->function_without_prototype_map()
7513 : global_context->strict_mode_function_without_prototype_map();
7514
7515 if (map() == no_prototype_map) {
7516 // Be idempotent.
7517 return this;
7518 }
7519
7520 ASSERT(map() == (shared()->is_classic_mode()
7521 ? global_context->function_map()
7522 : global_context->strict_mode_function_map()));
7523
7524 set_map(no_prototype_map);
7525 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
7526 return this;
7527 }
7528
7529
SetInstanceClassName(String * name)7530 Object* JSFunction::SetInstanceClassName(String* name) {
7531 shared()->set_instance_class_name(name);
7532 return this;
7533 }
7534
7535
PrintName(FILE * out)7536 void JSFunction::PrintName(FILE* out) {
7537 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
7538 PrintF(out, "%s", *name);
7539 }
7540
7541
GlobalContextFromLiterals(FixedArray * literals)7542 Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7543 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7544 }
7545
7546
Initialize(const char * to_string,Object * to_number,byte kind)7547 MaybeObject* Oddball::Initialize(const char* to_string,
7548 Object* to_number,
7549 byte kind) {
7550 String* symbol;
7551 { MaybeObject* maybe_symbol =
7552 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
7553 if (!maybe_symbol->To(&symbol)) return maybe_symbol;
7554 }
7555 set_to_string(symbol);
7556 set_to_number(to_number);
7557 set_kind(kind);
7558 return this;
7559 }
7560
7561
DebugName()7562 String* SharedFunctionInfo::DebugName() {
7563 Object* n = name();
7564 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7565 return String::cast(n);
7566 }
7567
7568
HasSourceCode()7569 bool SharedFunctionInfo::HasSourceCode() {
7570 return !script()->IsUndefined() &&
7571 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
7572 }
7573
7574
GetSourceCode()7575 Handle<Object> SharedFunctionInfo::GetSourceCode() {
7576 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
7577 Handle<String> source(String::cast(Script::cast(script())->source()));
7578 return SubString(source, start_position(), end_position());
7579 }
7580
7581
SourceSize()7582 int SharedFunctionInfo::SourceSize() {
7583 return end_position() - start_position();
7584 }
7585
7586
CalculateInstanceSize()7587 int SharedFunctionInfo::CalculateInstanceSize() {
7588 int instance_size =
7589 JSObject::kHeaderSize +
7590 expected_nof_properties() * kPointerSize;
7591 if (instance_size > JSObject::kMaxInstanceSize) {
7592 instance_size = JSObject::kMaxInstanceSize;
7593 }
7594 return instance_size;
7595 }
7596
7597
CalculateInObjectProperties()7598 int SharedFunctionInfo::CalculateInObjectProperties() {
7599 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7600 }
7601
7602
CanGenerateInlineConstructor(Object * prototype)7603 bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7604 // Check the basic conditions for generating inline constructor code.
7605 if (!FLAG_inline_new
7606 || !has_only_simple_this_property_assignments()
7607 || this_property_assignments_count() == 0) {
7608 return false;
7609 }
7610
7611 // If the prototype is null inline constructors cause no problems.
7612 if (!prototype->IsJSObject()) {
7613 ASSERT(prototype->IsNull());
7614 return true;
7615 }
7616
7617 Heap* heap = GetHeap();
7618
7619 // Traverse the proposed prototype chain looking for setters for properties of
7620 // the same names as are set by the inline constructor.
7621 for (Object* obj = prototype;
7622 obj != heap->null_value();
7623 obj = obj->GetPrototype()) {
7624 JSObject* js_object = JSObject::cast(obj);
7625 for (int i = 0; i < this_property_assignments_count(); i++) {
7626 LookupResult result(heap->isolate());
7627 String* name = GetThisPropertyAssignmentName(i);
7628 js_object->LocalLookupRealNamedProperty(name, &result);
7629 if (result.IsFound() && result.type() == CALLBACKS) {
7630 return false;
7631 }
7632 }
7633 }
7634
7635 return true;
7636 }
7637
7638
ForbidInlineConstructor()7639 void SharedFunctionInfo::ForbidInlineConstructor() {
7640 set_compiler_hints(BooleanBit::set(compiler_hints(),
7641 kHasOnlySimpleThisPropertyAssignments,
7642 false));
7643 }
7644
7645
SetThisPropertyAssignmentsInfo(bool only_simple_this_property_assignments,FixedArray * assignments)7646 void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
7647 bool only_simple_this_property_assignments,
7648 FixedArray* assignments) {
7649 set_compiler_hints(BooleanBit::set(compiler_hints(),
7650 kHasOnlySimpleThisPropertyAssignments,
7651 only_simple_this_property_assignments));
7652 set_this_property_assignments(assignments);
7653 set_this_property_assignments_count(assignments->length() / 3);
7654 }
7655
7656
ClearThisPropertyAssignmentsInfo()7657 void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
7658 Heap* heap = GetHeap();
7659 set_compiler_hints(BooleanBit::set(compiler_hints(),
7660 kHasOnlySimpleThisPropertyAssignments,
7661 false));
7662 set_this_property_assignments(heap->undefined_value());
7663 set_this_property_assignments_count(0);
7664 }
7665
7666
GetThisPropertyAssignmentName(int index)7667 String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7668 Object* obj = this_property_assignments();
7669 ASSERT(obj->IsFixedArray());
7670 ASSERT(index < this_property_assignments_count());
7671 obj = FixedArray::cast(obj)->get(index * 3);
7672 ASSERT(obj->IsString());
7673 return String::cast(obj);
7674 }
7675
7676
IsThisPropertyAssignmentArgument(int index)7677 bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7678 Object* obj = this_property_assignments();
7679 ASSERT(obj->IsFixedArray());
7680 ASSERT(index < this_property_assignments_count());
7681 obj = FixedArray::cast(obj)->get(index * 3 + 1);
7682 return Smi::cast(obj)->value() != -1;
7683 }
7684
7685
GetThisPropertyAssignmentArgument(int index)7686 int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7687 ASSERT(IsThisPropertyAssignmentArgument(index));
7688 Object* obj =
7689 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7690 return Smi::cast(obj)->value();
7691 }
7692
7693
GetThisPropertyAssignmentConstant(int index)7694 Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7695 ASSERT(!IsThisPropertyAssignmentArgument(index));
7696 Object* obj =
7697 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7698 return obj;
7699 }
7700
7701
7702 // Support function for printing the source code to a StringStream
7703 // without any allocation in the heap.
SourceCodePrint(StringStream * accumulator,int max_length)7704 void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7705 int max_length) {
7706 // For some native functions there is no source.
7707 if (!HasSourceCode()) {
7708 accumulator->Add("<No Source>");
7709 return;
7710 }
7711
7712 // Get the source for the script which this function came from.
7713 // Don't use String::cast because we don't want more assertion errors while
7714 // we are already creating a stack dump.
7715 String* script_source =
7716 reinterpret_cast<String*>(Script::cast(script())->source());
7717
7718 if (!script_source->LooksValid()) {
7719 accumulator->Add("<Invalid Source>");
7720 return;
7721 }
7722
7723 if (!is_toplevel()) {
7724 accumulator->Add("function ");
7725 Object* name = this->name();
7726 if (name->IsString() && String::cast(name)->length() > 0) {
7727 accumulator->PrintName(name);
7728 }
7729 }
7730
7731 int len = end_position() - start_position();
7732 if (len <= max_length || max_length < 0) {
7733 accumulator->Put(script_source, start_position(), end_position());
7734 } else {
7735 accumulator->Put(script_source,
7736 start_position(),
7737 start_position() + max_length);
7738 accumulator->Add("...\n");
7739 }
7740 }
7741
7742
IsCodeEquivalent(Code * code,Code * recompiled)7743 static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7744 if (code->instruction_size() != recompiled->instruction_size()) return false;
7745 ByteArray* code_relocation = code->relocation_info();
7746 ByteArray* recompiled_relocation = recompiled->relocation_info();
7747 int length = code_relocation->length();
7748 if (length != recompiled_relocation->length()) return false;
7749 int compare = memcmp(code_relocation->GetDataStartAddress(),
7750 recompiled_relocation->GetDataStartAddress(),
7751 length);
7752 return compare == 0;
7753 }
7754
7755
EnableDeoptimizationSupport(Code * recompiled)7756 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7757 ASSERT(!has_deoptimization_support());
7758 AssertNoAllocation no_allocation;
7759 Code* code = this->code();
7760 if (IsCodeEquivalent(code, recompiled)) {
7761 // Copy the deoptimization data from the recompiled code.
7762 code->set_deoptimization_data(recompiled->deoptimization_data());
7763 code->set_has_deoptimization_support(true);
7764 } else {
7765 // TODO(3025757): In case the recompiled isn't equivalent to the
7766 // old code, we have to replace it. We should try to avoid this
7767 // altogether because it flushes valuable type feedback by
7768 // effectively resetting all IC state.
7769 set_code(recompiled);
7770 }
7771 ASSERT(has_deoptimization_support());
7772 }
7773
7774
DisableOptimization()7775 void SharedFunctionInfo::DisableOptimization() {
7776 // Disable optimization for the shared function info and mark the
7777 // code as non-optimizable. The marker on the shared function info
7778 // is there because we flush non-optimized code thereby loosing the
7779 // non-optimizable information for the code. When the code is
7780 // regenerated and set on the shared function info it is marked as
7781 // non-optimizable if optimization is disabled for the shared
7782 // function info.
7783 set_optimization_disabled(true);
7784 // Code should be the lazy compilation stub or else unoptimized. If the
7785 // latter, disable optimization for the code too.
7786 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7787 if (code()->kind() == Code::FUNCTION) {
7788 code()->set_optimizable(false);
7789 }
7790 if (FLAG_trace_opt) {
7791 PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
7792 }
7793 }
7794
7795
VerifyBailoutId(int id)7796 bool SharedFunctionInfo::VerifyBailoutId(int id) {
7797 ASSERT(id != AstNode::kNoNumber);
7798 Code* unoptimized = code();
7799 DeoptimizationOutputData* data =
7800 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7801 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7802 USE(ignore);
7803 return true; // Return true if there was no ASSERT.
7804 }
7805
7806
StartInobjectSlackTracking(Map * map)7807 void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7808 ASSERT(!IsInobjectSlackTrackingInProgress());
7809
7810 if (!FLAG_clever_optimizations) return;
7811
7812 // Only initiate the tracking the first time.
7813 if (live_objects_may_exist()) return;
7814 set_live_objects_may_exist(true);
7815
7816 // No tracking during the snapshot construction phase.
7817 if (Serializer::enabled()) return;
7818
7819 if (map->unused_property_fields() == 0) return;
7820
7821 // Nonzero counter is a leftover from the previous attempt interrupted
7822 // by GC, keep it.
7823 if (construction_count() == 0) {
7824 set_construction_count(kGenerousAllocationCount);
7825 }
7826 set_initial_map(map);
7827 Builtins* builtins = map->GetHeap()->isolate()->builtins();
7828 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
7829 construct_stub());
7830 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
7831 }
7832
7833
7834 // Called from GC, hence reinterpret_cast and unchecked accessors.
DetachInitialMap()7835 void SharedFunctionInfo::DetachInitialMap() {
7836 Map* map = reinterpret_cast<Map*>(initial_map());
7837
7838 // Make the map remember to restore the link if it survives the GC.
7839 map->set_bit_field2(
7840 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7841
7842 // Undo state changes made by StartInobjectTracking (except the
7843 // construction_count). This way if the initial map does not survive the GC
7844 // then StartInobjectTracking will be called again the next time the
7845 // constructor is called. The countdown will continue and (possibly after
7846 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
7847 Heap* heap = map->GetHeap();
7848 set_initial_map(heap->raw_unchecked_undefined_value());
7849 Builtins* builtins = heap->isolate()->builtins();
7850 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
7851 *RawField(this, kConstructStubOffset));
7852 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
7853 // It is safe to clear the flag: it will be set again if the map is live.
7854 set_live_objects_may_exist(false);
7855 }
7856
7857
7858 // Called from GC, hence reinterpret_cast and unchecked accessors.
AttachInitialMap(Map * map)7859 void SharedFunctionInfo::AttachInitialMap(Map* map) {
7860 map->set_bit_field2(
7861 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7862
7863 // Resume inobject slack tracking.
7864 set_initial_map(map);
7865 Builtins* builtins = map->GetHeap()->isolate()->builtins();
7866 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
7867 *RawField(this, kConstructStubOffset));
7868 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
7869 // The map survived the gc, so there may be objects referencing it.
7870 set_live_objects_may_exist(true);
7871 }
7872
7873
ResetForNewContext(int new_ic_age)7874 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
7875 code()->ClearInlineCaches();
7876 set_ic_age(new_ic_age);
7877 if (code()->kind() == Code::FUNCTION) {
7878 code()->set_profiler_ticks(0);
7879 if (optimization_disabled() &&
7880 opt_count() >= Compiler::kDefaultMaxOptCount) {
7881 // Re-enable optimizations if they were disabled due to opt_count limit.
7882 set_optimization_disabled(false);
7883 code()->set_optimizable(true);
7884 }
7885 set_opt_count(0);
7886 }
7887 }
7888
7889
GetMinInobjectSlack(Map * map,void * data)7890 static void GetMinInobjectSlack(Map* map, void* data) {
7891 int slack = map->unused_property_fields();
7892 if (*reinterpret_cast<int*>(data) > slack) {
7893 *reinterpret_cast<int*>(data) = slack;
7894 }
7895 }
7896
7897
ShrinkInstanceSize(Map * map,void * data)7898 static void ShrinkInstanceSize(Map* map, void* data) {
7899 int slack = *reinterpret_cast<int*>(data);
7900 map->set_inobject_properties(map->inobject_properties() - slack);
7901 map->set_unused_property_fields(map->unused_property_fields() - slack);
7902 map->set_instance_size(map->instance_size() - slack * kPointerSize);
7903
7904 // Visitor id might depend on the instance size, recalculate it.
7905 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7906 }
7907
7908
CompleteInobjectSlackTracking()7909 void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7910 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7911 Map* map = Map::cast(initial_map());
7912
7913 Heap* heap = map->GetHeap();
7914 set_initial_map(heap->undefined_value());
7915 Builtins* builtins = heap->isolate()->builtins();
7916 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
7917 construct_stub());
7918 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
7919
7920 int slack = map->unused_property_fields();
7921 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7922 if (slack != 0) {
7923 // Resize the initial map and all maps in its transition tree.
7924 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
7925
7926 // Give the correct expected_nof_properties to initial maps created later.
7927 ASSERT(expected_nof_properties() >= slack);
7928 set_expected_nof_properties(expected_nof_properties() - slack);
7929 }
7930 }
7931
7932
SharedFunctionInfoIterateBody(ObjectVisitor * v)7933 void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
7934 v->VisitSharedFunctionInfo(this);
7935 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
7936 }
7937
7938
7939 #define DECLARE_TAG(ignore1, name, ignore2) name,
7940 const char* const VisitorSynchronization::kTags[
7941 VisitorSynchronization::kNumberOfSyncTags] = {
7942 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7943 };
7944 #undef DECLARE_TAG
7945
7946
7947 #define DECLARE_TAG(ignore1, ignore2, name) name,
7948 const char* const VisitorSynchronization::kTagNames[
7949 VisitorSynchronization::kNumberOfSyncTags] = {
7950 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7951 };
7952 #undef DECLARE_TAG
7953
7954
VisitCodeTarget(RelocInfo * rinfo)7955 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
7956 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
7957 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7958 Object* old_target = target;
7959 VisitPointer(&target);
7960 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7961 }
7962
7963
VisitCodeEntry(Address entry_address)7964 void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7965 Object* code = Code::GetObjectFromEntryAddress(entry_address);
7966 Object* old_code = code;
7967 VisitPointer(&code);
7968 if (code != old_code) {
7969 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7970 }
7971 }
7972
7973
VisitGlobalPropertyCell(RelocInfo * rinfo)7974 void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7975 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7976 Object* cell = rinfo->target_cell();
7977 Object* old_cell = cell;
7978 VisitPointer(&cell);
7979 if (cell != old_cell) {
7980 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7981 }
7982 }
7983
7984
VisitDebugTarget(RelocInfo * rinfo)7985 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
7986 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
7987 rinfo->IsPatchedReturnSequence()) ||
7988 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
7989 rinfo->IsPatchedDebugBreakSlotSequence()));
7990 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
7991 Object* old_target = target;
7992 VisitPointer(&target);
7993 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7994 }
7995
VisitEmbeddedPointer(RelocInfo * rinfo)7996 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
7997 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
7998 VisitPointer(rinfo->target_object_address());
7999 }
8000
VisitExternalReference(RelocInfo * rinfo)8001 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
8002 Address* p = rinfo->target_reference_address();
8003 VisitExternalReferences(p, p + 1);
8004 }
8005
InvalidateRelocation()8006 void Code::InvalidateRelocation() {
8007 set_relocation_info(GetHeap()->empty_byte_array());
8008 }
8009
8010
Relocate(intptr_t delta)8011 void Code::Relocate(intptr_t delta) {
8012 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
8013 it.rinfo()->apply(delta);
8014 }
8015 CPU::FlushICache(instruction_start(), instruction_size());
8016 }
8017
8018
CopyFrom(const CodeDesc & desc)8019 void Code::CopyFrom(const CodeDesc& desc) {
8020 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
8021
8022 // copy code
8023 memmove(instruction_start(), desc.buffer, desc.instr_size);
8024
8025 // copy reloc info
8026 memmove(relocation_start(),
8027 desc.buffer + desc.buffer_size - desc.reloc_size,
8028 desc.reloc_size);
8029
8030 // unbox handles and relocate
8031 intptr_t delta = instruction_start() - desc.buffer;
8032 int mode_mask = RelocInfo::kCodeTargetMask |
8033 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
8034 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
8035 RelocInfo::kApplyMask;
8036 Assembler* origin = desc.origin; // Needed to find target_object on X64.
8037 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
8038 RelocInfo::Mode mode = it.rinfo()->rmode();
8039 if (mode == RelocInfo::EMBEDDED_OBJECT) {
8040 Handle<Object> p = it.rinfo()->target_object_handle(origin);
8041 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
8042 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
8043 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
8044 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
8045 } else if (RelocInfo::IsCodeTarget(mode)) {
8046 // rewrite code handles in inline cache targets to direct
8047 // pointers to the first instruction in the code object
8048 Handle<Object> p = it.rinfo()->target_object_handle(origin);
8049 Code* code = Code::cast(*p);
8050 it.rinfo()->set_target_address(code->instruction_start(),
8051 SKIP_WRITE_BARRIER);
8052 } else {
8053 it.rinfo()->apply(delta);
8054 }
8055 }
8056 CPU::FlushICache(instruction_start(), instruction_size());
8057 }
8058
8059
8060 // Locate the source position which is closest to the address in the code. This
8061 // is using the source position information embedded in the relocation info.
8062 // The position returned is relative to the beginning of the script where the
8063 // source for this function is found.
SourcePosition(Address pc)8064 int Code::SourcePosition(Address pc) {
8065 int distance = kMaxInt;
8066 int position = RelocInfo::kNoPosition; // Initially no position found.
8067 // Run through all the relocation info to find the best matching source
8068 // position. All the code needs to be considered as the sequence of the
8069 // instructions in the code does not necessarily follow the same order as the
8070 // source.
8071 RelocIterator it(this, RelocInfo::kPositionMask);
8072 while (!it.done()) {
8073 // Only look at positions after the current pc.
8074 if (it.rinfo()->pc() < pc) {
8075 // Get position and distance.
8076
8077 int dist = static_cast<int>(pc - it.rinfo()->pc());
8078 int pos = static_cast<int>(it.rinfo()->data());
8079 // If this position is closer than the current candidate or if it has the
8080 // same distance as the current candidate and the position is higher then
8081 // this position is the new candidate.
8082 if ((dist < distance) ||
8083 (dist == distance && pos > position)) {
8084 position = pos;
8085 distance = dist;
8086 }
8087 }
8088 it.next();
8089 }
8090 return position;
8091 }
8092
8093
8094 // Same as Code::SourcePosition above except it only looks for statement
8095 // positions.
SourceStatementPosition(Address pc)8096 int Code::SourceStatementPosition(Address pc) {
8097 // First find the position as close as possible using all position
8098 // information.
8099 int position = SourcePosition(pc);
8100 // Now find the closest statement position before the position.
8101 int statement_position = 0;
8102 RelocIterator it(this, RelocInfo::kPositionMask);
8103 while (!it.done()) {
8104 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
8105 int p = static_cast<int>(it.rinfo()->data());
8106 if (statement_position < p && p <= position) {
8107 statement_position = p;
8108 }
8109 }
8110 it.next();
8111 }
8112 return statement_position;
8113 }
8114
8115
GetSafepointEntry(Address pc)8116 SafepointEntry Code::GetSafepointEntry(Address pc) {
8117 SafepointTable table(this);
8118 return table.FindEntry(pc);
8119 }
8120
8121
SetNoStackCheckTable()8122 void Code::SetNoStackCheckTable() {
8123 // Indicate the absence of a stack-check table by a table start after the
8124 // end of the instructions. Table start must be aligned, so round up.
8125 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
8126 }
8127
8128
FindFirstMap()8129 Map* Code::FindFirstMap() {
8130 ASSERT(is_inline_cache_stub());
8131 AssertNoAllocation no_allocation;
8132 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8133 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8134 RelocInfo* info = it.rinfo();
8135 Object* object = info->target_object();
8136 if (object->IsMap()) return Map::cast(object);
8137 }
8138 return NULL;
8139 }
8140
8141
ClearInlineCaches()8142 void Code::ClearInlineCaches() {
8143 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
8144 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
8145 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
8146 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
8147 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8148 RelocInfo* info = it.rinfo();
8149 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
8150 if (target->is_inline_cache_stub()) {
8151 IC::Clear(info->pc());
8152 }
8153 }
8154 }
8155
8156
8157 #ifdef ENABLE_DISASSEMBLER
8158
DeoptimizationInputDataPrint(FILE * out)8159 void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
8160 disasm::NameConverter converter;
8161 int deopt_count = DeoptCount();
8162 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
8163 if (0 == deopt_count) return;
8164
8165 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
8166 FLAG_print_code_verbose ? "commands" : "");
8167 for (int i = 0; i < deopt_count; i++) {
8168 PrintF(out, "%6d %6d %6d %6d",
8169 i,
8170 AstId(i)->value(),
8171 ArgumentsStackHeight(i)->value(),
8172 Pc(i)->value());
8173
8174 if (!FLAG_print_code_verbose) {
8175 PrintF(out, "\n");
8176 continue;
8177 }
8178 // Print details of the frame translation.
8179 int translation_index = TranslationIndex(i)->value();
8180 TranslationIterator iterator(TranslationByteArray(), translation_index);
8181 Translation::Opcode opcode =
8182 static_cast<Translation::Opcode>(iterator.Next());
8183 ASSERT(Translation::BEGIN == opcode);
8184 int frame_count = iterator.Next();
8185 int jsframe_count = iterator.Next();
8186 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
8187 Translation::StringFor(opcode),
8188 frame_count,
8189 jsframe_count);
8190
8191 while (iterator.HasNext() &&
8192 Translation::BEGIN !=
8193 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8194 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
8195
8196 switch (opcode) {
8197 case Translation::BEGIN:
8198 UNREACHABLE();
8199 break;
8200
8201 case Translation::JS_FRAME: {
8202 int ast_id = iterator.Next();
8203 int function_id = iterator.Next();
8204 JSFunction* function =
8205 JSFunction::cast(LiteralArray()->get(function_id));
8206 unsigned height = iterator.Next();
8207 PrintF(out, "{ast_id=%d, function=", ast_id);
8208 function->PrintName(out);
8209 PrintF(out, ", height=%u}", height);
8210 break;
8211 }
8212
8213 case Translation::ARGUMENTS_ADAPTOR_FRAME:
8214 case Translation::CONSTRUCT_STUB_FRAME: {
8215 int function_id = iterator.Next();
8216 JSFunction* function =
8217 JSFunction::cast(LiteralArray()->get(function_id));
8218 unsigned height = iterator.Next();
8219 PrintF(out, "{function=");
8220 function->PrintName(out);
8221 PrintF(out, ", height=%u}", height);
8222 break;
8223 }
8224
8225 case Translation::DUPLICATE:
8226 break;
8227
8228 case Translation::REGISTER: {
8229 int reg_code = iterator.Next();
8230 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8231 break;
8232 }
8233
8234 case Translation::INT32_REGISTER: {
8235 int reg_code = iterator.Next();
8236 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8237 break;
8238 }
8239
8240 case Translation::DOUBLE_REGISTER: {
8241 int reg_code = iterator.Next();
8242 PrintF(out, "{input=%s}",
8243 DoubleRegister::AllocationIndexToString(reg_code));
8244 break;
8245 }
8246
8247 case Translation::STACK_SLOT: {
8248 int input_slot_index = iterator.Next();
8249 PrintF(out, "{input=%d}", input_slot_index);
8250 break;
8251 }
8252
8253 case Translation::INT32_STACK_SLOT: {
8254 int input_slot_index = iterator.Next();
8255 PrintF(out, "{input=%d}", input_slot_index);
8256 break;
8257 }
8258
8259 case Translation::DOUBLE_STACK_SLOT: {
8260 int input_slot_index = iterator.Next();
8261 PrintF(out, "{input=%d}", input_slot_index);
8262 break;
8263 }
8264
8265 case Translation::LITERAL: {
8266 unsigned literal_index = iterator.Next();
8267 PrintF(out, "{literal_id=%u}", literal_index);
8268 break;
8269 }
8270
8271 case Translation::ARGUMENTS_OBJECT:
8272 break;
8273 }
8274 PrintF(out, "\n");
8275 }
8276 }
8277 }
8278
8279
DeoptimizationOutputDataPrint(FILE * out)8280 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8281 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
8282 this->DeoptPoints());
8283 if (this->DeoptPoints() == 0) return;
8284
8285 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
8286 for (int i = 0; i < this->DeoptPoints(); i++) {
8287 int pc_and_state = this->PcAndState(i)->value();
8288 PrintF("%6d %8d %s\n",
8289 this->AstId(i)->value(),
8290 FullCodeGenerator::PcField::decode(pc_and_state),
8291 FullCodeGenerator::State2String(
8292 FullCodeGenerator::StateField::decode(pc_and_state)));
8293 }
8294 }
8295
8296
8297 // Identify kind of code.
Kind2String(Kind kind)8298 const char* Code::Kind2String(Kind kind) {
8299 switch (kind) {
8300 case FUNCTION: return "FUNCTION";
8301 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
8302 case STUB: return "STUB";
8303 case BUILTIN: return "BUILTIN";
8304 case LOAD_IC: return "LOAD_IC";
8305 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8306 case STORE_IC: return "STORE_IC";
8307 case KEYED_STORE_IC: return "KEYED_STORE_IC";
8308 case CALL_IC: return "CALL_IC";
8309 case KEYED_CALL_IC: return "KEYED_CALL_IC";
8310 case UNARY_OP_IC: return "UNARY_OP_IC";
8311 case BINARY_OP_IC: return "BINARY_OP_IC";
8312 case COMPARE_IC: return "COMPARE_IC";
8313 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
8314 }
8315 UNREACHABLE();
8316 return NULL;
8317 }
8318
8319
ICState2String(InlineCacheState state)8320 const char* Code::ICState2String(InlineCacheState state) {
8321 switch (state) {
8322 case UNINITIALIZED: return "UNINITIALIZED";
8323 case PREMONOMORPHIC: return "PREMONOMORPHIC";
8324 case MONOMORPHIC: return "MONOMORPHIC";
8325 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8326 case MEGAMORPHIC: return "MEGAMORPHIC";
8327 case DEBUG_BREAK: return "DEBUG_BREAK";
8328 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8329 }
8330 UNREACHABLE();
8331 return NULL;
8332 }
8333
8334
PropertyType2String(PropertyType type)8335 const char* Code::PropertyType2String(PropertyType type) {
8336 switch (type) {
8337 case NORMAL: return "NORMAL";
8338 case FIELD: return "FIELD";
8339 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8340 case CALLBACKS: return "CALLBACKS";
8341 case HANDLER: return "HANDLER";
8342 case INTERCEPTOR: return "INTERCEPTOR";
8343 case MAP_TRANSITION: return "MAP_TRANSITION";
8344 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
8345 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8346 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8347 }
8348 UNREACHABLE(); // keep the compiler happy
8349 return NULL;
8350 }
8351
8352
PrintExtraICState(FILE * out,Kind kind,ExtraICState extra)8353 void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8354 const char* name = NULL;
8355 switch (kind) {
8356 case CALL_IC:
8357 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8358 name = "STRING_INDEX_OUT_OF_BOUNDS";
8359 }
8360 break;
8361 case STORE_IC:
8362 case KEYED_STORE_IC:
8363 if (extra == kStrictMode) {
8364 name = "STRICT";
8365 }
8366 break;
8367 default:
8368 break;
8369 }
8370 if (name != NULL) {
8371 PrintF(out, "extra_ic_state = %s\n", name);
8372 } else {
8373 PrintF(out, "extra_ic_state = %d\n", extra);
8374 }
8375 }
8376
8377
Disassemble(const char * name,FILE * out)8378 void Code::Disassemble(const char* name, FILE* out) {
8379 PrintF(out, "kind = %s\n", Kind2String(kind()));
8380 if (is_inline_cache_stub()) {
8381 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
8382 PrintExtraICState(out, kind(), extra_ic_state());
8383 if (ic_state() == MONOMORPHIC) {
8384 PrintF(out, "type = %s\n", PropertyType2String(type()));
8385 }
8386 if (is_call_stub() || is_keyed_call_stub()) {
8387 PrintF(out, "argc = %d\n", arguments_count());
8388 }
8389 }
8390 if ((name != NULL) && (name[0] != '\0')) {
8391 PrintF(out, "name = %s\n", name);
8392 }
8393 if (kind() == OPTIMIZED_FUNCTION) {
8394 PrintF(out, "stack_slots = %d\n", stack_slots());
8395 }
8396
8397 PrintF(out, "Instructions (size = %d)\n", instruction_size());
8398 Disassembler::Decode(out, this);
8399 PrintF(out, "\n");
8400
8401 if (kind() == FUNCTION) {
8402 DeoptimizationOutputData* data =
8403 DeoptimizationOutputData::cast(this->deoptimization_data());
8404 data->DeoptimizationOutputDataPrint(out);
8405 } else if (kind() == OPTIMIZED_FUNCTION) {
8406 DeoptimizationInputData* data =
8407 DeoptimizationInputData::cast(this->deoptimization_data());
8408 data->DeoptimizationInputDataPrint(out);
8409 }
8410 PrintF("\n");
8411
8412 if (kind() == OPTIMIZED_FUNCTION) {
8413 SafepointTable table(this);
8414 PrintF(out, "Safepoints (size = %u)\n", table.size());
8415 for (unsigned i = 0; i < table.length(); i++) {
8416 unsigned pc_offset = table.GetPcOffset(i);
8417 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
8418 table.PrintEntry(i);
8419 PrintF(out, " (sp -> fp)");
8420 SafepointEntry entry = table.GetEntry(i);
8421 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8422 PrintF(out, " %6d", entry.deoptimization_index());
8423 } else {
8424 PrintF(out, " <none>");
8425 }
8426 if (entry.argument_count() > 0) {
8427 PrintF(out, " argc: %d", entry.argument_count());
8428 }
8429 PrintF(out, "\n");
8430 }
8431 PrintF(out, "\n");
8432 } else if (kind() == FUNCTION) {
8433 unsigned offset = stack_check_table_offset();
8434 // If there is no stack check table, the "table start" will at or after
8435 // (due to alignment) the end of the instruction stream.
8436 if (static_cast<int>(offset) < instruction_size()) {
8437 unsigned* address =
8438 reinterpret_cast<unsigned*>(instruction_start() + offset);
8439 unsigned length = address[0];
8440 PrintF(out, "Stack checks (size = %u)\n", length);
8441 PrintF(out, "ast_id pc_offset\n");
8442 for (unsigned i = 0; i < length; ++i) {
8443 unsigned index = (2 * i) + 1;
8444 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
8445 }
8446 PrintF(out, "\n");
8447 }
8448 }
8449
8450 PrintF("RelocInfo (size = %d)\n", relocation_size());
8451 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8452 PrintF(out, "\n");
8453 }
8454 #endif // ENABLE_DISASSEMBLER
8455
8456
SetFastElementsCapacityAndLength(int capacity,int length,SetFastElementsCapacityMode set_capacity_mode)8457 MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8458 int capacity,
8459 int length,
8460 SetFastElementsCapacityMode set_capacity_mode) {
8461 Heap* heap = GetHeap();
8462 // We should never end in here with a pixel or external array.
8463 ASSERT(!HasExternalArrayElements());
8464
8465 // Allocate a new fast elements backing store.
8466 FixedArray* new_elements;
8467 { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8468 if (!maybe->To(&new_elements)) return maybe;
8469 }
8470
8471 // Find the new map to use for this object if there is a map change.
8472 Map* new_map = NULL;
8473 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
8474 // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8475 // it, or if it's allowed and the old elements array contained only SMIs.
8476 bool has_fast_smi_only_elements =
8477 (set_capacity_mode == kForceSmiOnlyElements) ||
8478 ((set_capacity_mode == kAllowSmiOnlyElements) &&
8479 (elements()->map()->has_fast_smi_only_elements() ||
8480 elements() == heap->empty_fixed_array()));
8481 ElementsKind elements_kind = has_fast_smi_only_elements
8482 ? FAST_SMI_ONLY_ELEMENTS
8483 : FAST_ELEMENTS;
8484 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
8485 if (!maybe->To(&new_map)) return maybe;
8486 }
8487
8488 FixedArrayBase* old_elements = elements();
8489 ElementsKind elements_kind = GetElementsKind();
8490 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8491 ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
8492 ? FAST_SMI_ONLY_ELEMENTS
8493 : FAST_ELEMENTS;
8494 // int copy_size = Min(old_elements_raw->length(), new_elements->length());
8495 accessor->CopyElements(this, new_elements, to_kind);
8496 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8497 set_map_and_elements(new_map, new_elements);
8498 } else {
8499 FixedArray* parameter_map = FixedArray::cast(old_elements);
8500 parameter_map->set(1, new_elements);
8501 }
8502
8503 if (FLAG_trace_elements_transitions) {
8504 PrintElementsTransition(stdout, elements_kind, old_elements,
8505 GetElementsKind(), new_elements);
8506 }
8507
8508 // Update the length if necessary.
8509 if (IsJSArray()) {
8510 JSArray::cast(this)->set_length(Smi::FromInt(length));
8511 }
8512
8513 return new_elements;
8514 }
8515
8516
SetFastDoubleElementsCapacityAndLength(int capacity,int length)8517 MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8518 int capacity,
8519 int length) {
8520 Heap* heap = GetHeap();
8521 // We should never end in here with a pixel or external array.
8522 ASSERT(!HasExternalArrayElements());
8523
8524 FixedArrayBase* elems;
8525 { MaybeObject* maybe_obj =
8526 heap->AllocateUninitializedFixedDoubleArray(capacity);
8527 if (!maybe_obj->To(&elems)) return maybe_obj;
8528 }
8529
8530 Map* new_map;
8531 { MaybeObject* maybe_obj =
8532 GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
8533 if (!maybe_obj->To(&new_map)) return maybe_obj;
8534 }
8535
8536 FixedArrayBase* old_elements = elements();
8537 ElementsKind elements_kind = GetElementsKind();
8538 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8539 accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
8540 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8541 set_map_and_elements(new_map, elems);
8542 } else {
8543 FixedArray* parameter_map = FixedArray::cast(old_elements);
8544 parameter_map->set(1, elems);
8545 }
8546
8547 if (FLAG_trace_elements_transitions) {
8548 PrintElementsTransition(stdout, elements_kind, old_elements,
8549 FAST_DOUBLE_ELEMENTS, elems);
8550 }
8551
8552 if (IsJSArray()) {
8553 JSArray::cast(this)->set_length(Smi::FromInt(length));
8554 }
8555
8556 return this;
8557 }
8558
8559
Initialize(int capacity)8560 MaybeObject* JSArray::Initialize(int capacity) {
8561 Heap* heap = GetHeap();
8562 ASSERT(capacity >= 0);
8563 set_length(Smi::FromInt(0));
8564 FixedArray* new_elements;
8565 if (capacity == 0) {
8566 new_elements = heap->empty_fixed_array();
8567 } else {
8568 MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
8569 if (!maybe_obj->To(&new_elements)) return maybe_obj;
8570 }
8571 set_elements(new_elements);
8572 return this;
8573 }
8574
8575
Expand(int required_size)8576 void JSArray::Expand(int required_size) {
8577 GetIsolate()->factory()->SetElementsCapacityAndLength(
8578 Handle<JSArray>(this), required_size, required_size);
8579 }
8580
8581
SetElementsLength(Object * len)8582 MaybeObject* JSArray::SetElementsLength(Object* len) {
8583 // We should never end in here with a pixel or external array.
8584 ASSERT(AllowsSetElementsLength());
8585 return GetElementsAccessor()->SetLength(this, len);
8586 }
8587
8588
GetPrototypeTransition(Object * prototype)8589 Object* Map::GetPrototypeTransition(Object* prototype) {
8590 FixedArray* cache = prototype_transitions();
8591 int number_of_transitions = NumberOfProtoTransitions();
8592 const int proto_offset =
8593 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8594 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8595 const int step = kProtoTransitionElementsPerEntry;
8596 for (int i = 0; i < number_of_transitions; i++) {
8597 if (cache->get(proto_offset + i * step) == prototype) {
8598 Object* map = cache->get(map_offset + i * step);
8599 ASSERT(map->IsMap());
8600 return map;
8601 }
8602 }
8603 return NULL;
8604 }
8605
8606
PutPrototypeTransition(Object * prototype,Map * map)8607 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
8608 ASSERT(map->IsMap());
8609 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
8610 // Don't cache prototype transition if this map is shared.
8611 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8612
8613 FixedArray* cache = prototype_transitions();
8614
8615 const int step = kProtoTransitionElementsPerEntry;
8616 const int header = kProtoTransitionHeaderSize;
8617
8618 int capacity = (cache->length() - header) / step;
8619
8620 int transitions = NumberOfProtoTransitions() + 1;
8621
8622 if (transitions > capacity) {
8623 if (capacity > kMaxCachedPrototypeTransitions) return this;
8624
8625 FixedArray* new_cache;
8626 // Grow array by factor 2 over and above what we need.
8627 { MaybeObject* maybe_cache =
8628 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
8629 if (!maybe_cache->To(&new_cache)) return maybe_cache;
8630 }
8631
8632 for (int i = 0; i < capacity * step; i++) {
8633 new_cache->set(i + header, cache->get(i + header));
8634 }
8635 cache = new_cache;
8636 set_prototype_transitions(cache);
8637 }
8638
8639 int last = transitions - 1;
8640
8641 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8642 cache->set(header + last * step + kProtoTransitionMapOffset, map);
8643 SetNumberOfProtoTransitions(transitions);
8644
8645 return cache;
8646 }
8647
8648
SetPrototype(Object * value,bool skip_hidden_prototypes)8649 MaybeObject* JSReceiver::SetPrototype(Object* value,
8650 bool skip_hidden_prototypes) {
8651 #ifdef DEBUG
8652 int size = Size();
8653 #endif
8654
8655 Heap* heap = GetHeap();
8656 // Silently ignore the change if value is not a JSObject or null.
8657 // SpiderMonkey behaves this way.
8658 if (!value->IsJSReceiver() && !value->IsNull()) return value;
8659
8660 // From 8.6.2 Object Internal Methods
8661 // ...
8662 // In addition, if [[Extensible]] is false the value of the [[Class]] and
8663 // [[Prototype]] internal properties of the object may not be modified.
8664 // ...
8665 // Implementation specific extensions that modify [[Class]], [[Prototype]]
8666 // or [[Extensible]] must not violate the invariants defined in the preceding
8667 // paragraph.
8668 if (!this->map()->is_extensible()) {
8669 HandleScope scope(heap->isolate());
8670 Handle<Object> handle(this, heap->isolate());
8671 return heap->isolate()->Throw(
8672 *FACTORY->NewTypeError("non_extensible_proto",
8673 HandleVector<Object>(&handle, 1)));
8674 }
8675
8676 // Before we can set the prototype we need to be sure
8677 // prototype cycles are prevented.
8678 // It is sufficient to validate that the receiver is not in the new prototype
8679 // chain.
8680 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
8681 if (JSReceiver::cast(pt) == this) {
8682 // Cycle detected.
8683 HandleScope scope(heap->isolate());
8684 return heap->isolate()->Throw(
8685 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
8686 }
8687 }
8688
8689 JSReceiver* real_receiver = this;
8690
8691 if (skip_hidden_prototypes) {
8692 // Find the first object in the chain whose prototype object is not
8693 // hidden and set the new prototype on that object.
8694 Object* current_proto = real_receiver->GetPrototype();
8695 while (current_proto->IsJSObject() &&
8696 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8697 real_receiver = JSReceiver::cast(current_proto);
8698 current_proto = current_proto->GetPrototype();
8699 }
8700 }
8701
8702 // Set the new prototype of the object.
8703 Map* map = real_receiver->map();
8704
8705 // Nothing to do if prototype is already set.
8706 if (map->prototype() == value) return value;
8707
8708 Object* new_map = map->GetPrototypeTransition(value);
8709 if (new_map == NULL) {
8710 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8711 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8712 }
8713
8714 { MaybeObject* maybe_new_cache =
8715 map->PutPrototypeTransition(value, Map::cast(new_map));
8716 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8717 }
8718
8719 Map::cast(new_map)->set_prototype(value);
8720 }
8721 ASSERT(Map::cast(new_map)->prototype() == value);
8722 real_receiver->set_map(Map::cast(new_map));
8723
8724 heap->ClearInstanceofCache();
8725 ASSERT(size == Size());
8726 return value;
8727 }
8728
8729
EnsureCanContainElements(Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)8730 MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8731 uint32_t first_arg,
8732 uint32_t arg_count,
8733 EnsureElementsMode mode) {
8734 // Elements in |Arguments| are ordered backwards (because they're on the
8735 // stack), but the method that's called here iterates over them in forward
8736 // direction.
8737 return EnsureCanContainElements(
8738 args->arguments() - first_arg - (arg_count - 1),
8739 arg_count, mode);
8740 }
8741
8742
HasElementWithInterceptor(JSReceiver * receiver,uint32_t index)8743 bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
8744 Isolate* isolate = GetIsolate();
8745 // Make sure that the top context does not change when doing
8746 // callbacks or interceptor calls.
8747 AssertNoContextChange ncc;
8748 HandleScope scope(isolate);
8749 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8750 Handle<JSReceiver> receiver_handle(receiver);
8751 Handle<JSObject> holder_handle(this);
8752 CustomArguments args(isolate, interceptor->data(), receiver, this);
8753 v8::AccessorInfo info(args.end());
8754 if (!interceptor->query()->IsUndefined()) {
8755 v8::IndexedPropertyQuery query =
8756 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
8757 LOG(isolate,
8758 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
8759 v8::Handle<v8::Integer> result;
8760 {
8761 // Leaving JavaScript.
8762 VMState state(isolate, EXTERNAL);
8763 result = query(index, info);
8764 }
8765 if (!result.IsEmpty()) {
8766 ASSERT(result->IsInt32());
8767 return true; // absence of property is signaled by empty handle.
8768 }
8769 } else if (!interceptor->getter()->IsUndefined()) {
8770 v8::IndexedPropertyGetter getter =
8771 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
8772 LOG(isolate,
8773 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
8774 v8::Handle<v8::Value> result;
8775 {
8776 // Leaving JavaScript.
8777 VMState state(isolate, EXTERNAL);
8778 result = getter(index, info);
8779 }
8780 if (!result.IsEmpty()) return true;
8781 }
8782
8783 if (holder_handle->GetElementsAccessor()->HasElement(
8784 *receiver_handle, *holder_handle, index)) {
8785 return true;
8786 }
8787
8788 if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
8789 Object* pt = holder_handle->GetPrototype();
8790 if (pt->IsJSProxy()) {
8791 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8792 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8793 receiver, index) != ABSENT;
8794 }
8795 if (pt->IsNull()) return false;
8796 return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
8797 }
8798
8799
HasLocalElement(uint32_t index)8800 JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
8801 // Check access rights if needed.
8802 if (IsAccessCheckNeeded()) {
8803 Heap* heap = GetHeap();
8804 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8805 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8806 return UNDEFINED_ELEMENT;
8807 }
8808 }
8809
8810 if (IsJSGlobalProxy()) {
8811 Object* proto = GetPrototype();
8812 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8813 ASSERT(proto->IsJSGlobalObject());
8814 return JSObject::cast(proto)->HasLocalElement(index);
8815 }
8816
8817 // Check for lookup interceptor
8818 if (HasIndexedInterceptor()) {
8819 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8820 : UNDEFINED_ELEMENT;
8821 }
8822
8823 // Handle [] on String objects.
8824 if (this->IsStringObjectWithCharacterAt(index)) {
8825 return STRING_CHARACTER_ELEMENT;
8826 }
8827
8828 switch (GetElementsKind()) {
8829 case FAST_SMI_ONLY_ELEMENTS:
8830 case FAST_ELEMENTS: {
8831 uint32_t length = IsJSArray() ?
8832 static_cast<uint32_t>
8833 (Smi::cast(JSArray::cast(this)->length())->value()) :
8834 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8835 if ((index < length) &&
8836 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8837 return FAST_ELEMENT;
8838 }
8839 break;
8840 }
8841 case FAST_DOUBLE_ELEMENTS: {
8842 uint32_t length = IsJSArray() ?
8843 static_cast<uint32_t>
8844 (Smi::cast(JSArray::cast(this)->length())->value()) :
8845 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8846 if ((index < length) &&
8847 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8848 return FAST_ELEMENT;
8849 }
8850 break;
8851 }
8852 case EXTERNAL_PIXEL_ELEMENTS: {
8853 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
8854 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8855 break;
8856 }
8857 case EXTERNAL_BYTE_ELEMENTS:
8858 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8859 case EXTERNAL_SHORT_ELEMENTS:
8860 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8861 case EXTERNAL_INT_ELEMENTS:
8862 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8863 case EXTERNAL_FLOAT_ELEMENTS:
8864 case EXTERNAL_DOUBLE_ELEMENTS: {
8865 ExternalArray* array = ExternalArray::cast(elements());
8866 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8867 break;
8868 }
8869 case DICTIONARY_ELEMENTS: {
8870 if (element_dictionary()->FindEntry(index) !=
8871 SeededNumberDictionary::kNotFound) {
8872 return DICTIONARY_ELEMENT;
8873 }
8874 break;
8875 }
8876 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8877 // Aliased parameters and non-aliased elements in a fast backing store
8878 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8879 // backing store behave as DICTIONARY_ELEMENT.
8880 FixedArray* parameter_map = FixedArray::cast(elements());
8881 uint32_t length = parameter_map->length();
8882 Object* probe =
8883 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8884 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8885 // If not aliased, check the arguments.
8886 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8887 if (arguments->IsDictionary()) {
8888 SeededNumberDictionary* dictionary =
8889 SeededNumberDictionary::cast(arguments);
8890 if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
8891 return DICTIONARY_ELEMENT;
8892 }
8893 } else {
8894 length = arguments->length();
8895 probe = (index < length) ? arguments->get(index) : NULL;
8896 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8897 }
8898 break;
8899 }
8900 }
8901
8902 return UNDEFINED_ELEMENT;
8903 }
8904
8905
HasElementWithReceiver(JSReceiver * receiver,uint32_t index)8906 bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
8907 // Check access rights if needed.
8908 if (IsAccessCheckNeeded()) {
8909 Heap* heap = GetHeap();
8910 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8911 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8912 return false;
8913 }
8914 }
8915
8916 // Check for lookup interceptor
8917 if (HasIndexedInterceptor()) {
8918 return HasElementWithInterceptor(receiver, index);
8919 }
8920
8921 ElementsAccessor* accessor = GetElementsAccessor();
8922 if (accessor->HasElement(receiver, this, index)) {
8923 return true;
8924 }
8925
8926 // Handle [] on String objects.
8927 if (this->IsStringObjectWithCharacterAt(index)) return true;
8928
8929 Object* pt = GetPrototype();
8930 if (pt->IsNull()) return false;
8931 if (pt->IsJSProxy()) {
8932 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8933 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8934 receiver, index) != ABSENT;
8935 }
8936 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8937 }
8938
8939
SetElementWithInterceptor(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)8940 MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
8941 Object* value,
8942 PropertyAttributes attributes,
8943 StrictModeFlag strict_mode,
8944 bool check_prototype,
8945 SetPropertyMode set_mode) {
8946 Isolate* isolate = GetIsolate();
8947 // Make sure that the top context does not change when doing
8948 // callbacks or interceptor calls.
8949 AssertNoContextChange ncc;
8950 HandleScope scope(isolate);
8951 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8952 Handle<JSObject> this_handle(this);
8953 Handle<Object> value_handle(value, isolate);
8954 if (!interceptor->setter()->IsUndefined()) {
8955 v8::IndexedPropertySetter setter =
8956 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
8957 LOG(isolate,
8958 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8959 CustomArguments args(isolate, interceptor->data(), this, this);
8960 v8::AccessorInfo info(args.end());
8961 v8::Handle<v8::Value> result;
8962 {
8963 // Leaving JavaScript.
8964 VMState state(isolate, EXTERNAL);
8965 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8966 }
8967 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8968 if (!result.IsEmpty()) return *value_handle;
8969 }
8970 MaybeObject* raw_result =
8971 this_handle->SetElementWithoutInterceptor(index,
8972 *value_handle,
8973 attributes,
8974 strict_mode,
8975 check_prototype,
8976 set_mode);
8977 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8978 return raw_result;
8979 }
8980
8981
GetElementWithCallback(Object * receiver,Object * structure,uint32_t index,Object * holder)8982 MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8983 Object* structure,
8984 uint32_t index,
8985 Object* holder) {
8986 Isolate* isolate = GetIsolate();
8987 ASSERT(!structure->IsForeign());
8988
8989 // api style callbacks.
8990 if (structure->IsAccessorInfo()) {
8991 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
8992 Object* fun_obj = data->getter();
8993 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
8994 HandleScope scope(isolate);
8995 Handle<JSObject> self(JSObject::cast(receiver));
8996 Handle<JSObject> holder_handle(JSObject::cast(holder));
8997 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8998 Handle<String> key = isolate->factory()->NumberToString(number);
8999 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
9000 CustomArguments args(isolate, data->data(), *self, *holder_handle);
9001 v8::AccessorInfo info(args.end());
9002 v8::Handle<v8::Value> result;
9003 {
9004 // Leaving JavaScript.
9005 VMState state(isolate, EXTERNAL);
9006 result = call_fun(v8::Utils::ToLocal(key), info);
9007 }
9008 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9009 if (result.IsEmpty()) return isolate->heap()->undefined_value();
9010 return *v8::Utils::OpenHandle(*result);
9011 }
9012
9013 // __defineGetter__ callback
9014 if (structure->IsAccessorPair()) {
9015 Object* getter = AccessorPair::cast(structure)->getter();
9016 if (getter->IsSpecFunction()) {
9017 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9018 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
9019 }
9020 // Getter is not a function.
9021 return isolate->heap()->undefined_value();
9022 }
9023
9024 UNREACHABLE();
9025 return NULL;
9026 }
9027
9028
SetElementWithCallback(Object * structure,uint32_t index,Object * value,JSObject * holder,StrictModeFlag strict_mode)9029 MaybeObject* JSObject::SetElementWithCallback(Object* structure,
9030 uint32_t index,
9031 Object* value,
9032 JSObject* holder,
9033 StrictModeFlag strict_mode) {
9034 Isolate* isolate = GetIsolate();
9035 HandleScope scope(isolate);
9036
9037 // We should never get here to initialize a const with the hole
9038 // value since a const declaration would conflict with the setter.
9039 ASSERT(!value->IsTheHole());
9040 Handle<Object> value_handle(value, isolate);
9041
9042 // To accommodate both the old and the new api we switch on the
9043 // data structure used to store the callbacks. Eventually foreign
9044 // callbacks should be phased out.
9045 ASSERT(!structure->IsForeign());
9046
9047 if (structure->IsAccessorInfo()) {
9048 // api style callbacks
9049 Handle<JSObject> self(this);
9050 Handle<JSObject> holder_handle(JSObject::cast(holder));
9051 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
9052 Object* call_obj = data->setter();
9053 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9054 if (call_fun == NULL) return value;
9055 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9056 Handle<String> key(isolate->factory()->NumberToString(number));
9057 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9058 CustomArguments args(isolate, data->data(), *self, *holder_handle);
9059 v8::AccessorInfo info(args.end());
9060 {
9061 // Leaving JavaScript.
9062 VMState state(isolate, EXTERNAL);
9063 call_fun(v8::Utils::ToLocal(key),
9064 v8::Utils::ToLocal(value_handle),
9065 info);
9066 }
9067 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9068 return *value_handle;
9069 }
9070
9071 if (structure->IsAccessorPair()) {
9072 Handle<Object> setter(AccessorPair::cast(structure)->setter());
9073 if (setter->IsSpecFunction()) {
9074 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9075 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
9076 } else {
9077 if (strict_mode == kNonStrictMode) {
9078 return value;
9079 }
9080 Handle<Object> holder_handle(holder, isolate);
9081 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
9082 Handle<Object> args[2] = { key, holder_handle };
9083 return isolate->Throw(
9084 *isolate->factory()->NewTypeError("no_setter_in_callback",
9085 HandleVector(args, 2)));
9086 }
9087 }
9088
9089 UNREACHABLE();
9090 return NULL;
9091 }
9092
9093
HasFastArgumentsElements()9094 bool JSObject::HasFastArgumentsElements() {
9095 Heap* heap = GetHeap();
9096 if (!elements()->IsFixedArray()) return false;
9097 FixedArray* elements = FixedArray::cast(this->elements());
9098 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9099 return false;
9100 }
9101 FixedArray* arguments = FixedArray::cast(elements->get(1));
9102 return !arguments->IsDictionary();
9103 }
9104
9105
HasDictionaryArgumentsElements()9106 bool JSObject::HasDictionaryArgumentsElements() {
9107 Heap* heap = GetHeap();
9108 if (!elements()->IsFixedArray()) return false;
9109 FixedArray* elements = FixedArray::cast(this->elements());
9110 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9111 return false;
9112 }
9113 FixedArray* arguments = FixedArray::cast(elements->get(1));
9114 return arguments->IsDictionary();
9115 }
9116
9117
9118 // Adding n elements in fast case is O(n*n).
9119 // Note: revisit design to have dual undefined values to capture absent
9120 // elements.
SetFastElement(uint32_t index,Object * value,StrictModeFlag strict_mode,bool check_prototype)9121 MaybeObject* JSObject::SetFastElement(uint32_t index,
9122 Object* value,
9123 StrictModeFlag strict_mode,
9124 bool check_prototype) {
9125 ASSERT(HasFastTypeElements() ||
9126 HasFastArgumentsElements());
9127
9128 FixedArray* backing_store = FixedArray::cast(elements());
9129 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9130 backing_store = FixedArray::cast(backing_store->get(1));
9131 } else {
9132 MaybeObject* maybe = EnsureWritableFastElements();
9133 if (!maybe->To(&backing_store)) return maybe;
9134 }
9135 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
9136
9137 if (check_prototype &&
9138 (index >= capacity || backing_store->get(index)->IsTheHole())) {
9139 bool found;
9140 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9141 value,
9142 &found,
9143 strict_mode);
9144 if (found) return result;
9145 }
9146
9147 uint32_t new_capacity = capacity;
9148 // Check if the length property of this object needs to be updated.
9149 uint32_t array_length = 0;
9150 bool must_update_array_length = false;
9151 if (IsJSArray()) {
9152 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9153 if (index >= array_length) {
9154 must_update_array_length = true;
9155 array_length = index + 1;
9156 }
9157 }
9158 // Check if the capacity of the backing store needs to be increased, or if
9159 // a transition to slow elements is necessary.
9160 if (index >= capacity) {
9161 bool convert_to_slow = true;
9162 if ((index - capacity) < kMaxGap) {
9163 new_capacity = NewElementsCapacity(index + 1);
9164 ASSERT(new_capacity > index);
9165 if (!ShouldConvertToSlowElements(new_capacity)) {
9166 convert_to_slow = false;
9167 }
9168 }
9169 if (convert_to_slow) {
9170 MaybeObject* result = NormalizeElements();
9171 if (result->IsFailure()) return result;
9172 return SetDictionaryElement(index, value, NONE, strict_mode,
9173 check_prototype);
9174 }
9175 }
9176 // Convert to fast double elements if appropriate.
9177 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9178 MaybeObject* maybe =
9179 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9180 if (maybe->IsFailure()) return maybe;
9181 FixedDoubleArray::cast(elements())->set(index, value->Number());
9182 return value;
9183 }
9184 // Change elements kind from SMI_ONLY to generic FAST if necessary.
9185 if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9186 Map* new_map;
9187 { MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9188 FAST_ELEMENTS);
9189 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9190 }
9191 set_map(new_map);
9192 if (FLAG_trace_elements_transitions) {
9193 PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9194 FAST_ELEMENTS, elements());
9195 }
9196 }
9197 // Increase backing store capacity if that's been decided previously.
9198 if (new_capacity != capacity) {
9199 FixedArray* new_elements;
9200 SetFastElementsCapacityMode set_capacity_mode =
9201 value->IsSmi() && HasFastSmiOnlyElements()
9202 ? kAllowSmiOnlyElements
9203 : kDontAllowSmiOnlyElements;
9204 { MaybeObject* maybe =
9205 SetFastElementsCapacityAndLength(new_capacity,
9206 array_length,
9207 set_capacity_mode);
9208 if (!maybe->To(&new_elements)) return maybe;
9209 }
9210 new_elements->set(index, value);
9211 return value;
9212 }
9213 // Finally, set the new element and length.
9214 ASSERT(elements()->IsFixedArray());
9215 backing_store->set(index, value);
9216 if (must_update_array_length) {
9217 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9218 }
9219 return value;
9220 }
9221
9222
SetDictionaryElement(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)9223 MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9224 Object* value,
9225 PropertyAttributes attributes,
9226 StrictModeFlag strict_mode,
9227 bool check_prototype,
9228 SetPropertyMode set_mode) {
9229 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9230 Isolate* isolate = GetIsolate();
9231 Heap* heap = isolate->heap();
9232
9233 // Insert element in the dictionary.
9234 FixedArray* elements = FixedArray::cast(this->elements());
9235 bool is_arguments =
9236 (elements->map() == heap->non_strict_arguments_elements_map());
9237 SeededNumberDictionary* dictionary = NULL;
9238 if (is_arguments) {
9239 dictionary = SeededNumberDictionary::cast(elements->get(1));
9240 } else {
9241 dictionary = SeededNumberDictionary::cast(elements);
9242 }
9243
9244 int entry = dictionary->FindEntry(index);
9245 if (entry != SeededNumberDictionary::kNotFound) {
9246 Object* element = dictionary->ValueAt(entry);
9247 PropertyDetails details = dictionary->DetailsAt(entry);
9248 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
9249 return SetElementWithCallback(element, index, value, this, strict_mode);
9250 } else {
9251 dictionary->UpdateMaxNumberKey(index);
9252 // If a value has not been initialized we allow writing to it even if it
9253 // is read-only (a declared const that has not been initialized). If a
9254 // value is being defined we skip attribute checks completely.
9255 if (set_mode == DEFINE_PROPERTY) {
9256 details = PropertyDetails(attributes, NORMAL, details.index());
9257 dictionary->DetailsAtPut(entry, details);
9258 } else if (details.IsReadOnly() && !element->IsTheHole()) {
9259 if (strict_mode == kNonStrictMode) {
9260 return isolate->heap()->undefined_value();
9261 } else {
9262 Handle<Object> holder(this);
9263 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9264 Handle<Object> args[2] = { number, holder };
9265 Handle<Object> error =
9266 isolate->factory()->NewTypeError("strict_read_only_property",
9267 HandleVector(args, 2));
9268 return isolate->Throw(*error);
9269 }
9270 }
9271 // Elements of the arguments object in slow mode might be slow aliases.
9272 if (is_arguments && element->IsAliasedArgumentsEntry()) {
9273 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
9274 Context* context = Context::cast(elements->get(0));
9275 int context_index = entry->aliased_context_slot();
9276 ASSERT(!context->get(context_index)->IsTheHole());
9277 context->set(context_index, value);
9278 // For elements that are still writable we keep slow aliasing.
9279 if (!details.IsReadOnly()) value = element;
9280 }
9281 dictionary->ValueAtPut(entry, value);
9282 }
9283 } else {
9284 // Index not already used. Look for an accessor in the prototype chain.
9285 if (check_prototype) {
9286 bool found;
9287 MaybeObject* result =
9288 SetElementWithCallbackSetterInPrototypes(
9289 index, value, &found, strict_mode);
9290 if (found) return result;
9291 }
9292 // When we set the is_extensible flag to false we always force the
9293 // element into dictionary mode (and force them to stay there).
9294 if (!map()->is_extensible()) {
9295 if (strict_mode == kNonStrictMode) {
9296 return isolate->heap()->undefined_value();
9297 } else {
9298 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9299 Handle<String> name = isolate->factory()->NumberToString(number);
9300 Handle<Object> args[1] = { name };
9301 Handle<Object> error =
9302 isolate->factory()->NewTypeError("object_not_extensible",
9303 HandleVector(args, 1));
9304 return isolate->Throw(*error);
9305 }
9306 }
9307 FixedArrayBase* new_dictionary;
9308 PropertyDetails details = PropertyDetails(attributes, NORMAL);
9309 MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details);
9310 if (!maybe->To(&new_dictionary)) return maybe;
9311 if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
9312 if (is_arguments) {
9313 elements->set(1, new_dictionary);
9314 } else {
9315 set_elements(new_dictionary);
9316 }
9317 dictionary = SeededNumberDictionary::cast(new_dictionary);
9318 }
9319 }
9320
9321 // Update the array length if this JSObject is an array.
9322 if (IsJSArray()) {
9323 MaybeObject* result =
9324 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9325 if (result->IsFailure()) return result;
9326 }
9327
9328 // Attempt to put this object back in fast case.
9329 if (ShouldConvertToFastElements()) {
9330 uint32_t new_length = 0;
9331 if (IsJSArray()) {
9332 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9333 } else {
9334 new_length = dictionary->max_number_key() + 1;
9335 }
9336 SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9337 ? kAllowSmiOnlyElements
9338 : kDontAllowSmiOnlyElements;
9339 bool has_smi_only_elements = false;
9340 bool should_convert_to_fast_double_elements =
9341 ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9342 if (has_smi_only_elements) {
9343 set_capacity_mode = kForceSmiOnlyElements;
9344 }
9345 MaybeObject* result = should_convert_to_fast_double_elements
9346 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
9347 : SetFastElementsCapacityAndLength(new_length,
9348 new_length,
9349 set_capacity_mode);
9350 if (result->IsFailure()) return result;
9351 #ifdef DEBUG
9352 if (FLAG_trace_normalization) {
9353 PrintF("Object elements are fast case again:\n");
9354 Print();
9355 }
9356 #endif
9357 }
9358 return value;
9359 }
9360
9361
SetFastDoubleElement(uint32_t index,Object * value,StrictModeFlag strict_mode,bool check_prototype)9362 MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9363 uint32_t index,
9364 Object* value,
9365 StrictModeFlag strict_mode,
9366 bool check_prototype) {
9367 ASSERT(HasFastDoubleElements());
9368
9369 FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
9370 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
9371
9372 // If storing to an element that isn't in the array, pass the store request
9373 // up the prototype chain before storing in the receiver's elements.
9374 if (check_prototype &&
9375 (index >= elms_length ||
9376 FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
9377 bool found;
9378 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9379 value,
9380 &found,
9381 strict_mode);
9382 if (found) return result;
9383 }
9384
9385 // If the value object is not a heap number, switch to fast elements and try
9386 // again.
9387 bool value_is_smi = value->IsSmi();
9388 if (!value->IsNumber()) {
9389 Object* obj;
9390 uint32_t length = elms_length;
9391 if (IsJSArray()) {
9392 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9393 }
9394 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9395 elms_length,
9396 length,
9397 kDontAllowSmiOnlyElements);
9398 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9399 return SetFastElement(index,
9400 value,
9401 strict_mode,
9402 check_prototype);
9403 }
9404
9405 double double_value = value_is_smi
9406 ? static_cast<double>(Smi::cast(value)->value())
9407 : HeapNumber::cast(value)->value();
9408
9409 // Check whether there is extra space in the fixed array.
9410 if (index < elms_length) {
9411 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9412 elms->set(index, double_value);
9413 if (IsJSArray()) {
9414 // Update the length of the array if needed.
9415 uint32_t array_length = 0;
9416 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9417 if (index >= array_length) {
9418 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
9419 }
9420 }
9421 return value;
9422 }
9423
9424 // Allow gap in fast case.
9425 if ((index - elms_length) < kMaxGap) {
9426 // Try allocating extra space.
9427 int new_capacity = NewElementsCapacity(index+1);
9428 if (!ShouldConvertToSlowElements(new_capacity)) {
9429 ASSERT(static_cast<uint32_t>(new_capacity) > index);
9430 Object* obj;
9431 { MaybeObject* maybe_obj =
9432 SetFastDoubleElementsCapacityAndLength(new_capacity,
9433 index + 1);
9434 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9435 }
9436 FixedDoubleArray::cast(elements())->set(index, double_value);
9437 return value;
9438 }
9439 }
9440
9441 // Otherwise default to slow case.
9442 ASSERT(HasFastDoubleElements());
9443 ASSERT(map()->has_fast_double_elements());
9444 ASSERT(elements()->IsFixedDoubleArray());
9445 Object* obj;
9446 { MaybeObject* maybe_obj = NormalizeElements();
9447 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9448 }
9449 ASSERT(HasDictionaryElements());
9450 return SetElement(index, value, NONE, strict_mode, check_prototype);
9451 }
9452
9453
SetElement(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_proto)9454 MaybeObject* JSReceiver::SetElement(uint32_t index,
9455 Object* value,
9456 PropertyAttributes attributes,
9457 StrictModeFlag strict_mode,
9458 bool check_proto) {
9459 if (IsJSProxy()) {
9460 return JSProxy::cast(this)->SetElementWithHandler(
9461 index, value, strict_mode);
9462 } else {
9463 return JSObject::cast(this)->SetElement(
9464 index, value, attributes, strict_mode, check_proto);
9465 }
9466 }
9467
9468
SetOwnElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,StrictModeFlag strict_mode)9469 Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9470 uint32_t index,
9471 Handle<Object> value,
9472 StrictModeFlag strict_mode) {
9473 ASSERT(!object->HasExternalArrayElements());
9474 CALL_HEAP_FUNCTION(
9475 object->GetIsolate(),
9476 object->SetElement(index, *value, NONE, strict_mode, false),
9477 Object);
9478 }
9479
9480
SetElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attr,StrictModeFlag strict_mode,SetPropertyMode set_mode)9481 Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9482 uint32_t index,
9483 Handle<Object> value,
9484 PropertyAttributes attr,
9485 StrictModeFlag strict_mode,
9486 SetPropertyMode set_mode) {
9487 if (object->HasExternalArrayElements()) {
9488 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9489 bool has_exception;
9490 Handle<Object> number = Execution::ToNumber(value, &has_exception);
9491 if (has_exception) return Handle<Object>();
9492 value = number;
9493 }
9494 }
9495 CALL_HEAP_FUNCTION(
9496 object->GetIsolate(),
9497 object->SetElement(index, *value, attr, strict_mode, true, set_mode),
9498 Object);
9499 }
9500
9501
SetElement(uint32_t index,Object * value,PropertyAttributes attributes,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)9502 MaybeObject* JSObject::SetElement(uint32_t index,
9503 Object* value,
9504 PropertyAttributes attributes,
9505 StrictModeFlag strict_mode,
9506 bool check_prototype,
9507 SetPropertyMode set_mode) {
9508 // Check access rights if needed.
9509 if (IsAccessCheckNeeded()) {
9510 Heap* heap = GetHeap();
9511 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
9512 HandleScope scope(heap->isolate());
9513 Handle<Object> value_handle(value);
9514 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9515 return *value_handle;
9516 }
9517 }
9518
9519 if (IsJSGlobalProxy()) {
9520 Object* proto = GetPrototype();
9521 if (proto->IsNull()) return value;
9522 ASSERT(proto->IsJSGlobalObject());
9523 return JSObject::cast(proto)->SetElement(index,
9524 value,
9525 attributes,
9526 strict_mode,
9527 check_prototype,
9528 set_mode);
9529 }
9530
9531 // Don't allow element properties to be redefined for external arrays.
9532 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
9533 Isolate* isolate = GetHeap()->isolate();
9534 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9535 Handle<Object> args[] = { Handle<Object>(this), number };
9536 Handle<Object> error = isolate->factory()->NewTypeError(
9537 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
9538 return isolate->Throw(*error);
9539 }
9540
9541 // Normalize the elements to enable attributes on the property.
9542 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
9543 SeededNumberDictionary* dictionary;
9544 MaybeObject* maybe_object = NormalizeElements();
9545 if (!maybe_object->To(&dictionary)) return maybe_object;
9546 // Make sure that we never go back to fast case.
9547 dictionary->set_requires_slow_elements();
9548 }
9549
9550 // Check for lookup interceptor
9551 if (HasIndexedInterceptor()) {
9552 return SetElementWithInterceptor(index,
9553 value,
9554 attributes,
9555 strict_mode,
9556 check_prototype,
9557 set_mode);
9558 }
9559
9560 return SetElementWithoutInterceptor(index,
9561 value,
9562 attributes,
9563 strict_mode,
9564 check_prototype,
9565 set_mode);
9566 }
9567
9568
SetElementWithoutInterceptor(uint32_t index,Object * value,PropertyAttributes attr,StrictModeFlag strict_mode,bool check_prototype,SetPropertyMode set_mode)9569 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
9570 Object* value,
9571 PropertyAttributes attr,
9572 StrictModeFlag strict_mode,
9573 bool check_prototype,
9574 SetPropertyMode set_mode) {
9575 ASSERT(HasDictionaryElements() ||
9576 HasDictionaryArgumentsElements() ||
9577 (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
9578 Isolate* isolate = GetIsolate();
9579 switch (GetElementsKind()) {
9580 case FAST_SMI_ONLY_ELEMENTS:
9581 case FAST_ELEMENTS:
9582 return SetFastElement(index, value, strict_mode, check_prototype);
9583 case FAST_DOUBLE_ELEMENTS:
9584 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
9585 case EXTERNAL_PIXEL_ELEMENTS: {
9586 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
9587 return pixels->SetValue(index, value);
9588 }
9589 case EXTERNAL_BYTE_ELEMENTS: {
9590 ExternalByteArray* array = ExternalByteArray::cast(elements());
9591 return array->SetValue(index, value);
9592 }
9593 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9594 ExternalUnsignedByteArray* array =
9595 ExternalUnsignedByteArray::cast(elements());
9596 return array->SetValue(index, value);
9597 }
9598 case EXTERNAL_SHORT_ELEMENTS: {
9599 ExternalShortArray* array = ExternalShortArray::cast(elements());
9600 return array->SetValue(index, value);
9601 }
9602 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9603 ExternalUnsignedShortArray* array =
9604 ExternalUnsignedShortArray::cast(elements());
9605 return array->SetValue(index, value);
9606 }
9607 case EXTERNAL_INT_ELEMENTS: {
9608 ExternalIntArray* array = ExternalIntArray::cast(elements());
9609 return array->SetValue(index, value);
9610 }
9611 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9612 ExternalUnsignedIntArray* array =
9613 ExternalUnsignedIntArray::cast(elements());
9614 return array->SetValue(index, value);
9615 }
9616 case EXTERNAL_FLOAT_ELEMENTS: {
9617 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9618 return array->SetValue(index, value);
9619 }
9620 case EXTERNAL_DOUBLE_ELEMENTS: {
9621 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9622 return array->SetValue(index, value);
9623 }
9624 case DICTIONARY_ELEMENTS:
9625 return SetDictionaryElement(index, value, attr, strict_mode,
9626 check_prototype, set_mode);
9627 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9628 FixedArray* parameter_map = FixedArray::cast(elements());
9629 uint32_t length = parameter_map->length();
9630 Object* probe =
9631 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
9632 if (probe != NULL && !probe->IsTheHole()) {
9633 Context* context = Context::cast(parameter_map->get(0));
9634 int context_index = Smi::cast(probe)->value();
9635 ASSERT(!context->get(context_index)->IsTheHole());
9636 context->set(context_index, value);
9637 // Redefining attributes of an aliased element destroys fast aliasing.
9638 if (set_mode == SET_PROPERTY || attr == NONE) return value;
9639 parameter_map->set_the_hole(index + 2);
9640 // For elements that are still writable we re-establish slow aliasing.
9641 if ((attr & READ_ONLY) == 0) {
9642 MaybeObject* maybe_entry =
9643 isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
9644 if (!maybe_entry->ToObject(&value)) return maybe_entry;
9645 }
9646 }
9647 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9648 if (arguments->IsDictionary()) {
9649 return SetDictionaryElement(index, value, attr, strict_mode,
9650 check_prototype, set_mode);
9651 } else {
9652 return SetFastElement(index, value, strict_mode, check_prototype);
9653 }
9654 }
9655 }
9656 // All possible cases have been handled above. Add a return to avoid the
9657 // complaints from the compiler.
9658 UNREACHABLE();
9659 return isolate->heap()->null_value();
9660 }
9661
9662
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)9663 Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9664 ElementsKind to_kind) {
9665 CALL_HEAP_FUNCTION(object->GetIsolate(),
9666 object->TransitionElementsKind(to_kind),
9667 Object);
9668 }
9669
9670
TransitionElementsKind(ElementsKind to_kind)9671 MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
9672 ElementsKind from_kind = map()->elements_kind();
9673
9674 Isolate* isolate = GetIsolate();
9675 if ((from_kind == FAST_SMI_ONLY_ELEMENTS ||
9676 elements() == isolate->heap()->empty_fixed_array()) &&
9677 to_kind == FAST_ELEMENTS) {
9678 ASSERT(from_kind != FAST_ELEMENTS);
9679 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9680 Map* new_map;
9681 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9682 set_map(new_map);
9683 if (FLAG_trace_elements_transitions) {
9684 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9685 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9686 }
9687 return this;
9688 }
9689
9690 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9691 uint32_t capacity = static_cast<uint32_t>(elms->length());
9692 uint32_t length = capacity;
9693
9694 if (IsJSArray()) {
9695 Object* raw_length = JSArray::cast(this)->length();
9696 if (raw_length->IsUndefined()) {
9697 // If length is undefined, then JSArray is being initialized and has no
9698 // elements, assume a length of zero.
9699 length = 0;
9700 } else {
9701 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9702 }
9703 }
9704
9705 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9706 to_kind == FAST_DOUBLE_ELEMENTS) {
9707 MaybeObject* maybe_result =
9708 SetFastDoubleElementsCapacityAndLength(capacity, length);
9709 if (maybe_result->IsFailure()) return maybe_result;
9710 return this;
9711 }
9712
9713 if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
9714 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9715 capacity, length, kDontAllowSmiOnlyElements);
9716 if (maybe_result->IsFailure()) return maybe_result;
9717 return this;
9718 }
9719
9720 // This method should never be called for any other case than the ones
9721 // handled above.
9722 UNREACHABLE();
9723 return GetIsolate()->heap()->null_value();
9724 }
9725
9726
9727 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)9728 bool Map::IsValidElementsTransition(ElementsKind from_kind,
9729 ElementsKind to_kind) {
9730 return
9731 (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9732 (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9733 (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9734 }
9735
9736
JSArrayUpdateLengthFromIndex(uint32_t index,Object * value)9737 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9738 Object* value) {
9739 uint32_t old_len = 0;
9740 CHECK(length()->ToArrayIndex(&old_len));
9741 // Check to see if we need to update the length. For now, we make
9742 // sure that the length stays within 32-bits (unsigned).
9743 if (index >= old_len && index != 0xffffffff) {
9744 Object* len;
9745 { MaybeObject* maybe_len =
9746 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
9747 if (!maybe_len->ToObject(&len)) return maybe_len;
9748 }
9749 set_length(len);
9750 }
9751 return value;
9752 }
9753
9754
GetElementWithInterceptor(Object * receiver,uint32_t index)9755 MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
9756 uint32_t index) {
9757 Isolate* isolate = GetIsolate();
9758 // Make sure that the top context does not change when doing
9759 // callbacks or interceptor calls.
9760 AssertNoContextChange ncc;
9761 HandleScope scope(isolate);
9762 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9763 Handle<Object> this_handle(receiver, isolate);
9764 Handle<JSObject> holder_handle(this, isolate);
9765 if (!interceptor->getter()->IsUndefined()) {
9766 v8::IndexedPropertyGetter getter =
9767 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
9768 LOG(isolate,
9769 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9770 CustomArguments args(isolate, interceptor->data(), receiver, this);
9771 v8::AccessorInfo info(args.end());
9772 v8::Handle<v8::Value> result;
9773 {
9774 // Leaving JavaScript.
9775 VMState state(isolate, EXTERNAL);
9776 result = getter(index, info);
9777 }
9778 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9779 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9780 }
9781
9782 Heap* heap = holder_handle->GetHeap();
9783 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
9784 MaybeObject* raw_result = handler->Get(*this_handle,
9785 *holder_handle,
9786 index);
9787 if (raw_result != heap->the_hole_value()) return raw_result;
9788
9789 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9790
9791 Object* pt = holder_handle->GetPrototype();
9792 if (pt == heap->null_value()) return heap->undefined_value();
9793 return pt->GetElementWithReceiver(*this_handle, index);
9794 }
9795
9796
HasDenseElements()9797 bool JSObject::HasDenseElements() {
9798 int capacity = 0;
9799 int used = 0;
9800 GetElementsCapacityAndUsage(&capacity, &used);
9801 return (capacity == 0) || (used > (capacity / 2));
9802 }
9803
9804
GetElementsCapacityAndUsage(int * capacity,int * used)9805 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9806 *capacity = 0;
9807 *used = 0;
9808
9809 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9810 FixedArray* backing_store = NULL;
9811 switch (GetElementsKind()) {
9812 case NON_STRICT_ARGUMENTS_ELEMENTS:
9813 backing_store_base =
9814 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9815 backing_store = FixedArray::cast(backing_store_base);
9816 if (backing_store->IsDictionary()) {
9817 SeededNumberDictionary* dictionary =
9818 SeededNumberDictionary::cast(backing_store);
9819 *capacity = dictionary->Capacity();
9820 *used = dictionary->NumberOfElements();
9821 break;
9822 }
9823 // Fall through.
9824 case FAST_SMI_ONLY_ELEMENTS:
9825 case FAST_ELEMENTS:
9826 backing_store = FixedArray::cast(backing_store_base);
9827 *capacity = backing_store->length();
9828 for (int i = 0; i < *capacity; ++i) {
9829 if (!backing_store->get(i)->IsTheHole()) ++(*used);
9830 }
9831 break;
9832 case DICTIONARY_ELEMENTS: {
9833 SeededNumberDictionary* dictionary =
9834 SeededNumberDictionary::cast(FixedArray::cast(elements()));
9835 *capacity = dictionary->Capacity();
9836 *used = dictionary->NumberOfElements();
9837 break;
9838 }
9839 case FAST_DOUBLE_ELEMENTS: {
9840 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9841 *capacity = elms->length();
9842 for (int i = 0; i < *capacity; i++) {
9843 if (!elms->is_the_hole(i)) ++(*used);
9844 }
9845 break;
9846 }
9847 case EXTERNAL_BYTE_ELEMENTS:
9848 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9849 case EXTERNAL_SHORT_ELEMENTS:
9850 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9851 case EXTERNAL_INT_ELEMENTS:
9852 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9853 case EXTERNAL_FLOAT_ELEMENTS:
9854 case EXTERNAL_DOUBLE_ELEMENTS:
9855 case EXTERNAL_PIXEL_ELEMENTS:
9856 // External arrays are considered 100% used.
9857 ExternalArray* external_array = ExternalArray::cast(elements());
9858 *capacity = external_array->length();
9859 *used = external_array->length();
9860 break;
9861 }
9862 }
9863
9864
ShouldConvertToSlowElements(int new_capacity)9865 bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
9866 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
9867 kMaxUncheckedFastElementsLength);
9868 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
9869 (new_capacity <= kMaxUncheckedFastElementsLength &&
9870 GetHeap()->InNewSpace(this))) {
9871 return false;
9872 }
9873 // If the fast-case backing storage takes up roughly three times as
9874 // much space (in machine words) as a dictionary backing storage
9875 // would, the object should have slow elements.
9876 int old_capacity = 0;
9877 int used_elements = 0;
9878 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
9879 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
9880 SeededNumberDictionary::kEntrySize;
9881 return 3 * dictionary_size <= new_capacity;
9882 }
9883
9884
ShouldConvertToFastElements()9885 bool JSObject::ShouldConvertToFastElements() {
9886 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9887 // If the elements are sparse, we should not go back to fast case.
9888 if (!HasDenseElements()) return false;
9889 // An object requiring access checks is never allowed to have fast
9890 // elements. If it had fast elements we would skip security checks.
9891 if (IsAccessCheckNeeded()) return false;
9892
9893 FixedArray* elements = FixedArray::cast(this->elements());
9894 SeededNumberDictionary* dictionary = NULL;
9895 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
9896 dictionary = SeededNumberDictionary::cast(elements->get(1));
9897 } else {
9898 dictionary = SeededNumberDictionary::cast(elements);
9899 }
9900 // If an element has been added at a very high index in the elements
9901 // dictionary, we cannot go back to fast case.
9902 if (dictionary->requires_slow_elements()) return false;
9903 // If the dictionary backing storage takes up roughly half as much
9904 // space (in machine words) as a fast-case backing storage would,
9905 // the object should have fast elements.
9906 uint32_t array_size = 0;
9907 if (IsJSArray()) {
9908 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
9909 } else {
9910 array_size = dictionary->max_number_key();
9911 }
9912 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
9913 SeededNumberDictionary::kEntrySize;
9914 return 2 * dictionary_size >= array_size;
9915 }
9916
9917
ShouldConvertToFastDoubleElements(bool * has_smi_only_elements)9918 bool JSObject::ShouldConvertToFastDoubleElements(
9919 bool* has_smi_only_elements) {
9920 *has_smi_only_elements = false;
9921 if (FLAG_unbox_double_arrays) {
9922 ASSERT(HasDictionaryElements());
9923 SeededNumberDictionary* dictionary =
9924 SeededNumberDictionary::cast(elements());
9925 bool found_double = false;
9926 for (int i = 0; i < dictionary->Capacity(); i++) {
9927 Object* key = dictionary->KeyAt(i);
9928 if (key->IsNumber()) {
9929 Object* value = dictionary->ValueAt(i);
9930 if (!value->IsNumber()) return false;
9931 if (!value->IsSmi()) {
9932 found_double = true;
9933 }
9934 }
9935 }
9936 *has_smi_only_elements = !found_double;
9937 return found_double;
9938 } else {
9939 return false;
9940 }
9941 }
9942
9943
9944 // Certain compilers request function template instantiation when they
9945 // see the definition of the other template functions in the
9946 // class. This requires us to have the template functions put
9947 // together, so even though this function belongs in objects-debug.cc,
9948 // we keep it here instead to satisfy certain compilers.
9949 #ifdef OBJECT_PRINT
9950 template<typename Shape, typename Key>
Print(FILE * out)9951 void Dictionary<Shape, Key>::Print(FILE* out) {
9952 int capacity = HashTable<Shape, Key>::Capacity();
9953 for (int i = 0; i < capacity; i++) {
9954 Object* k = HashTable<Shape, Key>::KeyAt(i);
9955 if (HashTable<Shape, Key>::IsKey(k)) {
9956 PrintF(out, " ");
9957 if (k->IsString()) {
9958 String::cast(k)->StringPrint(out);
9959 } else {
9960 k->ShortPrint(out);
9961 }
9962 PrintF(out, ": ");
9963 ValueAt(i)->ShortPrint(out);
9964 PrintF(out, "\n");
9965 }
9966 }
9967 }
9968 #endif
9969
9970
9971 template<typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)9972 void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
9973 int pos = 0;
9974 int capacity = HashTable<Shape, Key>::Capacity();
9975 AssertNoAllocation no_gc;
9976 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
9977 for (int i = 0; i < capacity; i++) {
9978 Object* k = Dictionary<Shape, Key>::KeyAt(i);
9979 if (Dictionary<Shape, Key>::IsKey(k)) {
9980 elements->set(pos++, ValueAt(i), mode);
9981 }
9982 }
9983 ASSERT(pos == elements->length());
9984 }
9985
9986
GetNamedInterceptor()9987 InterceptorInfo* JSObject::GetNamedInterceptor() {
9988 ASSERT(map()->has_named_interceptor());
9989 JSFunction* constructor = JSFunction::cast(map()->constructor());
9990 ASSERT(constructor->shared()->IsApiFunction());
9991 Object* result =
9992 constructor->shared()->get_api_func_data()->named_property_handler();
9993 return InterceptorInfo::cast(result);
9994 }
9995
9996
GetIndexedInterceptor()9997 InterceptorInfo* JSObject::GetIndexedInterceptor() {
9998 ASSERT(map()->has_indexed_interceptor());
9999 JSFunction* constructor = JSFunction::cast(map()->constructor());
10000 ASSERT(constructor->shared()->IsApiFunction());
10001 Object* result =
10002 constructor->shared()->get_api_func_data()->indexed_property_handler();
10003 return InterceptorInfo::cast(result);
10004 }
10005
10006
GetPropertyPostInterceptor(JSReceiver * receiver,String * name,PropertyAttributes * attributes)10007 MaybeObject* JSObject::GetPropertyPostInterceptor(
10008 JSReceiver* receiver,
10009 String* name,
10010 PropertyAttributes* attributes) {
10011 // Check local property in holder, ignore interceptor.
10012 LookupResult result(GetIsolate());
10013 LocalLookupRealNamedProperty(name, &result);
10014 if (result.IsProperty()) {
10015 return GetProperty(receiver, &result, name, attributes);
10016 }
10017 // Continue searching via the prototype chain.
10018 Object* pt = GetPrototype();
10019 *attributes = ABSENT;
10020 if (pt->IsNull()) return GetHeap()->undefined_value();
10021 return pt->GetPropertyWithReceiver(receiver, name, attributes);
10022 }
10023
10024
GetLocalPropertyPostInterceptor(JSReceiver * receiver,String * name,PropertyAttributes * attributes)10025 MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
10026 JSReceiver* receiver,
10027 String* name,
10028 PropertyAttributes* attributes) {
10029 // Check local property in holder, ignore interceptor.
10030 LookupResult result(GetIsolate());
10031 LocalLookupRealNamedProperty(name, &result);
10032 if (result.IsProperty()) {
10033 return GetProperty(receiver, &result, name, attributes);
10034 }
10035 return GetHeap()->undefined_value();
10036 }
10037
10038
GetPropertyWithInterceptor(JSReceiver * receiver,String * name,PropertyAttributes * attributes)10039 MaybeObject* JSObject::GetPropertyWithInterceptor(
10040 JSReceiver* receiver,
10041 String* name,
10042 PropertyAttributes* attributes) {
10043 Isolate* isolate = GetIsolate();
10044 InterceptorInfo* interceptor = GetNamedInterceptor();
10045 HandleScope scope(isolate);
10046 Handle<JSReceiver> receiver_handle(receiver);
10047 Handle<JSObject> holder_handle(this);
10048 Handle<String> name_handle(name);
10049
10050 if (!interceptor->getter()->IsUndefined()) {
10051 v8::NamedPropertyGetter getter =
10052 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
10053 LOG(isolate,
10054 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10055 CustomArguments args(isolate, interceptor->data(), receiver, this);
10056 v8::AccessorInfo info(args.end());
10057 v8::Handle<v8::Value> result;
10058 {
10059 // Leaving JavaScript.
10060 VMState state(isolate, EXTERNAL);
10061 result = getter(v8::Utils::ToLocal(name_handle), info);
10062 }
10063 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
10064 if (!result.IsEmpty()) {
10065 *attributes = NONE;
10066 return *v8::Utils::OpenHandle(*result);
10067 }
10068 }
10069
10070 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
10071 *receiver_handle,
10072 *name_handle,
10073 attributes);
10074 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
10075 return result;
10076 }
10077
10078
HasRealNamedProperty(String * key)10079 bool JSObject::HasRealNamedProperty(String* key) {
10080 // Check access rights if needed.
10081 Isolate* isolate = GetIsolate();
10082 if (IsAccessCheckNeeded()) {
10083 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10084 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10085 return false;
10086 }
10087 }
10088
10089 LookupResult result(isolate);
10090 LocalLookupRealNamedProperty(key, &result);
10091 return result.IsProperty() && (result.type() != INTERCEPTOR);
10092 }
10093
10094
HasRealElementProperty(uint32_t index)10095 bool JSObject::HasRealElementProperty(uint32_t index) {
10096 // Check access rights if needed.
10097 if (IsAccessCheckNeeded()) {
10098 Heap* heap = GetHeap();
10099 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10100 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10101 return false;
10102 }
10103 }
10104
10105 // Handle [] on String objects.
10106 if (this->IsStringObjectWithCharacterAt(index)) return true;
10107
10108 switch (GetElementsKind()) {
10109 case FAST_SMI_ONLY_ELEMENTS:
10110 case FAST_ELEMENTS: {
10111 uint32_t length = IsJSArray() ?
10112 static_cast<uint32_t>(
10113 Smi::cast(JSArray::cast(this)->length())->value()) :
10114 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10115 return (index < length) &&
10116 !FixedArray::cast(elements())->get(index)->IsTheHole();
10117 }
10118 case FAST_DOUBLE_ELEMENTS: {
10119 uint32_t length = IsJSArray() ?
10120 static_cast<uint32_t>(
10121 Smi::cast(JSArray::cast(this)->length())->value()) :
10122 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
10123 return (index < length) &&
10124 !FixedDoubleArray::cast(elements())->is_the_hole(index);
10125 break;
10126 }
10127 case EXTERNAL_PIXEL_ELEMENTS: {
10128 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
10129 return index < static_cast<uint32_t>(pixels->length());
10130 }
10131 case EXTERNAL_BYTE_ELEMENTS:
10132 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10133 case EXTERNAL_SHORT_ELEMENTS:
10134 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10135 case EXTERNAL_INT_ELEMENTS:
10136 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10137 case EXTERNAL_FLOAT_ELEMENTS:
10138 case EXTERNAL_DOUBLE_ELEMENTS: {
10139 ExternalArray* array = ExternalArray::cast(elements());
10140 return index < static_cast<uint32_t>(array->length());
10141 }
10142 case DICTIONARY_ELEMENTS: {
10143 return element_dictionary()->FindEntry(index)
10144 != SeededNumberDictionary::kNotFound;
10145 }
10146 case NON_STRICT_ARGUMENTS_ELEMENTS:
10147 UNIMPLEMENTED();
10148 break;
10149 }
10150 // All possibilities have been handled above already.
10151 UNREACHABLE();
10152 return GetHeap()->null_value();
10153 }
10154
10155
HasRealNamedCallbackProperty(String * key)10156 bool JSObject::HasRealNamedCallbackProperty(String* key) {
10157 // Check access rights if needed.
10158 Isolate* isolate = GetIsolate();
10159 if (IsAccessCheckNeeded()) {
10160 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10161 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10162 return false;
10163 }
10164 }
10165
10166 LookupResult result(isolate);
10167 LocalLookupRealNamedProperty(key, &result);
10168 return result.IsFound() && (result.type() == CALLBACKS);
10169 }
10170
10171
NumberOfLocalProperties(PropertyAttributes filter)10172 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
10173 return HasFastProperties() ?
10174 map()->NumberOfDescribedProperties(filter) :
10175 property_dictionary()->NumberOfElementsFilterAttributes(filter);
10176 }
10177
10178
SwapPairs(FixedArray * numbers,int i,int j)10179 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
10180 Object* temp = get(i);
10181 set(i, get(j));
10182 set(j, temp);
10183 if (this != numbers) {
10184 temp = numbers->get(i);
10185 numbers->set(i, Smi::cast(numbers->get(j)));
10186 numbers->set(j, Smi::cast(temp));
10187 }
10188 }
10189
10190
InsertionSortPairs(FixedArray * content,FixedArray * numbers,int len)10191 static void InsertionSortPairs(FixedArray* content,
10192 FixedArray* numbers,
10193 int len) {
10194 for (int i = 1; i < len; i++) {
10195 int j = i;
10196 while (j > 0 &&
10197 (NumberToUint32(numbers->get(j - 1)) >
10198 NumberToUint32(numbers->get(j)))) {
10199 content->SwapPairs(numbers, j - 1, j);
10200 j--;
10201 }
10202 }
10203 }
10204
10205
HeapSortPairs(FixedArray * content,FixedArray * numbers,int len)10206 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
10207 // In-place heap sort.
10208 ASSERT(content->length() == numbers->length());
10209
10210 // Bottom-up max-heap construction.
10211 for (int i = 1; i < len; ++i) {
10212 int child_index = i;
10213 while (child_index > 0) {
10214 int parent_index = ((child_index + 1) >> 1) - 1;
10215 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10216 uint32_t child_value = NumberToUint32(numbers->get(child_index));
10217 if (parent_value < child_value) {
10218 content->SwapPairs(numbers, parent_index, child_index);
10219 } else {
10220 break;
10221 }
10222 child_index = parent_index;
10223 }
10224 }
10225
10226 // Extract elements and create sorted array.
10227 for (int i = len - 1; i > 0; --i) {
10228 // Put max element at the back of the array.
10229 content->SwapPairs(numbers, 0, i);
10230 // Sift down the new top element.
10231 int parent_index = 0;
10232 while (true) {
10233 int child_index = ((parent_index + 1) << 1) - 1;
10234 if (child_index >= i) break;
10235 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10236 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10237 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10238 if (child_index + 1 >= i || child1_value > child2_value) {
10239 if (parent_value > child1_value) break;
10240 content->SwapPairs(numbers, parent_index, child_index);
10241 parent_index = child_index;
10242 } else {
10243 if (parent_value > child2_value) break;
10244 content->SwapPairs(numbers, parent_index, child_index + 1);
10245 parent_index = child_index + 1;
10246 }
10247 }
10248 }
10249 }
10250
10251
10252 // Sort this array and the numbers as pairs wrt. the (distinct) numbers.
SortPairs(FixedArray * numbers,uint32_t len)10253 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10254 ASSERT(this->length() == numbers->length());
10255 // For small arrays, simply use insertion sort.
10256 if (len <= 10) {
10257 InsertionSortPairs(this, numbers, len);
10258 return;
10259 }
10260 // Check the range of indices.
10261 uint32_t min_index = NumberToUint32(numbers->get(0));
10262 uint32_t max_index = min_index;
10263 uint32_t i;
10264 for (i = 1; i < len; i++) {
10265 if (NumberToUint32(numbers->get(i)) < min_index) {
10266 min_index = NumberToUint32(numbers->get(i));
10267 } else if (NumberToUint32(numbers->get(i)) > max_index) {
10268 max_index = NumberToUint32(numbers->get(i));
10269 }
10270 }
10271 if (max_index - min_index + 1 == len) {
10272 // Indices form a contiguous range, unless there are duplicates.
10273 // Do an in-place linear time sort assuming distinct numbers, but
10274 // avoid hanging in case they are not.
10275 for (i = 0; i < len; i++) {
10276 uint32_t p;
10277 uint32_t j = 0;
10278 // While the current element at i is not at its correct position p,
10279 // swap the elements at these two positions.
10280 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
10281 j++ < len) {
10282 SwapPairs(numbers, i, p);
10283 }
10284 }
10285 } else {
10286 HeapSortPairs(this, numbers, len);
10287 return;
10288 }
10289 }
10290
10291
10292 // Fill in the names of local properties into the supplied storage. The main
10293 // purpose of this function is to provide reflection information for the object
10294 // mirrors.
GetLocalPropertyNames(FixedArray * storage,int index)10295 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
10296 ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
10297 if (HasFastProperties()) {
10298 DescriptorArray* descs = map()->instance_descriptors();
10299 for (int i = 0; i < descs->number_of_descriptors(); i++) {
10300 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
10301 }
10302 ASSERT(storage->length() >= index);
10303 } else {
10304 property_dictionary()->CopyKeysTo(storage,
10305 index,
10306 StringDictionary::UNSORTED);
10307 }
10308 }
10309
10310
NumberOfLocalElements(PropertyAttributes filter)10311 int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10312 return GetLocalElementKeys(NULL, filter);
10313 }
10314
10315
NumberOfEnumElements()10316 int JSObject::NumberOfEnumElements() {
10317 // Fast case for objects with no elements.
10318 if (!IsJSValue() && HasFastElements()) {
10319 uint32_t length = IsJSArray() ?
10320 static_cast<uint32_t>(
10321 Smi::cast(JSArray::cast(this)->length())->value()) :
10322 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10323 if (length == 0) return 0;
10324 }
10325 // Compute the number of enumerable elements.
10326 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10327 }
10328
10329
GetLocalElementKeys(FixedArray * storage,PropertyAttributes filter)10330 int JSObject::GetLocalElementKeys(FixedArray* storage,
10331 PropertyAttributes filter) {
10332 int counter = 0;
10333 switch (GetElementsKind()) {
10334 case FAST_SMI_ONLY_ELEMENTS:
10335 case FAST_ELEMENTS: {
10336 int length = IsJSArray() ?
10337 Smi::cast(JSArray::cast(this)->length())->value() :
10338 FixedArray::cast(elements())->length();
10339 for (int i = 0; i < length; i++) {
10340 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10341 if (storage != NULL) {
10342 storage->set(counter, Smi::FromInt(i));
10343 }
10344 counter++;
10345 }
10346 }
10347 ASSERT(!storage || storage->length() >= counter);
10348 break;
10349 }
10350 case FAST_DOUBLE_ELEMENTS: {
10351 int length = IsJSArray() ?
10352 Smi::cast(JSArray::cast(this)->length())->value() :
10353 FixedDoubleArray::cast(elements())->length();
10354 for (int i = 0; i < length; i++) {
10355 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10356 if (storage != NULL) {
10357 storage->set(counter, Smi::FromInt(i));
10358 }
10359 counter++;
10360 }
10361 }
10362 ASSERT(!storage || storage->length() >= counter);
10363 break;
10364 }
10365 case EXTERNAL_PIXEL_ELEMENTS: {
10366 int length = ExternalPixelArray::cast(elements())->length();
10367 while (counter < length) {
10368 if (storage != NULL) {
10369 storage->set(counter, Smi::FromInt(counter));
10370 }
10371 counter++;
10372 }
10373 ASSERT(!storage || storage->length() >= counter);
10374 break;
10375 }
10376 case EXTERNAL_BYTE_ELEMENTS:
10377 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10378 case EXTERNAL_SHORT_ELEMENTS:
10379 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10380 case EXTERNAL_INT_ELEMENTS:
10381 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10382 case EXTERNAL_FLOAT_ELEMENTS:
10383 case EXTERNAL_DOUBLE_ELEMENTS: {
10384 int length = ExternalArray::cast(elements())->length();
10385 while (counter < length) {
10386 if (storage != NULL) {
10387 storage->set(counter, Smi::FromInt(counter));
10388 }
10389 counter++;
10390 }
10391 ASSERT(!storage || storage->length() >= counter);
10392 break;
10393 }
10394 case DICTIONARY_ELEMENTS: {
10395 if (storage != NULL) {
10396 element_dictionary()->CopyKeysTo(storage,
10397 filter,
10398 SeededNumberDictionary::SORTED);
10399 }
10400 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
10401 break;
10402 }
10403 case NON_STRICT_ARGUMENTS_ELEMENTS: {
10404 FixedArray* parameter_map = FixedArray::cast(elements());
10405 int mapped_length = parameter_map->length() - 2;
10406 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10407 if (arguments->IsDictionary()) {
10408 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10409 // will insert in storage starting at index 0.
10410 SeededNumberDictionary* dictionary =
10411 SeededNumberDictionary::cast(arguments);
10412 if (storage != NULL) {
10413 dictionary->CopyKeysTo(
10414 storage, filter, SeededNumberDictionary::UNSORTED);
10415 }
10416 counter += dictionary->NumberOfElementsFilterAttributes(filter);
10417 for (int i = 0; i < mapped_length; ++i) {
10418 if (!parameter_map->get(i + 2)->IsTheHole()) {
10419 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10420 ++counter;
10421 }
10422 }
10423 if (storage != NULL) storage->SortPairs(storage, counter);
10424
10425 } else {
10426 int backing_length = arguments->length();
10427 int i = 0;
10428 for (; i < mapped_length; ++i) {
10429 if (!parameter_map->get(i + 2)->IsTheHole()) {
10430 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10431 ++counter;
10432 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10433 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10434 ++counter;
10435 }
10436 }
10437 for (; i < backing_length; ++i) {
10438 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10439 ++counter;
10440 }
10441 }
10442 break;
10443 }
10444 }
10445
10446 if (this->IsJSValue()) {
10447 Object* val = JSValue::cast(this)->value();
10448 if (val->IsString()) {
10449 String* str = String::cast(val);
10450 if (storage) {
10451 for (int i = 0; i < str->length(); i++) {
10452 storage->set(counter + i, Smi::FromInt(i));
10453 }
10454 }
10455 counter += str->length();
10456 }
10457 }
10458 ASSERT(!storage || storage->length() == counter);
10459 return counter;
10460 }
10461
10462
GetEnumElementKeys(FixedArray * storage)10463 int JSObject::GetEnumElementKeys(FixedArray* storage) {
10464 return GetLocalElementKeys(storage,
10465 static_cast<PropertyAttributes>(DONT_ENUM));
10466 }
10467
10468
10469 // StringKey simply carries a string object as key.
10470 class StringKey : public HashTableKey {
10471 public:
StringKey(String * string)10472 explicit StringKey(String* string) :
10473 string_(string),
10474 hash_(HashForObject(string)) { }
10475
IsMatch(Object * string)10476 bool IsMatch(Object* string) {
10477 // We know that all entries in a hash table had their hash keys created.
10478 // Use that knowledge to have fast failure.
10479 if (hash_ != HashForObject(string)) {
10480 return false;
10481 }
10482 return string_->Equals(String::cast(string));
10483 }
10484
Hash()10485 uint32_t Hash() { return hash_; }
10486
HashForObject(Object * other)10487 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
10488
AsObject()10489 Object* AsObject() { return string_; }
10490
10491 String* string_;
10492 uint32_t hash_;
10493 };
10494
10495
10496 // StringSharedKeys are used as keys in the eval cache.
10497 class StringSharedKey : public HashTableKey {
10498 public:
StringSharedKey(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int scope_position)10499 StringSharedKey(String* source,
10500 SharedFunctionInfo* shared,
10501 LanguageMode language_mode,
10502 int scope_position)
10503 : source_(source),
10504 shared_(shared),
10505 language_mode_(language_mode),
10506 scope_position_(scope_position) { }
10507
IsMatch(Object * other)10508 bool IsMatch(Object* other) {
10509 if (!other->IsFixedArray()) return false;
10510 FixedArray* other_array = FixedArray::cast(other);
10511 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10512 if (shared != shared_) return false;
10513 int language_unchecked = Smi::cast(other_array->get(2))->value();
10514 ASSERT(language_unchecked == CLASSIC_MODE ||
10515 language_unchecked == STRICT_MODE ||
10516 language_unchecked == EXTENDED_MODE);
10517 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10518 if (language_mode != language_mode_) return false;
10519 int scope_position = Smi::cast(other_array->get(3))->value();
10520 if (scope_position != scope_position_) return false;
10521 String* source = String::cast(other_array->get(1));
10522 return source->Equals(source_);
10523 }
10524
StringSharedHashHelper(String * source,SharedFunctionInfo * shared,LanguageMode language_mode,int scope_position)10525 static uint32_t StringSharedHashHelper(String* source,
10526 SharedFunctionInfo* shared,
10527 LanguageMode language_mode,
10528 int scope_position) {
10529 uint32_t hash = source->Hash();
10530 if (shared->HasSourceCode()) {
10531 // Instead of using the SharedFunctionInfo pointer in the hash
10532 // code computation, we use a combination of the hash of the
10533 // script source code and the start position of the calling scope.
10534 // We do this to ensure that the cache entries can survive garbage
10535 // collection.
10536 Script* script = Script::cast(shared->script());
10537 hash ^= String::cast(script->source())->Hash();
10538 if (language_mode == STRICT_MODE) hash ^= 0x8000;
10539 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
10540 hash += scope_position;
10541 }
10542 return hash;
10543 }
10544
Hash()10545 uint32_t Hash() {
10546 return StringSharedHashHelper(
10547 source_, shared_, language_mode_, scope_position_);
10548 }
10549
HashForObject(Object * obj)10550 uint32_t HashForObject(Object* obj) {
10551 FixedArray* other_array = FixedArray::cast(obj);
10552 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10553 String* source = String::cast(other_array->get(1));
10554 int language_unchecked = Smi::cast(other_array->get(2))->value();
10555 ASSERT(language_unchecked == CLASSIC_MODE ||
10556 language_unchecked == STRICT_MODE ||
10557 language_unchecked == EXTENDED_MODE);
10558 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10559 int scope_position = Smi::cast(other_array->get(3))->value();
10560 return StringSharedHashHelper(
10561 source, shared, language_mode, scope_position);
10562 }
10563
AsObject()10564 MUST_USE_RESULT MaybeObject* AsObject() {
10565 Object* obj;
10566 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
10567 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10568 }
10569 FixedArray* other_array = FixedArray::cast(obj);
10570 other_array->set(0, shared_);
10571 other_array->set(1, source_);
10572 other_array->set(2, Smi::FromInt(language_mode_));
10573 other_array->set(3, Smi::FromInt(scope_position_));
10574 return other_array;
10575 }
10576
10577 private:
10578 String* source_;
10579 SharedFunctionInfo* shared_;
10580 LanguageMode language_mode_;
10581 int scope_position_;
10582 };
10583
10584
10585 // RegExpKey carries the source and flags of a regular expression as key.
10586 class RegExpKey : public HashTableKey {
10587 public:
RegExpKey(String * string,JSRegExp::Flags flags)10588 RegExpKey(String* string, JSRegExp::Flags flags)
10589 : string_(string),
10590 flags_(Smi::FromInt(flags.value())) { }
10591
10592 // Rather than storing the key in the hash table, a pointer to the
10593 // stored value is stored where the key should be. IsMatch then
10594 // compares the search key to the found object, rather than comparing
10595 // a key to a key.
IsMatch(Object * obj)10596 bool IsMatch(Object* obj) {
10597 FixedArray* val = FixedArray::cast(obj);
10598 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10599 && (flags_ == val->get(JSRegExp::kFlagsIndex));
10600 }
10601
Hash()10602 uint32_t Hash() { return RegExpHash(string_, flags_); }
10603
AsObject()10604 Object* AsObject() {
10605 // Plain hash maps, which is where regexp keys are used, don't
10606 // use this function.
10607 UNREACHABLE();
10608 return NULL;
10609 }
10610
HashForObject(Object * obj)10611 uint32_t HashForObject(Object* obj) {
10612 FixedArray* val = FixedArray::cast(obj);
10613 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10614 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10615 }
10616
RegExpHash(String * string,Smi * flags)10617 static uint32_t RegExpHash(String* string, Smi* flags) {
10618 return string->Hash() + flags->value();
10619 }
10620
10621 String* string_;
10622 Smi* flags_;
10623 };
10624
10625 // Utf8SymbolKey carries a vector of chars as key.
10626 class Utf8SymbolKey : public HashTableKey {
10627 public:
Utf8SymbolKey(Vector<const char> string,uint32_t seed)10628 explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10629 : string_(string), hash_field_(0), seed_(seed) { }
10630
IsMatch(Object * string)10631 bool IsMatch(Object* string) {
10632 return String::cast(string)->IsEqualTo(string_);
10633 }
10634
Hash()10635 uint32_t Hash() {
10636 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
10637 unibrow::Utf8InputBuffer<> buffer(string_.start(),
10638 static_cast<unsigned>(string_.length()));
10639 chars_ = buffer.Utf16Length();
10640 hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
10641 uint32_t result = hash_field_ >> String::kHashShift;
10642 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10643 return result;
10644 }
10645
HashForObject(Object * other)10646 uint32_t HashForObject(Object* other) {
10647 return String::cast(other)->Hash();
10648 }
10649
AsObject()10650 MaybeObject* AsObject() {
10651 if (hash_field_ == 0) Hash();
10652 return Isolate::Current()->heap()->AllocateSymbol(
10653 string_, chars_, hash_field_);
10654 }
10655
10656 Vector<const char> string_;
10657 uint32_t hash_field_;
10658 int chars_; // Caches the number of characters when computing the hash code.
10659 uint32_t seed_;
10660 };
10661
10662
10663 template <typename Char>
10664 class SequentialSymbolKey : public HashTableKey {
10665 public:
SequentialSymbolKey(Vector<const Char> string,uint32_t seed)10666 explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10667 : string_(string), hash_field_(0), seed_(seed) { }
10668
Hash()10669 uint32_t Hash() {
10670 StringHasher hasher(string_.length(), seed_);
10671
10672 // Very long strings have a trivial hash that doesn't inspect the
10673 // string contents.
10674 if (hasher.has_trivial_hash()) {
10675 hash_field_ = hasher.GetHashField();
10676 } else {
10677 int i = 0;
10678 // Do the iterative array index computation as long as there is a
10679 // chance this is an array index.
10680 while (i < string_.length() && hasher.is_array_index()) {
10681 hasher.AddCharacter(static_cast<uc32>(string_[i]));
10682 i++;
10683 }
10684
10685 // Process the remaining characters without updating the array
10686 // index.
10687 while (i < string_.length()) {
10688 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10689 i++;
10690 }
10691 hash_field_ = hasher.GetHashField();
10692 }
10693
10694 uint32_t result = hash_field_ >> String::kHashShift;
10695 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10696 return result;
10697 }
10698
10699
HashForObject(Object * other)10700 uint32_t HashForObject(Object* other) {
10701 return String::cast(other)->Hash();
10702 }
10703
10704 Vector<const Char> string_;
10705 uint32_t hash_field_;
10706 uint32_t seed_;
10707 };
10708
10709
10710
10711 class AsciiSymbolKey : public SequentialSymbolKey<char> {
10712 public:
AsciiSymbolKey(Vector<const char> str,uint32_t seed)10713 AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10714 : SequentialSymbolKey<char>(str, seed) { }
10715
IsMatch(Object * string)10716 bool IsMatch(Object* string) {
10717 return String::cast(string)->IsAsciiEqualTo(string_);
10718 }
10719
AsObject()10720 MaybeObject* AsObject() {
10721 if (hash_field_ == 0) Hash();
10722 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
10723 }
10724 };
10725
10726
10727 class SubStringAsciiSymbolKey : public HashTableKey {
10728 public:
SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,int from,int length,uint32_t seed)10729 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10730 int from,
10731 int length,
10732 uint32_t seed)
10733 : string_(string), from_(from), length_(length), seed_(seed) { }
10734
Hash()10735 uint32_t Hash() {
10736 ASSERT(length_ >= 0);
10737 ASSERT(from_ + length_ <= string_->length());
10738 StringHasher hasher(length_, string_->GetHeap()->HashSeed());
10739
10740 // Very long strings have a trivial hash that doesn't inspect the
10741 // string contents.
10742 if (hasher.has_trivial_hash()) {
10743 hash_field_ = hasher.GetHashField();
10744 } else {
10745 int i = 0;
10746 // Do the iterative array index computation as long as there is a
10747 // chance this is an array index.
10748 while (i < length_ && hasher.is_array_index()) {
10749 hasher.AddCharacter(static_cast<uc32>(
10750 string_->SeqAsciiStringGet(i + from_)));
10751 i++;
10752 }
10753
10754 // Process the remaining characters without updating the array
10755 // index.
10756 while (i < length_) {
10757 hasher.AddCharacterNoIndex(static_cast<uc32>(
10758 string_->SeqAsciiStringGet(i + from_)));
10759 i++;
10760 }
10761 hash_field_ = hasher.GetHashField();
10762 }
10763
10764 uint32_t result = hash_field_ >> String::kHashShift;
10765 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10766 return result;
10767 }
10768
10769
HashForObject(Object * other)10770 uint32_t HashForObject(Object* other) {
10771 return String::cast(other)->Hash();
10772 }
10773
IsMatch(Object * string)10774 bool IsMatch(Object* string) {
10775 Vector<const char> chars(string_->GetChars() + from_, length_);
10776 return String::cast(string)->IsAsciiEqualTo(chars);
10777 }
10778
AsObject()10779 MaybeObject* AsObject() {
10780 if (hash_field_ == 0) Hash();
10781 Vector<const char> chars(string_->GetChars() + from_, length_);
10782 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10783 }
10784
10785 private:
10786 Handle<SeqAsciiString> string_;
10787 int from_;
10788 int length_;
10789 uint32_t hash_field_;
10790 uint32_t seed_;
10791 };
10792
10793
10794 class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10795 public:
TwoByteSymbolKey(Vector<const uc16> str,uint32_t seed)10796 explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10797 : SequentialSymbolKey<uc16>(str, seed) { }
10798
IsMatch(Object * string)10799 bool IsMatch(Object* string) {
10800 return String::cast(string)->IsTwoByteEqualTo(string_);
10801 }
10802
AsObject()10803 MaybeObject* AsObject() {
10804 if (hash_field_ == 0) Hash();
10805 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
10806 }
10807 };
10808
10809
10810 // SymbolKey carries a string/symbol object as key.
10811 class SymbolKey : public HashTableKey {
10812 public:
SymbolKey(String * string)10813 explicit SymbolKey(String* string)
10814 : string_(string) { }
10815
IsMatch(Object * string)10816 bool IsMatch(Object* string) {
10817 return String::cast(string)->Equals(string_);
10818 }
10819
Hash()10820 uint32_t Hash() { return string_->Hash(); }
10821
HashForObject(Object * other)10822 uint32_t HashForObject(Object* other) {
10823 return String::cast(other)->Hash();
10824 }
10825
AsObject()10826 MaybeObject* AsObject() {
10827 // Attempt to flatten the string, so that symbols will most often
10828 // be flat strings.
10829 string_ = string_->TryFlattenGetString();
10830 Heap* heap = string_->GetHeap();
10831 // Transform string to symbol if possible.
10832 Map* map = heap->SymbolMapForString(string_);
10833 if (map != NULL) {
10834 string_->set_map_no_write_barrier(map);
10835 ASSERT(string_->IsSymbol());
10836 return string_;
10837 }
10838 // Otherwise allocate a new symbol.
10839 StringInputBuffer buffer(string_);
10840 return heap->AllocateInternalSymbol(&buffer,
10841 string_->length(),
10842 string_->hash_field());
10843 }
10844
StringHash(Object * obj)10845 static uint32_t StringHash(Object* obj) {
10846 return String::cast(obj)->Hash();
10847 }
10848
10849 String* string_;
10850 };
10851
10852
10853 template<typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)10854 void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
10855 IteratePointers(v, 0, kElementsStartOffset);
10856 }
10857
10858
10859 template<typename Shape, typename Key>
IterateElements(ObjectVisitor * v)10860 void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
10861 IteratePointers(v,
10862 kElementsStartOffset,
10863 kHeaderSize + length() * kPointerSize);
10864 }
10865
10866
10867 template<typename Shape, typename Key>
Allocate(int at_least_space_for,PretenureFlag pretenure)10868 MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10869 PretenureFlag pretenure) {
10870 int capacity = ComputeCapacity(at_least_space_for);
10871 if (capacity > HashTable::kMaxCapacity) {
10872 return Failure::OutOfMemoryException();
10873 }
10874
10875 Object* obj;
10876 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10877 AllocateHashTable(EntryToIndex(capacity), pretenure);
10878 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10879 }
10880 HashTable::cast(obj)->SetNumberOfElements(0);
10881 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
10882 HashTable::cast(obj)->SetCapacity(capacity);
10883 return obj;
10884 }
10885
10886
10887 // Find entry for key otherwise return kNotFound.
FindEntry(String * key)10888 int StringDictionary::FindEntry(String* key) {
10889 if (!key->IsSymbol()) {
10890 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
10891 }
10892
10893 // Optimized for symbol key. Knowledge of the key type allows:
10894 // 1. Move the check if the key is a symbol out of the loop.
10895 // 2. Avoid comparing hash codes in symbol to symbol comparison.
10896 // 3. Detect a case when a dictionary key is not a symbol but the key is.
10897 // In case of positive result the dictionary key may be replaced by
10898 // the symbol with minimal performance penalty. It gives a chance to
10899 // perform further lookups in code stubs (and significant performance boost
10900 // a certain style of code).
10901
10902 // EnsureCapacity will guarantee the hash table is never full.
10903 uint32_t capacity = Capacity();
10904 uint32_t entry = FirstProbe(key->Hash(), capacity);
10905 uint32_t count = 1;
10906
10907 while (true) {
10908 int index = EntryToIndex(entry);
10909 Object* element = get(index);
10910 if (element->IsUndefined()) break; // Empty entry.
10911 if (key == element) return entry;
10912 if (!element->IsSymbol() &&
10913 !element->IsTheHole() &&
10914 String::cast(element)->Equals(key)) {
10915 // Replace a non-symbol key by the equivalent symbol for faster further
10916 // lookups.
10917 set(index, key);
10918 return entry;
10919 }
10920 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
10921 entry = NextProbe(entry, count++, capacity);
10922 }
10923 return kNotFound;
10924 }
10925
10926
ContainsTransition(int entry)10927 bool StringDictionary::ContainsTransition(int entry) {
10928 switch (DetailsAt(entry).type()) {
10929 case MAP_TRANSITION:
10930 case CONSTANT_TRANSITION:
10931 case ELEMENTS_TRANSITION:
10932 return true;
10933 case CALLBACKS: {
10934 Object* value = ValueAt(entry);
10935 if (!value->IsAccessorPair()) return false;
10936 AccessorPair* accessors = AccessorPair::cast(value);
10937 return accessors->getter()->IsMap() || accessors->setter()->IsMap();
10938 }
10939 case NORMAL:
10940 case FIELD:
10941 case CONSTANT_FUNCTION:
10942 case HANDLER:
10943 case INTERCEPTOR:
10944 case NULL_DESCRIPTOR:
10945 return false;
10946 }
10947 UNREACHABLE(); // Keep the compiler happy.
10948 return false;
10949 }
10950
10951
10952 template<typename Shape, typename Key>
Rehash(HashTable * new_table,Key key)10953 MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
10954 ASSERT(NumberOfElements() < new_table->Capacity());
10955
10956 AssertNoAllocation no_gc;
10957 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
10958
10959 // Copy prefix to new array.
10960 for (int i = kPrefixStartIndex;
10961 i < kPrefixStartIndex + Shape::kPrefixSize;
10962 i++) {
10963 new_table->set(i, get(i), mode);
10964 }
10965
10966 // Rehash the elements.
10967 int capacity = Capacity();
10968 for (int i = 0; i < capacity; i++) {
10969 uint32_t from_index = EntryToIndex(i);
10970 Object* k = get(from_index);
10971 if (IsKey(k)) {
10972 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
10973 uint32_t insertion_index =
10974 EntryToIndex(new_table->FindInsertionEntry(hash));
10975 for (int j = 0; j < Shape::kEntrySize; j++) {
10976 new_table->set(insertion_index + j, get(from_index + j), mode);
10977 }
10978 }
10979 }
10980 new_table->SetNumberOfElements(NumberOfElements());
10981 new_table->SetNumberOfDeletedElements(0);
10982 return new_table;
10983 }
10984
10985
10986 template<typename Shape, typename Key>
EnsureCapacity(int n,Key key)10987 MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
10988 int capacity = Capacity();
10989 int nof = NumberOfElements() + n;
10990 int nod = NumberOfDeletedElements();
10991 // Return if:
10992 // 50% is still free after adding n elements and
10993 // at most 50% of the free elements are deleted elements.
10994 if (nod <= (capacity - nof) >> 1) {
10995 int needed_free = nof >> 1;
10996 if (nof + needed_free <= capacity) return this;
10997 }
10998
10999 const int kMinCapacityForPretenure = 256;
11000 bool pretenure =
11001 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
11002 Object* obj;
11003 { MaybeObject* maybe_obj =
11004 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
11005 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11006 }
11007
11008 return Rehash(HashTable::cast(obj), key);
11009 }
11010
11011
11012 template<typename Shape, typename Key>
Shrink(Key key)11013 MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
11014 int capacity = Capacity();
11015 int nof = NumberOfElements();
11016
11017 // Shrink to fit the number of elements if only a quarter of the
11018 // capacity is filled with elements.
11019 if (nof > (capacity >> 2)) return this;
11020 // Allocate a new dictionary with room for at least the current
11021 // number of elements. The allocation method will make sure that
11022 // there is extra room in the dictionary for additions. Don't go
11023 // lower than room for 16 elements.
11024 int at_least_room_for = nof;
11025 if (at_least_room_for < 16) return this;
11026
11027 const int kMinCapacityForPretenure = 256;
11028 bool pretenure =
11029 (at_least_room_for > kMinCapacityForPretenure) &&
11030 !GetHeap()->InNewSpace(this);
11031 Object* obj;
11032 { MaybeObject* maybe_obj =
11033 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
11034 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11035 }
11036
11037 return Rehash(HashTable::cast(obj), key);
11038 }
11039
11040
11041 template<typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)11042 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
11043 uint32_t capacity = Capacity();
11044 uint32_t entry = FirstProbe(hash, capacity);
11045 uint32_t count = 1;
11046 // EnsureCapacity will guarantee the hash table is never full.
11047 while (true) {
11048 Object* element = KeyAt(entry);
11049 if (element->IsUndefined() || element->IsTheHole()) break;
11050 entry = NextProbe(entry, count++, capacity);
11051 }
11052 return entry;
11053 }
11054
11055 // Force instantiation of template instances class.
11056 // Please note this list is compiler dependent.
11057
11058 template class HashTable<SymbolTableShape, HashTableKey*>;
11059
11060 template class HashTable<CompilationCacheShape, HashTableKey*>;
11061
11062 template class HashTable<MapCacheShape, HashTableKey*>;
11063
11064 template class HashTable<ObjectHashTableShape<1>, Object*>;
11065
11066 template class HashTable<ObjectHashTableShape<2>, Object*>;
11067
11068 template class Dictionary<StringDictionaryShape, String*>;
11069
11070 template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
11071
11072 template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11073
11074 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11075 Allocate(int at_least_space_for);
11076
11077 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11078 Allocate(int at_least_space_for);
11079
11080 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
11081 int);
11082
11083 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
11084 uint32_t, Object*);
11085
11086 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11087 AtPut(uint32_t, Object*);
11088
11089 template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11090 SlowReverseLookup(Object* value);
11091
11092 template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11093 SlowReverseLookup(Object* value);
11094
11095 template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11096 Object*);
11097
11098 template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
11099 FixedArray*,
11100 PropertyAttributes,
11101 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
11102
11103 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11104 int, JSObject::DeleteMode);
11105
11106 template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11107 DeleteProperty(int, JSObject::DeleteMode);
11108
11109 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11110 String*);
11111
11112 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
11113 uint32_t);
11114
11115 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
11116 FixedArray*,
11117 int,
11118 Dictionary<StringDictionaryShape, String*>::SortMode);
11119
11120 template int
11121 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11122 PropertyAttributes);
11123
11124 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
11125 String*, Object*, PropertyDetails);
11126
11127 template MaybeObject*
11128 Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11129
11130 template int
11131 Dictionary<SeededNumberDictionaryShape, uint32_t>::
11132 NumberOfElementsFilterAttributes(PropertyAttributes);
11133
11134 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
11135 uint32_t, Object*, PropertyDetails);
11136
11137 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11138 uint32_t, Object*, PropertyDetails);
11139
11140 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11141 EnsureCapacity(int, uint32_t);
11142
11143 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11144 EnsureCapacity(int, uint32_t);
11145
11146 template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11147 EnsureCapacity(int, String*);
11148
11149 template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11150 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11151
11152 template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11153 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11154
11155 template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
11156 String*, Object*, PropertyDetails, uint32_t);
11157
11158 template
11159 int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
11160
11161 template
11162 int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
11163
11164 template
11165 int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
11166
11167
11168 // Collates undefined and unexisting elements below limit from position
11169 // zero of the elements. The object stays in Dictionary mode.
PrepareSlowElementsForSort(uint32_t limit)11170 MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
11171 ASSERT(HasDictionaryElements());
11172 // Must stay in dictionary mode, either because of requires_slow_elements,
11173 // or because we are not going to sort (and therefore compact) all of the
11174 // elements.
11175 SeededNumberDictionary* dict = element_dictionary();
11176 HeapNumber* result_double = NULL;
11177 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11178 // Allocate space for result before we start mutating the object.
11179 Object* new_double;
11180 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
11181 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11182 }
11183 result_double = HeapNumber::cast(new_double);
11184 }
11185
11186 Object* obj;
11187 { MaybeObject* maybe_obj =
11188 SeededNumberDictionary::Allocate(dict->NumberOfElements());
11189 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11190 }
11191 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
11192
11193 AssertNoAllocation no_alloc;
11194
11195 uint32_t pos = 0;
11196 uint32_t undefs = 0;
11197 int capacity = dict->Capacity();
11198 for (int i = 0; i < capacity; i++) {
11199 Object* k = dict->KeyAt(i);
11200 if (dict->IsKey(k)) {
11201 ASSERT(k->IsNumber());
11202 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11203 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11204 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11205 Object* value = dict->ValueAt(i);
11206 PropertyDetails details = dict->DetailsAt(i);
11207 if (details.type() == CALLBACKS) {
11208 // Bail out and do the sorting of undefineds and array holes in JS.
11209 return Smi::FromInt(-1);
11210 }
11211 uint32_t key = NumberToUint32(k);
11212 // In the following we assert that adding the entry to the new dictionary
11213 // does not cause GC. This is the case because we made sure to allocate
11214 // the dictionary big enough above, so it need not grow.
11215 if (key < limit) {
11216 if (value->IsUndefined()) {
11217 undefs++;
11218 } else {
11219 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11220 // Adding an entry with the key beyond smi-range requires
11221 // allocation. Bailout.
11222 return Smi::FromInt(-1);
11223 }
11224 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
11225 pos++;
11226 }
11227 } else {
11228 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11229 // Adding an entry with the key beyond smi-range requires
11230 // allocation. Bailout.
11231 return Smi::FromInt(-1);
11232 }
11233 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
11234 }
11235 }
11236 }
11237
11238 uint32_t result = pos;
11239 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
11240 Heap* heap = GetHeap();
11241 while (undefs > 0) {
11242 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11243 // Adding an entry with the key beyond smi-range requires
11244 // allocation. Bailout.
11245 return Smi::FromInt(-1);
11246 }
11247 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
11248 ToObjectUnchecked();
11249 pos++;
11250 undefs--;
11251 }
11252
11253 set_elements(new_dict);
11254
11255 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11256 return Smi::FromInt(static_cast<int>(result));
11257 }
11258
11259 ASSERT_NE(NULL, result_double);
11260 result_double->set_value(static_cast<double>(result));
11261 return result_double;
11262 }
11263
11264
11265 // Collects all defined (non-hole) and non-undefined (array) elements at
11266 // the start of the elements array.
11267 // If the object is in dictionary mode, it is converted to fast elements
11268 // mode.
PrepareElementsForSort(uint32_t limit)11269 MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
11270 Heap* heap = GetHeap();
11271
11272 if (HasDictionaryElements()) {
11273 // Convert to fast elements containing only the existing properties.
11274 // Ordering is irrelevant, since we are going to sort anyway.
11275 SeededNumberDictionary* dict = element_dictionary();
11276 if (IsJSArray() || dict->requires_slow_elements() ||
11277 dict->max_number_key() >= limit) {
11278 return PrepareSlowElementsForSort(limit);
11279 }
11280 // Convert to fast elements.
11281
11282 Object* obj;
11283 { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11284 FAST_ELEMENTS);
11285 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11286 }
11287 Map* new_map = Map::cast(obj);
11288
11289 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
11290 Object* new_array;
11291 { MaybeObject* maybe_new_array =
11292 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
11293 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11294 }
11295 FixedArray* fast_elements = FixedArray::cast(new_array);
11296 dict->CopyValuesTo(fast_elements);
11297
11298 set_map(new_map);
11299 set_elements(fast_elements);
11300 } else if (HasExternalArrayElements()) {
11301 // External arrays cannot have holes or undefined elements.
11302 return Smi::FromInt(ExternalArray::cast(elements())->length());
11303 } else if (!HasFastDoubleElements()) {
11304 Object* obj;
11305 { MaybeObject* maybe_obj = EnsureWritableFastElements();
11306 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11307 }
11308 }
11309 ASSERT(HasFastTypeElements() || HasFastDoubleElements());
11310
11311 // Collect holes at the end, undefined before that and the rest at the
11312 // start, and return the number of non-hole, non-undefined values.
11313
11314 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11315 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
11316 if (limit > elements_length) {
11317 limit = elements_length ;
11318 }
11319 if (limit == 0) {
11320 return Smi::FromInt(0);
11321 }
11322
11323 HeapNumber* result_double = NULL;
11324 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11325 // Pessimistically allocate space for return value before
11326 // we start mutating the array.
11327 Object* new_double;
11328 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
11329 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11330 }
11331 result_double = HeapNumber::cast(new_double);
11332 }
11333
11334 uint32_t result = 0;
11335 if (elements_base->map() == heap->fixed_double_array_map()) {
11336 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11337 // Split elements into defined and the_hole, in that order.
11338 unsigned int holes = limit;
11339 // Assume most arrays contain no holes and undefined values, so minimize the
11340 // number of stores of non-undefined, non-the-hole values.
11341 for (unsigned int i = 0; i < holes; i++) {
11342 if (elements->is_the_hole(i)) {
11343 holes--;
11344 } else {
11345 continue;
11346 }
11347 // Position i needs to be filled.
11348 while (holes > i) {
11349 if (elements->is_the_hole(holes)) {
11350 holes--;
11351 } else {
11352 elements->set(i, elements->get_scalar(holes));
11353 break;
11354 }
11355 }
11356 }
11357 result = holes;
11358 while (holes < limit) {
11359 elements->set_the_hole(holes);
11360 holes++;
11361 }
11362 } else {
11363 FixedArray* elements = FixedArray::cast(elements_base);
11364 AssertNoAllocation no_alloc;
11365
11366 // Split elements into defined, undefined and the_hole, in that order. Only
11367 // count locations for undefined and the hole, and fill them afterwards.
11368 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11369 unsigned int undefs = limit;
11370 unsigned int holes = limit;
11371 // Assume most arrays contain no holes and undefined values, so minimize the
11372 // number of stores of non-undefined, non-the-hole values.
11373 for (unsigned int i = 0; i < undefs; i++) {
11374 Object* current = elements->get(i);
11375 if (current->IsTheHole()) {
11376 holes--;
11377 undefs--;
11378 } else if (current->IsUndefined()) {
11379 undefs--;
11380 } else {
11381 continue;
11382 }
11383 // Position i needs to be filled.
11384 while (undefs > i) {
11385 current = elements->get(undefs);
11386 if (current->IsTheHole()) {
11387 holes--;
11388 undefs--;
11389 } else if (current->IsUndefined()) {
11390 undefs--;
11391 } else {
11392 elements->set(i, current, write_barrier);
11393 break;
11394 }
11395 }
11396 }
11397 result = undefs;
11398 while (undefs < holes) {
11399 elements->set_undefined(undefs);
11400 undefs++;
11401 }
11402 while (holes < limit) {
11403 elements->set_the_hole(holes);
11404 holes++;
11405 }
11406 }
11407
11408 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11409 return Smi::FromInt(static_cast<int>(result));
11410 }
11411 ASSERT_NE(NULL, result_double);
11412 result_double->set_value(static_cast<double>(result));
11413 return result_double;
11414 }
11415
11416
SetValue(uint32_t index,Object * value)11417 Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
11418 uint8_t clamped_value = 0;
11419 if (index < static_cast<uint32_t>(length())) {
11420 if (value->IsSmi()) {
11421 int int_value = Smi::cast(value)->value();
11422 if (int_value < 0) {
11423 clamped_value = 0;
11424 } else if (int_value > 255) {
11425 clamped_value = 255;
11426 } else {
11427 clamped_value = static_cast<uint8_t>(int_value);
11428 }
11429 } else if (value->IsHeapNumber()) {
11430 double double_value = HeapNumber::cast(value)->value();
11431 if (!(double_value > 0)) {
11432 // NaN and less than zero clamp to zero.
11433 clamped_value = 0;
11434 } else if (double_value > 255) {
11435 // Greater than 255 clamp to 255.
11436 clamped_value = 255;
11437 } else {
11438 // Other doubles are rounded to the nearest integer.
11439 clamped_value = static_cast<uint8_t>(double_value + 0.5);
11440 }
11441 } else {
11442 // Clamp undefined to zero (default). All other types have been
11443 // converted to a number type further up in the call chain.
11444 ASSERT(value->IsUndefined());
11445 }
11446 set(index, clamped_value);
11447 }
11448 return Smi::FromInt(clamped_value);
11449 }
11450
11451
11452 template<typename ExternalArrayClass, typename ValueType>
ExternalArrayIntSetter(Heap * heap,ExternalArrayClass * receiver,uint32_t index,Object * value)11453 static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11454 ExternalArrayClass* receiver,
11455 uint32_t index,
11456 Object* value) {
11457 ValueType cast_value = 0;
11458 if (index < static_cast<uint32_t>(receiver->length())) {
11459 if (value->IsSmi()) {
11460 int int_value = Smi::cast(value)->value();
11461 cast_value = static_cast<ValueType>(int_value);
11462 } else if (value->IsHeapNumber()) {
11463 double double_value = HeapNumber::cast(value)->value();
11464 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11465 } else {
11466 // Clamp undefined to zero (default). All other types have been
11467 // converted to a number type further up in the call chain.
11468 ASSERT(value->IsUndefined());
11469 }
11470 receiver->set(index, cast_value);
11471 }
11472 return heap->NumberFromInt32(cast_value);
11473 }
11474
11475
SetValue(uint32_t index,Object * value)11476 MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
11477 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
11478 (GetHeap(), this, index, value);
11479 }
11480
11481
SetValue(uint32_t index,Object * value)11482 MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11483 Object* value) {
11484 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
11485 (GetHeap(), this, index, value);
11486 }
11487
11488
SetValue(uint32_t index,Object * value)11489 MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11490 Object* value) {
11491 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
11492 (GetHeap(), this, index, value);
11493 }
11494
11495
SetValue(uint32_t index,Object * value)11496 MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11497 Object* value) {
11498 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
11499 (GetHeap(), this, index, value);
11500 }
11501
11502
SetValue(uint32_t index,Object * value)11503 MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
11504 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
11505 (GetHeap(), this, index, value);
11506 }
11507
11508
SetValue(uint32_t index,Object * value)11509 MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
11510 uint32_t cast_value = 0;
11511 Heap* heap = GetHeap();
11512 if (index < static_cast<uint32_t>(length())) {
11513 if (value->IsSmi()) {
11514 int int_value = Smi::cast(value)->value();
11515 cast_value = static_cast<uint32_t>(int_value);
11516 } else if (value->IsHeapNumber()) {
11517 double double_value = HeapNumber::cast(value)->value();
11518 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11519 } else {
11520 // Clamp undefined to zero (default). All other types have been
11521 // converted to a number type further up in the call chain.
11522 ASSERT(value->IsUndefined());
11523 }
11524 set(index, cast_value);
11525 }
11526 return heap->NumberFromUint32(cast_value);
11527 }
11528
11529
SetValue(uint32_t index,Object * value)11530 MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
11531 float cast_value = static_cast<float>(OS::nan_value());
11532 Heap* heap = GetHeap();
11533 if (index < static_cast<uint32_t>(length())) {
11534 if (value->IsSmi()) {
11535 int int_value = Smi::cast(value)->value();
11536 cast_value = static_cast<float>(int_value);
11537 } else if (value->IsHeapNumber()) {
11538 double double_value = HeapNumber::cast(value)->value();
11539 cast_value = static_cast<float>(double_value);
11540 } else {
11541 // Clamp undefined to NaN (default). All other types have been
11542 // converted to a number type further up in the call chain.
11543 ASSERT(value->IsUndefined());
11544 }
11545 set(index, cast_value);
11546 }
11547 return heap->AllocateHeapNumber(cast_value);
11548 }
11549
11550
SetValue(uint32_t index,Object * value)11551 MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
11552 double double_value = OS::nan_value();
11553 Heap* heap = GetHeap();
11554 if (index < static_cast<uint32_t>(length())) {
11555 if (value->IsSmi()) {
11556 int int_value = Smi::cast(value)->value();
11557 double_value = static_cast<double>(int_value);
11558 } else if (value->IsHeapNumber()) {
11559 double_value = HeapNumber::cast(value)->value();
11560 } else {
11561 // Clamp undefined to NaN (default). All other types have been
11562 // converted to a number type further up in the call chain.
11563 ASSERT(value->IsUndefined());
11564 }
11565 set(index, double_value);
11566 }
11567 return heap->AllocateHeapNumber(double_value);
11568 }
11569
11570
GetPropertyCell(LookupResult * result)11571 JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
11572 ASSERT(!HasFastProperties());
11573 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
11574 return JSGlobalPropertyCell::cast(value);
11575 }
11576
11577
EnsurePropertyCell(Handle<GlobalObject> global,Handle<String> name)11578 Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11579 Handle<GlobalObject> global,
11580 Handle<String> name) {
11581 Isolate* isolate = global->GetIsolate();
11582 CALL_HEAP_FUNCTION(isolate,
11583 global->EnsurePropertyCell(*name),
11584 JSGlobalPropertyCell);
11585 }
11586
11587
EnsurePropertyCell(String * name)11588 MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
11589 ASSERT(!HasFastProperties());
11590 int entry = property_dictionary()->FindEntry(name);
11591 if (entry == StringDictionary::kNotFound) {
11592 Heap* heap = GetHeap();
11593 Object* cell;
11594 { MaybeObject* maybe_cell =
11595 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
11596 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11597 }
11598 PropertyDetails details(NONE, NORMAL);
11599 details = details.AsDeleted();
11600 Object* dictionary;
11601 { MaybeObject* maybe_dictionary =
11602 property_dictionary()->Add(name, cell, details);
11603 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11604 }
11605 set_properties(StringDictionary::cast(dictionary));
11606 return cell;
11607 } else {
11608 Object* value = property_dictionary()->ValueAt(entry);
11609 ASSERT(value->IsJSGlobalPropertyCell());
11610 return value;
11611 }
11612 }
11613
11614
LookupString(String * string,Object ** s)11615 MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
11616 SymbolKey key(string);
11617 return LookupKey(&key, s);
11618 }
11619
11620
11621 // This class is used for looking up two character strings in the symbol table.
11622 // If we don't have a hit we don't want to waste much time so we unroll the
11623 // string hash calculation loop here for speed. Doesn't work if the two
11624 // characters form a decimal integer, since such strings have a different hash
11625 // algorithm.
11626 class TwoCharHashTableKey : public HashTableKey {
11627 public:
TwoCharHashTableKey(uint32_t c1,uint32_t c2,uint32_t seed)11628 TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
11629 : c1_(c1), c2_(c2) {
11630 // Char 1.
11631 uint32_t hash = seed;
11632 hash += c1;
11633 hash += hash << 10;
11634 hash ^= hash >> 6;
11635 // Char 2.
11636 hash += c2;
11637 hash += hash << 10;
11638 hash ^= hash >> 6;
11639 // GetHash.
11640 hash += hash << 3;
11641 hash ^= hash >> 11;
11642 hash += hash << 15;
11643 if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
11644 #ifdef DEBUG
11645 StringHasher hasher(2, seed);
11646 hasher.AddCharacter(c1);
11647 hasher.AddCharacter(c2);
11648 // If this assert fails then we failed to reproduce the two-character
11649 // version of the string hashing algorithm above. One reason could be
11650 // that we were passed two digits as characters, since the hash
11651 // algorithm is different in that case.
11652 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11653 #endif
11654 hash_ = hash;
11655 }
11656
IsMatch(Object * o)11657 bool IsMatch(Object* o) {
11658 if (!o->IsString()) return false;
11659 String* other = String::cast(o);
11660 if (other->length() != 2) return false;
11661 if (other->Get(0) != c1_) return false;
11662 return other->Get(1) == c2_;
11663 }
11664
Hash()11665 uint32_t Hash() { return hash_; }
HashForObject(Object * key)11666 uint32_t HashForObject(Object* key) {
11667 if (!key->IsString()) return 0;
11668 return String::cast(key)->Hash();
11669 }
11670
AsObject()11671 Object* AsObject() {
11672 // The TwoCharHashTableKey is only used for looking in the symbol
11673 // table, not for adding to it.
11674 UNREACHABLE();
11675 return NULL;
11676 }
11677
11678 private:
11679 uint32_t c1_;
11680 uint32_t c2_;
11681 uint32_t hash_;
11682 };
11683
11684
LookupSymbolIfExists(String * string,String ** symbol)11685 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11686 SymbolKey key(string);
11687 int entry = FindEntry(&key);
11688 if (entry == kNotFound) {
11689 return false;
11690 } else {
11691 String* result = String::cast(KeyAt(entry));
11692 ASSERT(StringShape(result).IsSymbol());
11693 *symbol = result;
11694 return true;
11695 }
11696 }
11697
11698
LookupTwoCharsSymbolIfExists(uint32_t c1,uint32_t c2,String ** symbol)11699 bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11700 uint32_t c2,
11701 String** symbol) {
11702 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
11703 int entry = FindEntry(&key);
11704 if (entry == kNotFound) {
11705 return false;
11706 } else {
11707 String* result = String::cast(KeyAt(entry));
11708 ASSERT(StringShape(result).IsSymbol());
11709 *symbol = result;
11710 return true;
11711 }
11712 }
11713
11714
LookupSymbol(Vector<const char> str,Object ** s)11715 MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11716 Object** s) {
11717 Utf8SymbolKey key(str, GetHeap()->HashSeed());
11718 return LookupKey(&key, s);
11719 }
11720
11721
LookupAsciiSymbol(Vector<const char> str,Object ** s)11722 MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11723 Object** s) {
11724 AsciiSymbolKey key(str, GetHeap()->HashSeed());
11725 return LookupKey(&key, s);
11726 }
11727
11728
LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,int from,int length,Object ** s)11729 MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11730 int from,
11731 int length,
11732 Object** s) {
11733 SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
11734 return LookupKey(&key, s);
11735 }
11736
11737
LookupTwoByteSymbol(Vector<const uc16> str,Object ** s)11738 MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11739 Object** s) {
11740 TwoByteSymbolKey key(str, GetHeap()->HashSeed());
11741 return LookupKey(&key, s);
11742 }
11743
LookupKey(HashTableKey * key,Object ** s)11744 MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
11745 int entry = FindEntry(key);
11746
11747 // Symbol already in table.
11748 if (entry != kNotFound) {
11749 *s = KeyAt(entry);
11750 return this;
11751 }
11752
11753 // Adding new symbol. Grow table if needed.
11754 Object* obj;
11755 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11756 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11757 }
11758
11759 // Create symbol object.
11760 Object* symbol;
11761 { MaybeObject* maybe_symbol = key->AsObject();
11762 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11763 }
11764
11765 // If the symbol table grew as part of EnsureCapacity, obj is not
11766 // the current symbol table and therefore we cannot use
11767 // SymbolTable::cast here.
11768 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11769
11770 // Add the new symbol and return it along with the symbol table.
11771 entry = table->FindInsertionEntry(key->Hash());
11772 table->set(EntryToIndex(entry), symbol);
11773 table->ElementAdded();
11774 *s = symbol;
11775 return table;
11776 }
11777
11778
Lookup(String * src)11779 Object* CompilationCacheTable::Lookup(String* src) {
11780 StringKey key(src);
11781 int entry = FindEntry(&key);
11782 if (entry == kNotFound) return GetHeap()->undefined_value();
11783 return get(EntryToIndex(entry) + 1);
11784 }
11785
11786
LookupEval(String * src,Context * context,LanguageMode language_mode,int scope_position)11787 Object* CompilationCacheTable::LookupEval(String* src,
11788 Context* context,
11789 LanguageMode language_mode,
11790 int scope_position) {
11791 StringSharedKey key(src,
11792 context->closure()->shared(),
11793 language_mode,
11794 scope_position);
11795 int entry = FindEntry(&key);
11796 if (entry == kNotFound) return GetHeap()->undefined_value();
11797 return get(EntryToIndex(entry) + 1);
11798 }
11799
11800
LookupRegExp(String * src,JSRegExp::Flags flags)11801 Object* CompilationCacheTable::LookupRegExp(String* src,
11802 JSRegExp::Flags flags) {
11803 RegExpKey key(src, flags);
11804 int entry = FindEntry(&key);
11805 if (entry == kNotFound) return GetHeap()->undefined_value();
11806 return get(EntryToIndex(entry) + 1);
11807 }
11808
11809
Put(String * src,Object * value)11810 MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
11811 StringKey key(src);
11812 Object* obj;
11813 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11814 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11815 }
11816
11817 CompilationCacheTable* cache =
11818 reinterpret_cast<CompilationCacheTable*>(obj);
11819 int entry = cache->FindInsertionEntry(key.Hash());
11820 cache->set(EntryToIndex(entry), src);
11821 cache->set(EntryToIndex(entry) + 1, value);
11822 cache->ElementAdded();
11823 return cache;
11824 }
11825
11826
PutEval(String * src,Context * context,SharedFunctionInfo * value,int scope_position)11827 MaybeObject* CompilationCacheTable::PutEval(String* src,
11828 Context* context,
11829 SharedFunctionInfo* value,
11830 int scope_position) {
11831 StringSharedKey key(src,
11832 context->closure()->shared(),
11833 value->language_mode(),
11834 scope_position);
11835 Object* obj;
11836 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11837 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11838 }
11839
11840 CompilationCacheTable* cache =
11841 reinterpret_cast<CompilationCacheTable*>(obj);
11842 int entry = cache->FindInsertionEntry(key.Hash());
11843
11844 Object* k;
11845 { MaybeObject* maybe_k = key.AsObject();
11846 if (!maybe_k->ToObject(&k)) return maybe_k;
11847 }
11848
11849 cache->set(EntryToIndex(entry), k);
11850 cache->set(EntryToIndex(entry) + 1, value);
11851 cache->ElementAdded();
11852 return cache;
11853 }
11854
11855
PutRegExp(String * src,JSRegExp::Flags flags,FixedArray * value)11856 MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11857 JSRegExp::Flags flags,
11858 FixedArray* value) {
11859 RegExpKey key(src, flags);
11860 Object* obj;
11861 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11862 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11863 }
11864
11865 CompilationCacheTable* cache =
11866 reinterpret_cast<CompilationCacheTable*>(obj);
11867 int entry = cache->FindInsertionEntry(key.Hash());
11868 // We store the value in the key slot, and compare the search key
11869 // to the stored value with a custon IsMatch function during lookups.
11870 cache->set(EntryToIndex(entry), value);
11871 cache->set(EntryToIndex(entry) + 1, value);
11872 cache->ElementAdded();
11873 return cache;
11874 }
11875
11876
Remove(Object * value)11877 void CompilationCacheTable::Remove(Object* value) {
11878 Object* the_hole_value = GetHeap()->the_hole_value();
11879 for (int entry = 0, size = Capacity(); entry < size; entry++) {
11880 int entry_index = EntryToIndex(entry);
11881 int value_index = entry_index + 1;
11882 if (get(value_index) == value) {
11883 NoWriteBarrierSet(this, entry_index, the_hole_value);
11884 NoWriteBarrierSet(this, value_index, the_hole_value);
11885 ElementRemoved();
11886 }
11887 }
11888 return;
11889 }
11890
11891
11892 // SymbolsKey used for HashTable where key is array of symbols.
11893 class SymbolsKey : public HashTableKey {
11894 public:
SymbolsKey(FixedArray * symbols)11895 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
11896
IsMatch(Object * symbols)11897 bool IsMatch(Object* symbols) {
11898 FixedArray* o = FixedArray::cast(symbols);
11899 int len = symbols_->length();
11900 if (o->length() != len) return false;
11901 for (int i = 0; i < len; i++) {
11902 if (o->get(i) != symbols_->get(i)) return false;
11903 }
11904 return true;
11905 }
11906
Hash()11907 uint32_t Hash() { return HashForObject(symbols_); }
11908
HashForObject(Object * obj)11909 uint32_t HashForObject(Object* obj) {
11910 FixedArray* symbols = FixedArray::cast(obj);
11911 int len = symbols->length();
11912 uint32_t hash = 0;
11913 for (int i = 0; i < len; i++) {
11914 hash ^= String::cast(symbols->get(i))->Hash();
11915 }
11916 return hash;
11917 }
11918
AsObject()11919 Object* AsObject() { return symbols_; }
11920
11921 private:
11922 FixedArray* symbols_;
11923 };
11924
11925
Lookup(FixedArray * array)11926 Object* MapCache::Lookup(FixedArray* array) {
11927 SymbolsKey key(array);
11928 int entry = FindEntry(&key);
11929 if (entry == kNotFound) return GetHeap()->undefined_value();
11930 return get(EntryToIndex(entry) + 1);
11931 }
11932
11933
Put(FixedArray * array,Map * value)11934 MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
11935 SymbolsKey key(array);
11936 Object* obj;
11937 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11938 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11939 }
11940
11941 MapCache* cache = reinterpret_cast<MapCache*>(obj);
11942 int entry = cache->FindInsertionEntry(key.Hash());
11943 cache->set(EntryToIndex(entry), array);
11944 cache->set(EntryToIndex(entry) + 1, value);
11945 cache->ElementAdded();
11946 return cache;
11947 }
11948
11949
11950 template<typename Shape, typename Key>
Allocate(int at_least_space_for)11951 MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
11952 Object* obj;
11953 { MaybeObject* maybe_obj =
11954 HashTable<Shape, Key>::Allocate(at_least_space_for);
11955 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11956 }
11957 // Initialize the next enumeration index.
11958 Dictionary<Shape, Key>::cast(obj)->
11959 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
11960 return obj;
11961 }
11962
11963
11964 template<typename Shape, typename Key>
GenerateNewEnumerationIndices()11965 MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
11966 Heap* heap = Dictionary<Shape, Key>::GetHeap();
11967 int length = HashTable<Shape, Key>::NumberOfElements();
11968
11969 // Allocate and initialize iteration order array.
11970 Object* obj;
11971 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
11972 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11973 }
11974 FixedArray* iteration_order = FixedArray::cast(obj);
11975 for (int i = 0; i < length; i++) {
11976 iteration_order->set(i, Smi::FromInt(i));
11977 }
11978
11979 // Allocate array with enumeration order.
11980 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
11981 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11982 }
11983 FixedArray* enumeration_order = FixedArray::cast(obj);
11984
11985 // Fill the enumeration order array with property details.
11986 int capacity = HashTable<Shape, Key>::Capacity();
11987 int pos = 0;
11988 for (int i = 0; i < capacity; i++) {
11989 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
11990 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
11991 }
11992 }
11993
11994 // Sort the arrays wrt. enumeration order.
11995 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
11996
11997 // Overwrite the enumeration_order with the enumeration indices.
11998 for (int i = 0; i < length; i++) {
11999 int index = Smi::cast(iteration_order->get(i))->value();
12000 int enum_index = PropertyDetails::kInitialIndex + i;
12001 enumeration_order->set(index, Smi::FromInt(enum_index));
12002 }
12003
12004 // Update the dictionary with new indices.
12005 capacity = HashTable<Shape, Key>::Capacity();
12006 pos = 0;
12007 for (int i = 0; i < capacity; i++) {
12008 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
12009 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
12010 PropertyDetails details = DetailsAt(i);
12011 PropertyDetails new_details =
12012 PropertyDetails(details.attributes(), details.type(), enum_index);
12013 DetailsAtPut(i, new_details);
12014 }
12015 }
12016
12017 // Set the next enumeration index.
12018 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
12019 return this;
12020 }
12021
12022 template<typename Shape, typename Key>
EnsureCapacity(int n,Key key)12023 MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
12024 // Check whether there are enough enumeration indices to add n elements.
12025 if (Shape::kIsEnumerable &&
12026 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
12027 // If not, we generate new indices for the properties.
12028 Object* result;
12029 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12030 if (!maybe_result->ToObject(&result)) return maybe_result;
12031 }
12032 }
12033 return HashTable<Shape, Key>::EnsureCapacity(n, key);
12034 }
12035
12036
12037 template<typename Shape, typename Key>
DeleteProperty(int entry,JSReceiver::DeleteMode mode)12038 Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
12039 JSReceiver::DeleteMode mode) {
12040 Heap* heap = Dictionary<Shape, Key>::GetHeap();
12041 PropertyDetails details = DetailsAt(entry);
12042 // Ignore attributes if forcing a deletion.
12043 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
12044 return heap->false_value();
12045 }
12046 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
12047 HashTable<Shape, Key>::ElementRemoved();
12048 return heap->true_value();
12049 }
12050
12051
12052 template<typename Shape, typename Key>
Shrink(Key key)12053 MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12054 return HashTable<Shape, Key>::Shrink(key);
12055 }
12056
12057
12058 template<typename Shape, typename Key>
AtPut(Key key,Object * value)12059 MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
12060 int entry = this->FindEntry(key);
12061
12062 // If the entry is present set the value;
12063 if (entry != Dictionary<Shape, Key>::kNotFound) {
12064 ValueAtPut(entry, value);
12065 return this;
12066 }
12067
12068 // Check whether the dictionary should be extended.
12069 Object* obj;
12070 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12071 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12072 }
12073
12074 Object* k;
12075 { MaybeObject* maybe_k = Shape::AsObject(key);
12076 if (!maybe_k->ToObject(&k)) return maybe_k;
12077 }
12078 PropertyDetails details = PropertyDetails(NONE, NORMAL);
12079
12080 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12081 Dictionary<Shape, Key>::Hash(key));
12082 }
12083
12084
12085 template<typename Shape, typename Key>
Add(Key key,Object * value,PropertyDetails details)12086 MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12087 Object* value,
12088 PropertyDetails details) {
12089 // Valdate key is absent.
12090 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
12091 // Check whether the dictionary should be extended.
12092 Object* obj;
12093 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12094 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12095 }
12096
12097 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12098 Dictionary<Shape, Key>::Hash(key));
12099 }
12100
12101
12102 // Add a key, value pair to the dictionary.
12103 template<typename Shape, typename Key>
AddEntry(Key key,Object * value,PropertyDetails details,uint32_t hash)12104 MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12105 Object* value,
12106 PropertyDetails details,
12107 uint32_t hash) {
12108 // Compute the key object.
12109 Object* k;
12110 { MaybeObject* maybe_k = Shape::AsObject(key);
12111 if (!maybe_k->ToObject(&k)) return maybe_k;
12112 }
12113
12114 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
12115 // Insert element at empty or deleted entry
12116 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
12117 // Assign an enumeration index to the property and update
12118 // SetNextEnumerationIndex.
12119 int index = NextEnumerationIndex();
12120 details = PropertyDetails(details.attributes(), details.type(), index);
12121 SetNextEnumerationIndex(index + 1);
12122 }
12123 SetEntry(entry, k, value, details);
12124 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12125 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12126 HashTable<Shape, Key>::ElementAdded();
12127 return this;
12128 }
12129
12130
UpdateMaxNumberKey(uint32_t key)12131 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
12132 // If the dictionary requires slow elements an element has already
12133 // been added at a high index.
12134 if (requires_slow_elements()) return;
12135 // Check if this index is high enough that we should require slow
12136 // elements.
12137 if (key > kRequiresSlowElementsLimit) {
12138 set_requires_slow_elements();
12139 return;
12140 }
12141 // Update max key value.
12142 Object* max_index_object = get(kMaxNumberKeyIndex);
12143 if (!max_index_object->IsSmi() || max_number_key() < key) {
12144 FixedArray::set(kMaxNumberKeyIndex,
12145 Smi::FromInt(key << kRequiresSlowElementsTagSize));
12146 }
12147 }
12148
12149
AddNumberEntry(uint32_t key,Object * value,PropertyDetails details)12150 MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12151 Object* value,
12152 PropertyDetails details) {
12153 UpdateMaxNumberKey(key);
12154 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12155 return Add(key, value, details);
12156 }
12157
12158
AddNumberEntry(uint32_t key,Object * value)12159 MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12160 Object* value) {
12161 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12162 return Add(key, value, PropertyDetails(NONE, NORMAL));
12163 }
12164
12165
AtNumberPut(uint32_t key,Object * value)12166 MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
12167 UpdateMaxNumberKey(key);
12168 return AtPut(key, value);
12169 }
12170
12171
AtNumberPut(uint32_t key,Object * value)12172 MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12173 Object* value) {
12174 return AtPut(key, value);
12175 }
12176
12177
Set(Handle<SeededNumberDictionary> dictionary,uint32_t index,Handle<Object> value,PropertyDetails details)12178 Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12179 Handle<SeededNumberDictionary> dictionary,
12180 uint32_t index,
12181 Handle<Object> value,
12182 PropertyDetails details) {
12183 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12184 dictionary->Set(index, *value, details),
12185 SeededNumberDictionary);
12186 }
12187
12188
Set(Handle<UnseededNumberDictionary> dictionary,uint32_t index,Handle<Object> value)12189 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12190 Handle<UnseededNumberDictionary> dictionary,
12191 uint32_t index,
12192 Handle<Object> value) {
12193 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12194 dictionary->Set(index, *value),
12195 UnseededNumberDictionary);
12196 }
12197
12198
Set(uint32_t key,Object * value,PropertyDetails details)12199 MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12200 Object* value,
12201 PropertyDetails details) {
12202 int entry = FindEntry(key);
12203 if (entry == kNotFound) return AddNumberEntry(key, value, details);
12204 // Preserve enumeration index.
12205 details = PropertyDetails(details.attributes(),
12206 details.type(),
12207 DetailsAt(entry).index());
12208 MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
12209 Object* object_key;
12210 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12211 SetEntry(entry, object_key, value, details);
12212 return this;
12213 }
12214
12215
Set(uint32_t key,Object * value)12216 MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12217 Object* value) {
12218 int entry = FindEntry(key);
12219 if (entry == kNotFound) return AddNumberEntry(key, value);
12220 MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12221 Object* object_key;
12222 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12223 SetEntry(entry, object_key, value);
12224 return this;
12225 }
12226
12227
12228
12229 template<typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyAttributes filter)12230 int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12231 PropertyAttributes filter) {
12232 int capacity = HashTable<Shape, Key>::Capacity();
12233 int result = 0;
12234 for (int i = 0; i < capacity; i++) {
12235 Object* k = HashTable<Shape, Key>::KeyAt(i);
12236 if (HashTable<Shape, Key>::IsKey(k)) {
12237 PropertyDetails details = DetailsAt(i);
12238 if (details.IsDeleted()) continue;
12239 PropertyAttributes attr = details.attributes();
12240 if ((attr & filter) == 0) result++;
12241 }
12242 }
12243 return result;
12244 }
12245
12246
12247 template<typename Shape, typename Key>
NumberOfEnumElements()12248 int Dictionary<Shape, Key>::NumberOfEnumElements() {
12249 return NumberOfElementsFilterAttributes(
12250 static_cast<PropertyAttributes>(DONT_ENUM));
12251 }
12252
12253
12254 template<typename Shape, typename Key>
CopyKeysTo(FixedArray * storage,PropertyAttributes filter,typename Dictionary<Shape,Key>::SortMode sort_mode)12255 void Dictionary<Shape, Key>::CopyKeysTo(
12256 FixedArray* storage,
12257 PropertyAttributes filter,
12258 typename Dictionary<Shape, Key>::SortMode sort_mode) {
12259 ASSERT(storage->length() >= NumberOfEnumElements());
12260 int capacity = HashTable<Shape, Key>::Capacity();
12261 int index = 0;
12262 for (int i = 0; i < capacity; i++) {
12263 Object* k = HashTable<Shape, Key>::KeyAt(i);
12264 if (HashTable<Shape, Key>::IsKey(k)) {
12265 PropertyDetails details = DetailsAt(i);
12266 if (details.IsDeleted()) continue;
12267 PropertyAttributes attr = details.attributes();
12268 if ((attr & filter) == 0) storage->set(index++, k);
12269 }
12270 }
12271 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12272 storage->SortPairs(storage, index);
12273 }
12274 ASSERT(storage->length() >= index);
12275 }
12276
12277
CopyEnumKeysTo(FixedArray * storage,FixedArray * sort_array)12278 void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12279 FixedArray* sort_array) {
12280 ASSERT(storage->length() >= NumberOfEnumElements());
12281 int capacity = Capacity();
12282 int index = 0;
12283 for (int i = 0; i < capacity; i++) {
12284 Object* k = KeyAt(i);
12285 if (IsKey(k)) {
12286 PropertyDetails details = DetailsAt(i);
12287 if (details.IsDeleted() || details.IsDontEnum()) continue;
12288 storage->set(index, k);
12289 sort_array->set(index, Smi::FromInt(details.index()));
12290 index++;
12291 }
12292 }
12293 storage->SortPairs(sort_array, sort_array->length());
12294 ASSERT(storage->length() >= index);
12295 }
12296
12297
12298 template<typename Shape, typename Key>
CopyKeysTo(FixedArray * storage,int index,typename Dictionary<Shape,Key>::SortMode sort_mode)12299 void Dictionary<Shape, Key>::CopyKeysTo(
12300 FixedArray* storage,
12301 int index,
12302 typename Dictionary<Shape, Key>::SortMode sort_mode) {
12303 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12304 static_cast<PropertyAttributes>(NONE)));
12305 int capacity = HashTable<Shape, Key>::Capacity();
12306 for (int i = 0; i < capacity; i++) {
12307 Object* k = HashTable<Shape, Key>::KeyAt(i);
12308 if (HashTable<Shape, Key>::IsKey(k)) {
12309 PropertyDetails details = DetailsAt(i);
12310 if (details.IsDeleted()) continue;
12311 storage->set(index++, k);
12312 }
12313 }
12314 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12315 storage->SortPairs(storage, index);
12316 }
12317 ASSERT(storage->length() >= index);
12318 }
12319
12320
12321 // Backwards lookup (slow).
12322 template<typename Shape, typename Key>
SlowReverseLookup(Object * value)12323 Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12324 int capacity = HashTable<Shape, Key>::Capacity();
12325 for (int i = 0; i < capacity; i++) {
12326 Object* k = HashTable<Shape, Key>::KeyAt(i);
12327 if (Dictionary<Shape, Key>::IsKey(k)) {
12328 Object* e = ValueAt(i);
12329 if (e->IsJSGlobalPropertyCell()) {
12330 e = JSGlobalPropertyCell::cast(e)->value();
12331 }
12332 if (e == value) return k;
12333 }
12334 }
12335 Heap* heap = Dictionary<Shape, Key>::GetHeap();
12336 return heap->undefined_value();
12337 }
12338
12339
TransformPropertiesToFastFor(JSObject * obj,int unused_property_fields)12340 MaybeObject* StringDictionary::TransformPropertiesToFastFor(
12341 JSObject* obj, int unused_property_fields) {
12342 // Make sure we preserve dictionary representation if there are too many
12343 // descriptors.
12344 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12345
12346 // Figure out if it is necessary to generate new enumeration indices.
12347 int max_enumeration_index =
12348 NextEnumerationIndex() +
12349 (DescriptorArray::kMaxNumberOfDescriptors -
12350 NumberOfElements());
12351 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
12352 Object* result;
12353 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12354 if (!maybe_result->ToObject(&result)) return maybe_result;
12355 }
12356 }
12357
12358 int instance_descriptor_length = 0;
12359 int number_of_fields = 0;
12360
12361 Heap* heap = GetHeap();
12362
12363 // Compute the length of the instance descriptor.
12364 int capacity = Capacity();
12365 for (int i = 0; i < capacity; i++) {
12366 Object* k = KeyAt(i);
12367 if (IsKey(k)) {
12368 Object* value = ValueAt(i);
12369 PropertyType type = DetailsAt(i).type();
12370 ASSERT(type != FIELD);
12371 instance_descriptor_length++;
12372 if (type == NORMAL &&
12373 (!value->IsJSFunction() || heap->InNewSpace(value))) {
12374 number_of_fields += 1;
12375 }
12376 }
12377 }
12378
12379 // Allocate the instance descriptor.
12380 DescriptorArray* descriptors;
12381 { MaybeObject* maybe_descriptors =
12382 DescriptorArray::Allocate(instance_descriptor_length);
12383 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12384 return maybe_descriptors;
12385 }
12386 }
12387
12388 DescriptorArray::WhitenessWitness witness(descriptors);
12389
12390 int inobject_props = obj->map()->inobject_properties();
12391 int number_of_allocated_fields =
12392 number_of_fields + unused_property_fields - inobject_props;
12393 if (number_of_allocated_fields < 0) {
12394 // There is enough inobject space for all fields (including unused).
12395 number_of_allocated_fields = 0;
12396 unused_property_fields = inobject_props - number_of_fields;
12397 }
12398
12399 // Allocate the fixed array for the fields.
12400 Object* fields;
12401 { MaybeObject* maybe_fields =
12402 heap->AllocateFixedArray(number_of_allocated_fields);
12403 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12404 }
12405
12406 // Fill in the instance descriptor and the fields.
12407 int next_descriptor = 0;
12408 int current_offset = 0;
12409 for (int i = 0; i < capacity; i++) {
12410 Object* k = KeyAt(i);
12411 if (IsKey(k)) {
12412 Object* value = ValueAt(i);
12413 // Ensure the key is a symbol before writing into the instance descriptor.
12414 Object* key;
12415 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
12416 if (!maybe_key->ToObject(&key)) return maybe_key;
12417 }
12418 PropertyDetails details = DetailsAt(i);
12419 PropertyType type = details.type();
12420
12421 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
12422 ConstantFunctionDescriptor d(String::cast(key),
12423 JSFunction::cast(value),
12424 details.attributes(),
12425 details.index());
12426 descriptors->Set(next_descriptor++, &d, witness);
12427 } else if (type == NORMAL) {
12428 if (current_offset < inobject_props) {
12429 obj->InObjectPropertyAtPut(current_offset,
12430 value,
12431 UPDATE_WRITE_BARRIER);
12432 } else {
12433 int offset = current_offset - inobject_props;
12434 FixedArray::cast(fields)->set(offset, value);
12435 }
12436 FieldDescriptor d(String::cast(key),
12437 current_offset++,
12438 details.attributes(),
12439 details.index());
12440 descriptors->Set(next_descriptor++, &d, witness);
12441 } else if (type == CALLBACKS) {
12442 if (value->IsAccessorPair()) {
12443 MaybeObject* maybe_copy =
12444 AccessorPair::cast(value)->CopyWithoutTransitions();
12445 if (!maybe_copy->To(&value)) return maybe_copy;
12446 }
12447 CallbacksDescriptor d(String::cast(key),
12448 value,
12449 details.attributes(),
12450 details.index());
12451 descriptors->Set(next_descriptor++, &d, witness);
12452 } else {
12453 UNREACHABLE();
12454 }
12455 }
12456 }
12457 ASSERT(current_offset == number_of_fields);
12458
12459 descriptors->Sort(witness);
12460 // Allocate new map.
12461 Object* new_map;
12462 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12463 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12464 }
12465
12466 // Transform the object.
12467 obj->set_map(Map::cast(new_map));
12468 obj->map()->set_instance_descriptors(descriptors);
12469 obj->map()->set_unused_property_fields(unused_property_fields);
12470
12471 obj->set_properties(FixedArray::cast(fields));
12472 ASSERT(obj->IsJSObject());
12473
12474 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
12475 // Check that it really works.
12476 ASSERT(obj->HasFastProperties());
12477
12478 return obj;
12479 }
12480
12481
Contains(Object * key)12482 bool ObjectHashSet::Contains(Object* key) {
12483 ASSERT(IsKey(key));
12484
12485 // If the object does not have an identity hash, it was never used as a key.
12486 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12487 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12488 }
12489 return (FindEntry(key) != kNotFound);
12490 }
12491
12492
Add(Object * key)12493 MaybeObject* ObjectHashSet::Add(Object* key) {
12494 ASSERT(IsKey(key));
12495
12496 // Make sure the key object has an identity hash code.
12497 int hash;
12498 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12499 if (maybe_hash->IsFailure()) return maybe_hash;
12500 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12501 }
12502 int entry = FindEntry(key);
12503
12504 // Check whether key is already present.
12505 if (entry != kNotFound) return this;
12506
12507 // Check whether the hash set should be extended and add entry.
12508 Object* obj;
12509 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12510 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12511 }
12512 ObjectHashSet* table = ObjectHashSet::cast(obj);
12513 entry = table->FindInsertionEntry(hash);
12514 table->set(EntryToIndex(entry), key);
12515 table->ElementAdded();
12516 return table;
12517 }
12518
12519
Remove(Object * key)12520 MaybeObject* ObjectHashSet::Remove(Object* key) {
12521 ASSERT(IsKey(key));
12522
12523 // If the object does not have an identity hash, it was never used as a key.
12524 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12525 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12526 }
12527 int entry = FindEntry(key);
12528
12529 // Check whether key is actually present.
12530 if (entry == kNotFound) return this;
12531
12532 // Remove entry and try to shrink this hash set.
12533 set_the_hole(EntryToIndex(entry));
12534 ElementRemoved();
12535 return Shrink(key);
12536 }
12537
12538
Lookup(Object * key)12539 Object* ObjectHashTable::Lookup(Object* key) {
12540 ASSERT(IsKey(key));
12541
12542 // If the object does not have an identity hash, it was never used as a key.
12543 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12544 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12545 return GetHeap()->undefined_value();
12546 }
12547 }
12548 int entry = FindEntry(key);
12549 if (entry == kNotFound) return GetHeap()->undefined_value();
12550 return get(EntryToIndex(entry) + 1);
12551 }
12552
12553
Put(Object * key,Object * value)12554 MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
12555 ASSERT(IsKey(key));
12556
12557 // Make sure the key object has an identity hash code.
12558 int hash;
12559 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12560 if (maybe_hash->IsFailure()) return maybe_hash;
12561 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12562 }
12563 int entry = FindEntry(key);
12564
12565 // Check whether to perform removal operation.
12566 if (value->IsUndefined()) {
12567 if (entry == kNotFound) return this;
12568 RemoveEntry(entry);
12569 return Shrink(key);
12570 }
12571
12572 // Key is already in table, just overwrite value.
12573 if (entry != kNotFound) {
12574 set(EntryToIndex(entry) + 1, value);
12575 return this;
12576 }
12577
12578 // Check whether the hash table should be extended.
12579 Object* obj;
12580 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12581 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12582 }
12583 ObjectHashTable* table = ObjectHashTable::cast(obj);
12584 table->AddEntry(table->FindInsertionEntry(hash), key, value);
12585 return table;
12586 }
12587
12588
AddEntry(int entry,Object * key,Object * value)12589 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
12590 set(EntryToIndex(entry), key);
12591 set(EntryToIndex(entry) + 1, value);
12592 ElementAdded();
12593 }
12594
12595
RemoveEntry(int entry)12596 void ObjectHashTable::RemoveEntry(int entry) {
12597 set_the_hole(EntryToIndex(entry));
12598 set_the_hole(EntryToIndex(entry) + 1);
12599 ElementRemoved();
12600 }
12601
12602
12603 #ifdef ENABLE_DEBUGGER_SUPPORT
12604 // Check if there is a break point at this code position.
HasBreakPoint(int code_position)12605 bool DebugInfo::HasBreakPoint(int code_position) {
12606 // Get the break point info object for this code position.
12607 Object* break_point_info = GetBreakPointInfo(code_position);
12608
12609 // If there is no break point info object or no break points in the break
12610 // point info object there is no break point at this code position.
12611 if (break_point_info->IsUndefined()) return false;
12612 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12613 }
12614
12615
12616 // Get the break point info object for this code position.
GetBreakPointInfo(int code_position)12617 Object* DebugInfo::GetBreakPointInfo(int code_position) {
12618 // Find the index of the break point info object for this code position.
12619 int index = GetBreakPointInfoIndex(code_position);
12620
12621 // Return the break point info object if any.
12622 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
12623 return BreakPointInfo::cast(break_points()->get(index));
12624 }
12625
12626
12627 // Clear a break point at the specified code position.
ClearBreakPoint(Handle<DebugInfo> debug_info,int code_position,Handle<Object> break_point_object)12628 void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12629 int code_position,
12630 Handle<Object> break_point_object) {
12631 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12632 if (break_point_info->IsUndefined()) return;
12633 BreakPointInfo::ClearBreakPoint(
12634 Handle<BreakPointInfo>::cast(break_point_info),
12635 break_point_object);
12636 }
12637
12638
SetBreakPoint(Handle<DebugInfo> debug_info,int code_position,int source_position,int statement_position,Handle<Object> break_point_object)12639 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12640 int code_position,
12641 int source_position,
12642 int statement_position,
12643 Handle<Object> break_point_object) {
12644 Isolate* isolate = Isolate::Current();
12645 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12646 if (!break_point_info->IsUndefined()) {
12647 BreakPointInfo::SetBreakPoint(
12648 Handle<BreakPointInfo>::cast(break_point_info),
12649 break_point_object);
12650 return;
12651 }
12652
12653 // Adding a new break point for a code position which did not have any
12654 // break points before. Try to find a free slot.
12655 int index = kNoBreakPointInfo;
12656 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12657 if (debug_info->break_points()->get(i)->IsUndefined()) {
12658 index = i;
12659 break;
12660 }
12661 }
12662 if (index == kNoBreakPointInfo) {
12663 // No free slot - extend break point info array.
12664 Handle<FixedArray> old_break_points =
12665 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
12666 Handle<FixedArray> new_break_points =
12667 isolate->factory()->NewFixedArray(
12668 old_break_points->length() +
12669 Debug::kEstimatedNofBreakPointsInFunction);
12670
12671 debug_info->set_break_points(*new_break_points);
12672 for (int i = 0; i < old_break_points->length(); i++) {
12673 new_break_points->set(i, old_break_points->get(i));
12674 }
12675 index = old_break_points->length();
12676 }
12677 ASSERT(index != kNoBreakPointInfo);
12678
12679 // Allocate new BreakPointInfo object and set the break point.
12680 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12681 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
12682 new_break_point_info->set_code_position(Smi::FromInt(code_position));
12683 new_break_point_info->set_source_position(Smi::FromInt(source_position));
12684 new_break_point_info->
12685 set_statement_position(Smi::FromInt(statement_position));
12686 new_break_point_info->set_break_point_objects(
12687 isolate->heap()->undefined_value());
12688 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12689 debug_info->break_points()->set(index, *new_break_point_info);
12690 }
12691
12692
12693 // Get the break point objects for a code position.
GetBreakPointObjects(int code_position)12694 Object* DebugInfo::GetBreakPointObjects(int code_position) {
12695 Object* break_point_info = GetBreakPointInfo(code_position);
12696 if (break_point_info->IsUndefined()) {
12697 return GetHeap()->undefined_value();
12698 }
12699 return BreakPointInfo::cast(break_point_info)->break_point_objects();
12700 }
12701
12702
12703 // Get the total number of break points.
GetBreakPointCount()12704 int DebugInfo::GetBreakPointCount() {
12705 if (break_points()->IsUndefined()) return 0;
12706 int count = 0;
12707 for (int i = 0; i < break_points()->length(); i++) {
12708 if (!break_points()->get(i)->IsUndefined()) {
12709 BreakPointInfo* break_point_info =
12710 BreakPointInfo::cast(break_points()->get(i));
12711 count += break_point_info->GetBreakPointCount();
12712 }
12713 }
12714 return count;
12715 }
12716
12717
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)12718 Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12719 Handle<Object> break_point_object) {
12720 Heap* heap = debug_info->GetHeap();
12721 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
12722 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12723 if (!debug_info->break_points()->get(i)->IsUndefined()) {
12724 Handle<BreakPointInfo> break_point_info =
12725 Handle<BreakPointInfo>(BreakPointInfo::cast(
12726 debug_info->break_points()->get(i)));
12727 if (BreakPointInfo::HasBreakPointObject(break_point_info,
12728 break_point_object)) {
12729 return *break_point_info;
12730 }
12731 }
12732 }
12733 return heap->undefined_value();
12734 }
12735
12736
12737 // Find the index of the break point info object for the specified code
12738 // position.
GetBreakPointInfoIndex(int code_position)12739 int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12740 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12741 for (int i = 0; i < break_points()->length(); i++) {
12742 if (!break_points()->get(i)->IsUndefined()) {
12743 BreakPointInfo* break_point_info =
12744 BreakPointInfo::cast(break_points()->get(i));
12745 if (break_point_info->code_position()->value() == code_position) {
12746 return i;
12747 }
12748 }
12749 }
12750 return kNoBreakPointInfo;
12751 }
12752
12753
12754 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)12755 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12756 Handle<Object> break_point_object) {
12757 Isolate* isolate = Isolate::Current();
12758 // If there are no break points just ignore.
12759 if (break_point_info->break_point_objects()->IsUndefined()) return;
12760 // If there is a single break point clear it if it is the same.
12761 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12762 if (break_point_info->break_point_objects() == *break_point_object) {
12763 break_point_info->set_break_point_objects(
12764 isolate->heap()->undefined_value());
12765 }
12766 return;
12767 }
12768 // If there are multiple break points shrink the array
12769 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12770 Handle<FixedArray> old_array =
12771 Handle<FixedArray>(
12772 FixedArray::cast(break_point_info->break_point_objects()));
12773 Handle<FixedArray> new_array =
12774 isolate->factory()->NewFixedArray(old_array->length() - 1);
12775 int found_count = 0;
12776 for (int i = 0; i < old_array->length(); i++) {
12777 if (old_array->get(i) == *break_point_object) {
12778 ASSERT(found_count == 0);
12779 found_count++;
12780 } else {
12781 new_array->set(i - found_count, old_array->get(i));
12782 }
12783 }
12784 // If the break point was found in the list change it.
12785 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12786 }
12787
12788
12789 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)12790 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12791 Handle<Object> break_point_object) {
12792 // If there was no break point objects before just set it.
12793 if (break_point_info->break_point_objects()->IsUndefined()) {
12794 break_point_info->set_break_point_objects(*break_point_object);
12795 return;
12796 }
12797 // If the break point object is the same as before just ignore.
12798 if (break_point_info->break_point_objects() == *break_point_object) return;
12799 // If there was one break point object before replace with array.
12800 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12801 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
12802 array->set(0, break_point_info->break_point_objects());
12803 array->set(1, *break_point_object);
12804 break_point_info->set_break_point_objects(*array);
12805 return;
12806 }
12807 // If there was more than one break point before extend array.
12808 Handle<FixedArray> old_array =
12809 Handle<FixedArray>(
12810 FixedArray::cast(break_point_info->break_point_objects()));
12811 Handle<FixedArray> new_array =
12812 FACTORY->NewFixedArray(old_array->length() + 1);
12813 for (int i = 0; i < old_array->length(); i++) {
12814 // If the break point was there before just ignore.
12815 if (old_array->get(i) == *break_point_object) return;
12816 new_array->set(i, old_array->get(i));
12817 }
12818 // Add the new break point.
12819 new_array->set(old_array->length(), *break_point_object);
12820 break_point_info->set_break_point_objects(*new_array);
12821 }
12822
12823
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)12824 bool BreakPointInfo::HasBreakPointObject(
12825 Handle<BreakPointInfo> break_point_info,
12826 Handle<Object> break_point_object) {
12827 // No break point.
12828 if (break_point_info->break_point_objects()->IsUndefined()) return false;
12829 // Single break point.
12830 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12831 return break_point_info->break_point_objects() == *break_point_object;
12832 }
12833 // Multiple break points.
12834 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12835 for (int i = 0; i < array->length(); i++) {
12836 if (array->get(i) == *break_point_object) {
12837 return true;
12838 }
12839 }
12840 return false;
12841 }
12842
12843
12844 // Get the number of break points.
GetBreakPointCount()12845 int BreakPointInfo::GetBreakPointCount() {
12846 // No break point.
12847 if (break_point_objects()->IsUndefined()) return 0;
12848 // Single break point.
12849 if (!break_point_objects()->IsFixedArray()) return 1;
12850 // Multiple break points.
12851 return FixedArray::cast(break_point_objects())->length();
12852 }
12853 #endif // ENABLE_DEBUGGER_SUPPORT
12854
12855
GetField(Object * object,Smi * index)12856 MaybeObject* JSDate::GetField(Object* object, Smi* index) {
12857 return JSDate::cast(object)->DoGetField(
12858 static_cast<FieldIndex>(index->value()));
12859 }
12860
12861
DoGetField(FieldIndex index)12862 Object* JSDate::DoGetField(FieldIndex index) {
12863 ASSERT(index != kDateValue);
12864
12865 DateCache* date_cache = GetIsolate()->date_cache();
12866
12867 if (index < kFirstUncachedField) {
12868 Object* stamp = cache_stamp();
12869 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
12870 // Since the stamp is not NaN, the value is also not NaN.
12871 int64_t local_time_ms =
12872 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
12873 SetLocalFields(local_time_ms, date_cache);
12874 }
12875 switch (index) {
12876 case kYear: return year();
12877 case kMonth: return month();
12878 case kDay: return day();
12879 case kWeekday: return weekday();
12880 case kHour: return hour();
12881 case kMinute: return min();
12882 case kSecond: return sec();
12883 default: UNREACHABLE();
12884 }
12885 }
12886
12887 if (index >= kFirstUTCField) {
12888 return GetUTCField(index, value()->Number(), date_cache);
12889 }
12890
12891 double time = value()->Number();
12892 if (isnan(time)) return GetIsolate()->heap()->nan_value();
12893
12894 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
12895 int days = DateCache::DaysFromTime(local_time_ms);
12896
12897 if (index == kDays) return Smi::FromInt(days);
12898
12899 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12900 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
12901 ASSERT(index == kTimeInDay);
12902 return Smi::FromInt(time_in_day_ms);
12903 }
12904
12905
GetUTCField(FieldIndex index,double value,DateCache * date_cache)12906 Object* JSDate::GetUTCField(FieldIndex index,
12907 double value,
12908 DateCache* date_cache) {
12909 ASSERT(index >= kFirstUTCField);
12910
12911 if (isnan(value)) return GetIsolate()->heap()->nan_value();
12912
12913 int64_t time_ms = static_cast<int64_t>(value);
12914
12915 if (index == kTimezoneOffset) {
12916 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
12917 }
12918
12919 int days = DateCache::DaysFromTime(time_ms);
12920
12921 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
12922
12923 if (index <= kDayUTC) {
12924 int year, month, day;
12925 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12926 if (index == kYearUTC) return Smi::FromInt(year);
12927 if (index == kMonthUTC) return Smi::FromInt(month);
12928 ASSERT(index == kDayUTC);
12929 return Smi::FromInt(day);
12930 }
12931
12932 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
12933 switch (index) {
12934 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
12935 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
12936 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
12937 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
12938 case kDaysUTC: return Smi::FromInt(days);
12939 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
12940 default: UNREACHABLE();
12941 }
12942
12943 UNREACHABLE();
12944 return NULL;
12945 }
12946
12947
SetValue(Object * value,bool is_value_nan)12948 void JSDate::SetValue(Object* value, bool is_value_nan) {
12949 set_value(value);
12950 if (is_value_nan) {
12951 HeapNumber* nan = GetIsolate()->heap()->nan_value();
12952 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
12953 set_year(nan, SKIP_WRITE_BARRIER);
12954 set_month(nan, SKIP_WRITE_BARRIER);
12955 set_day(nan, SKIP_WRITE_BARRIER);
12956 set_hour(nan, SKIP_WRITE_BARRIER);
12957 set_min(nan, SKIP_WRITE_BARRIER);
12958 set_sec(nan, SKIP_WRITE_BARRIER);
12959 set_weekday(nan, SKIP_WRITE_BARRIER);
12960 } else {
12961 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
12962 }
12963 }
12964
12965
SetLocalFields(int64_t local_time_ms,DateCache * date_cache)12966 void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
12967 int days = DateCache::DaysFromTime(local_time_ms);
12968 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12969 int year, month, day;
12970 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12971 int weekday = date_cache->Weekday(days);
12972 int hour = time_in_day_ms / (60 * 60 * 1000);
12973 int min = (time_in_day_ms / (60 * 1000)) % 60;
12974 int sec = (time_in_day_ms / 1000) % 60;
12975 set_cache_stamp(date_cache->stamp());
12976 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
12977 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
12978 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
12979 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
12980 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
12981 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
12982 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
12983 }
12984
12985 } } // namespace v8::internal
12986