1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #include "src/accessors.h"
8 #include "src/allocation-site-scopes.h"
9 #include "src/api.h"
10 #include "src/arguments.h"
11 #include "src/base/bits.h"
12 #include "src/bootstrapper.h"
13 #include "src/code-stubs.h"
14 #include "src/codegen.h"
15 #include "src/cpu-profiler.h"
16 #include "src/date.h"
17 #include "src/debug.h"
18 #include "src/deoptimizer.h"
19 #include "src/elements.h"
20 #include "src/execution.h"
21 #include "src/field-index-inl.h"
22 #include "src/field-index.h"
23 #include "src/full-codegen.h"
24 #include "src/heap/mark-compact.h"
25 #include "src/heap/objects-visiting-inl.h"
26 #include "src/hydrogen.h"
27 #include "src/ic/ic.h"
28 #include "src/isolate-inl.h"
29 #include "src/log.h"
30 #include "src/lookup.h"
31 #include "src/macro-assembler.h"
32 #include "src/objects-inl.h"
33 #include "src/prototype.h"
34 #include "src/safepoint-table.h"
35 #include "src/string-search.h"
36 #include "src/string-stream.h"
37 #include "src/utils.h"
38 
39 #ifdef ENABLE_DISASSEMBLER
40 #include "src/disasm.h"
41 #include "src/disassembler.h"
42 #endif
43 
44 namespace v8 {
45 namespace internal {
46 
OptimalType(Isolate * isolate,Representation representation)47 Handle<HeapType> Object::OptimalType(Isolate* isolate,
48                                      Representation representation) {
49   if (representation.IsNone()) return HeapType::None(isolate);
50   if (FLAG_track_field_types) {
51     if (representation.IsHeapObject() && IsHeapObject()) {
52       // We can track only JavaScript objects with stable maps.
53       Handle<Map> map(HeapObject::cast(this)->map(), isolate);
54       if (map->is_stable() &&
55           map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
56           map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
57         return HeapType::Class(map, isolate);
58       }
59     }
60   }
61   return HeapType::Any(isolate);
62 }
63 
64 
ToObject(Isolate * isolate,Handle<Object> object,Handle<Context> native_context)65 MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
66                                          Handle<Object> object,
67                                          Handle<Context> native_context) {
68   if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
69   Handle<JSFunction> constructor;
70   if (object->IsNumber()) {
71     constructor = handle(native_context->number_function(), isolate);
72   } else if (object->IsBoolean()) {
73     constructor = handle(native_context->boolean_function(), isolate);
74   } else if (object->IsString()) {
75     constructor = handle(native_context->string_function(), isolate);
76   } else if (object->IsSymbol()) {
77     constructor = handle(native_context->symbol_function(), isolate);
78   } else {
79     return MaybeHandle<JSReceiver>();
80   }
81   Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
82   Handle<JSValue>::cast(result)->set_value(*object);
83   return result;
84 }
85 
86 
BooleanValue()87 bool Object::BooleanValue() {
88   if (IsBoolean()) return IsTrue();
89   if (IsSmi()) return Smi::cast(this)->value() != 0;
90   if (IsUndefined() || IsNull()) return false;
91   if (IsUndetectableObject()) return false;   // Undetectable object is false.
92   if (IsString()) return String::cast(this)->length() != 0;
93   if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
94   return true;
95 }
96 
97 
IsCallable() const98 bool Object::IsCallable() const {
99   const Object* fun = this;
100   while (fun->IsJSFunctionProxy()) {
101     fun = JSFunctionProxy::cast(fun)->call_trap();
102   }
103   return fun->IsJSFunction() ||
104          (fun->IsHeapObject() &&
105           HeapObject::cast(fun)->map()->has_instance_call_handler());
106 }
107 
108 
GetProperty(LookupIterator * it)109 MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
110   for (; it->IsFound(); it->Next()) {
111     switch (it->state()) {
112       case LookupIterator::NOT_FOUND:
113       case LookupIterator::TRANSITION:
114         UNREACHABLE();
115       case LookupIterator::JSPROXY:
116         return JSProxy::GetPropertyWithHandler(it->GetHolder<JSProxy>(),
117                                                it->GetReceiver(), it->name());
118       case LookupIterator::INTERCEPTOR: {
119         MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithInterceptor(
120             it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
121         if (!maybe_result.is_null()) return maybe_result;
122         if (it->isolate()->has_pending_exception()) return maybe_result;
123         break;
124       }
125       case LookupIterator::ACCESS_CHECK:
126         if (it->HasAccess(v8::ACCESS_GET)) break;
127         return JSObject::GetPropertyWithFailedAccessCheck(it);
128       case LookupIterator::ACCESSOR:
129         return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
130                                        it->GetHolder<JSObject>(),
131                                        it->GetAccessors());
132       case LookupIterator::DATA:
133         return it->GetDataValue();
134     }
135   }
136   return it->factory()->undefined_value();
137 }
138 
139 
GetDataProperty(Handle<JSObject> object,Handle<Name> key)140 Handle<Object> JSObject::GetDataProperty(Handle<JSObject> object,
141                                          Handle<Name> key) {
142   LookupIterator it(object, key,
143                     LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
144   return GetDataProperty(&it);
145 }
146 
147 
GetDataProperty(LookupIterator * it)148 Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
149   for (; it->IsFound(); it->Next()) {
150     switch (it->state()) {
151       case LookupIterator::INTERCEPTOR:
152       case LookupIterator::NOT_FOUND:
153       case LookupIterator::TRANSITION:
154         UNREACHABLE();
155       case LookupIterator::ACCESS_CHECK:
156         if (it->HasAccess(v8::ACCESS_GET)) continue;
157       // Fall through.
158       case LookupIterator::JSPROXY:
159         it->NotFound();
160         return it->isolate()->factory()->undefined_value();
161       case LookupIterator::ACCESSOR:
162         // TODO(verwaest): For now this doesn't call into
163         // ExecutableAccessorInfo, since clients don't need it. Update once
164         // relevant.
165         it->NotFound();
166         return it->isolate()->factory()->undefined_value();
167       case LookupIterator::DATA:
168         return it->GetDataValue();
169     }
170   }
171   return it->isolate()->factory()->undefined_value();
172 }
173 
174 
ToInt32(int32_t * value)175 bool Object::ToInt32(int32_t* value) {
176   if (IsSmi()) {
177     *value = Smi::cast(this)->value();
178     return true;
179   }
180   if (IsHeapNumber()) {
181     double num = HeapNumber::cast(this)->value();
182     if (FastI2D(FastD2I(num)) == num) {
183       *value = FastD2I(num);
184       return true;
185     }
186   }
187   return false;
188 }
189 
190 
ToUint32(uint32_t * value)191 bool Object::ToUint32(uint32_t* value) {
192   if (IsSmi()) {
193     int num = Smi::cast(this)->value();
194     if (num >= 0) {
195       *value = static_cast<uint32_t>(num);
196       return true;
197     }
198   }
199   if (IsHeapNumber()) {
200     double num = HeapNumber::cast(this)->value();
201     if (num >= 0 && FastUI2D(FastD2UI(num)) == num) {
202       *value = FastD2UI(num);
203       return true;
204     }
205   }
206   return false;
207 }
208 
209 
IsTemplateFor(Object * object)210 bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
211   if (!object->IsHeapObject()) return false;
212   return IsTemplateFor(HeapObject::cast(object)->map());
213 }
214 
215 
IsTemplateFor(Map * map)216 bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
217   // There is a constraint on the object; check.
218   if (!map->IsJSObjectMap()) return false;
219   // Fetch the constructor function of the object.
220   Object* cons_obj = map->constructor();
221   if (!cons_obj->IsJSFunction()) return false;
222   JSFunction* fun = JSFunction::cast(cons_obj);
223   // Iterate through the chain of inheriting function templates to
224   // see if the required one occurs.
225   for (Object* type = fun->shared()->function_data();
226        type->IsFunctionTemplateInfo();
227        type = FunctionTemplateInfo::cast(type)->parent_template()) {
228     if (type == this) return true;
229   }
230   // Didn't find the required type in the inheritance chain.
231   return false;
232 }
233 
234 
235 template<typename To>
CheckedCast(void * from)236 static inline To* CheckedCast(void *from) {
237   uintptr_t temp = reinterpret_cast<uintptr_t>(from);
238   DCHECK(temp % sizeof(To) == 0);
239   return reinterpret_cast<To*>(temp);
240 }
241 
242 
PerformCompare(const BitmaskCompareDescriptor & descriptor,char * ptr,Isolate * isolate)243 static Handle<Object> PerformCompare(const BitmaskCompareDescriptor& descriptor,
244                                      char* ptr,
245                                      Isolate* isolate) {
246   uint32_t bitmask = descriptor.bitmask;
247   uint32_t compare_value = descriptor.compare_value;
248   uint32_t value;
249   switch (descriptor.size) {
250     case 1:
251       value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
252       compare_value &= 0xff;
253       bitmask &= 0xff;
254       break;
255     case 2:
256       value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
257       compare_value &= 0xffff;
258       bitmask &= 0xffff;
259       break;
260     case 4:
261       value = *CheckedCast<uint32_t>(ptr);
262       break;
263     default:
264       UNREACHABLE();
265       return isolate->factory()->undefined_value();
266   }
267   return isolate->factory()->ToBoolean(
268       (bitmask & value) == (bitmask & compare_value));
269 }
270 
271 
PerformCompare(const PointerCompareDescriptor & descriptor,char * ptr,Isolate * isolate)272 static Handle<Object> PerformCompare(const PointerCompareDescriptor& descriptor,
273                                      char* ptr,
274                                      Isolate* isolate) {
275   uintptr_t compare_value =
276       reinterpret_cast<uintptr_t>(descriptor.compare_value);
277   uintptr_t value = *CheckedCast<uintptr_t>(ptr);
278   return isolate->factory()->ToBoolean(compare_value == value);
279 }
280 
281 
GetPrimitiveValue(const PrimitiveValueDescriptor & descriptor,char * ptr,Isolate * isolate)282 static Handle<Object> GetPrimitiveValue(
283     const PrimitiveValueDescriptor& descriptor,
284     char* ptr,
285     Isolate* isolate) {
286   int32_t int32_value = 0;
287   switch (descriptor.data_type) {
288     case kDescriptorInt8Type:
289       int32_value = *CheckedCast<int8_t>(ptr);
290       break;
291     case kDescriptorUint8Type:
292       int32_value = *CheckedCast<uint8_t>(ptr);
293       break;
294     case kDescriptorInt16Type:
295       int32_value = *CheckedCast<int16_t>(ptr);
296       break;
297     case kDescriptorUint16Type:
298       int32_value = *CheckedCast<uint16_t>(ptr);
299       break;
300     case kDescriptorInt32Type:
301       int32_value = *CheckedCast<int32_t>(ptr);
302       break;
303     case kDescriptorUint32Type: {
304       uint32_t value = *CheckedCast<uint32_t>(ptr);
305       AllowHeapAllocation allow_gc;
306       return isolate->factory()->NewNumberFromUint(value);
307     }
308     case kDescriptorBoolType: {
309       uint8_t byte = *CheckedCast<uint8_t>(ptr);
310       return isolate->factory()->ToBoolean(
311           byte & (0x1 << descriptor.bool_offset));
312     }
313     case kDescriptorFloatType: {
314       float value = *CheckedCast<float>(ptr);
315       AllowHeapAllocation allow_gc;
316       return isolate->factory()->NewNumber(value);
317     }
318     case kDescriptorDoubleType: {
319       double value = *CheckedCast<double>(ptr);
320       AllowHeapAllocation allow_gc;
321       return isolate->factory()->NewNumber(value);
322     }
323   }
324   AllowHeapAllocation allow_gc;
325   return isolate->factory()->NewNumberFromInt(int32_value);
326 }
327 
328 
GetDeclaredAccessorProperty(Handle<Object> receiver,Handle<DeclaredAccessorInfo> info,Isolate * isolate)329 static Handle<Object> GetDeclaredAccessorProperty(
330     Handle<Object> receiver,
331     Handle<DeclaredAccessorInfo> info,
332     Isolate* isolate) {
333   DisallowHeapAllocation no_gc;
334   char* current = reinterpret_cast<char*>(*receiver);
335   DeclaredAccessorDescriptorIterator iterator(info->descriptor());
336   while (true) {
337     const DeclaredAccessorDescriptorData* data = iterator.Next();
338     switch (data->type) {
339       case kDescriptorReturnObject: {
340         DCHECK(iterator.Complete());
341         current = *CheckedCast<char*>(current);
342         return handle(*CheckedCast<Object*>(current), isolate);
343       }
344       case kDescriptorPointerDereference:
345         DCHECK(!iterator.Complete());
346         current = *reinterpret_cast<char**>(current);
347         break;
348       case kDescriptorPointerShift:
349         DCHECK(!iterator.Complete());
350         current += data->pointer_shift_descriptor.byte_offset;
351         break;
352       case kDescriptorObjectDereference: {
353         DCHECK(!iterator.Complete());
354         Object* object = CheckedCast<Object>(current);
355         int field = data->object_dereference_descriptor.internal_field;
356         Object* smi = JSObject::cast(object)->GetInternalField(field);
357         DCHECK(smi->IsSmi());
358         current = reinterpret_cast<char*>(smi);
359         break;
360       }
361       case kDescriptorBitmaskCompare:
362         DCHECK(iterator.Complete());
363         return PerformCompare(data->bitmask_compare_descriptor,
364                               current,
365                               isolate);
366       case kDescriptorPointerCompare:
367         DCHECK(iterator.Complete());
368         return PerformCompare(data->pointer_compare_descriptor,
369                               current,
370                               isolate);
371       case kDescriptorPrimitiveValue:
372         DCHECK(iterator.Complete());
373         return GetPrimitiveValue(data->primitive_value_descriptor,
374                                  current,
375                                  isolate);
376     }
377   }
378   UNREACHABLE();
379   return isolate->factory()->undefined_value();
380 }
381 
382 
EnsureWritableFastElements(Handle<JSObject> object)383 Handle<FixedArray> JSObject::EnsureWritableFastElements(
384     Handle<JSObject> object) {
385   DCHECK(object->HasFastSmiOrObjectElements());
386   Isolate* isolate = object->GetIsolate();
387   Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
388   if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
389   Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
390       elems, isolate->factory()->fixed_array_map());
391   object->set_elements(*writable_elems);
392   isolate->counters()->cow_arrays_converted()->Increment();
393   return writable_elems;
394 }
395 
396 
GetPropertyWithHandler(Handle<JSProxy> proxy,Handle<Object> receiver,Handle<Name> name)397 MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy,
398                                                     Handle<Object> receiver,
399                                                     Handle<Name> name) {
400   Isolate* isolate = proxy->GetIsolate();
401 
402   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
403   if (name->IsSymbol()) return isolate->factory()->undefined_value();
404 
405   Handle<Object> args[] = { receiver, name };
406   return CallTrap(
407       proxy, "get",  isolate->derived_get_trap(), arraysize(args), args);
408 }
409 
410 
GetPropertyWithAccessor(Handle<Object> receiver,Handle<Name> name,Handle<JSObject> holder,Handle<Object> structure)411 MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
412                                                     Handle<Name> name,
413                                                     Handle<JSObject> holder,
414                                                     Handle<Object> structure) {
415   Isolate* isolate = name->GetIsolate();
416   DCHECK(!structure->IsForeign());
417   // api style callbacks.
418   if (structure->IsAccessorInfo()) {
419     Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
420     if (!info->IsCompatibleReceiver(*receiver)) {
421       Handle<Object> args[2] = { name, receiver };
422       THROW_NEW_ERROR(isolate,
423                       NewTypeError("incompatible_method_receiver",
424                                    HandleVector(args, arraysize(args))),
425                       Object);
426     }
427     if (structure->IsDeclaredAccessorInfo()) {
428       return GetDeclaredAccessorProperty(
429           receiver,
430           Handle<DeclaredAccessorInfo>::cast(structure),
431           isolate);
432     }
433 
434     Handle<ExecutableAccessorInfo> data =
435         Handle<ExecutableAccessorInfo>::cast(structure);
436     v8::AccessorNameGetterCallback call_fun =
437         v8::ToCData<v8::AccessorNameGetterCallback>(data->getter());
438     if (call_fun == NULL) return isolate->factory()->undefined_value();
439 
440     LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
441     PropertyCallbackArguments args(isolate, data->data(), *receiver, *holder);
442     v8::Handle<v8::Value> result =
443         args.Call(call_fun, v8::Utils::ToLocal(name));
444     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
445     if (result.IsEmpty()) {
446       return isolate->factory()->undefined_value();
447     }
448     Handle<Object> return_value = v8::Utils::OpenHandle(*result);
449     return_value->VerifyApiCallResultType();
450     // Rebox handle before return.
451     return handle(*return_value, isolate);
452   }
453 
454   // __defineGetter__ callback
455   Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
456                         isolate);
457   if (getter->IsSpecFunction()) {
458     // TODO(rossberg): nicer would be to cast to some JSCallable here...
459     return Object::GetPropertyWithDefinedGetter(
460         receiver, Handle<JSReceiver>::cast(getter));
461   }
462   // Getter is not a function.
463   return isolate->factory()->undefined_value();
464 }
465 
466 
IsCompatibleReceiverType(Isolate * isolate,Handle<AccessorInfo> info,Handle<HeapType> type)467 bool AccessorInfo::IsCompatibleReceiverType(Isolate* isolate,
468                                             Handle<AccessorInfo> info,
469                                             Handle<HeapType> type) {
470   if (!info->HasExpectedReceiverType()) return true;
471   Handle<Map> map = IC::TypeToMap(*type, isolate);
472   if (!map->IsJSObjectMap()) return false;
473   return FunctionTemplateInfo::cast(info->expected_receiver_type())
474       ->IsTemplateFor(*map);
475 }
476 
477 
SetPropertyWithAccessor(Handle<Object> receiver,Handle<Name> name,Handle<Object> value,Handle<JSObject> holder,Handle<Object> structure,StrictMode strict_mode)478 MaybeHandle<Object> Object::SetPropertyWithAccessor(
479     Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
480     Handle<JSObject> holder, Handle<Object> structure, StrictMode strict_mode) {
481   Isolate* isolate = name->GetIsolate();
482 
483   // We should never get here to initialize a const with the hole
484   // value since a const declaration would conflict with the setter.
485   DCHECK(!structure->IsForeign());
486   if (structure->IsExecutableAccessorInfo()) {
487     // Don't call executable accessor setters with non-JSObject receivers.
488     if (!receiver->IsJSObject()) return value;
489     // api style callbacks
490     ExecutableAccessorInfo* info = ExecutableAccessorInfo::cast(*structure);
491     if (!info->IsCompatibleReceiver(*receiver)) {
492       Handle<Object> args[2] = { name, receiver };
493       THROW_NEW_ERROR(isolate,
494                       NewTypeError("incompatible_method_receiver",
495                                    HandleVector(args, arraysize(args))),
496                       Object);
497     }
498     Object* call_obj = info->setter();
499     v8::AccessorNameSetterCallback call_fun =
500         v8::ToCData<v8::AccessorNameSetterCallback>(call_obj);
501     if (call_fun == NULL) return value;
502     LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
503     PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
504     args.Call(call_fun,
505               v8::Utils::ToLocal(name),
506               v8::Utils::ToLocal(value));
507     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
508     return value;
509   }
510 
511   if (structure->IsAccessorPair()) {
512     Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
513     if (setter->IsSpecFunction()) {
514       // TODO(rossberg): nicer would be to cast to some JSCallable here...
515       return SetPropertyWithDefinedSetter(
516           receiver, Handle<JSReceiver>::cast(setter), value);
517     } else {
518       if (strict_mode == SLOPPY) return value;
519       Handle<Object> args[2] = { name, holder };
520       THROW_NEW_ERROR(
521           isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
522           Object);
523     }
524   }
525 
526   // TODO(dcarney): Handle correctly.
527   if (structure->IsDeclaredAccessorInfo()) {
528     return value;
529   }
530 
531   UNREACHABLE();
532   return MaybeHandle<Object>();
533 }
534 
535 
GetPropertyWithDefinedGetter(Handle<Object> receiver,Handle<JSReceiver> getter)536 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
537     Handle<Object> receiver,
538     Handle<JSReceiver> getter) {
539   Isolate* isolate = getter->GetIsolate();
540   Debug* debug = isolate->debug();
541   // Handle stepping into a getter if step into is active.
542   // TODO(rossberg): should this apply to getters that are function proxies?
543   if (debug->StepInActive() && getter->IsJSFunction()) {
544     debug->HandleStepIn(
545         Handle<JSFunction>::cast(getter), Handle<Object>::null(), 0, false);
546   }
547 
548   return Execution::Call(isolate, getter, receiver, 0, NULL, true);
549 }
550 
551 
SetPropertyWithDefinedSetter(Handle<Object> receiver,Handle<JSReceiver> setter,Handle<Object> value)552 MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
553     Handle<Object> receiver,
554     Handle<JSReceiver> setter,
555     Handle<Object> value) {
556   Isolate* isolate = setter->GetIsolate();
557 
558   Debug* debug = isolate->debug();
559   // Handle stepping into a setter if step into is active.
560   // TODO(rossberg): should this apply to getters that are function proxies?
561   if (debug->StepInActive() && setter->IsJSFunction()) {
562     debug->HandleStepIn(
563         Handle<JSFunction>::cast(setter), Handle<Object>::null(), 0, false);
564   }
565 
566   Handle<Object> argv[] = { value };
567   RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver,
568                                                arraysize(argv), argv, true),
569                       Object);
570   return value;
571 }
572 
573 
FindAllCanReadHolder(LookupIterator * it)574 static bool FindAllCanReadHolder(LookupIterator* it) {
575   for (; it->IsFound(); it->Next()) {
576     if (it->state() == LookupIterator::ACCESSOR) {
577       Handle<Object> accessors = it->GetAccessors();
578       if (accessors->IsAccessorInfo()) {
579         if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
580       }
581     }
582   }
583   return false;
584 }
585 
586 
GetPropertyWithFailedAccessCheck(LookupIterator * it)587 MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
588     LookupIterator* it) {
589   Handle<JSObject> checked = it->GetHolder<JSObject>();
590   if (FindAllCanReadHolder(it)) {
591     return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
592                                    it->GetHolder<JSObject>(),
593                                    it->GetAccessors());
594   }
595   it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET);
596   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
597   return it->factory()->undefined_value();
598 }
599 
600 
GetPropertyAttributesWithFailedAccessCheck(LookupIterator * it)601 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
602     LookupIterator* it) {
603   Handle<JSObject> checked = it->GetHolder<JSObject>();
604   if (FindAllCanReadHolder(it))
605     return maybe(it->property_details().attributes());
606   it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS);
607   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
608                                       Maybe<PropertyAttributes>());
609   return maybe(ABSENT);
610 }
611 
612 
FindAllCanWriteHolder(LookupIterator * it)613 static bool FindAllCanWriteHolder(LookupIterator* it) {
614   for (; it->IsFound(); it->Next()) {
615     if (it->state() == LookupIterator::ACCESSOR) {
616       Handle<Object> accessors = it->GetAccessors();
617       if (accessors->IsAccessorInfo()) {
618         if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
619       }
620     }
621   }
622   return false;
623 }
624 
625 
SetPropertyWithFailedAccessCheck(LookupIterator * it,Handle<Object> value,StrictMode strict_mode)626 MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
627     LookupIterator* it, Handle<Object> value, StrictMode strict_mode) {
628   Handle<JSObject> checked = it->GetHolder<JSObject>();
629   if (FindAllCanWriteHolder(it)) {
630     return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
631                                    it->GetHolder<JSObject>(),
632                                    it->GetAccessors(), strict_mode);
633   }
634 
635   it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET);
636   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
637   return value;
638 }
639 
640 
SetNormalizedProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyDetails details)641 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
642                                      Handle<Name> name,
643                                      Handle<Object> value,
644                                      PropertyDetails details) {
645   DCHECK(!object->HasFastProperties());
646   Handle<NameDictionary> property_dictionary(object->property_dictionary());
647 
648   if (!name->IsUniqueName()) {
649     name = object->GetIsolate()->factory()->InternalizeString(
650         Handle<String>::cast(name));
651   }
652 
653   int entry = property_dictionary->FindEntry(name);
654   if (entry == NameDictionary::kNotFound) {
655     Handle<Object> store_value = value;
656     if (object->IsGlobalObject()) {
657       store_value = object->GetIsolate()->factory()->NewPropertyCell(value);
658     }
659 
660     property_dictionary = NameDictionary::Add(
661         property_dictionary, name, store_value, details);
662     object->set_properties(*property_dictionary);
663     return;
664   }
665 
666   PropertyDetails original_details = property_dictionary->DetailsAt(entry);
667   int enumeration_index;
668   // Preserve the enumeration index unless the property was deleted.
669   if (original_details.IsDeleted()) {
670     enumeration_index = property_dictionary->NextEnumerationIndex();
671     property_dictionary->SetNextEnumerationIndex(enumeration_index + 1);
672   } else {
673     enumeration_index = original_details.dictionary_index();
674     DCHECK(enumeration_index > 0);
675   }
676 
677   details = PropertyDetails(
678       details.attributes(), details.type(), enumeration_index);
679 
680   if (object->IsGlobalObject()) {
681     Handle<PropertyCell> cell(
682         PropertyCell::cast(property_dictionary->ValueAt(entry)));
683     PropertyCell::SetValueInferType(cell, value);
684     // Please note we have to update the property details.
685     property_dictionary->DetailsAtPut(entry, details);
686   } else {
687     property_dictionary->SetEntry(entry, name, value, details);
688   }
689 }
690 
691 
DeleteNormalizedProperty(Handle<JSObject> object,Handle<Name> name,DeleteMode mode)692 Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
693                                                   Handle<Name> name,
694                                                   DeleteMode mode) {
695   DCHECK(!object->HasFastProperties());
696   Isolate* isolate = object->GetIsolate();
697   Handle<NameDictionary> dictionary(object->property_dictionary());
698   int entry = dictionary->FindEntry(name);
699   if (entry != NameDictionary::kNotFound) {
700     // If we have a global object set the cell to the hole.
701     if (object->IsGlobalObject()) {
702       PropertyDetails details = dictionary->DetailsAt(entry);
703       if (!details.IsConfigurable()) {
704         if (mode != FORCE_DELETION) return isolate->factory()->false_value();
705         // When forced to delete global properties, we have to make a
706         // map change to invalidate any ICs that think they can load
707         // from the non-configurable cell without checking if it contains
708         // the hole value.
709         Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
710         DCHECK(new_map->is_dictionary_map());
711         JSObject::MigrateToMap(object, new_map);
712       }
713       Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
714       Handle<Object> value = isolate->factory()->the_hole_value();
715       PropertyCell::SetValueInferType(cell, value);
716       dictionary->DetailsAtPut(entry, details.AsDeleted());
717     } else {
718       Handle<Object> deleted(
719           NameDictionary::DeleteProperty(dictionary, entry, mode));
720       if (*deleted == isolate->heap()->true_value()) {
721         Handle<NameDictionary> new_properties =
722             NameDictionary::Shrink(dictionary, name);
723         object->set_properties(*new_properties);
724       }
725       return deleted;
726     }
727   }
728   return isolate->factory()->true_value();
729 }
730 
731 
IsDirty()732 bool JSObject::IsDirty() {
733   Object* cons_obj = map()->constructor();
734   if (!cons_obj->IsJSFunction())
735     return true;
736   JSFunction* fun = JSFunction::cast(cons_obj);
737   if (!fun->shared()->IsApiFunction())
738     return true;
739   // If the object is fully fast case and has the same map it was
740   // created with then no changes can have been made to it.
741   return map() != fun->initial_map()
742       || !HasFastObjectElements()
743       || !HasFastProperties();
744 }
745 
746 
GetElementWithReceiver(Isolate * isolate,Handle<Object> object,Handle<Object> receiver,uint32_t index)747 MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
748                                                    Handle<Object> object,
749                                                    Handle<Object> receiver,
750                                                    uint32_t index) {
751   if (object->IsUndefined()) {
752     // TODO(verwaest): Why is this check here?
753     UNREACHABLE();
754     return isolate->factory()->undefined_value();
755   }
756 
757   // Iterate up the prototype chain until an element is found or the null
758   // prototype is encountered.
759   for (PrototypeIterator iter(isolate, object,
760                               object->IsJSProxy() || object->IsJSObject()
761                                   ? PrototypeIterator::START_AT_RECEIVER
762                                   : PrototypeIterator::START_AT_PROTOTYPE);
763        !iter.IsAtEnd(); iter.Advance()) {
764     if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
765       return JSProxy::GetElementWithHandler(
766           Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
767           index);
768     }
769 
770     // Inline the case for JSObjects. Doing so significantly improves the
771     // performance of fetching elements where checking the prototype chain is
772     // necessary.
773     Handle<JSObject> js_object =
774         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
775 
776     // Check access rights if needed.
777     if (js_object->IsAccessCheckNeeded()) {
778       if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
779         isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
780         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
781         return isolate->factory()->undefined_value();
782       }
783     }
784 
785     if (js_object->HasIndexedInterceptor()) {
786       return JSObject::GetElementWithInterceptor(js_object, receiver, index);
787     }
788 
789     if (js_object->elements() != isolate->heap()->empty_fixed_array()) {
790       Handle<Object> result;
791       ASSIGN_RETURN_ON_EXCEPTION(
792           isolate, result,
793           js_object->GetElementsAccessor()->Get(receiver, js_object, index),
794           Object);
795       if (!result->IsTheHole()) return result;
796     }
797   }
798 
799   return isolate->factory()->undefined_value();
800 }
801 
802 
GetRootMap(Isolate * isolate)803 Map* Object::GetRootMap(Isolate* isolate) {
804   DisallowHeapAllocation no_alloc;
805   if (IsSmi()) {
806     Context* context = isolate->context()->native_context();
807     return context->number_function()->initial_map();
808   }
809 
810   HeapObject* heap_object = HeapObject::cast(this);
811 
812   // The object is either a number, a string, a boolean,
813   // a real JS object, or a Harmony proxy.
814   if (heap_object->IsJSReceiver()) {
815     return heap_object->map();
816   }
817   Context* context = isolate->context()->native_context();
818 
819   if (heap_object->IsHeapNumber()) {
820     return context->number_function()->initial_map();
821   }
822   if (heap_object->IsString()) {
823     return context->string_function()->initial_map();
824   }
825   if (heap_object->IsSymbol()) {
826     return context->symbol_function()->initial_map();
827   }
828   if (heap_object->IsBoolean()) {
829     return context->boolean_function()->initial_map();
830   }
831   return isolate->heap()->null_value()->map();
832 }
833 
834 
GetHash()835 Object* Object::GetHash() {
836   // The object is either a number, a name, an odd-ball,
837   // a real JS object, or a Harmony proxy.
838   if (IsNumber()) {
839     uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
840     return Smi::FromInt(hash & Smi::kMaxValue);
841   }
842   if (IsName()) {
843     uint32_t hash = Name::cast(this)->Hash();
844     return Smi::FromInt(hash);
845   }
846   if (IsOddball()) {
847     uint32_t hash = Oddball::cast(this)->to_string()->Hash();
848     return Smi::FromInt(hash);
849   }
850 
851   DCHECK(IsJSReceiver());
852   return JSReceiver::cast(this)->GetIdentityHash();
853 }
854 
855 
GetOrCreateHash(Isolate * isolate,Handle<Object> object)856 Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
857   Handle<Object> hash(object->GetHash(), isolate);
858   if (hash->IsSmi()) return Handle<Smi>::cast(hash);
859 
860   DCHECK(object->IsJSReceiver());
861   return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
862 }
863 
864 
SameValue(Object * other)865 bool Object::SameValue(Object* other) {
866   if (other == this) return true;
867 
868   // The object is either a number, a name, an odd-ball,
869   // a real JS object, or a Harmony proxy.
870   if (IsNumber() && other->IsNumber()) {
871     double this_value = Number();
872     double other_value = other->Number();
873     bool equal = this_value == other_value;
874     // SameValue(NaN, NaN) is true.
875     if (!equal) return std::isnan(this_value) && std::isnan(other_value);
876     // SameValue(0.0, -0.0) is false.
877     return (this_value != 0) || ((1 / this_value) == (1 / other_value));
878   }
879   if (IsString() && other->IsString()) {
880     return String::cast(this)->Equals(String::cast(other));
881   }
882   return false;
883 }
884 
885 
SameValueZero(Object * other)886 bool Object::SameValueZero(Object* other) {
887   if (other == this) return true;
888 
889   // The object is either a number, a name, an odd-ball,
890   // a real JS object, or a Harmony proxy.
891   if (IsNumber() && other->IsNumber()) {
892     double this_value = Number();
893     double other_value = other->Number();
894     // +0 == -0 is true
895     return this_value == other_value
896         || (std::isnan(this_value) && std::isnan(other_value));
897   }
898   if (IsString() && other->IsString()) {
899     return String::cast(this)->Equals(String::cast(other));
900   }
901   return false;
902 }
903 
904 
ShortPrint(FILE * out)905 void Object::ShortPrint(FILE* out) {
906   OFStream os(out);
907   os << Brief(this);
908 }
909 
910 
ShortPrint(StringStream * accumulator)911 void Object::ShortPrint(StringStream* accumulator) {
912   OStringStream os;
913   os << Brief(this);
914   accumulator->Add(os.c_str());
915 }
916 
917 
operator <<(OStream & os,const Brief & v)918 OStream& operator<<(OStream& os, const Brief& v) {
919   if (v.value->IsSmi()) {
920     Smi::cast(v.value)->SmiPrint(os);
921   } else {
922     // TODO(svenpanne) Const-correct HeapObjectShortPrint!
923     HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
924     obj->HeapObjectShortPrint(os);
925   }
926   return os;
927 }
928 
929 
SmiPrint(OStream & os) const930 void Smi::SmiPrint(OStream& os) const {  // NOLINT
931   os << value();
932 }
933 
934 
935 // Should a word be prefixed by 'a' or 'an' in order to read naturally in
936 // English?  Returns false for non-ASCII or words that don't start with
937 // a capital letter.  The a/an rule follows pronunciation in English.
938 // We don't use the BBC's overcorrect "an historic occasion" though if
939 // you speak a dialect you may well say "an 'istoric occasion".
AnWord(String * str)940 static bool AnWord(String* str) {
941   if (str->length() == 0) return false;  // A nothing.
942   int c0 = str->Get(0);
943   int c1 = str->length() > 1 ? str->Get(1) : 0;
944   if (c0 == 'U') {
945     if (c1 > 'Z') {
946       return true;  // An Umpire, but a UTF8String, a U.
947     }
948   } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
949     return true;    // An Ape, an ABCBook.
950   } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
951            (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
952             c0 == 'S' || c0 == 'X')) {
953     return true;    // An MP3File, an M.
954   }
955   return false;
956 }
957 
958 
SlowFlatten(Handle<ConsString> cons,PretenureFlag pretenure)959 Handle<String> String::SlowFlatten(Handle<ConsString> cons,
960                                    PretenureFlag pretenure) {
961   DCHECK(AllowHeapAllocation::IsAllowed());
962   DCHECK(cons->second()->length() != 0);
963   Isolate* isolate = cons->GetIsolate();
964   int length = cons->length();
965   PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
966                                                             : TENURED;
967   Handle<SeqString> result;
968   if (cons->IsOneByteRepresentation()) {
969     Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
970         length, tenure).ToHandleChecked();
971     DisallowHeapAllocation no_gc;
972     WriteToFlat(*cons, flat->GetChars(), 0, length);
973     result = flat;
974   } else {
975     Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
976         length, tenure).ToHandleChecked();
977     DisallowHeapAllocation no_gc;
978     WriteToFlat(*cons, flat->GetChars(), 0, length);
979     result = flat;
980   }
981   cons->set_first(*result);
982   cons->set_second(isolate->heap()->empty_string());
983   DCHECK(result->IsFlat());
984   return result;
985 }
986 
987 
988 
MakeExternal(v8::String::ExternalStringResource * resource)989 bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
990   // Externalizing twice leaks the external resource, so it's
991   // prohibited by the API.
992   DCHECK(!this->IsExternalString());
993 #ifdef ENABLE_SLOW_DCHECKS
994   if (FLAG_enable_slow_asserts) {
995     // Assert that the resource and the string are equivalent.
996     DCHECK(static_cast<size_t>(this->length()) == resource->length());
997     ScopedVector<uc16> smart_chars(this->length());
998     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
999     DCHECK(memcmp(smart_chars.start(),
1000                   resource->data(),
1001                   resource->length() * sizeof(smart_chars[0])) == 0);
1002   }
1003 #endif  // DEBUG
1004   int size = this->Size();  // Byte size of the original string.
1005   // Abort if size does not allow in-place conversion.
1006   if (size < ExternalString::kShortSize) return false;
1007   Heap* heap = GetHeap();
1008   bool is_one_byte = this->IsOneByteRepresentation();
1009   bool is_internalized = this->IsInternalizedString();
1010 
1011   // Morph the string to an external string by replacing the map and
1012   // reinitializing the fields.  This won't work if the space the existing
1013   // string occupies is too small for a regular  external string.
1014   // Instead, we resort to a short external string instead, omitting
1015   // the field caching the address of the backing store.  When we encounter
1016   // short external strings in generated code, we need to bailout to runtime.
1017   Map* new_map;
1018   if (size < ExternalString::kSize) {
1019     new_map = is_internalized
1020         ? (is_one_byte
1021            ? heap->short_external_internalized_string_with_one_byte_data_map()
1022            : heap->short_external_internalized_string_map())
1023         : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
1024                        : heap->short_external_string_map());
1025   } else {
1026     new_map = is_internalized
1027         ? (is_one_byte
1028            ? heap->external_internalized_string_with_one_byte_data_map()
1029            : heap->external_internalized_string_map())
1030         : (is_one_byte ? heap->external_string_with_one_byte_data_map()
1031                        : heap->external_string_map());
1032   }
1033 
1034   // Byte size of the external String object.
1035   int new_size = this->SizeFromMap(new_map);
1036   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1037 
1038   // We are storing the new map using release store after creating a filler for
1039   // the left-over space to avoid races with the sweeper thread.
1040   this->synchronized_set_map(new_map);
1041 
1042   ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1043   self->set_resource(resource);
1044   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
1045 
1046   heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
1047   return true;
1048 }
1049 
1050 
MakeExternal(v8::String::ExternalOneByteStringResource * resource)1051 bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
1052   // Externalizing twice leaks the external resource, so it's
1053   // prohibited by the API.
1054   DCHECK(!this->IsExternalString());
1055 #ifdef ENABLE_SLOW_DCHECKS
1056   if (FLAG_enable_slow_asserts) {
1057     // Assert that the resource and the string are equivalent.
1058     DCHECK(static_cast<size_t>(this->length()) == resource->length());
1059     if (this->IsTwoByteRepresentation()) {
1060       ScopedVector<uint16_t> smart_chars(this->length());
1061       String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1062       DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
1063     }
1064     ScopedVector<char> smart_chars(this->length());
1065     String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1066     DCHECK(memcmp(smart_chars.start(),
1067                   resource->data(),
1068                   resource->length() * sizeof(smart_chars[0])) == 0);
1069   }
1070 #endif  // DEBUG
1071   int size = this->Size();  // Byte size of the original string.
1072   // Abort if size does not allow in-place conversion.
1073   if (size < ExternalString::kShortSize) return false;
1074   Heap* heap = GetHeap();
1075   bool is_internalized = this->IsInternalizedString();
1076 
1077   // Morph the string to an external string by replacing the map and
1078   // reinitializing the fields.  This won't work if the space the existing
1079   // string occupies is too small for a regular  external string.
1080   // Instead, we resort to a short external string instead, omitting
1081   // the field caching the address of the backing store.  When we encounter
1082   // short external strings in generated code, we need to bailout to runtime.
1083   Map* new_map;
1084   if (size < ExternalString::kSize) {
1085     new_map = is_internalized
1086                   ? heap->short_external_one_byte_internalized_string_map()
1087                   : heap->short_external_one_byte_string_map();
1088   } else {
1089     new_map = is_internalized
1090                   ? heap->external_one_byte_internalized_string_map()
1091                   : heap->external_one_byte_string_map();
1092   }
1093 
1094   // Byte size of the external String object.
1095   int new_size = this->SizeFromMap(new_map);
1096   heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1097 
1098   // We are storing the new map using release store after creating a filler for
1099   // the left-over space to avoid races with the sweeper thread.
1100   this->synchronized_set_map(new_map);
1101 
1102   ExternalOneByteString* self = ExternalOneByteString::cast(this);
1103   self->set_resource(resource);
1104   if (is_internalized) self->Hash();  // Force regeneration of the hash value.
1105 
1106   heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
1107   return true;
1108 }
1109 
1110 
StringShortPrint(StringStream * accumulator)1111 void String::StringShortPrint(StringStream* accumulator) {
1112   int len = length();
1113   if (len > kMaxShortPrintLength) {
1114     accumulator->Add("<Very long string[%u]>", len);
1115     return;
1116   }
1117 
1118   if (!LooksValid()) {
1119     accumulator->Add("<Invalid String>");
1120     return;
1121   }
1122 
1123   ConsStringIteratorOp op;
1124   StringCharacterStream stream(this, &op);
1125 
1126   bool truncated = false;
1127   if (len > kMaxShortPrintLength) {
1128     len = kMaxShortPrintLength;
1129     truncated = true;
1130   }
1131   bool one_byte = true;
1132   for (int i = 0; i < len; i++) {
1133     uint16_t c = stream.GetNext();
1134 
1135     if (c < 32 || c >= 127) {
1136       one_byte = false;
1137     }
1138   }
1139   stream.Reset(this);
1140   if (one_byte) {
1141     accumulator->Add("<String[%u]: ", length());
1142     for (int i = 0; i < len; i++) {
1143       accumulator->Put(static_cast<char>(stream.GetNext()));
1144     }
1145     accumulator->Put('>');
1146   } else {
1147     // Backslash indicates that the string contains control
1148     // characters and that backslashes are therefore escaped.
1149     accumulator->Add("<String[%u]\\: ", length());
1150     for (int i = 0; i < len; i++) {
1151       uint16_t c = stream.GetNext();
1152       if (c == '\n') {
1153         accumulator->Add("\\n");
1154       } else if (c == '\r') {
1155         accumulator->Add("\\r");
1156       } else if (c == '\\') {
1157         accumulator->Add("\\\\");
1158       } else if (c < 32 || c > 126) {
1159         accumulator->Add("\\x%02x", c);
1160       } else {
1161         accumulator->Put(static_cast<char>(c));
1162       }
1163     }
1164     if (truncated) {
1165       accumulator->Put('.');
1166       accumulator->Put('.');
1167       accumulator->Put('.');
1168     }
1169     accumulator->Put('>');
1170   }
1171   return;
1172 }
1173 
1174 
PrintUC16(OStream & os,int start,int end)1175 void String::PrintUC16(OStream& os, int start, int end) {  // NOLINT
1176   if (end < 0) end = length();
1177   ConsStringIteratorOp op;
1178   StringCharacterStream stream(this, &op, start);
1179   for (int i = start; i < end && stream.HasMore(); i++) {
1180     os << AsUC16(stream.GetNext());
1181   }
1182 }
1183 
1184 
JSObjectShortPrint(StringStream * accumulator)1185 void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1186   switch (map()->instance_type()) {
1187     case JS_ARRAY_TYPE: {
1188       double length = JSArray::cast(this)->length()->IsUndefined()
1189           ? 0
1190           : JSArray::cast(this)->length()->Number();
1191       accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
1192       break;
1193     }
1194     case JS_WEAK_MAP_TYPE: {
1195       accumulator->Add("<JS WeakMap>");
1196       break;
1197     }
1198     case JS_WEAK_SET_TYPE: {
1199       accumulator->Add("<JS WeakSet>");
1200       break;
1201     }
1202     case JS_REGEXP_TYPE: {
1203       accumulator->Add("<JS RegExp>");
1204       break;
1205     }
1206     case JS_FUNCTION_TYPE: {
1207       JSFunction* function = JSFunction::cast(this);
1208       Object* fun_name = function->shared()->DebugName();
1209       bool printed = false;
1210       if (fun_name->IsString()) {
1211         String* str = String::cast(fun_name);
1212         if (str->length() > 0) {
1213           accumulator->Add("<JS Function ");
1214           accumulator->Put(str);
1215           printed = true;
1216         }
1217       }
1218       if (!printed) {
1219         accumulator->Add("<JS Function");
1220       }
1221       accumulator->Add(" (SharedFunctionInfo %p)",
1222                        reinterpret_cast<void*>(function->shared()));
1223       accumulator->Put('>');
1224       break;
1225     }
1226     case JS_GENERATOR_OBJECT_TYPE: {
1227       accumulator->Add("<JS Generator>");
1228       break;
1229     }
1230     case JS_MODULE_TYPE: {
1231       accumulator->Add("<JS Module>");
1232       break;
1233     }
1234     // All other JSObjects are rather similar to each other (JSObject,
1235     // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1236     default: {
1237       Map* map_of_this = map();
1238       Heap* heap = GetHeap();
1239       Object* constructor = map_of_this->constructor();
1240       bool printed = false;
1241       if (constructor->IsHeapObject() &&
1242           !heap->Contains(HeapObject::cast(constructor))) {
1243         accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1244       } else {
1245         bool global_object = IsJSGlobalProxy();
1246         if (constructor->IsJSFunction()) {
1247           if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
1248             accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1249           } else {
1250             Object* constructor_name =
1251                 JSFunction::cast(constructor)->shared()->name();
1252             if (constructor_name->IsString()) {
1253               String* str = String::cast(constructor_name);
1254               if (str->length() > 0) {
1255                 bool vowel = AnWord(str);
1256                 accumulator->Add("<%sa%s ",
1257                        global_object ? "Global Object: " : "",
1258                        vowel ? "n" : "");
1259                 accumulator->Put(str);
1260                 accumulator->Add(" with %smap %p",
1261                     map_of_this->is_deprecated() ? "deprecated " : "",
1262                     map_of_this);
1263                 printed = true;
1264               }
1265             }
1266           }
1267         }
1268         if (!printed) {
1269           accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1270         }
1271       }
1272       if (IsJSValue()) {
1273         accumulator->Add(" value = ");
1274         JSValue::cast(this)->value()->ShortPrint(accumulator);
1275       }
1276       accumulator->Put('>');
1277       break;
1278     }
1279   }
1280 }
1281 
1282 
PrintElementsTransition(FILE * file,Handle<JSObject> object,ElementsKind from_kind,Handle<FixedArrayBase> from_elements,ElementsKind to_kind,Handle<FixedArrayBase> to_elements)1283 void JSObject::PrintElementsTransition(
1284     FILE* file, Handle<JSObject> object,
1285     ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
1286     ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
1287   if (from_kind != to_kind) {
1288     OFStream os(file);
1289     os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
1290        << ElementsKindToString(to_kind) << "] in ";
1291     JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
1292     PrintF(file, " for ");
1293     object->ShortPrint(file);
1294     PrintF(file, " from ");
1295     from_elements->ShortPrint(file);
1296     PrintF(file, " to ");
1297     to_elements->ShortPrint(file);
1298     PrintF(file, "\n");
1299   }
1300 }
1301 
1302 
PrintGeneralization(FILE * file,const char * reason,int modify_index,int split,int descriptors,bool constant_to_field,Representation old_representation,Representation new_representation,HeapType * old_field_type,HeapType * new_field_type)1303 void Map::PrintGeneralization(FILE* file,
1304                               const char* reason,
1305                               int modify_index,
1306                               int split,
1307                               int descriptors,
1308                               bool constant_to_field,
1309                               Representation old_representation,
1310                               Representation new_representation,
1311                               HeapType* old_field_type,
1312                               HeapType* new_field_type) {
1313   OFStream os(file);
1314   os << "[generalizing ";
1315   constructor_name()->PrintOn(file);
1316   os << "] ";
1317   Name* name = instance_descriptors()->GetKey(modify_index);
1318   if (name->IsString()) {
1319     String::cast(name)->PrintOn(file);
1320   } else {
1321     os << "{symbol " << static_cast<void*>(name) << "}";
1322   }
1323   os << ":";
1324   if (constant_to_field) {
1325     os << "c";
1326   } else {
1327     os << old_representation.Mnemonic() << "{";
1328     old_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
1329     os << "}";
1330   }
1331   os << "->" << new_representation.Mnemonic() << "{";
1332   new_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
1333   os << "} (";
1334   if (strlen(reason) > 0) {
1335     os << reason;
1336   } else {
1337     os << "+" << (descriptors - split) << " maps";
1338   }
1339   os << ") [";
1340   JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
1341   os << "]\n";
1342 }
1343 
1344 
PrintInstanceMigration(FILE * file,Map * original_map,Map * new_map)1345 void JSObject::PrintInstanceMigration(FILE* file,
1346                                       Map* original_map,
1347                                       Map* new_map) {
1348   PrintF(file, "[migrating ");
1349   map()->constructor_name()->PrintOn(file);
1350   PrintF(file, "] ");
1351   DescriptorArray* o = original_map->instance_descriptors();
1352   DescriptorArray* n = new_map->instance_descriptors();
1353   for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
1354     Representation o_r = o->GetDetails(i).representation();
1355     Representation n_r = n->GetDetails(i).representation();
1356     if (!o_r.Equals(n_r)) {
1357       String::cast(o->GetKey(i))->PrintOn(file);
1358       PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
1359     } else if (o->GetDetails(i).type() == CONSTANT &&
1360                n->GetDetails(i).type() == FIELD) {
1361       Name* name = o->GetKey(i);
1362       if (name->IsString()) {
1363         String::cast(name)->PrintOn(file);
1364       } else {
1365         PrintF(file, "{symbol %p}", static_cast<void*>(name));
1366       }
1367       PrintF(file, " ");
1368     }
1369   }
1370   PrintF(file, "\n");
1371 }
1372 
1373 
HeapObjectShortPrint(OStream & os)1374 void HeapObject::HeapObjectShortPrint(OStream& os) {  // NOLINT
1375   Heap* heap = GetHeap();
1376   if (!heap->Contains(this)) {
1377     os << "!!!INVALID POINTER!!!";
1378     return;
1379   }
1380   if (!heap->Contains(map())) {
1381     os << "!!!INVALID MAP!!!";
1382     return;
1383   }
1384 
1385   os << this << " ";
1386 
1387   if (IsString()) {
1388     HeapStringAllocator allocator;
1389     StringStream accumulator(&allocator);
1390     String::cast(this)->StringShortPrint(&accumulator);
1391     os << accumulator.ToCString().get();
1392     return;
1393   }
1394   if (IsJSObject()) {
1395     HeapStringAllocator allocator;
1396     StringStream accumulator(&allocator);
1397     JSObject::cast(this)->JSObjectShortPrint(&accumulator);
1398     os << accumulator.ToCString().get();
1399     return;
1400   }
1401   switch (map()->instance_type()) {
1402     case MAP_TYPE:
1403       os << "<Map(elements=" << Map::cast(this)->elements_kind() << ")>";
1404       break;
1405     case FIXED_ARRAY_TYPE:
1406       os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
1407       break;
1408     case FIXED_DOUBLE_ARRAY_TYPE:
1409       os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
1410          << "]>";
1411       break;
1412     case BYTE_ARRAY_TYPE:
1413       os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
1414       break;
1415     case FREE_SPACE_TYPE:
1416       os << "<FreeSpace[" << FreeSpace::cast(this)->Size() << "]>";
1417       break;
1418 #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size)                \
1419   case EXTERNAL_##TYPE##_ARRAY_TYPE:                                          \
1420     os << "<External" #Type "Array["                                          \
1421        << External##Type##Array::cast(this)->length() << "]>";                \
1422     break;                                                                    \
1423   case FIXED_##TYPE##_ARRAY_TYPE:                                             \
1424     os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
1425        << "]>";                                                               \
1426     break;
1427 
1428     TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
1429 #undef TYPED_ARRAY_SHORT_PRINT
1430 
1431     case SHARED_FUNCTION_INFO_TYPE: {
1432       SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
1433       SmartArrayPointer<char> debug_name =
1434           shared->DebugName()->ToCString();
1435       if (debug_name[0] != 0) {
1436         os << "<SharedFunctionInfo " << debug_name.get() << ">";
1437       } else {
1438         os << "<SharedFunctionInfo>";
1439       }
1440       break;
1441     }
1442     case JS_MESSAGE_OBJECT_TYPE:
1443       os << "<JSMessageObject>";
1444       break;
1445 #define MAKE_STRUCT_CASE(NAME, Name, name) \
1446   case NAME##_TYPE:                        \
1447     os << "<" #Name ">";                   \
1448     break;
1449   STRUCT_LIST(MAKE_STRUCT_CASE)
1450 #undef MAKE_STRUCT_CASE
1451     case CODE_TYPE: {
1452       Code* code = Code::cast(this);
1453       os << "<Code: " << Code::Kind2String(code->kind()) << ">";
1454       break;
1455     }
1456     case ODDBALL_TYPE: {
1457       if (IsUndefined()) {
1458         os << "<undefined>";
1459       } else if (IsTheHole()) {
1460         os << "<the hole>";
1461       } else if (IsNull()) {
1462         os << "<null>";
1463       } else if (IsTrue()) {
1464         os << "<true>";
1465       } else if (IsFalse()) {
1466         os << "<false>";
1467       } else {
1468         os << "<Odd Oddball>";
1469       }
1470       break;
1471     }
1472     case SYMBOL_TYPE: {
1473       Symbol* symbol = Symbol::cast(this);
1474       os << "<Symbol: " << symbol->Hash();
1475       if (!symbol->name()->IsUndefined()) {
1476         os << " ";
1477         HeapStringAllocator allocator;
1478         StringStream accumulator(&allocator);
1479         String::cast(symbol->name())->StringShortPrint(&accumulator);
1480         os << accumulator.ToCString().get();
1481       }
1482       os << ">";
1483       break;
1484     }
1485     case HEAP_NUMBER_TYPE: {
1486       os << "<Number: ";
1487       HeapNumber::cast(this)->HeapNumberPrint(os);
1488       os << ">";
1489       break;
1490     }
1491     case MUTABLE_HEAP_NUMBER_TYPE: {
1492       os << "<MutableNumber: ";
1493       HeapNumber::cast(this)->HeapNumberPrint(os);
1494       os << '>';
1495       break;
1496     }
1497     case JS_PROXY_TYPE:
1498       os << "<JSProxy>";
1499       break;
1500     case JS_FUNCTION_PROXY_TYPE:
1501       os << "<JSFunctionProxy>";
1502       break;
1503     case FOREIGN_TYPE:
1504       os << "<Foreign>";
1505       break;
1506     case CELL_TYPE: {
1507       os << "Cell for ";
1508       HeapStringAllocator allocator;
1509       StringStream accumulator(&allocator);
1510       Cell::cast(this)->value()->ShortPrint(&accumulator);
1511       os << accumulator.ToCString().get();
1512       break;
1513     }
1514     case PROPERTY_CELL_TYPE: {
1515       os << "PropertyCell for ";
1516       HeapStringAllocator allocator;
1517       StringStream accumulator(&allocator);
1518       PropertyCell::cast(this)->value()->ShortPrint(&accumulator);
1519       os << accumulator.ToCString().get();
1520       break;
1521     }
1522     default:
1523       os << "<Other heap object (" << map()->instance_type() << ")>";
1524       break;
1525   }
1526 }
1527 
1528 
Iterate(ObjectVisitor * v)1529 void HeapObject::Iterate(ObjectVisitor* v) {
1530   // Handle header
1531   IteratePointer(v, kMapOffset);
1532   // Handle object body
1533   Map* m = map();
1534   IterateBody(m->instance_type(), SizeFromMap(m), v);
1535 }
1536 
1537 
IterateBody(InstanceType type,int object_size,ObjectVisitor * v)1538 void HeapObject::IterateBody(InstanceType type, int object_size,
1539                              ObjectVisitor* v) {
1540   // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1541   // During GC, the map pointer field is encoded.
1542   if (type < FIRST_NONSTRING_TYPE) {
1543     switch (type & kStringRepresentationMask) {
1544       case kSeqStringTag:
1545         break;
1546       case kConsStringTag:
1547         ConsString::BodyDescriptor::IterateBody(this, v);
1548         break;
1549       case kSlicedStringTag:
1550         SlicedString::BodyDescriptor::IterateBody(this, v);
1551         break;
1552       case kExternalStringTag:
1553         if ((type & kStringEncodingMask) == kOneByteStringTag) {
1554           reinterpret_cast<ExternalOneByteString*>(this)
1555               ->ExternalOneByteStringIterateBody(v);
1556         } else {
1557           reinterpret_cast<ExternalTwoByteString*>(this)->
1558               ExternalTwoByteStringIterateBody(v);
1559         }
1560         break;
1561     }
1562     return;
1563   }
1564 
1565   switch (type) {
1566     case FIXED_ARRAY_TYPE:
1567       FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
1568       break;
1569     case CONSTANT_POOL_ARRAY_TYPE:
1570       reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v);
1571       break;
1572     case FIXED_DOUBLE_ARRAY_TYPE:
1573       break;
1574     case JS_OBJECT_TYPE:
1575     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1576     case JS_GENERATOR_OBJECT_TYPE:
1577     case JS_MODULE_TYPE:
1578     case JS_VALUE_TYPE:
1579     case JS_DATE_TYPE:
1580     case JS_ARRAY_TYPE:
1581     case JS_ARRAY_BUFFER_TYPE:
1582     case JS_TYPED_ARRAY_TYPE:
1583     case JS_DATA_VIEW_TYPE:
1584     case JS_SET_TYPE:
1585     case JS_MAP_TYPE:
1586     case JS_SET_ITERATOR_TYPE:
1587     case JS_MAP_ITERATOR_TYPE:
1588     case JS_WEAK_MAP_TYPE:
1589     case JS_WEAK_SET_TYPE:
1590     case JS_REGEXP_TYPE:
1591     case JS_GLOBAL_PROXY_TYPE:
1592     case JS_GLOBAL_OBJECT_TYPE:
1593     case JS_BUILTINS_OBJECT_TYPE:
1594     case JS_MESSAGE_OBJECT_TYPE:
1595       JSObject::BodyDescriptor::IterateBody(this, object_size, v);
1596       break;
1597     case JS_FUNCTION_TYPE:
1598       reinterpret_cast<JSFunction*>(this)
1599           ->JSFunctionIterateBody(object_size, v);
1600       break;
1601     case ODDBALL_TYPE:
1602       Oddball::BodyDescriptor::IterateBody(this, v);
1603       break;
1604     case JS_PROXY_TYPE:
1605       JSProxy::BodyDescriptor::IterateBody(this, v);
1606       break;
1607     case JS_FUNCTION_PROXY_TYPE:
1608       JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1609       break;
1610     case FOREIGN_TYPE:
1611       reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
1612       break;
1613     case MAP_TYPE:
1614       Map::BodyDescriptor::IterateBody(this, v);
1615       break;
1616     case CODE_TYPE:
1617       reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1618       break;
1619     case CELL_TYPE:
1620       Cell::BodyDescriptor::IterateBody(this, v);
1621       break;
1622     case PROPERTY_CELL_TYPE:
1623       PropertyCell::BodyDescriptor::IterateBody(this, v);
1624       break;
1625     case SYMBOL_TYPE:
1626       Symbol::BodyDescriptor::IterateBody(this, v);
1627       break;
1628 
1629     case HEAP_NUMBER_TYPE:
1630     case MUTABLE_HEAP_NUMBER_TYPE:
1631     case FILLER_TYPE:
1632     case BYTE_ARRAY_TYPE:
1633     case FREE_SPACE_TYPE:
1634       break;
1635 
1636 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
1637     case EXTERNAL_##TYPE##_ARRAY_TYPE:                                         \
1638     case FIXED_##TYPE##_ARRAY_TYPE:                                            \
1639       break;
1640 
1641     TYPED_ARRAYS(TYPED_ARRAY_CASE)
1642 #undef TYPED_ARRAY_CASE
1643 
1644     case SHARED_FUNCTION_INFO_TYPE: {
1645       SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
1646       break;
1647     }
1648 
1649 #define MAKE_STRUCT_CASE(NAME, Name, name) \
1650         case NAME##_TYPE:
1651       STRUCT_LIST(MAKE_STRUCT_CASE)
1652 #undef MAKE_STRUCT_CASE
1653       if (type == ALLOCATION_SITE_TYPE) {
1654         AllocationSite::BodyDescriptor::IterateBody(this, v);
1655       } else {
1656         StructBodyDescriptor::IterateBody(this, object_size, v);
1657       }
1658       break;
1659     default:
1660       PrintF("Unknown type: %d\n", type);
1661       UNREACHABLE();
1662   }
1663 }
1664 
1665 
HeapNumberBooleanValue()1666 bool HeapNumber::HeapNumberBooleanValue() {
1667   return DoubleToBoolean(value());
1668 }
1669 
1670 
HeapNumberPrint(OStream & os)1671 void HeapNumber::HeapNumberPrint(OStream& os) {  // NOLINT
1672   os << value();
1673 }
1674 
1675 
class_name()1676 String* JSReceiver::class_name() {
1677   if (IsJSFunction() || IsJSFunctionProxy()) {
1678     return GetHeap()->Function_string();
1679   }
1680   if (map()->constructor()->IsJSFunction()) {
1681     JSFunction* constructor = JSFunction::cast(map()->constructor());
1682     return String::cast(constructor->shared()->instance_class_name());
1683   }
1684   // If the constructor is not present, return "Object".
1685   return GetHeap()->Object_string();
1686 }
1687 
1688 
constructor_name()1689 String* Map::constructor_name() {
1690   if (constructor()->IsJSFunction()) {
1691     JSFunction* constructor = JSFunction::cast(this->constructor());
1692     String* name = String::cast(constructor->shared()->name());
1693     if (name->length() > 0) return name;
1694     String* inferred_name = constructor->shared()->inferred_name();
1695     if (inferred_name->length() > 0) return inferred_name;
1696     Object* proto = prototype();
1697     if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
1698   }
1699   // TODO(rossberg): what about proxies?
1700   // If the constructor is not present, return "Object".
1701   return GetHeap()->Object_string();
1702 }
1703 
1704 
constructor_name()1705 String* JSReceiver::constructor_name() {
1706   return map()->constructor_name();
1707 }
1708 
1709 
CopyWithField(Handle<Map> map,Handle<Name> name,Handle<HeapType> type,PropertyAttributes attributes,Representation representation,TransitionFlag flag)1710 MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
1711                                     Handle<Name> name,
1712                                     Handle<HeapType> type,
1713                                     PropertyAttributes attributes,
1714                                     Representation representation,
1715                                     TransitionFlag flag) {
1716   DCHECK(DescriptorArray::kNotFound ==
1717          map->instance_descriptors()->Search(
1718              *name, map->NumberOfOwnDescriptors()));
1719 
1720   // Ensure the descriptor array does not get too big.
1721   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1722     return MaybeHandle<Map>();
1723   }
1724 
1725   Isolate* isolate = map->GetIsolate();
1726 
1727   // Compute the new index for new field.
1728   int index = map->NextFreePropertyIndex();
1729 
1730   if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
1731     representation = Representation::Tagged();
1732     type = HeapType::Any(isolate);
1733   }
1734 
1735   FieldDescriptor new_field_desc(name, index, type, attributes, representation);
1736   Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
1737   int unused_property_fields = new_map->unused_property_fields() - 1;
1738   if (unused_property_fields < 0) {
1739     unused_property_fields += JSObject::kFieldsAdded;
1740   }
1741   new_map->set_unused_property_fields(unused_property_fields);
1742   return new_map;
1743 }
1744 
1745 
CopyWithConstant(Handle<Map> map,Handle<Name> name,Handle<Object> constant,PropertyAttributes attributes,TransitionFlag flag)1746 MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
1747                                        Handle<Name> name,
1748                                        Handle<Object> constant,
1749                                        PropertyAttributes attributes,
1750                                        TransitionFlag flag) {
1751   // Ensure the descriptor array does not get too big.
1752   if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1753     return MaybeHandle<Map>();
1754   }
1755 
1756   // Allocate new instance descriptors with (name, constant) added.
1757   ConstantDescriptor new_constant_desc(name, constant, attributes);
1758   return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
1759 }
1760 
1761 
AddSlowProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)1762 void JSObject::AddSlowProperty(Handle<JSObject> object,
1763                                Handle<Name> name,
1764                                Handle<Object> value,
1765                                PropertyAttributes attributes) {
1766   DCHECK(!object->HasFastProperties());
1767   Isolate* isolate = object->GetIsolate();
1768   Handle<NameDictionary> dict(object->property_dictionary());
1769   if (object->IsGlobalObject()) {
1770     // In case name is an orphaned property reuse the cell.
1771     int entry = dict->FindEntry(name);
1772     if (entry != NameDictionary::kNotFound) {
1773       Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry)));
1774       PropertyCell::SetValueInferType(cell, value);
1775       // Assign an enumeration index to the property and update
1776       // SetNextEnumerationIndex.
1777       int index = dict->NextEnumerationIndex();
1778       PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1779       dict->SetNextEnumerationIndex(index + 1);
1780       dict->SetEntry(entry, name, cell, details);
1781       return;
1782     }
1783     Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
1784     PropertyCell::SetValueInferType(cell, value);
1785     value = cell;
1786   }
1787   PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
1788   Handle<NameDictionary> result =
1789       NameDictionary::Add(dict, name, value, details);
1790   if (*dict != *result) object->set_properties(*result);
1791 }
1792 
1793 
GetCreationContext()1794 Context* JSObject::GetCreationContext() {
1795   Object* constructor = this->map()->constructor();
1796   JSFunction* function;
1797   if (!constructor->IsJSFunction()) {
1798     // Functions have null as a constructor,
1799     // but any JSFunction knows its context immediately.
1800     function = JSFunction::cast(this);
1801   } else {
1802     function = JSFunction::cast(constructor);
1803   }
1804 
1805   return function->context()->native_context();
1806 }
1807 
1808 
EnqueueChangeRecord(Handle<JSObject> object,const char * type_str,Handle<Name> name,Handle<Object> old_value)1809 void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
1810                                    const char* type_str,
1811                                    Handle<Name> name,
1812                                    Handle<Object> old_value) {
1813   DCHECK(!object->IsJSGlobalProxy());
1814   DCHECK(!object->IsJSGlobalObject());
1815   Isolate* isolate = object->GetIsolate();
1816   HandleScope scope(isolate);
1817   Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
1818   Handle<Object> args[] = { type, object, name, old_value };
1819   int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
1820 
1821   Execution::Call(isolate,
1822                   Handle<JSFunction>(isolate->observers_notify_change()),
1823                   isolate->factory()->undefined_value(),
1824                   argc, args).Assert();
1825 }
1826 
1827 
Mnemonic() const1828 const char* Representation::Mnemonic() const {
1829   switch (kind_) {
1830     case kNone: return "v";
1831     case kTagged: return "t";
1832     case kSmi: return "s";
1833     case kDouble: return "d";
1834     case kInteger32: return "i";
1835     case kHeapObject: return "h";
1836     case kExternal: return "x";
1837     default:
1838       UNREACHABLE();
1839       return NULL;
1840   }
1841 }
1842 
1843 
InstancesNeedRewriting(Map * target,int target_number_of_fields,int target_inobject,int target_unused,int * old_number_of_fields)1844 bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
1845                                  int target_inobject, int target_unused,
1846                                  int* old_number_of_fields) {
1847   // If fields were added (or removed), rewrite the instance.
1848   *old_number_of_fields = NumberOfFields();
1849   DCHECK(target_number_of_fields >= *old_number_of_fields);
1850   if (target_number_of_fields != *old_number_of_fields) return true;
1851 
1852   // If smi descriptors were replaced by double descriptors, rewrite.
1853   DescriptorArray* old_desc = instance_descriptors();
1854   DescriptorArray* new_desc = target->instance_descriptors();
1855   int limit = NumberOfOwnDescriptors();
1856   for (int i = 0; i < limit; i++) {
1857     if (new_desc->GetDetails(i).representation().IsDouble() !=
1858         old_desc->GetDetails(i).representation().IsDouble()) {
1859       return true;
1860     }
1861   }
1862 
1863   // If no fields were added, and no inobject properties were removed, setting
1864   // the map is sufficient.
1865   if (target_inobject == inobject_properties()) return false;
1866   // In-object slack tracking may have reduced the object size of the new map.
1867   // In that case, succeed if all existing fields were inobject, and they still
1868   // fit within the new inobject size.
1869   DCHECK(target_inobject < inobject_properties());
1870   if (target_number_of_fields <= target_inobject) {
1871     DCHECK(target_number_of_fields + target_unused == target_inobject);
1872     return false;
1873   }
1874   // Otherwise, properties will need to be moved to the backing store.
1875   return true;
1876 }
1877 
1878 
ConnectElementsTransition(Handle<Map> parent,Handle<Map> child)1879 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) {
1880   Isolate* isolate = parent->GetIsolate();
1881   Handle<Name> name = isolate->factory()->elements_transition_symbol();
1882   ConnectTransition(parent, child, name, FULL_TRANSITION);
1883 }
1884 
1885 
MigrateToMap(Handle<JSObject> object,Handle<Map> new_map)1886 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
1887   if (object->map() == *new_map) return;
1888   if (object->HasFastProperties()) {
1889     if (!new_map->is_dictionary_map()) {
1890       Handle<Map> old_map(object->map());
1891       MigrateFastToFast(object, new_map);
1892       if (old_map->is_prototype_map()) {
1893         // Clear out the old descriptor array to avoid problems to sharing
1894         // the descriptor array without using an explicit.
1895         old_map->InitializeDescriptors(
1896             old_map->GetHeap()->empty_descriptor_array());
1897         // Ensure that no transition was inserted for prototype migrations.
1898         DCHECK(!old_map->HasTransitionArray());
1899         DCHECK(new_map->GetBackPointer()->IsUndefined());
1900       }
1901     } else {
1902       MigrateFastToSlow(object, new_map, 0);
1903     }
1904   } else {
1905     // For slow-to-fast migrations JSObject::TransformToFastProperties()
1906     // must be used instead.
1907     CHECK(new_map->is_dictionary_map());
1908 
1909     // Slow-to-slow migration is trivial.
1910     object->set_map(*new_map);
1911   }
1912 }
1913 
1914 
1915 // To migrate a fast instance to a fast map:
1916 // - First check whether the instance needs to be rewritten. If not, simply
1917 //   change the map.
1918 // - Otherwise, allocate a fixed array large enough to hold all fields, in
1919 //   addition to unused space.
1920 // - Copy all existing properties in, in the following order: backing store
1921 //   properties, unused fields, inobject properties.
1922 // - If all allocation succeeded, commit the state atomically:
1923 //   * Copy inobject properties from the backing store back into the object.
1924 //   * Trim the difference in instance size of the object. This also cleanly
1925 //     frees inobject properties that moved to the backing store.
1926 //   * If there are properties left in the backing store, trim of the space used
1927 //     to temporarily store the inobject properties.
1928 //   * If there are properties left in the backing store, install the backing
1929 //     store.
MigrateFastToFast(Handle<JSObject> object,Handle<Map> new_map)1930 void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
1931   Isolate* isolate = object->GetIsolate();
1932   Handle<Map> old_map(object->map());
1933   int old_number_of_fields;
1934   int number_of_fields = new_map->NumberOfFields();
1935   int inobject = new_map->inobject_properties();
1936   int unused = new_map->unused_property_fields();
1937 
1938   // Nothing to do if no functions were converted to fields and no smis were
1939   // converted to doubles.
1940   if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
1941                                        unused, &old_number_of_fields)) {
1942     object->synchronized_set_map(*new_map);
1943     return;
1944   }
1945 
1946   int total_size = number_of_fields + unused;
1947   int external = total_size - inobject;
1948 
1949   if (number_of_fields != old_number_of_fields &&
1950       new_map->GetBackPointer() == *old_map) {
1951     PropertyDetails details = new_map->GetLastDescriptorDetails();
1952 
1953     if (old_map->unused_property_fields() > 0) {
1954       if (details.representation().IsDouble()) {
1955         Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
1956         FieldIndex index =
1957             FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
1958         object->FastPropertyAtPut(index, *value);
1959       }
1960       object->synchronized_set_map(*new_map);
1961       return;
1962     }
1963 
1964     DCHECK(number_of_fields == old_number_of_fields + 1);
1965     // This migration is a transition from a map that has run out out property
1966     // space. Therefore it could be done by extending the backing store.
1967     Handle<FixedArray> old_storage = handle(object->properties(), isolate);
1968     Handle<FixedArray> new_storage =
1969         FixedArray::CopySize(old_storage, external);
1970 
1971     // Properly initialize newly added property.
1972     Handle<Object> value;
1973     if (details.representation().IsDouble()) {
1974       value = isolate->factory()->NewHeapNumber(0, MUTABLE);
1975     } else {
1976       value = isolate->factory()->uninitialized_value();
1977     }
1978     DCHECK(details.type() == FIELD);
1979     int target_index = details.field_index() - inobject;
1980     DCHECK(target_index >= 0);  // Must be a backing store index.
1981     new_storage->set(target_index, *value);
1982 
1983     // From here on we cannot fail and we shouldn't GC anymore.
1984     DisallowHeapAllocation no_allocation;
1985 
1986     // Set the new property value and do the map transition.
1987     object->set_properties(*new_storage);
1988     object->synchronized_set_map(*new_map);
1989     return;
1990   }
1991   Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
1992 
1993   Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
1994   Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
1995   int old_nof = old_map->NumberOfOwnDescriptors();
1996   int new_nof = new_map->NumberOfOwnDescriptors();
1997 
1998   // This method only supports generalizing instances to at least the same
1999   // number of properties.
2000   DCHECK(old_nof <= new_nof);
2001 
2002   for (int i = 0; i < old_nof; i++) {
2003     PropertyDetails details = new_descriptors->GetDetails(i);
2004     if (details.type() != FIELD) continue;
2005     PropertyDetails old_details = old_descriptors->GetDetails(i);
2006     if (old_details.type() == CALLBACKS) {
2007       DCHECK(details.representation().IsTagged());
2008       continue;
2009     }
2010     DCHECK(old_details.type() == CONSTANT ||
2011            old_details.type() == FIELD);
2012     Object* raw_value = old_details.type() == CONSTANT
2013         ? old_descriptors->GetValue(i)
2014         : object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i));
2015     Handle<Object> value(raw_value, isolate);
2016     if (!old_details.representation().IsDouble() &&
2017         details.representation().IsDouble()) {
2018       if (old_details.representation().IsNone()) {
2019         value = handle(Smi::FromInt(0), isolate);
2020       }
2021       value = Object::NewStorageFor(isolate, value, details.representation());
2022     } else if (old_details.representation().IsDouble() &&
2023                !details.representation().IsDouble()) {
2024       value = Object::WrapForRead(isolate, value, old_details.representation());
2025     }
2026     DCHECK(!(details.representation().IsDouble() && value->IsSmi()));
2027     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2028     if (target_index < 0) target_index += total_size;
2029     array->set(target_index, *value);
2030   }
2031 
2032   for (int i = old_nof; i < new_nof; i++) {
2033     PropertyDetails details = new_descriptors->GetDetails(i);
2034     if (details.type() != FIELD) continue;
2035     Handle<Object> value;
2036     if (details.representation().IsDouble()) {
2037       value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2038     } else {
2039       value = isolate->factory()->uninitialized_value();
2040     }
2041     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2042     if (target_index < 0) target_index += total_size;
2043     array->set(target_index, *value);
2044   }
2045 
2046   // From here on we cannot fail and we shouldn't GC anymore.
2047   DisallowHeapAllocation no_allocation;
2048 
2049   // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2050   // avoid overwriting |one_pointer_filler_map|.
2051   int limit = Min(inobject, number_of_fields);
2052   for (int i = 0; i < limit; i++) {
2053     FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
2054     object->FastPropertyAtPut(index, array->get(external + i));
2055   }
2056 
2057   Heap* heap = isolate->heap();
2058 
2059   // If there are properties in the new backing store, trim it to the correct
2060   // size and install the backing store into the object.
2061   if (external > 0) {
2062     heap->RightTrimFixedArray<Heap::FROM_MUTATOR>(*array, inobject);
2063     object->set_properties(*array);
2064   }
2065 
2066   // Create filler object past the new instance size.
2067   int new_instance_size = new_map->instance_size();
2068   int instance_size_delta = old_map->instance_size() - new_instance_size;
2069   DCHECK(instance_size_delta >= 0);
2070 
2071   if (instance_size_delta > 0) {
2072     Address address = object->address();
2073     heap->CreateFillerObjectAt(
2074         address + new_instance_size, instance_size_delta);
2075     heap->AdjustLiveBytes(address, -instance_size_delta, Heap::FROM_MUTATOR);
2076   }
2077 
2078   // We are storing the new map using release store after creating a filler for
2079   // the left-over space to avoid races with the sweeper thread.
2080   object->synchronized_set_map(*new_map);
2081 }
2082 
2083 
GeneralizeFieldRepresentation(Handle<JSObject> object,int modify_index,Representation new_representation,Handle<HeapType> new_field_type)2084 void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
2085                                              int modify_index,
2086                                              Representation new_representation,
2087                                              Handle<HeapType> new_field_type) {
2088   Handle<Map> new_map = Map::GeneralizeRepresentation(
2089       handle(object->map()), modify_index, new_representation, new_field_type,
2090       FORCE_FIELD);
2091   MigrateToMap(object, new_map);
2092 }
2093 
2094 
NumberOfFields()2095 int Map::NumberOfFields() {
2096   DescriptorArray* descriptors = instance_descriptors();
2097   int result = 0;
2098   for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
2099     if (descriptors->GetDetails(i).type() == FIELD) result++;
2100   }
2101   return result;
2102 }
2103 
2104 
CopyGeneralizeAllRepresentations(Handle<Map> map,int modify_index,StoreMode store_mode,PropertyAttributes attributes,const char * reason)2105 Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2106                                                   int modify_index,
2107                                                   StoreMode store_mode,
2108                                                   PropertyAttributes attributes,
2109                                                   const char* reason) {
2110   Isolate* isolate = map->GetIsolate();
2111   Handle<Map> new_map = Copy(map);
2112 
2113   DescriptorArray* descriptors = new_map->instance_descriptors();
2114   int length = descriptors->number_of_descriptors();
2115   for (int i = 0; i < length; i++) {
2116     descriptors->SetRepresentation(i, Representation::Tagged());
2117     if (descriptors->GetDetails(i).type() == FIELD) {
2118       descriptors->SetValue(i, HeapType::Any());
2119     }
2120   }
2121 
2122   // Unless the instance is being migrated, ensure that modify_index is a field.
2123   PropertyDetails details = descriptors->GetDetails(modify_index);
2124   if (store_mode == FORCE_FIELD &&
2125       (details.type() != FIELD || details.attributes() != attributes)) {
2126     int field_index = details.type() == FIELD ? details.field_index()
2127                                               : new_map->NumberOfFields();
2128     FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
2129                       field_index, attributes, Representation::Tagged());
2130     descriptors->Replace(modify_index, &d);
2131     if (details.type() != FIELD) {
2132       int unused_property_fields = new_map->unused_property_fields() - 1;
2133       if (unused_property_fields < 0) {
2134         unused_property_fields += JSObject::kFieldsAdded;
2135       }
2136       new_map->set_unused_property_fields(unused_property_fields);
2137     }
2138   } else {
2139     DCHECK(details.attributes() == attributes);
2140   }
2141 
2142   if (FLAG_trace_generalization) {
2143     HeapType* field_type = (details.type() == FIELD)
2144         ? map->instance_descriptors()->GetFieldType(modify_index)
2145         : NULL;
2146     map->PrintGeneralization(stdout, reason, modify_index,
2147                         new_map->NumberOfOwnDescriptors(),
2148                         new_map->NumberOfOwnDescriptors(),
2149                         details.type() == CONSTANT && store_mode == FORCE_FIELD,
2150                         details.representation(), Representation::Tagged(),
2151                         field_type, HeapType::Any());
2152   }
2153   return new_map;
2154 }
2155 
2156 
2157 // static
CopyGeneralizeAllRepresentations(Handle<Map> map,int modify_index,StoreMode store_mode,const char * reason)2158 Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2159                                                   int modify_index,
2160                                                   StoreMode store_mode,
2161                                                   const char* reason) {
2162   PropertyDetails details =
2163       map->instance_descriptors()->GetDetails(modify_index);
2164   return CopyGeneralizeAllRepresentations(map, modify_index, store_mode,
2165                                           details.attributes(), reason);
2166 }
2167 
2168 
DeprecateTransitionTree()2169 void Map::DeprecateTransitionTree() {
2170   if (is_deprecated()) return;
2171   if (HasTransitionArray()) {
2172     TransitionArray* transitions = this->transitions();
2173     for (int i = 0; i < transitions->number_of_transitions(); i++) {
2174       transitions->GetTarget(i)->DeprecateTransitionTree();
2175     }
2176   }
2177   deprecate();
2178   dependent_code()->DeoptimizeDependentCodeGroup(
2179       GetIsolate(), DependentCode::kTransitionGroup);
2180   NotifyLeafMapLayoutChange();
2181 }
2182 
2183 
2184 // Invalidates a transition target at |key|, and installs |new_descriptors| over
2185 // the current instance_descriptors to ensure proper sharing of descriptor
2186 // arrays.
DeprecateTarget(Name * key,DescriptorArray * new_descriptors)2187 void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
2188   if (HasTransitionArray()) {
2189     TransitionArray* transitions = this->transitions();
2190     int transition = transitions->Search(key);
2191     if (transition != TransitionArray::kNotFound) {
2192       transitions->GetTarget(transition)->DeprecateTransitionTree();
2193     }
2194   }
2195 
2196   // Don't overwrite the empty descriptor array.
2197   if (NumberOfOwnDescriptors() == 0) return;
2198 
2199   DescriptorArray* to_replace = instance_descriptors();
2200   Map* current = this;
2201   GetHeap()->incremental_marking()->RecordWrites(to_replace);
2202   while (current->instance_descriptors() == to_replace) {
2203     current->SetEnumLength(kInvalidEnumCacheSentinel);
2204     current->set_instance_descriptors(new_descriptors);
2205     Object* next = current->GetBackPointer();
2206     if (next->IsUndefined()) break;
2207     current = Map::cast(next);
2208   }
2209 
2210   set_owns_descriptors(false);
2211 }
2212 
2213 
FindRootMap()2214 Map* Map::FindRootMap() {
2215   Map* result = this;
2216   while (true) {
2217     Object* back = result->GetBackPointer();
2218     if (back->IsUndefined()) return result;
2219     result = Map::cast(back);
2220   }
2221 }
2222 
2223 
FindLastMatchMap(int verbatim,int length,DescriptorArray * descriptors)2224 Map* Map::FindLastMatchMap(int verbatim,
2225                            int length,
2226                            DescriptorArray* descriptors) {
2227   DisallowHeapAllocation no_allocation;
2228 
2229   // This can only be called on roots of transition trees.
2230   DCHECK(GetBackPointer()->IsUndefined());
2231 
2232   Map* current = this;
2233 
2234   for (int i = verbatim; i < length; i++) {
2235     if (!current->HasTransitionArray()) break;
2236     Name* name = descriptors->GetKey(i);
2237     TransitionArray* transitions = current->transitions();
2238     int transition = transitions->Search(name);
2239     if (transition == TransitionArray::kNotFound) break;
2240 
2241     Map* next = transitions->GetTarget(transition);
2242     DescriptorArray* next_descriptors = next->instance_descriptors();
2243 
2244     PropertyDetails details = descriptors->GetDetails(i);
2245     PropertyDetails next_details = next_descriptors->GetDetails(i);
2246     if (details.type() != next_details.type()) break;
2247     if (details.attributes() != next_details.attributes()) break;
2248     if (!details.representation().Equals(next_details.representation())) break;
2249     if (next_details.type() == FIELD) {
2250       if (!descriptors->GetFieldType(i)->NowIs(
2251               next_descriptors->GetFieldType(i))) break;
2252     } else {
2253       if (descriptors->GetValue(i) != next_descriptors->GetValue(i)) break;
2254     }
2255 
2256     current = next;
2257   }
2258   return current;
2259 }
2260 
2261 
FindFieldOwner(int descriptor)2262 Map* Map::FindFieldOwner(int descriptor) {
2263   DisallowHeapAllocation no_allocation;
2264   DCHECK_EQ(FIELD, instance_descriptors()->GetDetails(descriptor).type());
2265   Map* result = this;
2266   while (true) {
2267     Object* back = result->GetBackPointer();
2268     if (back->IsUndefined()) break;
2269     Map* parent = Map::cast(back);
2270     if (parent->NumberOfOwnDescriptors() <= descriptor) break;
2271     result = parent;
2272   }
2273   return result;
2274 }
2275 
2276 
UpdateFieldType(int descriptor,Handle<Name> name,Handle<HeapType> new_type)2277 void Map::UpdateFieldType(int descriptor, Handle<Name> name,
2278                           Handle<HeapType> new_type) {
2279   DisallowHeapAllocation no_allocation;
2280   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
2281   if (details.type() != FIELD) return;
2282   if (HasTransitionArray()) {
2283     TransitionArray* transitions = this->transitions();
2284     for (int i = 0; i < transitions->number_of_transitions(); ++i) {
2285       transitions->GetTarget(i)->UpdateFieldType(descriptor, name, new_type);
2286     }
2287   }
2288   // Skip if already updated the shared descriptor.
2289   if (instance_descriptors()->GetFieldType(descriptor) == *new_type) return;
2290   FieldDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
2291                     new_type, details.attributes(), details.representation());
2292   instance_descriptors()->Replace(descriptor, &d);
2293 }
2294 
2295 
2296 // static
GeneralizeFieldType(Handle<HeapType> type1,Handle<HeapType> type2,Isolate * isolate)2297 Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> type1,
2298                                           Handle<HeapType> type2,
2299                                           Isolate* isolate) {
2300   static const int kMaxClassesPerFieldType = 5;
2301   if (type1->NowIs(type2)) return type2;
2302   if (type2->NowIs(type1)) return type1;
2303   if (type1->NowStable() && type2->NowStable()) {
2304     Handle<HeapType> type = HeapType::Union(type1, type2, isolate);
2305     if (type->NumClasses() <= kMaxClassesPerFieldType) {
2306       DCHECK(type->NowStable());
2307       DCHECK(type1->NowIs(type));
2308       DCHECK(type2->NowIs(type));
2309       return type;
2310     }
2311   }
2312   return HeapType::Any(isolate);
2313 }
2314 
2315 
2316 // static
GeneralizeFieldType(Handle<Map> map,int modify_index,Handle<HeapType> new_field_type)2317 void Map::GeneralizeFieldType(Handle<Map> map,
2318                               int modify_index,
2319                               Handle<HeapType> new_field_type) {
2320   Isolate* isolate = map->GetIsolate();
2321 
2322   // Check if we actually need to generalize the field type at all.
2323   Handle<HeapType> old_field_type(
2324       map->instance_descriptors()->GetFieldType(modify_index), isolate);
2325   if (new_field_type->NowIs(old_field_type)) {
2326     DCHECK(Map::GeneralizeFieldType(old_field_type,
2327                                     new_field_type,
2328                                     isolate)->NowIs(old_field_type));
2329     return;
2330   }
2331 
2332   // Determine the field owner.
2333   Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
2334   Handle<DescriptorArray> descriptors(
2335       field_owner->instance_descriptors(), isolate);
2336   DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
2337 
2338   // Determine the generalized new field type.
2339   new_field_type = Map::GeneralizeFieldType(
2340       old_field_type, new_field_type, isolate);
2341 
2342   PropertyDetails details = descriptors->GetDetails(modify_index);
2343   Handle<Name> name(descriptors->GetKey(modify_index));
2344   field_owner->UpdateFieldType(modify_index, name, new_field_type);
2345   field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
2346       isolate, DependentCode::kFieldTypeGroup);
2347 
2348   if (FLAG_trace_generalization) {
2349     map->PrintGeneralization(
2350         stdout, "field type generalization",
2351         modify_index, map->NumberOfOwnDescriptors(),
2352         map->NumberOfOwnDescriptors(), false,
2353         details.representation(), details.representation(),
2354         *old_field_type, *new_field_type);
2355   }
2356 }
2357 
2358 
2359 // Generalize the representation of the descriptor at |modify_index|.
2360 // This method rewrites the transition tree to reflect the new change. To avoid
2361 // high degrees over polymorphism, and to stabilize quickly, on every rewrite
2362 // the new type is deduced by merging the current type with any potential new
2363 // (partial) version of the type in the transition tree.
2364 // To do this, on each rewrite:
2365 // - Search the root of the transition tree using FindRootMap.
2366 // - Find |target_map|, the newest matching version of this map using the keys
2367 //   in the |old_map|'s descriptor array to walk the transition tree.
2368 // - Merge/generalize the descriptor array of the |old_map| and |target_map|.
2369 // - Generalize the |modify_index| descriptor using |new_representation| and
2370 //   |new_field_type|.
2371 // - Walk the tree again starting from the root towards |target_map|. Stop at
2372 //   |split_map|, the first map who's descriptor array does not match the merged
2373 //   descriptor array.
2374 // - If |target_map| == |split_map|, |target_map| is in the expected state.
2375 //   Return it.
2376 // - Otherwise, invalidate the outdated transition target from |target_map|, and
2377 //   replace its transition tree with a new branch for the updated descriptors.
GeneralizeRepresentation(Handle<Map> old_map,int modify_index,Representation new_representation,Handle<HeapType> new_field_type,StoreMode store_mode)2378 Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
2379                                           int modify_index,
2380                                           Representation new_representation,
2381                                           Handle<HeapType> new_field_type,
2382                                           StoreMode store_mode) {
2383   Isolate* isolate = old_map->GetIsolate();
2384 
2385   Handle<DescriptorArray> old_descriptors(
2386       old_map->instance_descriptors(), isolate);
2387   int old_nof = old_map->NumberOfOwnDescriptors();
2388   PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2389   Representation old_representation = old_details.representation();
2390 
2391   // It's fine to transition from None to anything but double without any
2392   // modification to the object, because the default uninitialized value for
2393   // representation None can be overwritten by both smi and tagged values.
2394   // Doubles, however, would require a box allocation.
2395   if (old_representation.IsNone() &&
2396       !new_representation.IsNone() &&
2397       !new_representation.IsDouble()) {
2398     DCHECK(old_details.type() == FIELD);
2399     DCHECK(old_descriptors->GetFieldType(modify_index)->NowIs(
2400             HeapType::None()));
2401     if (FLAG_trace_generalization) {
2402       old_map->PrintGeneralization(
2403           stdout, "uninitialized field",
2404           modify_index, old_map->NumberOfOwnDescriptors(),
2405           old_map->NumberOfOwnDescriptors(), false,
2406           old_representation, new_representation,
2407           old_descriptors->GetFieldType(modify_index), *new_field_type);
2408     }
2409     old_descriptors->SetRepresentation(modify_index, new_representation);
2410     old_descriptors->SetValue(modify_index, *new_field_type);
2411     return old_map;
2412   }
2413 
2414   // Check the state of the root map.
2415   Handle<Map> root_map(old_map->FindRootMap(), isolate);
2416   if (!old_map->EquivalentToForTransition(*root_map)) {
2417     return CopyGeneralizeAllRepresentations(
2418         old_map, modify_index, store_mode, "not equivalent");
2419   }
2420   int root_nof = root_map->NumberOfOwnDescriptors();
2421   if (modify_index < root_nof) {
2422     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2423     if ((old_details.type() != FIELD && store_mode == FORCE_FIELD) ||
2424         (old_details.type() == FIELD &&
2425          (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
2426           !new_representation.fits_into(old_details.representation())))) {
2427       return CopyGeneralizeAllRepresentations(
2428           old_map, modify_index, store_mode, "root modification");
2429     }
2430   }
2431 
2432   Handle<Map> target_map = root_map;
2433   for (int i = root_nof; i < old_nof; ++i) {
2434     int j = target_map->SearchTransition(old_descriptors->GetKey(i));
2435     if (j == TransitionArray::kNotFound) break;
2436     Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2437     Handle<DescriptorArray> tmp_descriptors = handle(
2438         tmp_map->instance_descriptors(), isolate);
2439 
2440     // Check if target map is incompatible.
2441     PropertyDetails old_details = old_descriptors->GetDetails(i);
2442     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
2443     PropertyType old_type = old_details.type();
2444     PropertyType tmp_type = tmp_details.type();
2445     if (tmp_details.attributes() != old_details.attributes() ||
2446         ((tmp_type == CALLBACKS || old_type == CALLBACKS) &&
2447          (tmp_type != old_type ||
2448           tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
2449       return CopyGeneralizeAllRepresentations(
2450           old_map, modify_index, store_mode, "incompatible");
2451     }
2452     Representation old_representation = old_details.representation();
2453     Representation tmp_representation = tmp_details.representation();
2454     if (!old_representation.fits_into(tmp_representation) ||
2455         (!new_representation.fits_into(tmp_representation) &&
2456          modify_index == i)) {
2457       break;
2458     }
2459     if (tmp_type == FIELD) {
2460       // Generalize the field type as necessary.
2461       Handle<HeapType> old_field_type = (old_type == FIELD)
2462           ? handle(old_descriptors->GetFieldType(i), isolate)
2463           : old_descriptors->GetValue(i)->OptimalType(
2464               isolate, tmp_representation);
2465       if (modify_index == i) {
2466         old_field_type = GeneralizeFieldType(
2467             new_field_type, old_field_type, isolate);
2468       }
2469       GeneralizeFieldType(tmp_map, i, old_field_type);
2470     } else if (tmp_type == CONSTANT) {
2471       if (old_type != CONSTANT ||
2472           old_descriptors->GetConstant(i) != tmp_descriptors->GetConstant(i)) {
2473         break;
2474       }
2475     } else {
2476       DCHECK_EQ(tmp_type, old_type);
2477       DCHECK_EQ(tmp_descriptors->GetValue(i), old_descriptors->GetValue(i));
2478     }
2479     target_map = tmp_map;
2480   }
2481 
2482   // Directly change the map if the target map is more general.
2483   Handle<DescriptorArray> target_descriptors(
2484       target_map->instance_descriptors(), isolate);
2485   int target_nof = target_map->NumberOfOwnDescriptors();
2486   if (target_nof == old_nof &&
2487       (store_mode != FORCE_FIELD ||
2488        target_descriptors->GetDetails(modify_index).type() == FIELD)) {
2489     DCHECK(modify_index < target_nof);
2490     DCHECK(new_representation.fits_into(
2491             target_descriptors->GetDetails(modify_index).representation()));
2492     DCHECK(target_descriptors->GetDetails(modify_index).type() != FIELD ||
2493            new_field_type->NowIs(
2494                target_descriptors->GetFieldType(modify_index)));
2495     return target_map;
2496   }
2497 
2498   // Find the last compatible target map in the transition tree.
2499   for (int i = target_nof; i < old_nof; ++i) {
2500     int j = target_map->SearchTransition(old_descriptors->GetKey(i));
2501     if (j == TransitionArray::kNotFound) break;
2502     Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2503     Handle<DescriptorArray> tmp_descriptors(
2504         tmp_map->instance_descriptors(), isolate);
2505 
2506     // Check if target map is compatible.
2507     PropertyDetails old_details = old_descriptors->GetDetails(i);
2508     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
2509     if (tmp_details.attributes() != old_details.attributes() ||
2510         ((tmp_details.type() == CALLBACKS || old_details.type() == CALLBACKS) &&
2511          (tmp_details.type() != old_details.type() ||
2512           tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
2513       return CopyGeneralizeAllRepresentations(
2514           old_map, modify_index, store_mode, "incompatible");
2515     }
2516     target_map = tmp_map;
2517   }
2518   target_nof = target_map->NumberOfOwnDescriptors();
2519   target_descriptors = handle(target_map->instance_descriptors(), isolate);
2520 
2521   // Allocate a new descriptor array large enough to hold the required
2522   // descriptors, with minimally the exact same size as the old descriptor
2523   // array.
2524   int new_slack = Max(
2525       old_nof, old_descriptors->number_of_descriptors()) - old_nof;
2526   Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
2527       isolate, old_nof, new_slack);
2528   DCHECK(new_descriptors->length() > target_descriptors->length() ||
2529          new_descriptors->NumberOfSlackDescriptors() > 0 ||
2530          new_descriptors->number_of_descriptors() ==
2531          old_descriptors->number_of_descriptors());
2532   DCHECK(new_descriptors->number_of_descriptors() == old_nof);
2533 
2534   // 0 -> |root_nof|
2535   int current_offset = 0;
2536   for (int i = 0; i < root_nof; ++i) {
2537     PropertyDetails old_details = old_descriptors->GetDetails(i);
2538     if (old_details.type() == FIELD) current_offset++;
2539     Descriptor d(handle(old_descriptors->GetKey(i), isolate),
2540                  handle(old_descriptors->GetValue(i), isolate),
2541                  old_details);
2542     new_descriptors->Set(i, &d);
2543   }
2544 
2545   // |root_nof| -> |target_nof|
2546   for (int i = root_nof; i < target_nof; ++i) {
2547     Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
2548     PropertyDetails old_details = old_descriptors->GetDetails(i);
2549     PropertyDetails target_details = target_descriptors->GetDetails(i);
2550     target_details = target_details.CopyWithRepresentation(
2551         old_details.representation().generalize(
2552             target_details.representation()));
2553     if (modify_index == i) {
2554       target_details = target_details.CopyWithRepresentation(
2555           new_representation.generalize(target_details.representation()));
2556     }
2557     DCHECK_EQ(old_details.attributes(), target_details.attributes());
2558     if (old_details.type() == FIELD ||
2559         target_details.type() == FIELD ||
2560         (modify_index == i && store_mode == FORCE_FIELD) ||
2561         (target_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
2562       Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2563           ? handle(old_descriptors->GetFieldType(i), isolate)
2564           : old_descriptors->GetValue(i)->OptimalType(
2565               isolate, target_details.representation());
2566       Handle<HeapType> target_field_type = (target_details.type() == FIELD)
2567           ? handle(target_descriptors->GetFieldType(i), isolate)
2568           : target_descriptors->GetValue(i)->OptimalType(
2569               isolate, target_details.representation());
2570       target_field_type = GeneralizeFieldType(
2571           target_field_type, old_field_type, isolate);
2572       if (modify_index == i) {
2573         target_field_type = GeneralizeFieldType(
2574             target_field_type, new_field_type, isolate);
2575       }
2576       FieldDescriptor d(target_key,
2577                         current_offset++,
2578                         target_field_type,
2579                         target_details.attributes(),
2580                         target_details.representation());
2581       new_descriptors->Set(i, &d);
2582     } else {
2583       DCHECK_NE(FIELD, target_details.type());
2584       Descriptor d(target_key,
2585                    handle(target_descriptors->GetValue(i), isolate),
2586                    target_details);
2587       new_descriptors->Set(i, &d);
2588     }
2589   }
2590 
2591   // |target_nof| -> |old_nof|
2592   for (int i = target_nof; i < old_nof; ++i) {
2593     PropertyDetails old_details = old_descriptors->GetDetails(i);
2594     Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
2595     if (modify_index == i) {
2596       old_details = old_details.CopyWithRepresentation(
2597           new_representation.generalize(old_details.representation()));
2598     }
2599     if (old_details.type() == FIELD) {
2600       Handle<HeapType> old_field_type(
2601           old_descriptors->GetFieldType(i), isolate);
2602       if (modify_index == i) {
2603         old_field_type = GeneralizeFieldType(
2604             old_field_type, new_field_type, isolate);
2605       }
2606       FieldDescriptor d(old_key,
2607                         current_offset++,
2608                         old_field_type,
2609                         old_details.attributes(),
2610                         old_details.representation());
2611       new_descriptors->Set(i, &d);
2612     } else {
2613       DCHECK(old_details.type() == CONSTANT || old_details.type() == CALLBACKS);
2614       if (modify_index == i && store_mode == FORCE_FIELD) {
2615         FieldDescriptor d(old_key,
2616                           current_offset++,
2617                           GeneralizeFieldType(
2618                               old_descriptors->GetValue(i)->OptimalType(
2619                                   isolate, old_details.representation()),
2620                               new_field_type, isolate),
2621                           old_details.attributes(),
2622                           old_details.representation());
2623         new_descriptors->Set(i, &d);
2624       } else {
2625         DCHECK_NE(FIELD, old_details.type());
2626         Descriptor d(old_key,
2627                      handle(old_descriptors->GetValue(i), isolate),
2628                      old_details);
2629         new_descriptors->Set(i, &d);
2630       }
2631     }
2632   }
2633 
2634   new_descriptors->Sort();
2635 
2636   DCHECK(store_mode != FORCE_FIELD ||
2637          new_descriptors->GetDetails(modify_index).type() == FIELD);
2638 
2639   Handle<Map> split_map(root_map->FindLastMatchMap(
2640           root_nof, old_nof, *new_descriptors), isolate);
2641   int split_nof = split_map->NumberOfOwnDescriptors();
2642   DCHECK_NE(old_nof, split_nof);
2643 
2644   split_map->DeprecateTarget(
2645       old_descriptors->GetKey(split_nof), *new_descriptors);
2646 
2647   if (FLAG_trace_generalization) {
2648     PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2649     PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
2650     Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2651         ? handle(old_descriptors->GetFieldType(modify_index), isolate)
2652         : HeapType::Constant(handle(old_descriptors->GetValue(modify_index),
2653                                     isolate), isolate);
2654     Handle<HeapType> new_field_type = (new_details.type() == FIELD)
2655         ? handle(new_descriptors->GetFieldType(modify_index), isolate)
2656         : HeapType::Constant(handle(new_descriptors->GetValue(modify_index),
2657                                     isolate), isolate);
2658     old_map->PrintGeneralization(
2659         stdout, "", modify_index, split_nof, old_nof,
2660         old_details.type() == CONSTANT && store_mode == FORCE_FIELD,
2661         old_details.representation(), new_details.representation(),
2662         *old_field_type, *new_field_type);
2663   }
2664 
2665   // Add missing transitions.
2666   Handle<Map> new_map = split_map;
2667   for (int i = split_nof; i < old_nof; ++i) {
2668     new_map = CopyInstallDescriptors(new_map, i, new_descriptors);
2669   }
2670   new_map->set_owns_descriptors(true);
2671   return new_map;
2672 }
2673 
2674 
2675 // Generalize the representation of all FIELD descriptors.
GeneralizeAllFieldRepresentations(Handle<Map> map)2676 Handle<Map> Map::GeneralizeAllFieldRepresentations(
2677     Handle<Map> map) {
2678   Handle<DescriptorArray> descriptors(map->instance_descriptors());
2679   for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
2680     if (descriptors->GetDetails(i).type() == FIELD) {
2681       map = GeneralizeRepresentation(map, i, Representation::Tagged(),
2682                                      HeapType::Any(map->GetIsolate()),
2683                                      FORCE_FIELD);
2684     }
2685   }
2686   return map;
2687 }
2688 
2689 
2690 // static
TryUpdate(Handle<Map> map)2691 MaybeHandle<Map> Map::TryUpdate(Handle<Map> map) {
2692   Handle<Map> proto_map(map);
2693   while (proto_map->prototype()->IsJSObject()) {
2694     Handle<JSObject> holder(JSObject::cast(proto_map->prototype()));
2695     proto_map = Handle<Map>(holder->map());
2696     if (proto_map->is_deprecated() && JSObject::TryMigrateInstance(holder)) {
2697       proto_map = Handle<Map>(holder->map());
2698     }
2699   }
2700   return TryUpdateInternal(map);
2701 }
2702 
2703 
2704 // static
Update(Handle<Map> map)2705 Handle<Map> Map::Update(Handle<Map> map) {
2706   if (!map->is_deprecated()) return map;
2707   return GeneralizeRepresentation(map, 0, Representation::None(),
2708                                   HeapType::None(map->GetIsolate()),
2709                                   ALLOW_AS_CONSTANT);
2710 }
2711 
2712 
2713 // static
TryUpdateInternal(Handle<Map> old_map)2714 MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
2715   DisallowHeapAllocation no_allocation;
2716   DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
2717 
2718   if (!old_map->is_deprecated()) return old_map;
2719 
2720   // Check the state of the root map.
2721   Map* root_map = old_map->FindRootMap();
2722   if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
2723   int root_nof = root_map->NumberOfOwnDescriptors();
2724 
2725   int old_nof = old_map->NumberOfOwnDescriptors();
2726   DescriptorArray* old_descriptors = old_map->instance_descriptors();
2727 
2728   Map* new_map = root_map;
2729   for (int i = root_nof; i < old_nof; ++i) {
2730     int j = new_map->SearchTransition(old_descriptors->GetKey(i));
2731     if (j == TransitionArray::kNotFound) return MaybeHandle<Map>();
2732     new_map = new_map->GetTransition(j);
2733     DescriptorArray* new_descriptors = new_map->instance_descriptors();
2734 
2735     PropertyDetails new_details = new_descriptors->GetDetails(i);
2736     PropertyDetails old_details = old_descriptors->GetDetails(i);
2737     if (old_details.attributes() != new_details.attributes() ||
2738         !old_details.representation().fits_into(new_details.representation())) {
2739       return MaybeHandle<Map>();
2740     }
2741     PropertyType new_type = new_details.type();
2742     PropertyType old_type = old_details.type();
2743     Object* new_value = new_descriptors->GetValue(i);
2744     Object* old_value = old_descriptors->GetValue(i);
2745     switch (new_type) {
2746       case FIELD:
2747         if ((old_type == FIELD &&
2748              !HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) ||
2749             (old_type == CONSTANT &&
2750              !HeapType::cast(new_value)->NowContains(old_value)) ||
2751             (old_type == CALLBACKS &&
2752              !HeapType::Any()->Is(HeapType::cast(new_value)))) {
2753           return MaybeHandle<Map>();
2754         }
2755         break;
2756 
2757       case CONSTANT:
2758       case CALLBACKS:
2759         if (old_type != new_type || old_value != new_value) {
2760           return MaybeHandle<Map>();
2761         }
2762         break;
2763 
2764       case NORMAL:
2765         UNREACHABLE();
2766     }
2767   }
2768   if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
2769   return handle(new_map);
2770 }
2771 
2772 
SetPropertyWithInterceptor(LookupIterator * it,Handle<Object> value)2773 MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
2774                                                          Handle<Object> value) {
2775   // TODO(rossberg): Support symbols in the API.
2776   if (it->name()->IsSymbol()) return value;
2777 
2778   Handle<String> name_string = Handle<String>::cast(it->name());
2779   Handle<JSObject> holder = it->GetHolder<JSObject>();
2780   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
2781   if (interceptor->setter()->IsUndefined()) return MaybeHandle<Object>();
2782 
2783   LOG(it->isolate(),
2784       ApiNamedPropertyAccess("interceptor-named-set", *holder, *name_string));
2785   PropertyCallbackArguments args(it->isolate(), interceptor->data(), *holder,
2786                                  *holder);
2787   v8::NamedPropertySetterCallback setter =
2788       v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
2789   v8::Handle<v8::Value> result = args.Call(
2790       setter, v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value));
2791   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
2792   if (!result.IsEmpty()) return value;
2793 
2794   return MaybeHandle<Object>();
2795 }
2796 
2797 
SetProperty(Handle<Object> object,Handle<Name> name,Handle<Object> value,StrictMode strict_mode,StoreFromKeyed store_mode)2798 MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
2799                                         Handle<Name> name, Handle<Object> value,
2800                                         StrictMode strict_mode,
2801                                         StoreFromKeyed store_mode) {
2802   LookupIterator it(object, name);
2803   return SetProperty(&it, value, strict_mode, store_mode);
2804 }
2805 
2806 
SetProperty(LookupIterator * it,Handle<Object> value,StrictMode strict_mode,StoreFromKeyed store_mode)2807 MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
2808                                         Handle<Object> value,
2809                                         StrictMode strict_mode,
2810                                         StoreFromKeyed store_mode) {
2811   // Make sure that the top context does not change when doing callbacks or
2812   // interceptor calls.
2813   AssertNoContextChange ncc(it->isolate());
2814 
2815   bool done = false;
2816   for (; it->IsFound(); it->Next()) {
2817     switch (it->state()) {
2818       case LookupIterator::NOT_FOUND:
2819         UNREACHABLE();
2820 
2821       case LookupIterator::ACCESS_CHECK:
2822         // TODO(verwaest): Remove the distinction. This is mostly bogus since we
2823         // don't know whether we'll want to fetch attributes or call a setter
2824         // until we find the property.
2825         if (it->HasAccess(v8::ACCESS_SET)) break;
2826         return JSObject::SetPropertyWithFailedAccessCheck(it, value,
2827                                                           strict_mode);
2828 
2829       case LookupIterator::JSPROXY:
2830         if (it->HolderIsReceiverOrHiddenPrototype()) {
2831           return JSProxy::SetPropertyWithHandler(it->GetHolder<JSProxy>(),
2832                                                  it->GetReceiver(), it->name(),
2833                                                  value, strict_mode);
2834         } else {
2835           // TODO(verwaest): Use the MaybeHandle to indicate result.
2836           bool has_result = false;
2837           MaybeHandle<Object> maybe_result =
2838               JSProxy::SetPropertyViaPrototypesWithHandler(
2839                   it->GetHolder<JSProxy>(), it->GetReceiver(), it->name(),
2840                   value, strict_mode, &has_result);
2841           if (has_result) return maybe_result;
2842           done = true;
2843         }
2844         break;
2845 
2846       case LookupIterator::INTERCEPTOR:
2847         if (it->HolderIsReceiverOrHiddenPrototype()) {
2848           MaybeHandle<Object> maybe_result =
2849               JSObject::SetPropertyWithInterceptor(it, value);
2850           if (!maybe_result.is_null()) return maybe_result;
2851           if (it->isolate()->has_pending_exception()) return maybe_result;
2852         } else {
2853           Maybe<PropertyAttributes> maybe_attributes =
2854               JSObject::GetPropertyAttributesWithInterceptor(
2855                   it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
2856           if (!maybe_attributes.has_value) return MaybeHandle<Object>();
2857           done = maybe_attributes.value != ABSENT;
2858           if (done && (maybe_attributes.value & READ_ONLY) != 0) {
2859             return WriteToReadOnlyProperty(it, value, strict_mode);
2860           }
2861         }
2862         break;
2863 
2864       case LookupIterator::ACCESSOR:
2865         if (it->property_details().IsReadOnly()) {
2866           return WriteToReadOnlyProperty(it, value, strict_mode);
2867         }
2868         if (it->HolderIsReceiverOrHiddenPrototype() ||
2869             !it->GetAccessors()->IsDeclaredAccessorInfo()) {
2870           return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
2871                                          it->GetHolder<JSObject>(),
2872                                          it->GetAccessors(), strict_mode);
2873         }
2874         done = true;
2875         break;
2876 
2877       case LookupIterator::DATA:
2878         if (it->property_details().IsReadOnly()) {
2879           return WriteToReadOnlyProperty(it, value, strict_mode);
2880         }
2881         if (it->HolderIsReceiverOrHiddenPrototype()) {
2882           return SetDataProperty(it, value);
2883         }
2884         done = true;
2885         break;
2886 
2887       case LookupIterator::TRANSITION:
2888         done = true;
2889         break;
2890     }
2891 
2892     if (done) break;
2893   }
2894 
2895   // If the receiver is the JSGlobalObject, the store was contextual. In case
2896   // the property did not exist yet on the global object itself, we have to
2897   // throw a reference error in strict mode.
2898   if (it->GetReceiver()->IsJSGlobalObject() && strict_mode == STRICT) {
2899     Handle<Object> args[1] = {it->name()};
2900     THROW_NEW_ERROR(it->isolate(),
2901                     NewReferenceError("not_defined", HandleVector(args, 1)),
2902                     Object);
2903   }
2904 
2905   return AddDataProperty(it, value, NONE, strict_mode, store_mode);
2906 }
2907 
2908 
WriteToReadOnlyProperty(LookupIterator * it,Handle<Object> value,StrictMode strict_mode)2909 MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it,
2910                                                     Handle<Object> value,
2911                                                     StrictMode strict_mode) {
2912   if (strict_mode != STRICT) return value;
2913 
2914   Handle<Object> args[] = {it->name(), it->GetReceiver()};
2915   THROW_NEW_ERROR(it->isolate(),
2916                   NewTypeError("strict_read_only_property",
2917                                HandleVector(args, arraysize(args))),
2918                   Object);
2919 }
2920 
2921 
SetDataProperty(LookupIterator * it,Handle<Object> value)2922 Handle<Object> Object::SetDataProperty(LookupIterator* it,
2923                                        Handle<Object> value) {
2924   // Proxies are handled on the WithHandler path. Other non-JSObjects cannot
2925   // have own properties.
2926   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
2927 
2928   // Store on the holder which may be hidden behind the receiver.
2929   DCHECK(it->HolderIsReceiverOrHiddenPrototype());
2930 
2931   // Old value for the observation change record.
2932   // Fetch before transforming the object since the encoding may become
2933   // incompatible with what's cached in |it|.
2934   bool is_observed =
2935       receiver->map()->is_observed() &&
2936       !it->name().is_identical_to(it->factory()->hidden_string());
2937   MaybeHandle<Object> maybe_old;
2938   if (is_observed) maybe_old = it->GetDataValue();
2939 
2940   // Possibly migrate to the most up-to-date map that will be able to store
2941   // |value| under it->name().
2942   it->PrepareForDataProperty(value);
2943 
2944   // Write the property value.
2945   it->WriteDataValue(value);
2946 
2947   // Send the change record if there are observers.
2948   if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
2949     JSObject::EnqueueChangeRecord(receiver, "update", it->name(),
2950                                   maybe_old.ToHandleChecked());
2951   }
2952 
2953   return value;
2954 }
2955 
2956 
AddDataProperty(LookupIterator * it,Handle<Object> value,PropertyAttributes attributes,StrictMode strict_mode,StoreFromKeyed store_mode)2957 MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
2958                                             Handle<Object> value,
2959                                             PropertyAttributes attributes,
2960                                             StrictMode strict_mode,
2961                                             StoreFromKeyed store_mode) {
2962   DCHECK(!it->GetReceiver()->IsJSProxy());
2963   if (!it->GetReceiver()->IsJSObject()) {
2964     // TODO(verwaest): Throw a TypeError with a more specific message.
2965     return WriteToReadOnlyProperty(it, value, strict_mode);
2966   }
2967 
2968   Handle<JSObject> receiver = it->GetStoreTarget();
2969 
2970   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
2971   // instead. If the prototype is Null, the proxy is detached.
2972   if (receiver->IsJSGlobalProxy()) return value;
2973 
2974   // Possibly migrate to the most up-to-date map that will be able to store
2975   // |value| under it->name() with |attributes|.
2976   it->PrepareTransitionToDataProperty(value, attributes, store_mode);
2977   if (it->state() != LookupIterator::TRANSITION) {
2978     if (strict_mode == SLOPPY) return value;
2979 
2980     Handle<Object> args[1] = {it->name()};
2981     THROW_NEW_ERROR(it->isolate(),
2982                     NewTypeError("object_not_extensible",
2983                                  HandleVector(args, arraysize(args))),
2984                     Object);
2985   }
2986   it->ApplyTransitionToDataProperty();
2987 
2988   // TODO(verwaest): Encapsulate dictionary handling better.
2989   if (receiver->map()->is_dictionary_map()) {
2990     // TODO(verwaest): Probably should ensure this is done beforehand.
2991     it->InternalizeName();
2992     JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
2993   } else {
2994     // Write the property value.
2995     it->WriteDataValue(value);
2996   }
2997 
2998   // Send the change record if there are observers.
2999   if (receiver->map()->is_observed() &&
3000       !it->name().is_identical_to(it->factory()->hidden_string())) {
3001     JSObject::EnqueueChangeRecord(receiver, "add", it->name(),
3002                                   it->factory()->the_hole_value());
3003   }
3004 
3005   return value;
3006 }
3007 
3008 
SetElementWithCallbackSetterInPrototypes(Handle<JSObject> object,uint32_t index,Handle<Object> value,bool * found,StrictMode strict_mode)3009 MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
3010     Handle<JSObject> object,
3011     uint32_t index,
3012     Handle<Object> value,
3013     bool* found,
3014     StrictMode strict_mode) {
3015   Isolate *isolate = object->GetIsolate();
3016   for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd();
3017        iter.Advance()) {
3018     if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
3019       return JSProxy::SetPropertyViaPrototypesWithHandler(
3020           Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), object,
3021           isolate->factory()->Uint32ToString(index),  // name
3022           value, strict_mode, found);
3023     }
3024     Handle<JSObject> js_proto =
3025         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
3026     if (!js_proto->HasDictionaryElements()) {
3027       continue;
3028     }
3029     Handle<SeededNumberDictionary> dictionary(js_proto->element_dictionary());
3030     int entry = dictionary->FindEntry(index);
3031     if (entry != SeededNumberDictionary::kNotFound) {
3032       PropertyDetails details = dictionary->DetailsAt(entry);
3033       if (details.type() == CALLBACKS) {
3034         *found = true;
3035         Handle<Object> structure(dictionary->ValueAt(entry), isolate);
3036         return SetElementWithCallback(object, structure, index, value, js_proto,
3037                                       strict_mode);
3038       }
3039     }
3040   }
3041   *found = false;
3042   return isolate->factory()->the_hole_value();
3043 }
3044 
3045 
EnsureDescriptorSlack(Handle<Map> map,int slack)3046 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
3047   // Only supports adding slack to owned descriptors.
3048   DCHECK(map->owns_descriptors());
3049 
3050   Handle<DescriptorArray> descriptors(map->instance_descriptors());
3051   int old_size = map->NumberOfOwnDescriptors();
3052   if (slack <= descriptors->NumberOfSlackDescriptors()) return;
3053 
3054   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
3055       descriptors, old_size, slack);
3056 
3057   if (old_size == 0) {
3058     map->set_instance_descriptors(*new_descriptors);
3059     return;
3060   }
3061 
3062   // If the source descriptors had an enum cache we copy it. This ensures
3063   // that the maps to which we push the new descriptor array back can rely
3064   // on a cache always being available once it is set. If the map has more
3065   // enumerated descriptors than available in the original cache, the cache
3066   // will be lazily replaced by the extended cache when needed.
3067   if (descriptors->HasEnumCache()) {
3068     new_descriptors->CopyEnumCacheFrom(*descriptors);
3069   }
3070 
3071   // Replace descriptors by new_descriptors in all maps that share it.
3072   map->GetHeap()->incremental_marking()->RecordWrites(*descriptors);
3073 
3074   Map* walk_map;
3075   for (Object* current = map->GetBackPointer();
3076        !current->IsUndefined();
3077        current = walk_map->GetBackPointer()) {
3078     walk_map = Map::cast(current);
3079     if (walk_map->instance_descriptors() != *descriptors) break;
3080     walk_map->set_instance_descriptors(*new_descriptors);
3081   }
3082 
3083   map->set_instance_descriptors(*new_descriptors);
3084 }
3085 
3086 
3087 template<class T>
AppendUniqueCallbacks(NeanderArray * callbacks,Handle<typename T::Array> array,int valid_descriptors)3088 static int AppendUniqueCallbacks(NeanderArray* callbacks,
3089                                  Handle<typename T::Array> array,
3090                                  int valid_descriptors) {
3091   int nof_callbacks = callbacks->length();
3092 
3093   Isolate* isolate = array->GetIsolate();
3094   // Ensure the keys are unique names before writing them into the
3095   // instance descriptor. Since it may cause a GC, it has to be done before we
3096   // temporarily put the heap in an invalid state while appending descriptors.
3097   for (int i = 0; i < nof_callbacks; ++i) {
3098     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3099     if (entry->name()->IsUniqueName()) continue;
3100     Handle<String> key =
3101         isolate->factory()->InternalizeString(
3102             Handle<String>(String::cast(entry->name())));
3103     entry->set_name(*key);
3104   }
3105 
3106   // Fill in new callback descriptors.  Process the callbacks from
3107   // back to front so that the last callback with a given name takes
3108   // precedence over previously added callbacks with that name.
3109   for (int i = nof_callbacks - 1; i >= 0; i--) {
3110     Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3111     Handle<Name> key(Name::cast(entry->name()));
3112     // Check if a descriptor with this name already exists before writing.
3113     if (!T::Contains(key, entry, valid_descriptors, array)) {
3114       T::Insert(key, entry, valid_descriptors, array);
3115       valid_descriptors++;
3116     }
3117   }
3118 
3119   return valid_descriptors;
3120 }
3121 
3122 struct DescriptorArrayAppender {
3123   typedef DescriptorArray Array;
Containsv8::internal::DescriptorArrayAppender3124   static bool Contains(Handle<Name> key,
3125                        Handle<AccessorInfo> entry,
3126                        int valid_descriptors,
3127                        Handle<DescriptorArray> array) {
3128     DisallowHeapAllocation no_gc;
3129     return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
3130   }
Insertv8::internal::DescriptorArrayAppender3131   static void Insert(Handle<Name> key,
3132                      Handle<AccessorInfo> entry,
3133                      int valid_descriptors,
3134                      Handle<DescriptorArray> array) {
3135     DisallowHeapAllocation no_gc;
3136     CallbacksDescriptor desc(key, entry, entry->property_attributes());
3137     array->Append(&desc);
3138   }
3139 };
3140 
3141 
3142 struct FixedArrayAppender {
3143   typedef FixedArray Array;
Containsv8::internal::FixedArrayAppender3144   static bool Contains(Handle<Name> key,
3145                        Handle<AccessorInfo> entry,
3146                        int valid_descriptors,
3147                        Handle<FixedArray> array) {
3148     for (int i = 0; i < valid_descriptors; i++) {
3149       if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
3150     }
3151     return false;
3152   }
Insertv8::internal::FixedArrayAppender3153   static void Insert(Handle<Name> key,
3154                      Handle<AccessorInfo> entry,
3155                      int valid_descriptors,
3156                      Handle<FixedArray> array) {
3157     DisallowHeapAllocation no_gc;
3158     array->set(valid_descriptors, *entry);
3159   }
3160 };
3161 
3162 
AppendCallbackDescriptors(Handle<Map> map,Handle<Object> descriptors)3163 void Map::AppendCallbackDescriptors(Handle<Map> map,
3164                                     Handle<Object> descriptors) {
3165   int nof = map->NumberOfOwnDescriptors();
3166   Handle<DescriptorArray> array(map->instance_descriptors());
3167   NeanderArray callbacks(descriptors);
3168   DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length());
3169   nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
3170   map->SetNumberOfOwnDescriptors(nof);
3171 }
3172 
3173 
AppendUnique(Handle<Object> descriptors,Handle<FixedArray> array,int valid_descriptors)3174 int AccessorInfo::AppendUnique(Handle<Object> descriptors,
3175                                Handle<FixedArray> array,
3176                                int valid_descriptors) {
3177   NeanderArray callbacks(descriptors);
3178   DCHECK(array->length() >= callbacks.length() + valid_descriptors);
3179   return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
3180                                                    array,
3181                                                    valid_descriptors);
3182 }
3183 
3184 
ContainsMap(MapHandleList * maps,Handle<Map> map)3185 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
3186   DCHECK(!map.is_null());
3187   for (int i = 0; i < maps->length(); ++i) {
3188     if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
3189   }
3190   return false;
3191 }
3192 
3193 
3194 template <class T>
MaybeNull(T * p)3195 static Handle<T> MaybeNull(T* p) {
3196   if (p == NULL) return Handle<T>::null();
3197   return Handle<T>(p);
3198 }
3199 
3200 
FindTransitionedMap(MapHandleList * candidates)3201 Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
3202   ElementsKind kind = elements_kind();
3203   Handle<Map> transitioned_map = Handle<Map>::null();
3204   Handle<Map> current_map(this);
3205   bool packed = IsFastPackedElementsKind(kind);
3206   if (IsTransitionableFastElementsKind(kind)) {
3207     while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
3208       kind = GetNextMoreGeneralFastElementsKind(kind, false);
3209       Handle<Map> maybe_transitioned_map =
3210           MaybeNull(current_map->LookupElementsTransitionMap(kind));
3211       if (maybe_transitioned_map.is_null()) break;
3212       if (ContainsMap(candidates, maybe_transitioned_map) &&
3213           (packed || !IsFastPackedElementsKind(kind))) {
3214         transitioned_map = maybe_transitioned_map;
3215         if (!IsFastPackedElementsKind(kind)) packed = false;
3216       }
3217       current_map = maybe_transitioned_map;
3218     }
3219   }
3220   return transitioned_map;
3221 }
3222 
3223 
FindClosestElementsTransition(Map * map,ElementsKind to_kind)3224 static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
3225   Map* current_map = map;
3226   int target_kind =
3227       IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind)
3228       ? to_kind
3229       : TERMINAL_FAST_ELEMENTS_KIND;
3230 
3231   // Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data
3232   // allows to change elements from arbitrary kind to any ExternalArray
3233   // elements kind. Satisfy its requirements, checking whether we already
3234   // have the cached transition.
3235   if (IsExternalArrayElementsKind(to_kind) &&
3236       !IsFixedTypedArrayElementsKind(map->elements_kind())) {
3237     if (map->HasElementsTransition()) {
3238         Map* next_map = map->elements_transition_map();
3239         if (next_map->elements_kind() == to_kind) return next_map;
3240     }
3241     return map;
3242   }
3243 
3244   ElementsKind kind = map->elements_kind();
3245   while (kind != target_kind) {
3246     kind = GetNextTransitionElementsKind(kind);
3247     if (!current_map->HasElementsTransition()) return current_map;
3248     current_map = current_map->elements_transition_map();
3249   }
3250 
3251   if (to_kind != kind && current_map->HasElementsTransition()) {
3252     DCHECK(to_kind == DICTIONARY_ELEMENTS);
3253     Map* next_map = current_map->elements_transition_map();
3254     if (next_map->elements_kind() == to_kind) return next_map;
3255   }
3256 
3257   DCHECK(current_map->elements_kind() == target_kind);
3258   return current_map;
3259 }
3260 
3261 
LookupElementsTransitionMap(ElementsKind to_kind)3262 Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
3263   Map* to_map = FindClosestElementsTransition(this, to_kind);
3264   if (to_map->elements_kind() == to_kind) return to_map;
3265   return NULL;
3266 }
3267 
3268 
IsMapInArrayPrototypeChain()3269 bool Map::IsMapInArrayPrototypeChain() {
3270   Isolate* isolate = GetIsolate();
3271   if (isolate->initial_array_prototype()->map() == this) {
3272     return true;
3273   }
3274 
3275   if (isolate->initial_object_prototype()->map() == this) {
3276     return true;
3277   }
3278 
3279   return false;
3280 }
3281 
3282 
AddMissingElementsTransitions(Handle<Map> map,ElementsKind to_kind)3283 static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
3284                                                  ElementsKind to_kind) {
3285   DCHECK(IsTransitionElementsKind(map->elements_kind()));
3286 
3287   Handle<Map> current_map = map;
3288 
3289   ElementsKind kind = map->elements_kind();
3290   if (!map->is_prototype_map()) {
3291     while (kind != to_kind && !IsTerminalElementsKind(kind)) {
3292       kind = GetNextTransitionElementsKind(kind);
3293       current_map =
3294           Map::CopyAsElementsKind(current_map, kind, INSERT_TRANSITION);
3295     }
3296   }
3297 
3298   // In case we are exiting the fast elements kind system, just add the map in
3299   // the end.
3300   if (kind != to_kind) {
3301     current_map = Map::CopyAsElementsKind(
3302         current_map, to_kind, INSERT_TRANSITION);
3303   }
3304 
3305   DCHECK(current_map->elements_kind() == to_kind);
3306   return current_map;
3307 }
3308 
3309 
TransitionElementsTo(Handle<Map> map,ElementsKind to_kind)3310 Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
3311                                       ElementsKind to_kind) {
3312   ElementsKind from_kind = map->elements_kind();
3313   if (from_kind == to_kind) return map;
3314 
3315   Isolate* isolate = map->GetIsolate();
3316   Context* native_context = isolate->context()->native_context();
3317   Object* maybe_array_maps = native_context->js_array_maps();
3318   if (maybe_array_maps->IsFixedArray()) {
3319     DisallowHeapAllocation no_gc;
3320     FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
3321     if (array_maps->get(from_kind) == *map) {
3322       Object* maybe_transitioned_map = array_maps->get(to_kind);
3323       if (maybe_transitioned_map->IsMap()) {
3324         return handle(Map::cast(maybe_transitioned_map));
3325       }
3326     }
3327   }
3328 
3329   return TransitionElementsToSlow(map, to_kind);
3330 }
3331 
3332 
TransitionElementsToSlow(Handle<Map> map,ElementsKind to_kind)3333 Handle<Map> Map::TransitionElementsToSlow(Handle<Map> map,
3334                                           ElementsKind to_kind) {
3335   ElementsKind from_kind = map->elements_kind();
3336 
3337   if (from_kind == to_kind) {
3338     return map;
3339   }
3340 
3341   bool allow_store_transition =
3342       // Only remember the map transition if there is not an already existing
3343       // non-matching element transition.
3344       !map->IsUndefined() && !map->is_dictionary_map() &&
3345       IsTransitionElementsKind(from_kind);
3346 
3347   // Only store fast element maps in ascending generality.
3348   if (IsFastElementsKind(to_kind)) {
3349     allow_store_transition &=
3350         IsTransitionableFastElementsKind(from_kind) &&
3351         IsMoreGeneralElementsKindTransition(from_kind, to_kind);
3352   }
3353 
3354   if (!allow_store_transition) {
3355     return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
3356   }
3357 
3358   return Map::AsElementsKind(map, to_kind);
3359 }
3360 
3361 
3362 // static
AsElementsKind(Handle<Map> map,ElementsKind kind)3363 Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
3364   Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
3365 
3366   if (closest_map->elements_kind() == kind) {
3367     return closest_map;
3368   }
3369 
3370   return AddMissingElementsTransitions(closest_map, kind);
3371 }
3372 
3373 
GetElementsTransitionMap(Handle<JSObject> object,ElementsKind to_kind)3374 Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3375                                                ElementsKind to_kind) {
3376   Handle<Map> map(object->map());
3377   return Map::TransitionElementsTo(map, to_kind);
3378 }
3379 
3380 
HasPropertyWithHandler(Handle<JSProxy> proxy,Handle<Name> name)3381 Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
3382                                             Handle<Name> name) {
3383   Isolate* isolate = proxy->GetIsolate();
3384 
3385   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3386   if (name->IsSymbol()) return maybe(false);
3387 
3388   Handle<Object> args[] = { name };
3389   Handle<Object> result;
3390   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3391       isolate, result, CallTrap(proxy, "has", isolate->derived_has_trap(),
3392                                 arraysize(args), args),
3393       Maybe<bool>());
3394 
3395   return maybe(result->BooleanValue());
3396 }
3397 
3398 
SetPropertyWithHandler(Handle<JSProxy> proxy,Handle<Object> receiver,Handle<Name> name,Handle<Object> value,StrictMode strict_mode)3399 MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
3400                                                     Handle<Object> receiver,
3401                                                     Handle<Name> name,
3402                                                     Handle<Object> value,
3403                                                     StrictMode strict_mode) {
3404   Isolate* isolate = proxy->GetIsolate();
3405 
3406   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3407   if (name->IsSymbol()) return value;
3408 
3409   Handle<Object> args[] = { receiver, name, value };
3410   RETURN_ON_EXCEPTION(
3411       isolate,
3412       CallTrap(proxy,
3413                "set",
3414                isolate->derived_set_trap(),
3415                arraysize(args),
3416                args),
3417       Object);
3418 
3419   return value;
3420 }
3421 
3422 
SetPropertyViaPrototypesWithHandler(Handle<JSProxy> proxy,Handle<Object> receiver,Handle<Name> name,Handle<Object> value,StrictMode strict_mode,bool * done)3423 MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
3424     Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
3425     Handle<Object> value, StrictMode strict_mode, bool* done) {
3426   Isolate* isolate = proxy->GetIsolate();
3427   Handle<Object> handler(proxy->handler(), isolate);  // Trap might morph proxy.
3428 
3429   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3430   if (name->IsSymbol()) {
3431     *done = false;
3432     return isolate->factory()->the_hole_value();
3433   }
3434 
3435   *done = true;  // except where redefined...
3436   Handle<Object> args[] = { name };
3437   Handle<Object> result;
3438   ASSIGN_RETURN_ON_EXCEPTION(
3439       isolate, result,
3440       CallTrap(proxy,
3441                "getPropertyDescriptor",
3442                Handle<Object>(),
3443                arraysize(args),
3444                args),
3445       Object);
3446 
3447   if (result->IsUndefined()) {
3448     *done = false;
3449     return isolate->factory()->the_hole_value();
3450   }
3451 
3452   // Emulate [[GetProperty]] semantics for proxies.
3453   Handle<Object> argv[] = { result };
3454   Handle<Object> desc;
3455   ASSIGN_RETURN_ON_EXCEPTION(
3456       isolate, desc,
3457       Execution::Call(isolate,
3458                       isolate->to_complete_property_descriptor(),
3459                       result,
3460                       arraysize(argv),
3461                       argv),
3462       Object);
3463 
3464   // [[GetProperty]] requires to check that all properties are configurable.
3465   Handle<String> configurable_name =
3466       isolate->factory()->InternalizeOneByteString(
3467           STATIC_CHAR_VECTOR("configurable_"));
3468   Handle<Object> configurable =
3469       Object::GetProperty(desc, configurable_name).ToHandleChecked();
3470   DCHECK(configurable->IsBoolean());
3471   if (configurable->IsFalse()) {
3472     Handle<String> trap = isolate->factory()->InternalizeOneByteString(
3473         STATIC_CHAR_VECTOR("getPropertyDescriptor"));
3474     Handle<Object> args[] = { handler, trap, name };
3475     THROW_NEW_ERROR(isolate, NewTypeError("proxy_prop_not_configurable",
3476                                           HandleVector(args, arraysize(args))),
3477                     Object);
3478   }
3479   DCHECK(configurable->IsTrue());
3480 
3481   // Check for DataDescriptor.
3482   Handle<String> hasWritable_name =
3483       isolate->factory()->InternalizeOneByteString(
3484           STATIC_CHAR_VECTOR("hasWritable_"));
3485   Handle<Object> hasWritable =
3486       Object::GetProperty(desc, hasWritable_name).ToHandleChecked();
3487   DCHECK(hasWritable->IsBoolean());
3488   if (hasWritable->IsTrue()) {
3489     Handle<String> writable_name = isolate->factory()->InternalizeOneByteString(
3490         STATIC_CHAR_VECTOR("writable_"));
3491     Handle<Object> writable =
3492         Object::GetProperty(desc, writable_name).ToHandleChecked();
3493     DCHECK(writable->IsBoolean());
3494     *done = writable->IsFalse();
3495     if (!*done) return isolate->factory()->the_hole_value();
3496     if (strict_mode == SLOPPY) return value;
3497     Handle<Object> args[] = { name, receiver };
3498     THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
3499                                           HandleVector(args, arraysize(args))),
3500                     Object);
3501   }
3502 
3503   // We have an AccessorDescriptor.
3504   Handle<String> set_name =
3505       isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("set_"));
3506   Handle<Object> setter = Object::GetProperty(desc, set_name).ToHandleChecked();
3507   if (!setter->IsUndefined()) {
3508     // TODO(rossberg): nicer would be to cast to some JSCallable here...
3509     return SetPropertyWithDefinedSetter(
3510         receiver, Handle<JSReceiver>::cast(setter), value);
3511   }
3512 
3513   if (strict_mode == SLOPPY) return value;
3514   Handle<Object> args2[] = { name, proxy };
3515   THROW_NEW_ERROR(isolate, NewTypeError("no_setter_in_callback",
3516                                         HandleVector(args2, arraysize(args2))),
3517                   Object);
3518 }
3519 
3520 
DeletePropertyWithHandler(Handle<JSProxy> proxy,Handle<Name> name,DeleteMode mode)3521 MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
3522     Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
3523   Isolate* isolate = proxy->GetIsolate();
3524 
3525   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3526   if (name->IsSymbol()) return isolate->factory()->false_value();
3527 
3528   Handle<Object> args[] = { name };
3529   Handle<Object> result;
3530   ASSIGN_RETURN_ON_EXCEPTION(
3531       isolate, result,
3532       CallTrap(proxy,
3533                "delete",
3534                Handle<Object>(),
3535                arraysize(args),
3536                args),
3537       Object);
3538 
3539   bool result_bool = result->BooleanValue();
3540   if (mode == STRICT_DELETION && !result_bool) {
3541     Handle<Object> handler(proxy->handler(), isolate);
3542     Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
3543         STATIC_CHAR_VECTOR("delete"));
3544     Handle<Object> args[] = { handler, trap_name };
3545     THROW_NEW_ERROR(isolate, NewTypeError("handler_failed",
3546                                           HandleVector(args, arraysize(args))),
3547                     Object);
3548   }
3549   return isolate->factory()->ToBoolean(result_bool);
3550 }
3551 
3552 
DeleteElementWithHandler(Handle<JSProxy> proxy,uint32_t index,DeleteMode mode)3553 MaybeHandle<Object> JSProxy::DeleteElementWithHandler(
3554     Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
3555   Isolate* isolate = proxy->GetIsolate();
3556   Handle<String> name = isolate->factory()->Uint32ToString(index);
3557   return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
3558 }
3559 
3560 
GetPropertyAttributesWithHandler(Handle<JSProxy> proxy,Handle<Object> receiver,Handle<Name> name)3561 Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
3562     Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name) {
3563   Isolate* isolate = proxy->GetIsolate();
3564   HandleScope scope(isolate);
3565 
3566   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3567   if (name->IsSymbol()) return maybe(ABSENT);
3568 
3569   Handle<Object> args[] = { name };
3570   Handle<Object> result;
3571   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3572       isolate, result,
3573       proxy->CallTrap(proxy, "getPropertyDescriptor", Handle<Object>(),
3574                       arraysize(args), args),
3575       Maybe<PropertyAttributes>());
3576 
3577   if (result->IsUndefined()) return maybe(ABSENT);
3578 
3579   Handle<Object> argv[] = { result };
3580   Handle<Object> desc;
3581   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3582       isolate, desc,
3583       Execution::Call(isolate, isolate->to_complete_property_descriptor(),
3584                       result, arraysize(argv), argv),
3585       Maybe<PropertyAttributes>());
3586 
3587   // Convert result to PropertyAttributes.
3588   Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
3589       STATIC_CHAR_VECTOR("enumerable_"));
3590   Handle<Object> enumerable;
3591   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, enumerable,
3592                                    Object::GetProperty(desc, enum_n),
3593                                    Maybe<PropertyAttributes>());
3594   Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
3595       STATIC_CHAR_VECTOR("configurable_"));
3596   Handle<Object> configurable;
3597   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, configurable,
3598                                    Object::GetProperty(desc, conf_n),
3599                                    Maybe<PropertyAttributes>());
3600   Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
3601       STATIC_CHAR_VECTOR("writable_"));
3602   Handle<Object> writable;
3603   ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, writable,
3604                                    Object::GetProperty(desc, writ_n),
3605                                    Maybe<PropertyAttributes>());
3606   if (!writable->BooleanValue()) {
3607     Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
3608         STATIC_CHAR_VECTOR("set_"));
3609     Handle<Object> setter;
3610     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, setter,
3611                                      Object::GetProperty(desc, set_n),
3612                                      Maybe<PropertyAttributes>());
3613     writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
3614   }
3615 
3616   if (configurable->IsFalse()) {
3617     Handle<Object> handler(proxy->handler(), isolate);
3618     Handle<String> trap = isolate->factory()->InternalizeOneByteString(
3619         STATIC_CHAR_VECTOR("getPropertyDescriptor"));
3620     Handle<Object> args[] = { handler, trap, name };
3621     Handle<Object> error;
3622     MaybeHandle<Object> maybe_error = isolate->factory()->NewTypeError(
3623         "proxy_prop_not_configurable", HandleVector(args, arraysize(args)));
3624     if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
3625     return maybe(NONE);
3626   }
3627 
3628   int attributes = NONE;
3629   if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
3630   if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
3631   if (!writable->BooleanValue()) attributes |= READ_ONLY;
3632   return maybe(static_cast<PropertyAttributes>(attributes));
3633 }
3634 
3635 
GetElementAttributeWithHandler(Handle<JSProxy> proxy,Handle<JSReceiver> receiver,uint32_t index)3636 Maybe<PropertyAttributes> JSProxy::GetElementAttributeWithHandler(
3637     Handle<JSProxy> proxy, Handle<JSReceiver> receiver, uint32_t index) {
3638   Isolate* isolate = proxy->GetIsolate();
3639   Handle<String> name = isolate->factory()->Uint32ToString(index);
3640   return GetPropertyAttributesWithHandler(proxy, receiver, name);
3641 }
3642 
3643 
Fix(Handle<JSProxy> proxy)3644 void JSProxy::Fix(Handle<JSProxy> proxy) {
3645   Isolate* isolate = proxy->GetIsolate();
3646 
3647   // Save identity hash.
3648   Handle<Object> hash(proxy->GetIdentityHash(), isolate);
3649 
3650   if (proxy->IsJSFunctionProxy()) {
3651     isolate->factory()->BecomeJSFunction(proxy);
3652     // Code will be set on the JavaScript side.
3653   } else {
3654     isolate->factory()->BecomeJSObject(proxy);
3655   }
3656   DCHECK(proxy->IsJSObject());
3657 
3658   // Inherit identity, if it was present.
3659   if (hash->IsSmi()) {
3660     JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy),
3661                               Handle<Smi>::cast(hash));
3662   }
3663 }
3664 
3665 
CallTrap(Handle<JSProxy> proxy,const char * name,Handle<Object> derived,int argc,Handle<Object> argv[])3666 MaybeHandle<Object> JSProxy::CallTrap(Handle<JSProxy> proxy,
3667                                       const char* name,
3668                                       Handle<Object> derived,
3669                                       int argc,
3670                                       Handle<Object> argv[]) {
3671   Isolate* isolate = proxy->GetIsolate();
3672   Handle<Object> handler(proxy->handler(), isolate);
3673 
3674   Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
3675   Handle<Object> trap;
3676   ASSIGN_RETURN_ON_EXCEPTION(
3677       isolate, trap,
3678       Object::GetPropertyOrElement(handler, trap_name),
3679       Object);
3680 
3681   if (trap->IsUndefined()) {
3682     if (derived.is_null()) {
3683       Handle<Object> args[] = { handler, trap_name };
3684       THROW_NEW_ERROR(isolate,
3685                       NewTypeError("handler_trap_missing",
3686                                    HandleVector(args, arraysize(args))),
3687                       Object);
3688     }
3689     trap = Handle<Object>(derived);
3690   }
3691 
3692   return Execution::Call(isolate, trap, handler, argc, argv);
3693 }
3694 
3695 
AllocateStorageForMap(Handle<JSObject> object,Handle<Map> map)3696 void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
3697   DCHECK(object->map()->inobject_properties() == map->inobject_properties());
3698   ElementsKind obj_kind = object->map()->elements_kind();
3699   ElementsKind map_kind = map->elements_kind();
3700   if (map_kind != obj_kind) {
3701     ElementsKind to_kind = map_kind;
3702     if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) ||
3703         IsDictionaryElementsKind(obj_kind)) {
3704       to_kind = obj_kind;
3705     }
3706     if (IsDictionaryElementsKind(to_kind)) {
3707       NormalizeElements(object);
3708     } else {
3709       TransitionElementsKind(object, to_kind);
3710     }
3711     map = Map::AsElementsKind(map, to_kind);
3712   }
3713   JSObject::MigrateToMap(object, map);
3714 }
3715 
3716 
MigrateInstance(Handle<JSObject> object)3717 void JSObject::MigrateInstance(Handle<JSObject> object) {
3718   Handle<Map> original_map(object->map());
3719   Handle<Map> map = Map::Update(original_map);
3720   map->set_migration_target(true);
3721   MigrateToMap(object, map);
3722   if (FLAG_trace_migration) {
3723     object->PrintInstanceMigration(stdout, *original_map, *map);
3724   }
3725 }
3726 
3727 
3728 // static
TryMigrateInstance(Handle<JSObject> object)3729 bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
3730   Isolate* isolate = object->GetIsolate();
3731   DisallowDeoptimization no_deoptimization(isolate);
3732   Handle<Map> original_map(object->map(), isolate);
3733   Handle<Map> new_map;
3734   if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
3735     return false;
3736   }
3737   JSObject::MigrateToMap(object, new_map);
3738   if (FLAG_trace_migration) {
3739     object->PrintInstanceMigration(stdout, *original_map, object->map());
3740   }
3741   return true;
3742 }
3743 
3744 
MigrateToNewProperty(Handle<JSObject> object,Handle<Map> map,Handle<Object> value)3745 void JSObject::MigrateToNewProperty(Handle<JSObject> object,
3746                                     Handle<Map> map,
3747                                     Handle<Object> value) {
3748   JSObject::MigrateToMap(object, map);
3749   if (map->GetLastDescriptorDetails().type() != FIELD) return;
3750   object->WriteToField(map->LastAdded(), *value);
3751 }
3752 
3753 
WriteToField(int descriptor,Object * value)3754 void JSObject::WriteToField(int descriptor, Object* value) {
3755   DisallowHeapAllocation no_gc;
3756 
3757   DescriptorArray* desc = map()->instance_descriptors();
3758   PropertyDetails details = desc->GetDetails(descriptor);
3759 
3760   DCHECK(details.type() == FIELD);
3761 
3762   FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
3763   if (details.representation().IsDouble()) {
3764     // Nothing more to be done.
3765     if (value->IsUninitialized()) return;
3766     HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
3767     DCHECK(box->IsMutableHeapNumber());
3768     box->set_value(value->Number());
3769   } else {
3770     FastPropertyAtPut(index, value);
3771   }
3772 }
3773 
3774 
AddProperty(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)3775 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
3776                            Handle<Object> value,
3777                            PropertyAttributes attributes) {
3778   LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
3779   CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
3780 #ifdef DEBUG
3781   uint32_t index;
3782   DCHECK(!object->IsJSProxy());
3783   DCHECK(!name->AsArrayIndex(&index));
3784   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
3785   DCHECK(maybe.has_value);
3786   DCHECK(!it.IsFound());
3787   DCHECK(object->map()->is_extensible() ||
3788          name.is_identical_to(it.isolate()->factory()->hidden_string()));
3789 #endif
3790   AddDataProperty(&it, value, attributes, STRICT,
3791                   CERTAINLY_NOT_STORE_FROM_KEYED).Check();
3792 }
3793 
3794 
3795 // Reconfigures a property to a data property with attributes, even if it is not
3796 // reconfigurable.
SetOwnPropertyIgnoreAttributes(Handle<JSObject> object,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,ExecutableAccessorInfoHandling handling)3797 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
3798     Handle<JSObject> object,
3799     Handle<Name> name,
3800     Handle<Object> value,
3801     PropertyAttributes attributes,
3802     ExecutableAccessorInfoHandling handling) {
3803   DCHECK(!value->IsTheHole());
3804   LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
3805   bool is_observed = object->map()->is_observed() &&
3806                      *name != it.isolate()->heap()->hidden_string();
3807   for (; it.IsFound(); it.Next()) {
3808     switch (it.state()) {
3809       case LookupIterator::INTERCEPTOR:
3810       case LookupIterator::JSPROXY:
3811       case LookupIterator::NOT_FOUND:
3812       case LookupIterator::TRANSITION:
3813         UNREACHABLE();
3814 
3815       case LookupIterator::ACCESS_CHECK:
3816         if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) {
3817           return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
3818         }
3819         break;
3820 
3821       case LookupIterator::ACCESSOR: {
3822         PropertyDetails details = it.property_details();
3823         Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
3824         // Ensure the context isn't changed after calling into accessors.
3825         AssertNoContextChange ncc(it.isolate());
3826 
3827         Handle<Object> accessors = it.GetAccessors();
3828 
3829         if (is_observed && accessors->IsAccessorInfo()) {
3830           ASSIGN_RETURN_ON_EXCEPTION(
3831               it.isolate(), old_value,
3832               GetPropertyWithAccessor(it.GetReceiver(), it.name(),
3833                                       it.GetHolder<JSObject>(), accessors),
3834               Object);
3835         }
3836 
3837         // Special handling for ExecutableAccessorInfo, which behaves like a
3838         // data property.
3839         if (handling == DONT_FORCE_FIELD &&
3840             accessors->IsExecutableAccessorInfo()) {
3841           Handle<Object> result;
3842           ASSIGN_RETURN_ON_EXCEPTION(
3843               it.isolate(), result,
3844               JSObject::SetPropertyWithAccessor(it.GetReceiver(), it.name(),
3845                                                 value, it.GetHolder<JSObject>(),
3846                                                 accessors, STRICT),
3847               Object);
3848           DCHECK(result->SameValue(*value));
3849 
3850           if (details.attributes() == attributes) {
3851             // Regular property update if the attributes match.
3852             if (is_observed && !old_value->SameValue(*value)) {
3853               // If we are setting the prototype of a function and are
3854               // observed, don't send change records because the prototype
3855               // handles that itself.
3856               if (!object->IsJSFunction() ||
3857                   !Name::Equals(it.isolate()->factory()->prototype_string(),
3858                                 name) ||
3859                   !Handle<JSFunction>::cast(object)->should_have_prototype()) {
3860                 EnqueueChangeRecord(object, "update", name, old_value);
3861               }
3862             }
3863             return value;
3864           }
3865 
3866           // Reconfigure the accessor if attributes mismatch.
3867           Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor(
3868               it.isolate(), Handle<ExecutableAccessorInfo>::cast(accessors));
3869           new_data->set_property_attributes(attributes);
3870           // By clearing the setter we don't have to introduce a lookup to
3871           // the setter, simply make it unavailable to reflect the
3872           // attributes.
3873           if (attributes & READ_ONLY) new_data->clear_setter();
3874           SetPropertyCallback(object, name, new_data, attributes);
3875           if (is_observed) {
3876             if (old_value->SameValue(*value)) {
3877               old_value = it.isolate()->factory()->the_hole_value();
3878             }
3879             EnqueueChangeRecord(object, "reconfigure", name, old_value);
3880           }
3881           return value;
3882         }
3883 
3884         it.ReconfigureDataProperty(value, attributes);
3885         it.PrepareForDataProperty(value);
3886         it.WriteDataValue(value);
3887 
3888         if (is_observed) {
3889           if (old_value->SameValue(*value)) {
3890             old_value = it.isolate()->factory()->the_hole_value();
3891           }
3892           EnqueueChangeRecord(object, "reconfigure", name, old_value);
3893         }
3894 
3895         return value;
3896       }
3897 
3898       case LookupIterator::DATA: {
3899         PropertyDetails details = it.property_details();
3900         Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
3901         // Regular property update if the attributes match.
3902         if (details.attributes() == attributes) {
3903           return SetDataProperty(&it, value);
3904         }
3905         // Reconfigure the data property if the attributes mismatch.
3906         if (is_observed) old_value = it.GetDataValue();
3907 
3908         it.ReconfigureDataProperty(value, attributes);
3909         it.PrepareForDataProperty(value);
3910         it.WriteDataValue(value);
3911 
3912         if (is_observed) {
3913           if (old_value->SameValue(*value)) {
3914             old_value = it.isolate()->factory()->the_hole_value();
3915           }
3916           EnqueueChangeRecord(object, "reconfigure", name, old_value);
3917         }
3918 
3919         return value;
3920       }
3921     }
3922   }
3923 
3924   return AddDataProperty(&it, value, attributes, STRICT,
3925                          CERTAINLY_NOT_STORE_FROM_KEYED);
3926 }
3927 
3928 
GetPropertyAttributesWithInterceptor(Handle<JSObject> holder,Handle<Object> receiver,Handle<Name> name)3929 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
3930     Handle<JSObject> holder,
3931     Handle<Object> receiver,
3932     Handle<Name> name) {
3933   // TODO(rossberg): Support symbols in the API.
3934   if (name->IsSymbol()) return maybe(ABSENT);
3935 
3936   Isolate* isolate = holder->GetIsolate();
3937   HandleScope scope(isolate);
3938 
3939   // Make sure that the top context does not change when doing
3940   // callbacks or interceptor calls.
3941   AssertNoContextChange ncc(isolate);
3942 
3943   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
3944   PropertyCallbackArguments args(
3945       isolate, interceptor->data(), *receiver, *holder);
3946   if (!interceptor->query()->IsUndefined()) {
3947     v8::NamedPropertyQueryCallback query =
3948         v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query());
3949     LOG(isolate,
3950         ApiNamedPropertyAccess("interceptor-named-has", *holder, *name));
3951     v8::Handle<v8::Integer> result =
3952         args.Call(query, v8::Utils::ToLocal(Handle<String>::cast(name)));
3953     if (!result.IsEmpty()) {
3954       DCHECK(result->IsInt32());
3955       return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
3956     }
3957   } else if (!interceptor->getter()->IsUndefined()) {
3958     v8::NamedPropertyGetterCallback getter =
3959         v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
3960     LOG(isolate,
3961         ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
3962     v8::Handle<v8::Value> result =
3963         args.Call(getter, v8::Utils::ToLocal(Handle<String>::cast(name)));
3964     if (!result.IsEmpty()) return maybe(DONT_ENUM);
3965   }
3966 
3967   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
3968   return maybe(ABSENT);
3969 }
3970 
3971 
GetOwnPropertyAttributes(Handle<JSReceiver> object,Handle<Name> name)3972 Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
3973     Handle<JSReceiver> object, Handle<Name> name) {
3974   // Check whether the name is an array index.
3975   uint32_t index = 0;
3976   if (object->IsJSObject() && name->AsArrayIndex(&index)) {
3977     return GetOwnElementAttribute(object, index);
3978   }
3979   LookupIterator it(object, name, LookupIterator::HIDDEN);
3980   return GetPropertyAttributes(&it);
3981 }
3982 
3983 
GetPropertyAttributes(LookupIterator * it)3984 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
3985     LookupIterator* it) {
3986   for (; it->IsFound(); it->Next()) {
3987     switch (it->state()) {
3988       case LookupIterator::NOT_FOUND:
3989       case LookupIterator::TRANSITION:
3990         UNREACHABLE();
3991       case LookupIterator::JSPROXY:
3992         return JSProxy::GetPropertyAttributesWithHandler(
3993             it->GetHolder<JSProxy>(), it->GetReceiver(), it->name());
3994       case LookupIterator::INTERCEPTOR: {
3995         Maybe<PropertyAttributes> result =
3996             JSObject::GetPropertyAttributesWithInterceptor(
3997                 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
3998         if (!result.has_value) return result;
3999         if (result.value != ABSENT) return result;
4000         break;
4001       }
4002       case LookupIterator::ACCESS_CHECK:
4003         if (it->HasAccess(v8::ACCESS_HAS)) break;
4004         return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
4005       case LookupIterator::ACCESSOR:
4006       case LookupIterator::DATA:
4007         return maybe(it->property_details().attributes());
4008     }
4009   }
4010   return maybe(ABSENT);
4011 }
4012 
4013 
GetElementAttributeWithReceiver(Handle<JSObject> object,Handle<JSReceiver> receiver,uint32_t index,bool check_prototype)4014 Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver(
4015     Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4016     bool check_prototype) {
4017   Isolate* isolate = object->GetIsolate();
4018 
4019   // Check access rights if needed.
4020   if (object->IsAccessCheckNeeded()) {
4021     if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
4022       isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
4023       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
4024       return maybe(ABSENT);
4025     }
4026   }
4027 
4028   if (object->IsJSGlobalProxy()) {
4029     PrototypeIterator iter(isolate, object);
4030     if (iter.IsAtEnd()) return maybe(ABSENT);
4031     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4032     return JSObject::GetElementAttributeWithReceiver(
4033         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4034         index, check_prototype);
4035   }
4036 
4037   // Check for lookup interceptor except when bootstrapping.
4038   if (object->HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) {
4039     return JSObject::GetElementAttributeWithInterceptor(
4040         object, receiver, index, check_prototype);
4041   }
4042 
4043   return GetElementAttributeWithoutInterceptor(
4044       object, receiver, index, check_prototype);
4045 }
4046 
4047 
GetElementAttributeWithInterceptor(Handle<JSObject> object,Handle<JSReceiver> receiver,uint32_t index,bool check_prototype)4048 Maybe<PropertyAttributes> JSObject::GetElementAttributeWithInterceptor(
4049     Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4050     bool check_prototype) {
4051   Isolate* isolate = object->GetIsolate();
4052   HandleScope scope(isolate);
4053 
4054   // Make sure that the top context does not change when doing
4055   // callbacks or interceptor calls.
4056   AssertNoContextChange ncc(isolate);
4057 
4058   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
4059   PropertyCallbackArguments args(
4060       isolate, interceptor->data(), *receiver, *object);
4061   if (!interceptor->query()->IsUndefined()) {
4062     v8::IndexedPropertyQueryCallback query =
4063         v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
4064     LOG(isolate,
4065         ApiIndexedPropertyAccess("interceptor-indexed-has", *object, index));
4066     v8::Handle<v8::Integer> result = args.Call(query, index);
4067     if (!result.IsEmpty())
4068       return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
4069   } else if (!interceptor->getter()->IsUndefined()) {
4070     v8::IndexedPropertyGetterCallback getter =
4071         v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
4072     LOG(isolate,
4073         ApiIndexedPropertyAccess(
4074             "interceptor-indexed-get-has", *object, index));
4075     v8::Handle<v8::Value> result = args.Call(getter, index);
4076     if (!result.IsEmpty()) return maybe(NONE);
4077   }
4078 
4079   return GetElementAttributeWithoutInterceptor(
4080        object, receiver, index, check_prototype);
4081 }
4082 
4083 
GetElementAttributeWithoutInterceptor(Handle<JSObject> object,Handle<JSReceiver> receiver,uint32_t index,bool check_prototype)4084 Maybe<PropertyAttributes> JSObject::GetElementAttributeWithoutInterceptor(
4085     Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4086     bool check_prototype) {
4087   PropertyAttributes attr = object->GetElementsAccessor()->GetAttributes(
4088       receiver, object, index);
4089   if (attr != ABSENT) return maybe(attr);
4090 
4091   // Handle [] on String objects.
4092   if (object->IsStringObjectWithCharacterAt(index)) {
4093     return maybe(static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE));
4094   }
4095 
4096   if (!check_prototype) return maybe(ABSENT);
4097 
4098   PrototypeIterator iter(object->GetIsolate(), object);
4099   if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
4100     // We need to follow the spec and simulate a call to [[GetOwnProperty]].
4101     return JSProxy::GetElementAttributeWithHandler(
4102         Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4103         index);
4104   }
4105   if (iter.IsAtEnd()) return maybe(ABSENT);
4106   return GetElementAttributeWithReceiver(
4107       Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4108       index, true);
4109 }
4110 
4111 
New(Isolate * isolate)4112 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
4113   Handle<FixedArray> array(
4114       isolate->factory()->NewFixedArray(kEntries, TENURED));
4115   return Handle<NormalizedMapCache>::cast(array);
4116 }
4117 
4118 
Get(Handle<Map> fast_map,PropertyNormalizationMode mode)4119 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
4120                                          PropertyNormalizationMode mode) {
4121   DisallowHeapAllocation no_gc;
4122   Object* value = FixedArray::get(GetIndex(fast_map));
4123   if (!value->IsMap() ||
4124       !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
4125     return MaybeHandle<Map>();
4126   }
4127   return handle(Map::cast(value));
4128 }
4129 
4130 
Set(Handle<Map> fast_map,Handle<Map> normalized_map)4131 void NormalizedMapCache::Set(Handle<Map> fast_map,
4132                              Handle<Map> normalized_map) {
4133   DisallowHeapAllocation no_gc;
4134   DCHECK(normalized_map->is_dictionary_map());
4135   FixedArray::set(GetIndex(fast_map), *normalized_map);
4136 }
4137 
4138 
Clear()4139 void NormalizedMapCache::Clear() {
4140   int entries = length();
4141   for (int i = 0; i != entries; i++) {
4142     set_undefined(i);
4143   }
4144 }
4145 
4146 
UpdateMapCodeCache(Handle<HeapObject> object,Handle<Name> name,Handle<Code> code)4147 void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
4148                                     Handle<Name> name,
4149                                     Handle<Code> code) {
4150   Handle<Map> map(object->map());
4151   Map::UpdateCodeCache(map, name, code);
4152 }
4153 
4154 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties)4155 void JSObject::NormalizeProperties(Handle<JSObject> object,
4156                                    PropertyNormalizationMode mode,
4157                                    int expected_additional_properties) {
4158   if (!object->HasFastProperties()) return;
4159 
4160   Handle<Map> map(object->map());
4161   Handle<Map> new_map = Map::Normalize(map, mode);
4162 
4163   MigrateFastToSlow(object, new_map, expected_additional_properties);
4164 }
4165 
4166 
MigrateFastToSlow(Handle<JSObject> object,Handle<Map> new_map,int expected_additional_properties)4167 void JSObject::MigrateFastToSlow(Handle<JSObject> object,
4168                                  Handle<Map> new_map,
4169                                  int expected_additional_properties) {
4170   // The global object is always normalized.
4171   DCHECK(!object->IsGlobalObject());
4172   // JSGlobalProxy must never be normalized
4173   DCHECK(!object->IsJSGlobalProxy());
4174 
4175   Isolate* isolate = object->GetIsolate();
4176   HandleScope scope(isolate);
4177   Handle<Map> map(object->map());
4178 
4179   // Allocate new content.
4180   int real_size = map->NumberOfOwnDescriptors();
4181   int property_count = real_size;
4182   if (expected_additional_properties > 0) {
4183     property_count += expected_additional_properties;
4184   } else {
4185     property_count += 2;  // Make space for two more properties.
4186   }
4187   Handle<NameDictionary> dictionary =
4188       NameDictionary::New(isolate, property_count);
4189 
4190   Handle<DescriptorArray> descs(map->instance_descriptors());
4191   for (int i = 0; i < real_size; i++) {
4192     PropertyDetails details = descs->GetDetails(i);
4193     switch (details.type()) {
4194       case CONSTANT: {
4195         Handle<Name> key(descs->GetKey(i));
4196         Handle<Object> value(descs->GetConstant(i), isolate);
4197         PropertyDetails d = PropertyDetails(
4198             details.attributes(), NORMAL, i + 1);
4199         dictionary = NameDictionary::Add(dictionary, key, value, d);
4200         break;
4201       }
4202       case FIELD: {
4203         Handle<Name> key(descs->GetKey(i));
4204         FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4205         Handle<Object> value(
4206             object->RawFastPropertyAt(index), isolate);
4207         if (details.representation().IsDouble()) {
4208           DCHECK(value->IsMutableHeapNumber());
4209           Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
4210           value = isolate->factory()->NewHeapNumber(old->value());
4211         }
4212         PropertyDetails d =
4213             PropertyDetails(details.attributes(), NORMAL, i + 1);
4214         dictionary = NameDictionary::Add(dictionary, key, value, d);
4215         break;
4216       }
4217       case CALLBACKS: {
4218         Handle<Name> key(descs->GetKey(i));
4219         Handle<Object> value(descs->GetCallbacksObject(i), isolate);
4220         PropertyDetails d = PropertyDetails(
4221             details.attributes(), CALLBACKS, i + 1);
4222         dictionary = NameDictionary::Add(dictionary, key, value, d);
4223         break;
4224       }
4225       case NORMAL:
4226         UNREACHABLE();
4227         break;
4228     }
4229   }
4230 
4231   // Copy the next enumeration index from instance descriptor.
4232   dictionary->SetNextEnumerationIndex(real_size + 1);
4233 
4234   // From here on we cannot fail and we shouldn't GC anymore.
4235   DisallowHeapAllocation no_allocation;
4236 
4237   // Resize the object in the heap if necessary.
4238   int new_instance_size = new_map->instance_size();
4239   int instance_size_delta = map->instance_size() - new_instance_size;
4240   DCHECK(instance_size_delta >= 0);
4241 
4242   if (instance_size_delta > 0) {
4243     Heap* heap = isolate->heap();
4244     heap->CreateFillerObjectAt(object->address() + new_instance_size,
4245                                instance_size_delta);
4246     heap->AdjustLiveBytes(object->address(), -instance_size_delta,
4247                           Heap::FROM_MUTATOR);
4248   }
4249 
4250   // We are storing the new map using release store after creating a filler for
4251   // the left-over space to avoid races with the sweeper thread.
4252   object->synchronized_set_map(*new_map);
4253 
4254   object->set_properties(*dictionary);
4255 
4256   isolate->counters()->props_to_dictionary()->Increment();
4257 
4258 #ifdef DEBUG
4259   if (FLAG_trace_normalization) {
4260     OFStream os(stdout);
4261     os << "Object properties have been normalized:\n";
4262     object->Print(os);
4263   }
4264 #endif
4265 }
4266 
4267 
MigrateSlowToFast(Handle<JSObject> object,int unused_property_fields)4268 void JSObject::MigrateSlowToFast(Handle<JSObject> object,
4269                                  int unused_property_fields) {
4270   if (object->HasFastProperties()) return;
4271   DCHECK(!object->IsGlobalObject());
4272   Isolate* isolate = object->GetIsolate();
4273   Factory* factory = isolate->factory();
4274   Handle<NameDictionary> dictionary(object->property_dictionary());
4275 
4276   // Make sure we preserve dictionary representation if there are too many
4277   // descriptors.
4278   int number_of_elements = dictionary->NumberOfElements();
4279   if (number_of_elements > kMaxNumberOfDescriptors) return;
4280 
4281   if (number_of_elements != dictionary->NextEnumerationIndex()) {
4282     NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
4283   }
4284 
4285   int instance_descriptor_length = 0;
4286   int number_of_fields = 0;
4287 
4288   // Compute the length of the instance descriptor.
4289   int capacity = dictionary->Capacity();
4290   for (int i = 0; i < capacity; i++) {
4291     Object* k = dictionary->KeyAt(i);
4292     if (dictionary->IsKey(k)) {
4293       Object* value = dictionary->ValueAt(i);
4294       PropertyType type = dictionary->DetailsAt(i).type();
4295       DCHECK(type != FIELD);
4296       instance_descriptor_length++;
4297       if (type == NORMAL && !value->IsJSFunction()) {
4298         number_of_fields += 1;
4299       }
4300     }
4301   }
4302 
4303   int inobject_props = object->map()->inobject_properties();
4304 
4305   // Allocate new map.
4306   Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
4307   new_map->set_dictionary_map(false);
4308 
4309   if (instance_descriptor_length == 0) {
4310     DisallowHeapAllocation no_gc;
4311     DCHECK_LE(unused_property_fields, inobject_props);
4312     // Transform the object.
4313     new_map->set_unused_property_fields(inobject_props);
4314     object->synchronized_set_map(*new_map);
4315     object->set_properties(isolate->heap()->empty_fixed_array());
4316     // Check that it really works.
4317     DCHECK(object->HasFastProperties());
4318     return;
4319   }
4320 
4321   // Allocate the instance descriptor.
4322   Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
4323       isolate, instance_descriptor_length);
4324 
4325   int number_of_allocated_fields =
4326       number_of_fields + unused_property_fields - inobject_props;
4327   if (number_of_allocated_fields < 0) {
4328     // There is enough inobject space for all fields (including unused).
4329     number_of_allocated_fields = 0;
4330     unused_property_fields = inobject_props - number_of_fields;
4331   }
4332 
4333   // Allocate the fixed array for the fields.
4334   Handle<FixedArray> fields = factory->NewFixedArray(
4335       number_of_allocated_fields);
4336 
4337   // Fill in the instance descriptor and the fields.
4338   int current_offset = 0;
4339   for (int i = 0; i < capacity; i++) {
4340     Object* k = dictionary->KeyAt(i);
4341     if (dictionary->IsKey(k)) {
4342       Object* value = dictionary->ValueAt(i);
4343       Handle<Name> key;
4344       if (k->IsSymbol()) {
4345         key = handle(Symbol::cast(k));
4346       } else {
4347         // Ensure the key is a unique name before writing into the
4348         // instance descriptor.
4349         key = factory->InternalizeString(handle(String::cast(k)));
4350       }
4351 
4352       PropertyDetails details = dictionary->DetailsAt(i);
4353       int enumeration_index = details.dictionary_index();
4354       PropertyType type = details.type();
4355 
4356       if (value->IsJSFunction()) {
4357         ConstantDescriptor d(key,
4358                              handle(value, isolate),
4359                              details.attributes());
4360         descriptors->Set(enumeration_index - 1, &d);
4361       } else if (type == NORMAL) {
4362         if (current_offset < inobject_props) {
4363           object->InObjectPropertyAtPut(current_offset,
4364                                         value,
4365                                         UPDATE_WRITE_BARRIER);
4366         } else {
4367           int offset = current_offset - inobject_props;
4368           fields->set(offset, value);
4369         }
4370         FieldDescriptor d(key,
4371                           current_offset++,
4372                           details.attributes(),
4373                           // TODO(verwaest): value->OptimalRepresentation();
4374                           Representation::Tagged());
4375         descriptors->Set(enumeration_index - 1, &d);
4376       } else if (type == CALLBACKS) {
4377         CallbacksDescriptor d(key,
4378                               handle(value, isolate),
4379                               details.attributes());
4380         descriptors->Set(enumeration_index - 1, &d);
4381       } else {
4382         UNREACHABLE();
4383       }
4384     }
4385   }
4386   DCHECK(current_offset == number_of_fields);
4387 
4388   descriptors->Sort();
4389 
4390   DisallowHeapAllocation no_gc;
4391   new_map->InitializeDescriptors(*descriptors);
4392   new_map->set_unused_property_fields(unused_property_fields);
4393 
4394   // Transform the object.
4395   object->synchronized_set_map(*new_map);
4396 
4397   object->set_properties(*fields);
4398   DCHECK(object->IsJSObject());
4399 
4400   // Check that it really works.
4401   DCHECK(object->HasFastProperties());
4402 }
4403 
4404 
ResetElements(Handle<JSObject> object)4405 void JSObject::ResetElements(Handle<JSObject> object) {
4406   Isolate* isolate = object->GetIsolate();
4407   CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
4408   if (object->map()->has_dictionary_elements()) {
4409     Handle<SeededNumberDictionary> new_elements =
4410         SeededNumberDictionary::New(isolate, 0);
4411     object->set_elements(*new_elements);
4412   } else {
4413     object->set_elements(object->map()->GetInitialElements());
4414   }
4415 }
4416 
4417 
CopyFastElementsToDictionary(Handle<FixedArrayBase> array,int length,Handle<SeededNumberDictionary> dictionary)4418 static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
4419     Handle<FixedArrayBase> array,
4420     int length,
4421     Handle<SeededNumberDictionary> dictionary) {
4422   Isolate* isolate = array->GetIsolate();
4423   Factory* factory = isolate->factory();
4424   bool has_double_elements = array->IsFixedDoubleArray();
4425   for (int i = 0; i < length; i++) {
4426     Handle<Object> value;
4427     if (has_double_elements) {
4428       Handle<FixedDoubleArray> double_array =
4429           Handle<FixedDoubleArray>::cast(array);
4430       if (double_array->is_the_hole(i)) {
4431         value = factory->the_hole_value();
4432       } else {
4433         value = factory->NewHeapNumber(double_array->get_scalar(i));
4434       }
4435     } else {
4436       value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
4437     }
4438     if (!value->IsTheHole()) {
4439       PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
4440       dictionary =
4441           SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
4442     }
4443   }
4444   return dictionary;
4445 }
4446 
4447 
NormalizeElements(Handle<JSObject> object)4448 Handle<SeededNumberDictionary> JSObject::NormalizeElements(
4449     Handle<JSObject> object) {
4450   DCHECK(!object->HasExternalArrayElements() &&
4451          !object->HasFixedTypedArrayElements());
4452   Isolate* isolate = object->GetIsolate();
4453 
4454   // Find the backing store.
4455   Handle<FixedArrayBase> array(FixedArrayBase::cast(object->elements()));
4456   bool is_arguments =
4457       (array->map() == isolate->heap()->sloppy_arguments_elements_map());
4458   if (is_arguments) {
4459     array = handle(FixedArrayBase::cast(
4460         Handle<FixedArray>::cast(array)->get(1)));
4461   }
4462   if (array->IsDictionary()) return Handle<SeededNumberDictionary>::cast(array);
4463 
4464   DCHECK(object->HasFastSmiOrObjectElements() ||
4465          object->HasFastDoubleElements() ||
4466          object->HasFastArgumentsElements());
4467   // Compute the effective length and allocate a new backing store.
4468   int length = object->IsJSArray()
4469       ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
4470       : array->length();
4471   int old_capacity = 0;
4472   int used_elements = 0;
4473   object->GetElementsCapacityAndUsage(&old_capacity, &used_elements);
4474   Handle<SeededNumberDictionary> dictionary =
4475       SeededNumberDictionary::New(isolate, used_elements);
4476 
4477   dictionary = CopyFastElementsToDictionary(array, length, dictionary);
4478 
4479   // Switch to using the dictionary as the backing storage for elements.
4480   if (is_arguments) {
4481     FixedArray::cast(object->elements())->set(1, *dictionary);
4482   } else {
4483     // Set the new map first to satify the elements type assert in
4484     // set_elements().
4485     Handle<Map> new_map =
4486         JSObject::GetElementsTransitionMap(object, DICTIONARY_ELEMENTS);
4487 
4488     JSObject::MigrateToMap(object, new_map);
4489     object->set_elements(*dictionary);
4490   }
4491 
4492   isolate->counters()->elements_to_dictionary()->Increment();
4493 
4494 #ifdef DEBUG
4495   if (FLAG_trace_normalization) {
4496     OFStream os(stdout);
4497     os << "Object elements have been normalized:\n";
4498     object->Print(os);
4499   }
4500 #endif
4501 
4502   DCHECK(object->HasDictionaryElements() ||
4503          object->HasDictionaryArgumentsElements());
4504   return dictionary;
4505 }
4506 
4507 
GenerateIdentityHash(Isolate * isolate)4508 static Smi* GenerateIdentityHash(Isolate* isolate) {
4509   int hash_value;
4510   int attempts = 0;
4511   do {
4512     // Generate a random 32-bit hash value but limit range to fit
4513     // within a smi.
4514     hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
4515     attempts++;
4516   } while (hash_value == 0 && attempts < 30);
4517   hash_value = hash_value != 0 ? hash_value : 1;  // never return 0
4518 
4519   return Smi::FromInt(hash_value);
4520 }
4521 
4522 
SetIdentityHash(Handle<JSObject> object,Handle<Smi> hash)4523 void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
4524   DCHECK(!object->IsJSGlobalProxy());
4525   Isolate* isolate = object->GetIsolate();
4526   SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
4527 }
4528 
4529 
4530 template<typename ProxyType>
GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy)4531 static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
4532   Isolate* isolate = proxy->GetIsolate();
4533 
4534   Handle<Object> maybe_hash(proxy->hash(), isolate);
4535   if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
4536 
4537   Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4538   proxy->set_hash(*hash);
4539   return hash;
4540 }
4541 
4542 
GetIdentityHash()4543 Object* JSObject::GetIdentityHash() {
4544   DisallowHeapAllocation no_gc;
4545   Isolate* isolate = GetIsolate();
4546   if (IsJSGlobalProxy()) {
4547     return JSGlobalProxy::cast(this)->hash();
4548   }
4549   Object* stored_value =
4550       GetHiddenProperty(isolate->factory()->identity_hash_string());
4551   return stored_value->IsSmi()
4552       ? stored_value
4553       : isolate->heap()->undefined_value();
4554 }
4555 
4556 
GetOrCreateIdentityHash(Handle<JSObject> object)4557 Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
4558   if (object->IsJSGlobalProxy()) {
4559     return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
4560   }
4561 
4562   Isolate* isolate = object->GetIsolate();
4563 
4564   Handle<Object> maybe_hash(object->GetIdentityHash(), isolate);
4565   if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
4566 
4567   Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4568   SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
4569   return hash;
4570 }
4571 
4572 
GetIdentityHash()4573 Object* JSProxy::GetIdentityHash() {
4574   return this->hash();
4575 }
4576 
4577 
GetOrCreateIdentityHash(Handle<JSProxy> proxy)4578 Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
4579   return GetOrCreateIdentityHashHelper(proxy);
4580 }
4581 
4582 
GetHiddenProperty(Handle<Name> key)4583 Object* JSObject::GetHiddenProperty(Handle<Name> key) {
4584   DisallowHeapAllocation no_gc;
4585   DCHECK(key->IsUniqueName());
4586   if (IsJSGlobalProxy()) {
4587     // JSGlobalProxies store their hash internally.
4588     DCHECK(*key != GetHeap()->identity_hash_string());
4589     // For a proxy, use the prototype as target object.
4590     PrototypeIterator iter(GetIsolate(), this);
4591     // If the proxy is detached, return undefined.
4592     if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
4593     DCHECK(iter.GetCurrent()->IsJSGlobalObject());
4594     return JSObject::cast(iter.GetCurrent())->GetHiddenProperty(key);
4595   }
4596   DCHECK(!IsJSGlobalProxy());
4597   Object* inline_value = GetHiddenPropertiesHashTable();
4598 
4599   if (inline_value->IsSmi()) {
4600     // Handle inline-stored identity hash.
4601     if (*key == GetHeap()->identity_hash_string()) {
4602       return inline_value;
4603     } else {
4604       return GetHeap()->the_hole_value();
4605     }
4606   }
4607 
4608   if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
4609 
4610   ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
4611   Object* entry = hashtable->Lookup(key);
4612   return entry;
4613 }
4614 
4615 
SetHiddenProperty(Handle<JSObject> object,Handle<Name> key,Handle<Object> value)4616 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
4617                                            Handle<Name> key,
4618                                            Handle<Object> value) {
4619   Isolate* isolate = object->GetIsolate();
4620 
4621   DCHECK(key->IsUniqueName());
4622   if (object->IsJSGlobalProxy()) {
4623     // JSGlobalProxies store their hash internally.
4624     DCHECK(*key != *isolate->factory()->identity_hash_string());
4625     // For a proxy, use the prototype as target object.
4626     PrototypeIterator iter(isolate, object);
4627     // If the proxy is detached, return undefined.
4628     if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
4629     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4630     return SetHiddenProperty(
4631         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key,
4632         value);
4633   }
4634   DCHECK(!object->IsJSGlobalProxy());
4635 
4636   Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
4637 
4638   // If there is no backing store yet, store the identity hash inline.
4639   if (value->IsSmi() &&
4640       *key == *isolate->factory()->identity_hash_string() &&
4641       (inline_value->IsUndefined() || inline_value->IsSmi())) {
4642     return JSObject::SetHiddenPropertiesHashTable(object, value);
4643   }
4644 
4645   Handle<ObjectHashTable> hashtable =
4646       GetOrCreateHiddenPropertiesHashtable(object);
4647 
4648   // If it was found, check if the key is already in the dictionary.
4649   Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
4650                                                            value);
4651   if (*new_table != *hashtable) {
4652     // If adding the key expanded the dictionary (i.e., Add returned a new
4653     // dictionary), store it back to the object.
4654     SetHiddenPropertiesHashTable(object, new_table);
4655   }
4656 
4657   // Return this to mark success.
4658   return object;
4659 }
4660 
4661 
DeleteHiddenProperty(Handle<JSObject> object,Handle<Name> key)4662 void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
4663   Isolate* isolate = object->GetIsolate();
4664   DCHECK(key->IsUniqueName());
4665 
4666   if (object->IsJSGlobalProxy()) {
4667     PrototypeIterator iter(isolate, object);
4668     if (iter.IsAtEnd()) return;
4669     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4670     return DeleteHiddenProperty(
4671         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key);
4672   }
4673 
4674   Object* inline_value = object->GetHiddenPropertiesHashTable();
4675 
4676   // We never delete (inline-stored) identity hashes.
4677   DCHECK(*key != *isolate->factory()->identity_hash_string());
4678   if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
4679 
4680   Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
4681   bool was_present = false;
4682   ObjectHashTable::Remove(hashtable, key, &was_present);
4683 }
4684 
4685 
HasHiddenProperties(Handle<JSObject> object)4686 bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
4687   Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
4688   LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
4689   Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
4690   // Cannot get an exception since the hidden_string isn't accessible to JS.
4691   DCHECK(maybe.has_value);
4692   return maybe.value != ABSENT;
4693 }
4694 
4695 
GetHiddenPropertiesHashTable()4696 Object* JSObject::GetHiddenPropertiesHashTable() {
4697   DCHECK(!IsJSGlobalProxy());
4698   if (HasFastProperties()) {
4699     // If the object has fast properties, check whether the first slot
4700     // in the descriptor array matches the hidden string. Since the
4701     // hidden strings hash code is zero (and no other name has hash
4702     // code zero) it will always occupy the first entry if present.
4703     DescriptorArray* descriptors = this->map()->instance_descriptors();
4704     if (descriptors->number_of_descriptors() > 0) {
4705       int sorted_index = descriptors->GetSortedKeyIndex(0);
4706       if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
4707           sorted_index < map()->NumberOfOwnDescriptors()) {
4708         DCHECK(descriptors->GetType(sorted_index) == FIELD);
4709         DCHECK(descriptors->GetDetails(sorted_index).representation().
4710                IsCompatibleForLoad(Representation::Tagged()));
4711         FieldIndex index = FieldIndex::ForDescriptor(this->map(),
4712                                                      sorted_index);
4713         return this->RawFastPropertyAt(index);
4714       } else {
4715         return GetHeap()->undefined_value();
4716       }
4717     } else {
4718       return GetHeap()->undefined_value();
4719     }
4720   } else {
4721     Isolate* isolate = GetIsolate();
4722     LookupIterator it(handle(this), isolate->factory()->hidden_string(),
4723                       LookupIterator::OWN_SKIP_INTERCEPTOR);
4724     // Access check is always skipped for the hidden string anyways.
4725     return *GetDataProperty(&it);
4726   }
4727 }
4728 
GetOrCreateHiddenPropertiesHashtable(Handle<JSObject> object)4729 Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
4730     Handle<JSObject> object) {
4731   Isolate* isolate = object->GetIsolate();
4732 
4733   static const int kInitialCapacity = 4;
4734   Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
4735   if (inline_value->IsHashTable()) {
4736     return Handle<ObjectHashTable>::cast(inline_value);
4737   }
4738 
4739   Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
4740       isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
4741 
4742   if (inline_value->IsSmi()) {
4743     // We were storing the identity hash inline and now allocated an actual
4744     // dictionary.  Put the identity hash into the new dictionary.
4745     hashtable = ObjectHashTable::Put(hashtable,
4746                                      isolate->factory()->identity_hash_string(),
4747                                      inline_value);
4748   }
4749 
4750   SetHiddenPropertiesHashTable(object, hashtable);
4751   return hashtable;
4752 }
4753 
4754 
SetHiddenPropertiesHashTable(Handle<JSObject> object,Handle<Object> value)4755 Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
4756                                                       Handle<Object> value) {
4757   DCHECK(!object->IsJSGlobalProxy());
4758   Isolate* isolate = object->GetIsolate();
4759   Handle<Name> name = isolate->factory()->hidden_string();
4760   SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
4761   return object;
4762 }
4763 
4764 
DeletePropertyWithInterceptor(Handle<JSObject> holder,Handle<JSObject> receiver,Handle<Name> name)4765 MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
4766     Handle<JSObject> holder, Handle<JSObject> receiver, Handle<Name> name) {
4767   Isolate* isolate = holder->GetIsolate();
4768 
4769   // TODO(rossberg): Support symbols in the API.
4770   if (name->IsSymbol()) return MaybeHandle<Object>();
4771 
4772   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
4773   if (interceptor->deleter()->IsUndefined()) return MaybeHandle<Object>();
4774 
4775   v8::NamedPropertyDeleterCallback deleter =
4776       v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter());
4777   LOG(isolate,
4778       ApiNamedPropertyAccess("interceptor-named-delete", *holder, *name));
4779   PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
4780                                  *holder);
4781   v8::Handle<v8::Boolean> result =
4782       args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name)));
4783   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4784   if (result.IsEmpty()) return MaybeHandle<Object>();
4785 
4786   DCHECK(result->IsBoolean());
4787   Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4788   result_internal->VerifyApiCallResultType();
4789   // Rebox CustomArguments::kReturnValueOffset before returning.
4790   return handle(*result_internal, isolate);
4791 }
4792 
4793 
DeleteElementWithInterceptor(Handle<JSObject> object,uint32_t index)4794 MaybeHandle<Object> JSObject::DeleteElementWithInterceptor(
4795     Handle<JSObject> object,
4796     uint32_t index) {
4797   Isolate* isolate = object->GetIsolate();
4798   Factory* factory = isolate->factory();
4799 
4800   // Make sure that the top context does not change when doing
4801   // callbacks or interceptor calls.
4802   AssertNoContextChange ncc(isolate);
4803 
4804   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
4805   if (interceptor->deleter()->IsUndefined()) return factory->false_value();
4806   v8::IndexedPropertyDeleterCallback deleter =
4807       v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
4808   LOG(isolate,
4809       ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index));
4810   PropertyCallbackArguments args(
4811       isolate, interceptor->data(), *object, *object);
4812   v8::Handle<v8::Boolean> result = args.Call(deleter, index);
4813   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4814   if (!result.IsEmpty()) {
4815     DCHECK(result->IsBoolean());
4816     Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4817     result_internal->VerifyApiCallResultType();
4818     // Rebox CustomArguments::kReturnValueOffset before returning.
4819     return handle(*result_internal, isolate);
4820   }
4821   MaybeHandle<Object> delete_result = object->GetElementsAccessor()->Delete(
4822       object, index, NORMAL_DELETION);
4823   return delete_result;
4824 }
4825 
4826 
DeleteElement(Handle<JSObject> object,uint32_t index,DeleteMode mode)4827 MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
4828                                             uint32_t index,
4829                                             DeleteMode mode) {
4830   Isolate* isolate = object->GetIsolate();
4831   Factory* factory = isolate->factory();
4832 
4833   // Check access rights if needed.
4834   if (object->IsAccessCheckNeeded() &&
4835       !isolate->MayIndexedAccess(object, index, v8::ACCESS_DELETE)) {
4836     isolate->ReportFailedAccessCheck(object, v8::ACCESS_DELETE);
4837     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4838     return factory->false_value();
4839   }
4840 
4841   if (object->IsStringObjectWithCharacterAt(index)) {
4842     if (mode == STRICT_DELETION) {
4843       // Deleting a non-configurable property in strict mode.
4844       Handle<Object> name = factory->NewNumberFromUint(index);
4845       Handle<Object> args[2] = { name, object };
4846       THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property",
4847                                             HandleVector(args, 2)),
4848                       Object);
4849     }
4850     return factory->false_value();
4851   }
4852 
4853   if (object->IsJSGlobalProxy()) {
4854     PrototypeIterator iter(isolate, object);
4855     if (iter.IsAtEnd()) return factory->false_value();
4856     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4857     return DeleteElement(
4858         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
4859         mode);
4860   }
4861 
4862   Handle<Object> old_value;
4863   bool should_enqueue_change_record = false;
4864   if (object->map()->is_observed()) {
4865     Maybe<bool> maybe = HasOwnElement(object, index);
4866     if (!maybe.has_value) return MaybeHandle<Object>();
4867     should_enqueue_change_record = maybe.value;
4868     if (should_enqueue_change_record) {
4869       if (!GetOwnElementAccessorPair(object, index).is_null()) {
4870         old_value = Handle<Object>::cast(factory->the_hole_value());
4871       } else {
4872         old_value = Object::GetElement(
4873             isolate, object, index).ToHandleChecked();
4874       }
4875     }
4876   }
4877 
4878   // Skip interceptor if forcing deletion.
4879   MaybeHandle<Object> maybe_result;
4880   if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
4881     maybe_result = DeleteElementWithInterceptor(object, index);
4882   } else {
4883     maybe_result = object->GetElementsAccessor()->Delete(object, index, mode);
4884   }
4885   Handle<Object> result;
4886   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
4887 
4888   if (should_enqueue_change_record) {
4889     Maybe<bool> maybe = HasOwnElement(object, index);
4890     if (!maybe.has_value) return MaybeHandle<Object>();
4891     if (!maybe.value) {
4892       Handle<String> name = factory->Uint32ToString(index);
4893       EnqueueChangeRecord(object, "delete", name, old_value);
4894     }
4895   }
4896 
4897   return result;
4898 }
4899 
4900 
DeleteProperty(Handle<JSObject> object,Handle<Name> name,DeleteMode delete_mode)4901 MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
4902                                              Handle<Name> name,
4903                                              DeleteMode delete_mode) {
4904   // ECMA-262, 3rd, 8.6.2.5
4905   DCHECK(name->IsName());
4906 
4907   uint32_t index = 0;
4908   if (name->AsArrayIndex(&index)) {
4909     return DeleteElement(object, index, delete_mode);
4910   }
4911 
4912   // Skip interceptors on FORCE_DELETION.
4913   LookupIterator::Configuration config =
4914       delete_mode == FORCE_DELETION ? LookupIterator::HIDDEN_SKIP_INTERCEPTOR
4915                                     : LookupIterator::HIDDEN;
4916 
4917   LookupIterator it(object, name, config);
4918 
4919   bool is_observed = object->map()->is_observed() &&
4920                      *name != it.isolate()->heap()->hidden_string();
4921   Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
4922 
4923   for (; it.IsFound(); it.Next()) {
4924     switch (it.state()) {
4925       case LookupIterator::JSPROXY:
4926       case LookupIterator::NOT_FOUND:
4927       case LookupIterator::TRANSITION:
4928         UNREACHABLE();
4929       case LookupIterator::ACCESS_CHECK:
4930         if (it.HasAccess(v8::ACCESS_DELETE)) break;
4931         it.isolate()->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
4932                                               v8::ACCESS_DELETE);
4933         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it.isolate(), Object);
4934         return it.isolate()->factory()->false_value();
4935       case LookupIterator::INTERCEPTOR: {
4936         MaybeHandle<Object> maybe_result =
4937             JSObject::DeletePropertyWithInterceptor(it.GetHolder<JSObject>(),
4938                                                     object, it.name());
4939         // Delete with interceptor succeeded. Return result.
4940         if (!maybe_result.is_null()) return maybe_result;
4941         // An exception was thrown in the interceptor. Propagate.
4942         if (it.isolate()->has_pending_exception()) return maybe_result;
4943         break;
4944       }
4945       case LookupIterator::DATA:
4946         if (is_observed) {
4947           old_value = it.GetDataValue();
4948         }
4949       // Fall through.
4950       case LookupIterator::ACCESSOR: {
4951         if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) {
4952           // Fail if the property is not configurable.
4953           if (delete_mode == STRICT_DELETION) {
4954             Handle<Object> args[2] = {name, object};
4955             THROW_NEW_ERROR(it.isolate(),
4956                             NewTypeError("strict_delete_property",
4957                                          HandleVector(args, arraysize(args))),
4958                             Object);
4959           }
4960           return it.isolate()->factory()->false_value();
4961         }
4962 
4963         PropertyNormalizationMode mode = object->map()->is_prototype_map()
4964                                              ? KEEP_INOBJECT_PROPERTIES
4965                                              : CLEAR_INOBJECT_PROPERTIES;
4966         Handle<JSObject> holder = it.GetHolder<JSObject>();
4967         // TODO(verwaest): Remove this temporary compatibility hack when blink
4968         // tests are updated.
4969         if (!holder.is_identical_to(object) &&
4970             !(object->IsJSGlobalProxy() && holder->IsJSGlobalObject())) {
4971           return it.isolate()->factory()->true_value();
4972         }
4973         NormalizeProperties(holder, mode, 0);
4974         Handle<Object> result =
4975             DeleteNormalizedProperty(holder, name, delete_mode);
4976         ReoptimizeIfPrototype(holder);
4977 
4978         if (is_observed) {
4979           EnqueueChangeRecord(object, "delete", name, old_value);
4980         }
4981 
4982         return result;
4983       }
4984     }
4985   }
4986 
4987   return it.isolate()->factory()->true_value();
4988 }
4989 
4990 
DeleteElement(Handle<JSReceiver> object,uint32_t index,DeleteMode mode)4991 MaybeHandle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
4992                                               uint32_t index,
4993                                               DeleteMode mode) {
4994   if (object->IsJSProxy()) {
4995     return JSProxy::DeleteElementWithHandler(
4996         Handle<JSProxy>::cast(object), index, mode);
4997   }
4998   return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
4999 }
5000 
5001 
DeleteProperty(Handle<JSReceiver> object,Handle<Name> name,DeleteMode mode)5002 MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
5003                                                Handle<Name> name,
5004                                                DeleteMode mode) {
5005   if (object->IsJSProxy()) {
5006     return JSProxy::DeletePropertyWithHandler(
5007         Handle<JSProxy>::cast(object), name, mode);
5008   }
5009   return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
5010 }
5011 
5012 
ReferencesObjectFromElements(FixedArray * elements,ElementsKind kind,Object * object)5013 bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5014                                             ElementsKind kind,
5015                                             Object* object) {
5016   DCHECK(IsFastObjectElementsKind(kind) ||
5017          kind == DICTIONARY_ELEMENTS);
5018   if (IsFastObjectElementsKind(kind)) {
5019     int length = IsJSArray()
5020         ? Smi::cast(JSArray::cast(this)->length())->value()
5021         : elements->length();
5022     for (int i = 0; i < length; ++i) {
5023       Object* element = elements->get(i);
5024       if (!element->IsTheHole() && element == object) return true;
5025     }
5026   } else {
5027     Object* key =
5028         SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
5029     if (!key->IsUndefined()) return true;
5030   }
5031   return false;
5032 }
5033 
5034 
5035 // Check whether this object references another object.
ReferencesObject(Object * obj)5036 bool JSObject::ReferencesObject(Object* obj) {
5037   Map* map_of_this = map();
5038   Heap* heap = GetHeap();
5039   DisallowHeapAllocation no_allocation;
5040 
5041   // Is the object the constructor for this object?
5042   if (map_of_this->constructor() == obj) {
5043     return true;
5044   }
5045 
5046   // Is the object the prototype for this object?
5047   if (map_of_this->prototype() == obj) {
5048     return true;
5049   }
5050 
5051   // Check if the object is among the named properties.
5052   Object* key = SlowReverseLookup(obj);
5053   if (!key->IsUndefined()) {
5054     return true;
5055   }
5056 
5057   // Check if the object is among the indexed properties.
5058   ElementsKind kind = GetElementsKind();
5059   switch (kind) {
5060     // Raw pixels and external arrays do not reference other
5061     // objects.
5062 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
5063     case EXTERNAL_##TYPE##_ELEMENTS:                                           \
5064     case TYPE##_ELEMENTS:                                                      \
5065       break;
5066 
5067     TYPED_ARRAYS(TYPED_ARRAY_CASE)
5068 #undef TYPED_ARRAY_CASE
5069 
5070     case FAST_DOUBLE_ELEMENTS:
5071     case FAST_HOLEY_DOUBLE_ELEMENTS:
5072       break;
5073     case FAST_SMI_ELEMENTS:
5074     case FAST_HOLEY_SMI_ELEMENTS:
5075       break;
5076     case FAST_ELEMENTS:
5077     case FAST_HOLEY_ELEMENTS:
5078     case DICTIONARY_ELEMENTS: {
5079       FixedArray* elements = FixedArray::cast(this->elements());
5080       if (ReferencesObjectFromElements(elements, kind, obj)) return true;
5081       break;
5082     }
5083     case SLOPPY_ARGUMENTS_ELEMENTS: {
5084       FixedArray* parameter_map = FixedArray::cast(elements());
5085       // Check the mapped parameters.
5086       int length = parameter_map->length();
5087       for (int i = 2; i < length; ++i) {
5088         Object* value = parameter_map->get(i);
5089         if (!value->IsTheHole() && value == obj) return true;
5090       }
5091       // Check the arguments.
5092       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
5093       kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
5094           FAST_HOLEY_ELEMENTS;
5095       if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
5096       break;
5097     }
5098   }
5099 
5100   // For functions check the context.
5101   if (IsJSFunction()) {
5102     // Get the constructor function for arguments array.
5103     Map* arguments_map =
5104         heap->isolate()->context()->native_context()->sloppy_arguments_map();
5105     JSFunction* arguments_function =
5106         JSFunction::cast(arguments_map->constructor());
5107 
5108     // Get the context and don't check if it is the native context.
5109     JSFunction* f = JSFunction::cast(this);
5110     Context* context = f->context();
5111     if (context->IsNativeContext()) {
5112       return false;
5113     }
5114 
5115     // Check the non-special context slots.
5116     for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
5117       // Only check JS objects.
5118       if (context->get(i)->IsJSObject()) {
5119         JSObject* ctxobj = JSObject::cast(context->get(i));
5120         // If it is an arguments array check the content.
5121         if (ctxobj->map()->constructor() == arguments_function) {
5122           if (ctxobj->ReferencesObject(obj)) {
5123             return true;
5124           }
5125         } else if (ctxobj == obj) {
5126           return true;
5127         }
5128       }
5129     }
5130 
5131     // Check the context extension (if any) if it can have references.
5132     if (context->has_extension() && !context->IsCatchContext()) {
5133       // With harmony scoping, a JSFunction may have a global context.
5134       // TODO(mvstanton): walk into the ScopeInfo.
5135       if (FLAG_harmony_scoping && context->IsGlobalContext()) {
5136         return false;
5137       }
5138 
5139       return JSObject::cast(context->extension())->ReferencesObject(obj);
5140     }
5141   }
5142 
5143   // No references to object.
5144   return false;
5145 }
5146 
5147 
PreventExtensions(Handle<JSObject> object)5148 MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
5149   Isolate* isolate = object->GetIsolate();
5150 
5151   if (!object->map()->is_extensible()) return object;
5152 
5153   if (object->IsAccessCheckNeeded() &&
5154       !isolate->MayNamedAccess(
5155           object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5156     isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5157     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5158     return isolate->factory()->false_value();
5159   }
5160 
5161   if (object->IsJSGlobalProxy()) {
5162     PrototypeIterator iter(isolate, object);
5163     if (iter.IsAtEnd()) return object;
5164     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
5165     return PreventExtensions(
5166         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
5167   }
5168 
5169   // It's not possible to seal objects with external array elements
5170   if (object->HasExternalArrayElements() ||
5171       object->HasFixedTypedArrayElements()) {
5172     THROW_NEW_ERROR(isolate,
5173                     NewTypeError("cant_prevent_ext_external_array_elements",
5174                                  HandleVector(&object, 1)),
5175                     Object);
5176   }
5177 
5178   // If there are fast elements we normalize.
5179   Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
5180   DCHECK(object->HasDictionaryElements() ||
5181          object->HasDictionaryArgumentsElements());
5182 
5183   // Make sure that we never go back to fast case.
5184   dictionary->set_requires_slow_elements();
5185 
5186   // Do a map transition, other objects with this map may still
5187   // be extensible.
5188   // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
5189   Handle<Map> new_map = Map::Copy(handle(object->map()));
5190 
5191   new_map->set_is_extensible(false);
5192   JSObject::MigrateToMap(object, new_map);
5193   DCHECK(!object->map()->is_extensible());
5194 
5195   if (object->map()->is_observed()) {
5196     EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
5197                         isolate->factory()->the_hole_value());
5198   }
5199   return object;
5200 }
5201 
5202 
5203 template<typename Dictionary>
FreezeDictionary(Dictionary * dictionary)5204 static void FreezeDictionary(Dictionary* dictionary) {
5205   int capacity = dictionary->Capacity();
5206   for (int i = 0; i < capacity; i++) {
5207     Object* k = dictionary->KeyAt(i);
5208     if (dictionary->IsKey(k) &&
5209         !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
5210       PropertyDetails details = dictionary->DetailsAt(i);
5211       int attrs = DONT_DELETE;
5212       // READ_ONLY is an invalid attribute for JS setters/getters.
5213       if (details.type() == CALLBACKS) {
5214         Object* v = dictionary->ValueAt(i);
5215         if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
5216         if (!v->IsAccessorPair()) attrs |= READ_ONLY;
5217       } else {
5218         attrs |= READ_ONLY;
5219       }
5220       details = details.CopyAddAttributes(
5221           static_cast<PropertyAttributes>(attrs));
5222       dictionary->DetailsAtPut(i, details);
5223     }
5224   }
5225 }
5226 
5227 
Freeze(Handle<JSObject> object)5228 MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
5229   // Freezing sloppy arguments should be handled elsewhere.
5230   DCHECK(!object->HasSloppyArgumentsElements());
5231   DCHECK(!object->map()->is_observed());
5232 
5233   if (object->map()->is_frozen()) return object;
5234 
5235   Isolate* isolate = object->GetIsolate();
5236   if (object->IsAccessCheckNeeded() &&
5237       !isolate->MayNamedAccess(
5238           object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5239     isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5240     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5241     return isolate->factory()->false_value();
5242   }
5243 
5244   if (object->IsJSGlobalProxy()) {
5245     PrototypeIterator iter(isolate, object);
5246     if (iter.IsAtEnd()) return object;
5247     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
5248     return Freeze(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
5249   }
5250 
5251   // It's not possible to freeze objects with external array elements
5252   if (object->HasExternalArrayElements() ||
5253       object->HasFixedTypedArrayElements()) {
5254     THROW_NEW_ERROR(isolate,
5255                     NewTypeError("cant_prevent_ext_external_array_elements",
5256                                  HandleVector(&object, 1)),
5257                     Object);
5258   }
5259 
5260   Handle<SeededNumberDictionary> new_element_dictionary;
5261   if (!object->elements()->IsDictionary()) {
5262     int length = object->IsJSArray()
5263         ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5264         : object->elements()->length();
5265     if (length > 0) {
5266       int capacity = 0;
5267       int used = 0;
5268       object->GetElementsCapacityAndUsage(&capacity, &used);
5269       new_element_dictionary = SeededNumberDictionary::New(isolate, used);
5270 
5271       // Move elements to a dictionary; avoid calling NormalizeElements to avoid
5272       // unnecessary transitions.
5273       new_element_dictionary = CopyFastElementsToDictionary(
5274           handle(object->elements()), length, new_element_dictionary);
5275     } else {
5276       // No existing elements, use a pre-allocated empty backing store
5277       new_element_dictionary =
5278           isolate->factory()->empty_slow_element_dictionary();
5279     }
5280   }
5281 
5282   Handle<Map> old_map(object->map(), isolate);
5283   int transition_index = old_map->SearchTransition(
5284       isolate->heap()->frozen_symbol());
5285   if (transition_index != TransitionArray::kNotFound) {
5286     Handle<Map> transition_map(old_map->GetTransition(transition_index));
5287     DCHECK(transition_map->has_dictionary_elements());
5288     DCHECK(transition_map->is_frozen());
5289     DCHECK(!transition_map->is_extensible());
5290     JSObject::MigrateToMap(object, transition_map);
5291   } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
5292     // Create a new descriptor array with fully-frozen properties
5293     Handle<Map> new_map = Map::CopyForFreeze(old_map);
5294     JSObject::MigrateToMap(object, new_map);
5295   } else {
5296     DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
5297     // Slow path: need to normalize properties for safety
5298     NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
5299 
5300     // Create a new map, since other objects with this map may be extensible.
5301     // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
5302     Handle<Map> new_map = Map::Copy(handle(object->map()));
5303     new_map->freeze();
5304     new_map->set_is_extensible(false);
5305     new_map->set_elements_kind(DICTIONARY_ELEMENTS);
5306     JSObject::MigrateToMap(object, new_map);
5307 
5308     // Freeze dictionary-mode properties
5309     FreezeDictionary(object->property_dictionary());
5310   }
5311 
5312   DCHECK(object->map()->has_dictionary_elements());
5313   if (!new_element_dictionary.is_null()) {
5314     object->set_elements(*new_element_dictionary);
5315   }
5316 
5317   if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
5318     SeededNumberDictionary* dictionary = object->element_dictionary();
5319     // Make sure we never go back to the fast case
5320     dictionary->set_requires_slow_elements();
5321     // Freeze all elements in the dictionary
5322     FreezeDictionary(dictionary);
5323   }
5324 
5325   return object;
5326 }
5327 
5328 
SetObserved(Handle<JSObject> object)5329 void JSObject::SetObserved(Handle<JSObject> object) {
5330   DCHECK(!object->IsJSGlobalProxy());
5331   DCHECK(!object->IsJSGlobalObject());
5332   Isolate* isolate = object->GetIsolate();
5333   Handle<Map> new_map;
5334   Handle<Map> old_map(object->map(), isolate);
5335   DCHECK(!old_map->is_observed());
5336   int transition_index = old_map->SearchTransition(
5337       isolate->heap()->observed_symbol());
5338   if (transition_index != TransitionArray::kNotFound) {
5339     new_map = handle(old_map->GetTransition(transition_index), isolate);
5340     DCHECK(new_map->is_observed());
5341   } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
5342     new_map = Map::CopyForObserved(old_map);
5343   } else {
5344     new_map = Map::Copy(old_map);
5345     new_map->set_is_observed();
5346   }
5347   JSObject::MigrateToMap(object, new_map);
5348 }
5349 
5350 
FastPropertyAt(Handle<JSObject> object,Representation representation,FieldIndex index)5351 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
5352                                         Representation representation,
5353                                         FieldIndex index) {
5354   Isolate* isolate = object->GetIsolate();
5355   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
5356   return Object::WrapForRead(isolate, raw_value, representation);
5357 }
5358 
5359 
5360 template<class ContextObject>
5361 class JSObjectWalkVisitor {
5362  public:
JSObjectWalkVisitor(ContextObject * site_context,bool copying,JSObject::DeepCopyHints hints)5363   JSObjectWalkVisitor(ContextObject* site_context, bool copying,
5364                       JSObject::DeepCopyHints hints)
5365     : site_context_(site_context),
5366       copying_(copying),
5367       hints_(hints) {}
5368 
5369   MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
5370 
5371  protected:
VisitElementOrProperty(Handle<JSObject> object,Handle<JSObject> value)5372   MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
5373       Handle<JSObject> object,
5374       Handle<JSObject> value) {
5375     Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5376     MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
5377     site_context()->ExitScope(current_site, value);
5378     return copy_of_value;
5379   }
5380 
site_context()5381   inline ContextObject* site_context() { return site_context_; }
isolate()5382   inline Isolate* isolate() { return site_context()->isolate(); }
5383 
copying() const5384   inline bool copying() const { return copying_; }
5385 
5386  private:
5387   ContextObject* site_context_;
5388   const bool copying_;
5389   const JSObject::DeepCopyHints hints_;
5390 };
5391 
5392 
5393 template <class ContextObject>
StructureWalk(Handle<JSObject> object)5394 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
5395     Handle<JSObject> object) {
5396   Isolate* isolate = this->isolate();
5397   bool copying = this->copying();
5398   bool shallow = hints_ == JSObject::kObjectIsShallow;
5399 
5400   if (!shallow) {
5401     StackLimitCheck check(isolate);
5402 
5403     if (check.HasOverflowed()) {
5404       isolate->StackOverflow();
5405       return MaybeHandle<JSObject>();
5406     }
5407   }
5408 
5409   if (object->map()->is_deprecated()) {
5410     JSObject::MigrateInstance(object);
5411   }
5412 
5413   Handle<JSObject> copy;
5414   if (copying) {
5415     Handle<AllocationSite> site_to_pass;
5416     if (site_context()->ShouldCreateMemento(object)) {
5417       site_to_pass = site_context()->current();
5418     }
5419     copy = isolate->factory()->CopyJSObjectWithAllocationSite(
5420         object, site_to_pass);
5421   } else {
5422     copy = object;
5423   }
5424 
5425   DCHECK(copying || copy.is_identical_to(object));
5426 
5427   ElementsKind kind = copy->GetElementsKind();
5428   if (copying && IsFastSmiOrObjectElementsKind(kind) &&
5429       FixedArray::cast(copy->elements())->map() ==
5430         isolate->heap()->fixed_cow_array_map()) {
5431     isolate->counters()->cow_arrays_created_runtime()->Increment();
5432   }
5433 
5434   if (!shallow) {
5435     HandleScope scope(isolate);
5436 
5437     // Deep copy own properties.
5438     if (copy->HasFastProperties()) {
5439       Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
5440       int limit = copy->map()->NumberOfOwnDescriptors();
5441       for (int i = 0; i < limit; i++) {
5442         PropertyDetails details = descriptors->GetDetails(i);
5443         if (details.type() != FIELD) continue;
5444         FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
5445         Handle<Object> value(object->RawFastPropertyAt(index), isolate);
5446         if (value->IsJSObject()) {
5447           ASSIGN_RETURN_ON_EXCEPTION(
5448               isolate, value,
5449               VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5450               JSObject);
5451         } else {
5452           Representation representation = details.representation();
5453           value = Object::NewStorageFor(isolate, value, representation);
5454         }
5455         if (copying) {
5456           copy->FastPropertyAtPut(index, *value);
5457         }
5458       }
5459     } else {
5460       Handle<FixedArray> names =
5461           isolate->factory()->NewFixedArray(copy->NumberOfOwnProperties());
5462       copy->GetOwnPropertyNames(*names, 0);
5463       for (int i = 0; i < names->length(); i++) {
5464         DCHECK(names->get(i)->IsString());
5465         Handle<String> key_string(String::cast(names->get(i)));
5466         Maybe<PropertyAttributes> maybe =
5467             JSReceiver::GetOwnPropertyAttributes(copy, key_string);
5468         DCHECK(maybe.has_value);
5469         PropertyAttributes attributes = maybe.value;
5470         // Only deep copy fields from the object literal expression.
5471         // In particular, don't try to copy the length attribute of
5472         // an array.
5473         if (attributes != NONE) continue;
5474         Handle<Object> value =
5475             Object::GetProperty(copy, key_string).ToHandleChecked();
5476         if (value->IsJSObject()) {
5477           Handle<JSObject> result;
5478           ASSIGN_RETURN_ON_EXCEPTION(
5479               isolate, result,
5480               VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5481               JSObject);
5482           if (copying) {
5483             // Creating object copy for literals. No strict mode needed.
5484             JSObject::SetProperty(copy, key_string, result, SLOPPY).Assert();
5485           }
5486         }
5487       }
5488     }
5489 
5490     // Deep copy own elements.
5491     // Pixel elements cannot be created using an object literal.
5492     DCHECK(!copy->HasExternalArrayElements());
5493     switch (kind) {
5494       case FAST_SMI_ELEMENTS:
5495       case FAST_ELEMENTS:
5496       case FAST_HOLEY_SMI_ELEMENTS:
5497       case FAST_HOLEY_ELEMENTS: {
5498         Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
5499         if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
5500 #ifdef DEBUG
5501           for (int i = 0; i < elements->length(); i++) {
5502             DCHECK(!elements->get(i)->IsJSObject());
5503           }
5504 #endif
5505         } else {
5506           for (int i = 0; i < elements->length(); i++) {
5507             Handle<Object> value(elements->get(i), isolate);
5508             DCHECK(value->IsSmi() ||
5509                    value->IsTheHole() ||
5510                    (IsFastObjectElementsKind(copy->GetElementsKind())));
5511             if (value->IsJSObject()) {
5512               Handle<JSObject> result;
5513               ASSIGN_RETURN_ON_EXCEPTION(
5514                   isolate, result,
5515                   VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5516                   JSObject);
5517               if (copying) {
5518                 elements->set(i, *result);
5519               }
5520             }
5521           }
5522         }
5523         break;
5524       }
5525       case DICTIONARY_ELEMENTS: {
5526         Handle<SeededNumberDictionary> element_dictionary(
5527             copy->element_dictionary());
5528         int capacity = element_dictionary->Capacity();
5529         for (int i = 0; i < capacity; i++) {
5530           Object* k = element_dictionary->KeyAt(i);
5531           if (element_dictionary->IsKey(k)) {
5532             Handle<Object> value(element_dictionary->ValueAt(i), isolate);
5533             if (value->IsJSObject()) {
5534               Handle<JSObject> result;
5535               ASSIGN_RETURN_ON_EXCEPTION(
5536                   isolate, result,
5537                   VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5538                   JSObject);
5539               if (copying) {
5540                 element_dictionary->ValueAtPut(i, *result);
5541               }
5542             }
5543           }
5544         }
5545         break;
5546       }
5547       case SLOPPY_ARGUMENTS_ELEMENTS:
5548         UNIMPLEMENTED();
5549         break;
5550 
5551 
5552 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
5553       case EXTERNAL_##TYPE##_ELEMENTS:                                         \
5554       case TYPE##_ELEMENTS:                                                    \
5555 
5556       TYPED_ARRAYS(TYPED_ARRAY_CASE)
5557 #undef TYPED_ARRAY_CASE
5558 
5559       case FAST_DOUBLE_ELEMENTS:
5560       case FAST_HOLEY_DOUBLE_ELEMENTS:
5561         // No contained objects, nothing to do.
5562         break;
5563     }
5564   }
5565 
5566   return copy;
5567 }
5568 
5569 
DeepWalk(Handle<JSObject> object,AllocationSiteCreationContext * site_context)5570 MaybeHandle<JSObject> JSObject::DeepWalk(
5571     Handle<JSObject> object,
5572     AllocationSiteCreationContext* site_context) {
5573   JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
5574                                                        kNoHints);
5575   MaybeHandle<JSObject> result = v.StructureWalk(object);
5576   Handle<JSObject> for_assert;
5577   DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
5578   return result;
5579 }
5580 
5581 
DeepCopy(Handle<JSObject> object,AllocationSiteUsageContext * site_context,DeepCopyHints hints)5582 MaybeHandle<JSObject> JSObject::DeepCopy(
5583     Handle<JSObject> object,
5584     AllocationSiteUsageContext* site_context,
5585     DeepCopyHints hints) {
5586   JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
5587   MaybeHandle<JSObject> copy = v.StructureWalk(object);
5588   Handle<JSObject> for_assert;
5589   DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
5590   return copy;
5591 }
5592 
5593 
5594 // Tests for the fast common case for property enumeration:
5595 // - This object and all prototypes has an enum cache (which means that
5596 //   it is no proxy, has no interceptors and needs no access checks).
5597 // - This object has no elements.
5598 // - No prototype has enumerable properties/elements.
IsSimpleEnum()5599 bool JSReceiver::IsSimpleEnum() {
5600   for (PrototypeIterator iter(GetIsolate(), this,
5601                               PrototypeIterator::START_AT_RECEIVER);
5602        !iter.IsAtEnd(); iter.Advance()) {
5603     if (!iter.GetCurrent()->IsJSObject()) return false;
5604     JSObject* curr = JSObject::cast(iter.GetCurrent());
5605     int enum_length = curr->map()->EnumLength();
5606     if (enum_length == kInvalidEnumCacheSentinel) return false;
5607     if (curr->IsAccessCheckNeeded()) return false;
5608     DCHECK(!curr->HasNamedInterceptor());
5609     DCHECK(!curr->HasIndexedInterceptor());
5610     if (curr->NumberOfEnumElements() > 0) return false;
5611     if (curr != this && enum_length != 0) return false;
5612   }
5613   return true;
5614 }
5615 
5616 
FilterKey(Object * key,PropertyAttributes filter)5617 static bool FilterKey(Object* key, PropertyAttributes filter) {
5618   if ((filter & SYMBOLIC) && key->IsSymbol()) {
5619     return true;
5620   }
5621 
5622   if ((filter & PRIVATE_SYMBOL) &&
5623       key->IsSymbol() && Symbol::cast(key)->is_private()) {
5624     return true;
5625   }
5626 
5627   if ((filter & STRING) && !key->IsSymbol()) {
5628     return true;
5629   }
5630 
5631   return false;
5632 }
5633 
5634 
NumberOfDescribedProperties(DescriptorFlag which,PropertyAttributes filter)5635 int Map::NumberOfDescribedProperties(DescriptorFlag which,
5636                                      PropertyAttributes filter) {
5637   int result = 0;
5638   DescriptorArray* descs = instance_descriptors();
5639   int limit = which == ALL_DESCRIPTORS
5640       ? descs->number_of_descriptors()
5641       : NumberOfOwnDescriptors();
5642   for (int i = 0; i < limit; i++) {
5643     if ((descs->GetDetails(i).attributes() & filter) == 0 &&
5644         !FilterKey(descs->GetKey(i), filter)) {
5645       result++;
5646     }
5647   }
5648   return result;
5649 }
5650 
5651 
NextFreePropertyIndex()5652 int Map::NextFreePropertyIndex() {
5653   int max_index = -1;
5654   int number_of_own_descriptors = NumberOfOwnDescriptors();
5655   DescriptorArray* descs = instance_descriptors();
5656   for (int i = 0; i < number_of_own_descriptors; i++) {
5657     if (descs->GetType(i) == FIELD) {
5658       int current_index = descs->GetFieldIndex(i);
5659       if (current_index > max_index) max_index = current_index;
5660     }
5661   }
5662   return max_index + 1;
5663 }
5664 
5665 
ContainsOnlyValidKeys(Handle<FixedArray> array)5666 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
5667   int len = array->length();
5668   for (int i = 0; i < len; i++) {
5669     Object* e = array->get(i);
5670     if (!(e->IsString() || e->IsNumber())) return false;
5671   }
5672   return true;
5673 }
5674 
5675 
ReduceFixedArrayTo(Handle<FixedArray> array,int length)5676 static Handle<FixedArray> ReduceFixedArrayTo(
5677     Handle<FixedArray> array, int length) {
5678   DCHECK(array->length() >= length);
5679   if (array->length() == length) return array;
5680 
5681   Handle<FixedArray> new_array =
5682       array->GetIsolate()->factory()->NewFixedArray(length);
5683   for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
5684   return new_array;
5685 }
5686 
5687 
GetEnumPropertyKeys(Handle<JSObject> object,bool cache_result)5688 static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
5689                                               bool cache_result) {
5690   Isolate* isolate = object->GetIsolate();
5691   if (object->HasFastProperties()) {
5692     int own_property_count = object->map()->EnumLength();
5693     // If the enum length of the given map is set to kInvalidEnumCache, this
5694     // means that the map itself has never used the present enum cache. The
5695     // first step to using the cache is to set the enum length of the map by
5696     // counting the number of own descriptors that are not DONT_ENUM or
5697     // SYMBOLIC.
5698     if (own_property_count == kInvalidEnumCacheSentinel) {
5699       own_property_count = object->map()->NumberOfDescribedProperties(
5700           OWN_DESCRIPTORS, DONT_SHOW);
5701     } else {
5702       DCHECK(own_property_count == object->map()->NumberOfDescribedProperties(
5703           OWN_DESCRIPTORS, DONT_SHOW));
5704     }
5705 
5706     if (object->map()->instance_descriptors()->HasEnumCache()) {
5707       DescriptorArray* desc = object->map()->instance_descriptors();
5708       Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
5709 
5710       // In case the number of properties required in the enum are actually
5711       // present, we can reuse the enum cache. Otherwise, this means that the
5712       // enum cache was generated for a previous (smaller) version of the
5713       // Descriptor Array. In that case we regenerate the enum cache.
5714       if (own_property_count <= keys->length()) {
5715         if (cache_result) object->map()->SetEnumLength(own_property_count);
5716         isolate->counters()->enum_cache_hits()->Increment();
5717         return ReduceFixedArrayTo(keys, own_property_count);
5718       }
5719     }
5720 
5721     Handle<Map> map(object->map());
5722 
5723     if (map->instance_descriptors()->IsEmpty()) {
5724       isolate->counters()->enum_cache_hits()->Increment();
5725       if (cache_result) map->SetEnumLength(0);
5726       return isolate->factory()->empty_fixed_array();
5727     }
5728 
5729     isolate->counters()->enum_cache_misses()->Increment();
5730 
5731     Handle<FixedArray> storage = isolate->factory()->NewFixedArray(
5732         own_property_count);
5733     Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
5734         own_property_count);
5735 
5736     Handle<DescriptorArray> descs =
5737         Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
5738 
5739     int size = map->NumberOfOwnDescriptors();
5740     int index = 0;
5741 
5742     for (int i = 0; i < size; i++) {
5743       PropertyDetails details = descs->GetDetails(i);
5744       Object* key = descs->GetKey(i);
5745       if (!(details.IsDontEnum() || key->IsSymbol())) {
5746         storage->set(index, key);
5747         if (!indices.is_null()) {
5748           if (details.type() != FIELD) {
5749             indices = Handle<FixedArray>();
5750           } else {
5751             FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
5752             int load_by_field_index = field_index.GetLoadByFieldIndex();
5753             indices->set(index, Smi::FromInt(load_by_field_index));
5754           }
5755         }
5756         index++;
5757       }
5758     }
5759     DCHECK(index == storage->length());
5760 
5761     Handle<FixedArray> bridge_storage =
5762         isolate->factory()->NewFixedArray(
5763             DescriptorArray::kEnumCacheBridgeLength);
5764     DescriptorArray* desc = object->map()->instance_descriptors();
5765     desc->SetEnumCache(*bridge_storage,
5766                        *storage,
5767                        indices.is_null() ? Object::cast(Smi::FromInt(0))
5768                                          : Object::cast(*indices));
5769     if (cache_result) {
5770       object->map()->SetEnumLength(own_property_count);
5771     }
5772     return storage;
5773   } else {
5774     Handle<NameDictionary> dictionary(object->property_dictionary());
5775     int length = dictionary->NumberOfEnumElements();
5776     if (length == 0) {
5777       return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
5778     }
5779     Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
5780     dictionary->CopyEnumKeysTo(*storage);
5781     return storage;
5782   }
5783 }
5784 
5785 
GetKeys(Handle<JSReceiver> object,KeyCollectionType type)5786 MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
5787                                             KeyCollectionType type) {
5788   USE(ContainsOnlyValidKeys);
5789   Isolate* isolate = object->GetIsolate();
5790   Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
5791   Handle<JSFunction> arguments_function(
5792       JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
5793 
5794   // Only collect keys if access is permitted.
5795   for (PrototypeIterator iter(isolate, object,
5796                               PrototypeIterator::START_AT_RECEIVER);
5797        !iter.IsAtEnd(); iter.Advance()) {
5798     if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
5799       Handle<JSProxy> proxy(JSProxy::cast(*PrototypeIterator::GetCurrent(iter)),
5800                             isolate);
5801       Handle<Object> args[] = { proxy };
5802       Handle<Object> names;
5803       ASSIGN_RETURN_ON_EXCEPTION(
5804           isolate, names,
5805           Execution::Call(isolate,
5806                           isolate->proxy_enumerate(),
5807                           object,
5808                           arraysize(args),
5809                           args),
5810           FixedArray);
5811       ASSIGN_RETURN_ON_EXCEPTION(
5812           isolate, content,
5813           FixedArray::AddKeysFromArrayLike(
5814               content, Handle<JSObject>::cast(names)),
5815           FixedArray);
5816       break;
5817     }
5818 
5819     Handle<JSObject> current =
5820         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
5821 
5822     // Check access rights if required.
5823     if (current->IsAccessCheckNeeded() &&
5824         !isolate->MayNamedAccess(
5825             current, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5826       isolate->ReportFailedAccessCheck(current, v8::ACCESS_KEYS);
5827       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
5828       break;
5829     }
5830 
5831     // Compute the element keys.
5832     Handle<FixedArray> element_keys =
5833         isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
5834     current->GetEnumElementKeys(*element_keys);
5835     ASSIGN_RETURN_ON_EXCEPTION(
5836         isolate, content,
5837         FixedArray::UnionOfKeys(content, element_keys),
5838         FixedArray);
5839     DCHECK(ContainsOnlyValidKeys(content));
5840 
5841     // Add the element keys from the interceptor.
5842     if (current->HasIndexedInterceptor()) {
5843       Handle<JSObject> result;
5844       if (JSObject::GetKeysForIndexedInterceptor(
5845               current, object).ToHandle(&result)) {
5846         ASSIGN_RETURN_ON_EXCEPTION(
5847             isolate, content,
5848             FixedArray::AddKeysFromArrayLike(content, result),
5849             FixedArray);
5850       }
5851       DCHECK(ContainsOnlyValidKeys(content));
5852     }
5853 
5854     // We can cache the computed property keys if access checks are
5855     // not needed and no interceptors are involved.
5856     //
5857     // We do not use the cache if the object has elements and
5858     // therefore it does not make sense to cache the property names
5859     // for arguments objects.  Arguments objects will always have
5860     // elements.
5861     // Wrapped strings have elements, but don't have an elements
5862     // array or dictionary.  So the fast inline test for whether to
5863     // use the cache says yes, so we should not create a cache.
5864     bool cache_enum_keys =
5865         ((current->map()->constructor() != *arguments_function) &&
5866          !current->IsJSValue() &&
5867          !current->IsAccessCheckNeeded() &&
5868          !current->HasNamedInterceptor() &&
5869          !current->HasIndexedInterceptor());
5870     // Compute the property keys and cache them if possible.
5871     ASSIGN_RETURN_ON_EXCEPTION(
5872         isolate, content,
5873         FixedArray::UnionOfKeys(
5874             content, GetEnumPropertyKeys(current, cache_enum_keys)),
5875         FixedArray);
5876     DCHECK(ContainsOnlyValidKeys(content));
5877 
5878     // Add the property keys from the interceptor.
5879     if (current->HasNamedInterceptor()) {
5880       Handle<JSObject> result;
5881       if (JSObject::GetKeysForNamedInterceptor(
5882               current, object).ToHandle(&result)) {
5883         ASSIGN_RETURN_ON_EXCEPTION(
5884             isolate, content,
5885             FixedArray::AddKeysFromArrayLike(content, result),
5886             FixedArray);
5887       }
5888       DCHECK(ContainsOnlyValidKeys(content));
5889     }
5890 
5891     // If we only want own properties we bail out after the first
5892     // iteration.
5893     if (type == OWN_ONLY) break;
5894   }
5895   return content;
5896 }
5897 
5898 
5899 // Try to update an accessor in an elements dictionary. Return true if the
5900 // update succeeded, and false otherwise.
UpdateGetterSetterInDictionary(SeededNumberDictionary * dictionary,uint32_t index,Object * getter,Object * setter,PropertyAttributes attributes)5901 static bool UpdateGetterSetterInDictionary(
5902     SeededNumberDictionary* dictionary,
5903     uint32_t index,
5904     Object* getter,
5905     Object* setter,
5906     PropertyAttributes attributes) {
5907   int entry = dictionary->FindEntry(index);
5908   if (entry != SeededNumberDictionary::kNotFound) {
5909     Object* result = dictionary->ValueAt(entry);
5910     PropertyDetails details = dictionary->DetailsAt(entry);
5911     if (details.type() == CALLBACKS && result->IsAccessorPair()) {
5912       DCHECK(details.IsConfigurable());
5913       if (details.attributes() != attributes) {
5914         dictionary->DetailsAtPut(
5915             entry,
5916             PropertyDetails(attributes, CALLBACKS, index));
5917       }
5918       AccessorPair::cast(result)->SetComponents(getter, setter);
5919       return true;
5920     }
5921   }
5922   return false;
5923 }
5924 
5925 
DefineElementAccessor(Handle<JSObject> object,uint32_t index,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)5926 void JSObject::DefineElementAccessor(Handle<JSObject> object,
5927                                      uint32_t index,
5928                                      Handle<Object> getter,
5929                                      Handle<Object> setter,
5930                                      PropertyAttributes attributes) {
5931   switch (object->GetElementsKind()) {
5932     case FAST_SMI_ELEMENTS:
5933     case FAST_ELEMENTS:
5934     case FAST_DOUBLE_ELEMENTS:
5935     case FAST_HOLEY_SMI_ELEMENTS:
5936     case FAST_HOLEY_ELEMENTS:
5937     case FAST_HOLEY_DOUBLE_ELEMENTS:
5938       break;
5939 
5940 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
5941     case EXTERNAL_##TYPE##_ELEMENTS:                                           \
5942     case TYPE##_ELEMENTS:                                                      \
5943 
5944     TYPED_ARRAYS(TYPED_ARRAY_CASE)
5945 #undef TYPED_ARRAY_CASE
5946       // Ignore getters and setters on pixel and external array elements.
5947       return;
5948 
5949     case DICTIONARY_ELEMENTS:
5950       if (UpdateGetterSetterInDictionary(object->element_dictionary(),
5951                                          index,
5952                                          *getter,
5953                                          *setter,
5954                                          attributes)) {
5955         return;
5956       }
5957       break;
5958     case SLOPPY_ARGUMENTS_ELEMENTS: {
5959       // Ascertain whether we have read-only properties or an existing
5960       // getter/setter pair in an arguments elements dictionary backing
5961       // store.
5962       FixedArray* parameter_map = FixedArray::cast(object->elements());
5963       uint32_t length = parameter_map->length();
5964       Object* probe =
5965           index < (length - 2) ? parameter_map->get(index + 2) : NULL;
5966       if (probe == NULL || probe->IsTheHole()) {
5967         FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
5968         if (arguments->IsDictionary()) {
5969           SeededNumberDictionary* dictionary =
5970               SeededNumberDictionary::cast(arguments);
5971           if (UpdateGetterSetterInDictionary(dictionary,
5972                                              index,
5973                                              *getter,
5974                                              *setter,
5975                                              attributes)) {
5976             return;
5977           }
5978         }
5979       }
5980       break;
5981     }
5982   }
5983 
5984   Isolate* isolate = object->GetIsolate();
5985   Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
5986   accessors->SetComponents(*getter, *setter);
5987 
5988   SetElementCallback(object, index, accessors, attributes);
5989 }
5990 
5991 
DictionaryElementsInPrototypeChainOnly()5992 bool Map::DictionaryElementsInPrototypeChainOnly() {
5993   if (IsDictionaryElementsKind(elements_kind())) {
5994     return false;
5995   }
5996 
5997   for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
5998     if (iter.GetCurrent()->IsJSProxy()) {
5999       // Be conservative, don't walk into proxies.
6000       return true;
6001     }
6002 
6003     if (IsDictionaryElementsKind(
6004             JSObject::cast(iter.GetCurrent())->map()->elements_kind())) {
6005       return true;
6006     }
6007   }
6008 
6009   return false;
6010 }
6011 
6012 
SetElementCallback(Handle<JSObject> object,uint32_t index,Handle<Object> structure,PropertyAttributes attributes)6013 void JSObject::SetElementCallback(Handle<JSObject> object,
6014                                   uint32_t index,
6015                                   Handle<Object> structure,
6016                                   PropertyAttributes attributes) {
6017   Heap* heap = object->GetHeap();
6018   PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
6019 
6020   // Normalize elements to make this operation simple.
6021   bool had_dictionary_elements = object->HasDictionaryElements();
6022   Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
6023   DCHECK(object->HasDictionaryElements() ||
6024          object->HasDictionaryArgumentsElements());
6025   // Update the dictionary with the new CALLBACKS property.
6026   dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
6027                                            details);
6028   dictionary->set_requires_slow_elements();
6029 
6030   // Update the dictionary backing store on the object.
6031   if (object->elements()->map() == heap->sloppy_arguments_elements_map()) {
6032     // Also delete any parameter alias.
6033     //
6034     // TODO(kmillikin): when deleting the last parameter alias we could
6035     // switch to a direct backing store without the parameter map.  This
6036     // would allow GC of the context.
6037     FixedArray* parameter_map = FixedArray::cast(object->elements());
6038     if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
6039       parameter_map->set(index + 2, heap->the_hole_value());
6040     }
6041     parameter_map->set(1, *dictionary);
6042   } else {
6043     object->set_elements(*dictionary);
6044 
6045     if (!had_dictionary_elements) {
6046       // KeyedStoreICs (at least the non-generic ones) need a reset.
6047       heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
6048     }
6049   }
6050 }
6051 
6052 
SetPropertyCallback(Handle<JSObject> object,Handle<Name> name,Handle<Object> structure,PropertyAttributes attributes)6053 void JSObject::SetPropertyCallback(Handle<JSObject> object,
6054                                    Handle<Name> name,
6055                                    Handle<Object> structure,
6056                                    PropertyAttributes attributes) {
6057   PropertyNormalizationMode mode = object->map()->is_prototype_map()
6058                                        ? KEEP_INOBJECT_PROPERTIES
6059                                        : CLEAR_INOBJECT_PROPERTIES;
6060   // Normalize object to make this operation simple.
6061   NormalizeProperties(object, mode, 0);
6062 
6063   // For the global object allocate a new map to invalidate the global inline
6064   // caches which have a global property cell reference directly in the code.
6065   if (object->IsGlobalObject()) {
6066     Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
6067     DCHECK(new_map->is_dictionary_map());
6068     JSObject::MigrateToMap(object, new_map);
6069 
6070     // When running crankshaft, changing the map is not enough. We
6071     // need to deoptimize all functions that rely on this global
6072     // object.
6073     Deoptimizer::DeoptimizeGlobalObject(*object);
6074   }
6075 
6076   // Update the dictionary with the new CALLBACKS property.
6077   PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
6078   SetNormalizedProperty(object, name, structure, details);
6079 
6080   ReoptimizeIfPrototype(object);
6081 }
6082 
6083 
DefineAccessor(Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)6084 MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
6085                                              Handle<Name> name,
6086                                              Handle<Object> getter,
6087                                              Handle<Object> setter,
6088                                              PropertyAttributes attributes) {
6089   Isolate* isolate = object->GetIsolate();
6090   // Check access rights if needed.
6091   if (object->IsAccessCheckNeeded() &&
6092       !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6093     isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6094     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6095     return isolate->factory()->undefined_value();
6096   }
6097 
6098   if (object->IsJSGlobalProxy()) {
6099     PrototypeIterator iter(isolate, object);
6100     if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
6101     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
6102     DefineAccessor(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
6103                    name, getter, setter, attributes);
6104     return isolate->factory()->undefined_value();
6105   }
6106 
6107   // Make sure that the top context does not change when doing callbacks or
6108   // interceptor calls.
6109   AssertNoContextChange ncc(isolate);
6110 
6111   // Try to flatten before operating on the string.
6112   if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
6113 
6114   uint32_t index = 0;
6115   bool is_element = name->AsArrayIndex(&index);
6116 
6117   Handle<Object> old_value = isolate->factory()->the_hole_value();
6118   bool is_observed = object->map()->is_observed() &&
6119                      *name != isolate->heap()->hidden_string();
6120   bool preexists = false;
6121   if (is_observed) {
6122     if (is_element) {
6123       Maybe<bool> maybe = HasOwnElement(object, index);
6124       // Workaround for a GCC 4.4.3 bug which leads to "‘preexists’ may be used
6125       // uninitialized in this function".
6126       if (!maybe.has_value) {
6127         DCHECK(false);
6128         return isolate->factory()->undefined_value();
6129       }
6130       preexists = maybe.value;
6131       if (preexists && GetOwnElementAccessorPair(object, index).is_null()) {
6132         old_value =
6133             Object::GetElement(isolate, object, index).ToHandleChecked();
6134       }
6135     } else {
6136       LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
6137       CHECK(GetPropertyAttributes(&it).has_value);
6138       preexists = it.IsFound();
6139       if (preexists && (it.state() == LookupIterator::DATA ||
6140                         it.GetAccessors()->IsAccessorInfo())) {
6141         old_value = GetProperty(&it).ToHandleChecked();
6142       }
6143     }
6144   }
6145 
6146   if (is_element) {
6147     DefineElementAccessor(object, index, getter, setter, attributes);
6148   } else {
6149     DCHECK(getter->IsSpecFunction() || getter->IsUndefined() ||
6150            getter->IsNull());
6151     DCHECK(setter->IsSpecFunction() || setter->IsUndefined() ||
6152            setter->IsNull());
6153     // At least one of the accessors needs to be a new value.
6154     DCHECK(!getter->IsNull() || !setter->IsNull());
6155     LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
6156     if (it.state() == LookupIterator::ACCESS_CHECK) {
6157       // We already did an access check before. We do have access.
6158       it.Next();
6159     }
6160     if (!getter->IsNull()) {
6161       it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
6162     }
6163     if (!setter->IsNull()) {
6164       it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
6165     }
6166   }
6167 
6168   if (is_observed) {
6169     const char* type = preexists ? "reconfigure" : "add";
6170     EnqueueChangeRecord(object, type, name, old_value);
6171   }
6172 
6173   return isolate->factory()->undefined_value();
6174 }
6175 
6176 
SetAccessor(Handle<JSObject> object,Handle<AccessorInfo> info)6177 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
6178                                           Handle<AccessorInfo> info) {
6179   Isolate* isolate = object->GetIsolate();
6180   Factory* factory = isolate->factory();
6181   Handle<Name> name(Name::cast(info->name()));
6182 
6183   // Check access rights if needed.
6184   if (object->IsAccessCheckNeeded() &&
6185       !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6186     isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6187     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6188     return factory->undefined_value();
6189   }
6190 
6191   if (object->IsJSGlobalProxy()) {
6192     PrototypeIterator iter(isolate, object);
6193     if (iter.IsAtEnd()) return object;
6194     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
6195     return SetAccessor(
6196         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), info);
6197   }
6198 
6199   // Make sure that the top context does not change when doing callbacks or
6200   // interceptor calls.
6201   AssertNoContextChange ncc(isolate);
6202 
6203   // Try to flatten before operating on the string.
6204   if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
6205 
6206   uint32_t index = 0;
6207   bool is_element = name->AsArrayIndex(&index);
6208 
6209   if (is_element) {
6210     if (object->IsJSArray()) return factory->undefined_value();
6211 
6212     // Accessors overwrite previous callbacks (cf. with getters/setters).
6213     switch (object->GetElementsKind()) {
6214       case FAST_SMI_ELEMENTS:
6215       case FAST_ELEMENTS:
6216       case FAST_DOUBLE_ELEMENTS:
6217       case FAST_HOLEY_SMI_ELEMENTS:
6218       case FAST_HOLEY_ELEMENTS:
6219       case FAST_HOLEY_DOUBLE_ELEMENTS:
6220         break;
6221 
6222 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
6223       case EXTERNAL_##TYPE##_ELEMENTS:                                         \
6224       case TYPE##_ELEMENTS:                                                    \
6225 
6226       TYPED_ARRAYS(TYPED_ARRAY_CASE)
6227 #undef TYPED_ARRAY_CASE
6228         // Ignore getters and setters on pixel and external array
6229         // elements.
6230         return factory->undefined_value();
6231 
6232       case DICTIONARY_ELEMENTS:
6233         break;
6234       case SLOPPY_ARGUMENTS_ELEMENTS:
6235         UNIMPLEMENTED();
6236         break;
6237     }
6238 
6239     SetElementCallback(object, index, info, info->property_attributes());
6240   } else {
6241     // Lookup the name.
6242     LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
6243     CHECK(GetPropertyAttributes(&it).has_value);
6244     // ES5 forbids turning a property into an accessor if it's not
6245     // configurable. See 8.6.1 (Table 5).
6246     if (it.IsFound() && (it.IsReadOnly() || !it.IsConfigurable())) {
6247       return factory->undefined_value();
6248     }
6249 
6250     SetPropertyCallback(object, name, info, info->property_attributes());
6251   }
6252 
6253   return object;
6254 }
6255 
6256 
GetAccessor(Handle<JSObject> object,Handle<Name> name,AccessorComponent component)6257 MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
6258                                           Handle<Name> name,
6259                                           AccessorComponent component) {
6260   Isolate* isolate = object->GetIsolate();
6261 
6262   // Make sure that the top context does not change when doing callbacks or
6263   // interceptor calls.
6264   AssertNoContextChange ncc(isolate);
6265 
6266   // Make the lookup and include prototypes.
6267   uint32_t index = 0;
6268   if (name->AsArrayIndex(&index)) {
6269     for (PrototypeIterator iter(isolate, object,
6270                                 PrototypeIterator::START_AT_RECEIVER);
6271          !iter.IsAtEnd(); iter.Advance()) {
6272       Handle<Object> current = PrototypeIterator::GetCurrent(iter);
6273       // Check access rights if needed.
6274       if (current->IsAccessCheckNeeded() &&
6275           !isolate->MayNamedAccess(Handle<JSObject>::cast(current), name,
6276                                    v8::ACCESS_HAS)) {
6277         isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(current),
6278                                          v8::ACCESS_HAS);
6279         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6280         return isolate->factory()->undefined_value();
6281       }
6282 
6283       if (current->IsJSObject() &&
6284           Handle<JSObject>::cast(current)->HasDictionaryElements()) {
6285         JSObject* js_object = JSObject::cast(*current);
6286         SeededNumberDictionary* dictionary = js_object->element_dictionary();
6287         int entry = dictionary->FindEntry(index);
6288         if (entry != SeededNumberDictionary::kNotFound) {
6289           Object* element = dictionary->ValueAt(entry);
6290           if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
6291               element->IsAccessorPair()) {
6292             return handle(AccessorPair::cast(element)->GetComponent(component),
6293                           isolate);
6294           }
6295         }
6296       }
6297     }
6298   } else {
6299     LookupIterator it(object, name,
6300                       LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
6301     for (; it.IsFound(); it.Next()) {
6302       switch (it.state()) {
6303         case LookupIterator::INTERCEPTOR:
6304         case LookupIterator::NOT_FOUND:
6305         case LookupIterator::TRANSITION:
6306           UNREACHABLE();
6307 
6308         case LookupIterator::ACCESS_CHECK:
6309           if (it.HasAccess(v8::ACCESS_HAS)) continue;
6310           isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
6311                                            v8::ACCESS_HAS);
6312           RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6313           return isolate->factory()->undefined_value();
6314 
6315         case LookupIterator::JSPROXY:
6316           return isolate->factory()->undefined_value();
6317 
6318         case LookupIterator::DATA:
6319           continue;
6320         case LookupIterator::ACCESSOR: {
6321           Handle<Object> maybe_pair = it.GetAccessors();
6322           if (maybe_pair->IsAccessorPair()) {
6323             return handle(
6324                 AccessorPair::cast(*maybe_pair)->GetComponent(component),
6325                 isolate);
6326           }
6327         }
6328       }
6329     }
6330   }
6331   return isolate->factory()->undefined_value();
6332 }
6333 
6334 
SlowReverseLookup(Object * value)6335 Object* JSObject::SlowReverseLookup(Object* value) {
6336   if (HasFastProperties()) {
6337     int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
6338     DescriptorArray* descs = map()->instance_descriptors();
6339     for (int i = 0; i < number_of_own_descriptors; i++) {
6340       if (descs->GetType(i) == FIELD) {
6341         Object* property =
6342             RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i));
6343         if (descs->GetDetails(i).representation().IsDouble()) {
6344           DCHECK(property->IsMutableHeapNumber());
6345           if (value->IsNumber() && property->Number() == value->Number()) {
6346             return descs->GetKey(i);
6347           }
6348         } else if (property == value) {
6349           return descs->GetKey(i);
6350         }
6351       } else if (descs->GetType(i) == CONSTANT) {
6352         if (descs->GetConstant(i) == value) {
6353           return descs->GetKey(i);
6354         }
6355       }
6356     }
6357     return GetHeap()->undefined_value();
6358   } else {
6359     return property_dictionary()->SlowReverseLookup(value);
6360   }
6361 }
6362 
6363 
RawCopy(Handle<Map> map,int instance_size)6364 Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
6365   Handle<Map> result = map->GetIsolate()->factory()->NewMap(
6366       map->instance_type(), instance_size);
6367   result->set_prototype(map->prototype());
6368   result->set_constructor(map->constructor());
6369   result->set_bit_field(map->bit_field());
6370   result->set_bit_field2(map->bit_field2());
6371   int new_bit_field3 = map->bit_field3();
6372   new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
6373   new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
6374   new_bit_field3 = EnumLengthBits::update(new_bit_field3,
6375                                           kInvalidEnumCacheSentinel);
6376   new_bit_field3 = Deprecated::update(new_bit_field3, false);
6377   if (!map->is_dictionary_map()) {
6378     new_bit_field3 = IsUnstable::update(new_bit_field3, false);
6379   }
6380   new_bit_field3 = ConstructionCount::update(new_bit_field3,
6381                                              JSFunction::kNoSlackTracking);
6382   result->set_bit_field3(new_bit_field3);
6383   return result;
6384 }
6385 
6386 
Normalize(Handle<Map> fast_map,PropertyNormalizationMode mode)6387 Handle<Map> Map::Normalize(Handle<Map> fast_map,
6388                            PropertyNormalizationMode mode) {
6389   DCHECK(!fast_map->is_dictionary_map());
6390 
6391   Isolate* isolate = fast_map->GetIsolate();
6392   Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
6393                              isolate);
6394   bool use_cache = !maybe_cache->IsUndefined();
6395   Handle<NormalizedMapCache> cache;
6396   if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
6397 
6398   Handle<Map> new_map;
6399   if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
6400 #ifdef VERIFY_HEAP
6401     if (FLAG_verify_heap) new_map->DictionaryMapVerify();
6402 #endif
6403 #ifdef ENABLE_SLOW_DCHECKS
6404     if (FLAG_enable_slow_asserts) {
6405       // The cached map should match newly created normalized map bit-by-bit,
6406       // except for the code cache, which can contain some ics which can be
6407       // applied to the shared map.
6408       Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
6409 
6410       DCHECK(memcmp(fresh->address(),
6411                     new_map->address(),
6412                     Map::kCodeCacheOffset) == 0);
6413       STATIC_ASSERT(Map::kDependentCodeOffset ==
6414                     Map::kCodeCacheOffset + kPointerSize);
6415       int offset = Map::kDependentCodeOffset + kPointerSize;
6416       DCHECK(memcmp(fresh->address() + offset,
6417                     new_map->address() + offset,
6418                     Map::kSize - offset) == 0);
6419     }
6420 #endif
6421   } else {
6422     new_map = Map::CopyNormalized(fast_map, mode);
6423     if (use_cache) {
6424       cache->Set(fast_map, new_map);
6425       isolate->counters()->normalized_maps()->Increment();
6426     }
6427   }
6428   fast_map->NotifyLeafMapLayoutChange();
6429   return new_map;
6430 }
6431 
6432 
CopyNormalized(Handle<Map> map,PropertyNormalizationMode mode)6433 Handle<Map> Map::CopyNormalized(Handle<Map> map,
6434                                 PropertyNormalizationMode mode) {
6435   int new_instance_size = map->instance_size();
6436   if (mode == CLEAR_INOBJECT_PROPERTIES) {
6437     new_instance_size -= map->inobject_properties() * kPointerSize;
6438   }
6439 
6440   Handle<Map> result = RawCopy(map, new_instance_size);
6441 
6442   if (mode != CLEAR_INOBJECT_PROPERTIES) {
6443     result->set_inobject_properties(map->inobject_properties());
6444   }
6445 
6446   result->set_dictionary_map(true);
6447   result->set_migration_target(false);
6448 
6449 #ifdef VERIFY_HEAP
6450   if (FLAG_verify_heap) result->DictionaryMapVerify();
6451 #endif
6452 
6453   return result;
6454 }
6455 
6456 
CopyDropDescriptors(Handle<Map> map)6457 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
6458   Handle<Map> result = RawCopy(map, map->instance_size());
6459 
6460   // Please note instance_type and instance_size are set when allocated.
6461   result->set_inobject_properties(map->inobject_properties());
6462   result->set_unused_property_fields(map->unused_property_fields());
6463 
6464   result->set_pre_allocated_property_fields(
6465       map->pre_allocated_property_fields());
6466   result->ClearCodeCache(map->GetHeap());
6467   map->NotifyLeafMapLayoutChange();
6468   return result;
6469 }
6470 
6471 
ShareDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor)6472 Handle<Map> Map::ShareDescriptor(Handle<Map> map,
6473                                  Handle<DescriptorArray> descriptors,
6474                                  Descriptor* descriptor) {
6475   // Sanity check. This path is only to be taken if the map owns its descriptor
6476   // array, implying that its NumberOfOwnDescriptors equals the number of
6477   // descriptors in the descriptor array.
6478   DCHECK(map->NumberOfOwnDescriptors() ==
6479          map->instance_descriptors()->number_of_descriptors());
6480 
6481   Handle<Map> result = CopyDropDescriptors(map);
6482   Handle<Name> name = descriptor->GetKey();
6483 
6484   // Ensure there's space for the new descriptor in the shared descriptor array.
6485   if (descriptors->NumberOfSlackDescriptors() == 0) {
6486     int old_size = descriptors->number_of_descriptors();
6487     if (old_size == 0) {
6488       descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
6489     } else {
6490       EnsureDescriptorSlack(map, old_size < 4 ? 1 : old_size / 2);
6491       descriptors = handle(map->instance_descriptors());
6492     }
6493   }
6494 
6495   {
6496     DisallowHeapAllocation no_gc;
6497     descriptors->Append(descriptor);
6498     result->InitializeDescriptors(*descriptors);
6499   }
6500 
6501   DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
6502   ConnectTransition(map, result, name, SIMPLE_TRANSITION);
6503 
6504   return result;
6505 }
6506 
6507 
ConnectTransition(Handle<Map> parent,Handle<Map> child,Handle<Name> name,SimpleTransitionFlag flag)6508 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
6509                             Handle<Name> name, SimpleTransitionFlag flag) {
6510   parent->set_owns_descriptors(false);
6511   if (parent->is_prototype_map()) {
6512     DCHECK(child->is_prototype_map());
6513   } else {
6514     Handle<TransitionArray> transitions =
6515         TransitionArray::CopyInsert(parent, name, child, flag);
6516     parent->set_transitions(*transitions);
6517     child->SetBackPointer(*parent);
6518   }
6519 }
6520 
6521 
CopyReplaceDescriptors(Handle<Map> map,Handle<DescriptorArray> descriptors,TransitionFlag flag,MaybeHandle<Name> maybe_name,SimpleTransitionFlag simple_flag)6522 Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
6523                                         Handle<DescriptorArray> descriptors,
6524                                         TransitionFlag flag,
6525                                         MaybeHandle<Name> maybe_name,
6526                                         SimpleTransitionFlag simple_flag) {
6527   DCHECK(descriptors->IsSortedNoDuplicates());
6528 
6529   Handle<Map> result = CopyDropDescriptors(map);
6530   result->InitializeDescriptors(*descriptors);
6531 
6532   if (!map->is_prototype_map()) {
6533     if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
6534       Handle<Name> name;
6535       CHECK(maybe_name.ToHandle(&name));
6536       ConnectTransition(map, result, name, simple_flag);
6537     } else {
6538       int length = descriptors->number_of_descriptors();
6539       for (int i = 0; i < length; i++) {
6540         descriptors->SetRepresentation(i, Representation::Tagged());
6541         if (descriptors->GetDetails(i).type() == FIELD) {
6542           descriptors->SetValue(i, HeapType::Any());
6543         }
6544       }
6545     }
6546   }
6547 
6548   return result;
6549 }
6550 
6551 
6552 // Since this method is used to rewrite an existing transition tree, it can
6553 // always insert transitions without checking.
CopyInstallDescriptors(Handle<Map> map,int new_descriptor,Handle<DescriptorArray> descriptors)6554 Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
6555                                         int new_descriptor,
6556                                         Handle<DescriptorArray> descriptors) {
6557   DCHECK(descriptors->IsSortedNoDuplicates());
6558 
6559   Handle<Map> result = CopyDropDescriptors(map);
6560 
6561   result->InitializeDescriptors(*descriptors);
6562   result->SetNumberOfOwnDescriptors(new_descriptor + 1);
6563 
6564   int unused_property_fields = map->unused_property_fields();
6565   if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
6566     unused_property_fields = map->unused_property_fields() - 1;
6567     if (unused_property_fields < 0) {
6568       unused_property_fields += JSObject::kFieldsAdded;
6569     }
6570   }
6571 
6572   result->set_unused_property_fields(unused_property_fields);
6573 
6574   Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
6575   ConnectTransition(map, result, name, SIMPLE_TRANSITION);
6576 
6577   return result;
6578 }
6579 
6580 
CopyAsElementsKind(Handle<Map> map,ElementsKind kind,TransitionFlag flag)6581 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
6582                                     TransitionFlag flag) {
6583   if (flag == INSERT_TRANSITION) {
6584     DCHECK(!map->HasElementsTransition() ||
6585         ((map->elements_transition_map()->elements_kind() ==
6586           DICTIONARY_ELEMENTS ||
6587           IsExternalArrayElementsKind(
6588               map->elements_transition_map()->elements_kind())) &&
6589          (kind == DICTIONARY_ELEMENTS ||
6590           IsExternalArrayElementsKind(kind))));
6591     DCHECK(!IsFastElementsKind(kind) ||
6592            IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
6593     DCHECK(kind != map->elements_kind());
6594   }
6595 
6596   bool insert_transition =
6597       flag == INSERT_TRANSITION && !map->HasElementsTransition();
6598 
6599   if (insert_transition && map->owns_descriptors()) {
6600     // In case the map owned its own descriptors, share the descriptors and
6601     // transfer ownership to the new map.
6602     Handle<Map> new_map = CopyDropDescriptors(map);
6603 
6604     ConnectElementsTransition(map, new_map);
6605 
6606     new_map->set_elements_kind(kind);
6607     new_map->InitializeDescriptors(map->instance_descriptors());
6608     return new_map;
6609   }
6610 
6611   // In case the map did not own its own descriptors, a split is forced by
6612   // copying the map; creating a new descriptor array cell.
6613   // Create a new free-floating map only if we are not allowed to store it.
6614   Handle<Map> new_map = Copy(map);
6615 
6616   new_map->set_elements_kind(kind);
6617 
6618   if (insert_transition) {
6619     ConnectElementsTransition(map, new_map);
6620   }
6621 
6622   return new_map;
6623 }
6624 
6625 
CopyForObserved(Handle<Map> map)6626 Handle<Map> Map::CopyForObserved(Handle<Map> map) {
6627   DCHECK(!map->is_observed());
6628 
6629   Isolate* isolate = map->GetIsolate();
6630 
6631   // In case the map owned its own descriptors, share the descriptors and
6632   // transfer ownership to the new map.
6633   Handle<Map> new_map;
6634   if (map->owns_descriptors()) {
6635     new_map = CopyDropDescriptors(map);
6636   } else {
6637     DCHECK(!map->is_prototype_map());
6638     new_map = Copy(map);
6639   }
6640 
6641   new_map->set_is_observed();
6642   if (map->owns_descriptors()) {
6643     new_map->InitializeDescriptors(map->instance_descriptors());
6644   }
6645 
6646   Handle<Name> name = isolate->factory()->observed_symbol();
6647   ConnectTransition(map, new_map, name, FULL_TRANSITION);
6648 
6649   return new_map;
6650 }
6651 
6652 
Copy(Handle<Map> map)6653 Handle<Map> Map::Copy(Handle<Map> map) {
6654   Handle<DescriptorArray> descriptors(map->instance_descriptors());
6655   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
6656   Handle<DescriptorArray> new_descriptors =
6657       DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
6658   return CopyReplaceDescriptors(
6659       map, new_descriptors, OMIT_TRANSITION, MaybeHandle<Name>());
6660 }
6661 
6662 
Create(Isolate * isolate,int inobject_properties)6663 Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
6664   Handle<Map> copy = Copy(handle(isolate->object_function()->initial_map()));
6665 
6666   // Check that we do not overflow the instance size when adding the extra
6667   // inobject properties. If the instance size overflows, we allocate as many
6668   // properties as we can as inobject properties.
6669   int max_extra_properties =
6670       (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
6671 
6672   if (inobject_properties > max_extra_properties) {
6673     inobject_properties = max_extra_properties;
6674   }
6675 
6676   int new_instance_size =
6677       JSObject::kHeaderSize + kPointerSize * inobject_properties;
6678 
6679   // Adjust the map with the extra inobject properties.
6680   copy->set_inobject_properties(inobject_properties);
6681   copy->set_unused_property_fields(inobject_properties);
6682   copy->set_instance_size(new_instance_size);
6683   copy->set_visitor_id(StaticVisitorBase::GetVisitorId(*copy));
6684   return copy;
6685 }
6686 
6687 
CopyForFreeze(Handle<Map> map)6688 Handle<Map> Map::CopyForFreeze(Handle<Map> map) {
6689   int num_descriptors = map->NumberOfOwnDescriptors();
6690   Isolate* isolate = map->GetIsolate();
6691   Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
6692       handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN);
6693   Handle<Map> new_map = CopyReplaceDescriptors(
6694       map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol());
6695   new_map->freeze();
6696   new_map->set_is_extensible(false);
6697   new_map->set_elements_kind(DICTIONARY_ELEMENTS);
6698   return new_map;
6699 }
6700 
6701 
CanHoldValue(int descriptor,Object * value)6702 bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
6703   PropertyDetails details = GetDetails(descriptor);
6704   switch (details.type()) {
6705     case FIELD:
6706       return value->FitsRepresentation(details.representation()) &&
6707              GetFieldType(descriptor)->NowContains(value);
6708 
6709     case CONSTANT:
6710       DCHECK(GetConstant(descriptor) != value ||
6711              value->FitsRepresentation(details.representation()));
6712       return GetConstant(descriptor) == value;
6713 
6714     case CALLBACKS:
6715       return false;
6716 
6717     case NORMAL:
6718       UNREACHABLE();
6719       break;
6720   }
6721 
6722   UNREACHABLE();
6723   return false;
6724 }
6725 
6726 
PrepareForDataProperty(Handle<Map> map,int descriptor,Handle<Object> value)6727 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
6728                                         Handle<Object> value) {
6729   // Dictionaries can store any property value.
6730   if (map->is_dictionary_map()) return map;
6731 
6732   // Migrate to the newest map before storing the property.
6733   map = Update(map);
6734 
6735   Handle<DescriptorArray> descriptors(map->instance_descriptors());
6736 
6737   if (descriptors->CanHoldValue(descriptor, *value)) return map;
6738 
6739   Isolate* isolate = map->GetIsolate();
6740   Representation representation = value->OptimalRepresentation();
6741   Handle<HeapType> type = value->OptimalType(isolate, representation);
6742 
6743   return GeneralizeRepresentation(map, descriptor, representation, type,
6744                                   FORCE_FIELD);
6745 }
6746 
6747 
TransitionToDataProperty(Handle<Map> map,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes,StoreFromKeyed store_mode)6748 Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
6749                                           Handle<Object> value,
6750                                           PropertyAttributes attributes,
6751                                           StoreFromKeyed store_mode) {
6752   // Dictionary maps can always have additional data properties.
6753   if (map->is_dictionary_map()) return map;
6754 
6755   // Migrate to the newest map before storing the property.
6756   map = Update(map);
6757 
6758   int index = map->SearchTransition(*name);
6759   if (index != TransitionArray::kNotFound) {
6760     Handle<Map> transition(map->GetTransition(index));
6761     int descriptor = transition->LastAdded();
6762 
6763     // TODO(verwaest): Handle attributes better.
6764     DescriptorArray* descriptors = transition->instance_descriptors();
6765     if (descriptors->GetDetails(descriptor).attributes() != attributes) {
6766       return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
6767     }
6768 
6769     return Map::PrepareForDataProperty(transition, descriptor, value);
6770   }
6771 
6772   TransitionFlag flag = INSERT_TRANSITION;
6773   MaybeHandle<Map> maybe_map;
6774   if (value->IsJSFunction()) {
6775     maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
6776   } else if (!map->TooManyFastProperties(store_mode)) {
6777     Isolate* isolate = name->GetIsolate();
6778     Representation representation = value->OptimalRepresentation();
6779     Handle<HeapType> type = value->OptimalType(isolate, representation);
6780     maybe_map =
6781         Map::CopyWithField(map, name, type, attributes, representation, flag);
6782   }
6783 
6784   Handle<Map> result;
6785   if (!maybe_map.ToHandle(&result)) {
6786     return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
6787   }
6788 
6789   return result;
6790 }
6791 
6792 
ReconfigureDataProperty(Handle<Map> map,int descriptor,PropertyAttributes attributes)6793 Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
6794                                          PropertyAttributes attributes) {
6795   // Dictionaries have to be reconfigured in-place.
6796   DCHECK(!map->is_dictionary_map());
6797 
6798   // For now, give up on transitioning and just create a unique map.
6799   // TODO(verwaest/ishell): Cache transitions with different attributes.
6800   return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD,
6801                                           attributes, "attributes mismatch");
6802 }
6803 
6804 
TransitionToAccessorProperty(Handle<Map> map,Handle<Name> name,AccessorComponent component,Handle<Object> accessor,PropertyAttributes attributes)6805 Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
6806                                               Handle<Name> name,
6807                                               AccessorComponent component,
6808                                               Handle<Object> accessor,
6809                                               PropertyAttributes attributes) {
6810   Isolate* isolate = name->GetIsolate();
6811 
6812   // Dictionary maps can always have additional data properties.
6813   if (map->is_dictionary_map()) {
6814     // For global objects, property cells are inlined. We need to change the
6815     // map.
6816     if (map->IsGlobalObjectMap()) return Copy(map);
6817     return map;
6818   }
6819 
6820   // Migrate to the newest map before transitioning to the new property.
6821   map = Update(map);
6822 
6823   PropertyNormalizationMode mode = map->is_prototype_map()
6824                                        ? KEEP_INOBJECT_PROPERTIES
6825                                        : CLEAR_INOBJECT_PROPERTIES;
6826 
6827   int index = map->SearchTransition(*name);
6828   if (index != TransitionArray::kNotFound) {
6829     Handle<Map> transition(map->GetTransition(index));
6830     DescriptorArray* descriptors = transition->instance_descriptors();
6831     // Fast path, assume that we're modifying the last added descriptor.
6832     int descriptor = transition->LastAdded();
6833     if (descriptors->GetKey(descriptor) != *name) {
6834       // If not, search for the descriptor.
6835       descriptor = descriptors->SearchWithCache(*name, *transition);
6836     }
6837 
6838     if (descriptors->GetDetails(descriptor).type() != CALLBACKS) {
6839       return Map::Normalize(map, mode);
6840     }
6841 
6842     // TODO(verwaest): Handle attributes better.
6843     if (descriptors->GetDetails(descriptor).attributes() != attributes) {
6844       return Map::Normalize(map, mode);
6845     }
6846 
6847     Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
6848     if (!maybe_pair->IsAccessorPair()) {
6849       return Map::Normalize(map, mode);
6850     }
6851 
6852     Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
6853     if (pair->get(component) != *accessor) {
6854       return Map::Normalize(map, mode);
6855     }
6856 
6857     return transition;
6858   }
6859 
6860   Handle<AccessorPair> pair;
6861   DescriptorArray* old_descriptors = map->instance_descriptors();
6862   int descriptor = old_descriptors->SearchWithCache(*name, *map);
6863   if (descriptor != DescriptorArray::kNotFound) {
6864     PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
6865     if (old_details.type() != CALLBACKS) {
6866       return Map::Normalize(map, mode);
6867     }
6868 
6869     if (old_details.attributes() != attributes) {
6870       return Map::Normalize(map, mode);
6871     }
6872 
6873     Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
6874     if (!maybe_pair->IsAccessorPair()) {
6875       return Map::Normalize(map, mode);
6876     }
6877 
6878     Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
6879     if (current == *accessor) return map;
6880 
6881     if (!current->IsTheHole()) {
6882       return Map::Normalize(map, mode);
6883     }
6884 
6885     pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
6886   } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
6887              map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
6888     return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
6889   } else {
6890     pair = isolate->factory()->NewAccessorPair();
6891   }
6892 
6893   pair->set(component, *accessor);
6894   TransitionFlag flag = INSERT_TRANSITION;
6895   CallbacksDescriptor new_desc(name, pair, attributes);
6896   return Map::CopyInsertDescriptor(map, &new_desc, flag);
6897 }
6898 
6899 
CopyAddDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)6900 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
6901                                    Descriptor* descriptor,
6902                                    TransitionFlag flag) {
6903   Handle<DescriptorArray> descriptors(map->instance_descriptors());
6904 
6905   // Ensure the key is unique.
6906   descriptor->KeyToUniqueName();
6907 
6908   if (flag == INSERT_TRANSITION &&
6909       map->owns_descriptors() &&
6910       map->CanHaveMoreTransitions()) {
6911     return ShareDescriptor(map, descriptors, descriptor);
6912   }
6913 
6914   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
6915       descriptors, map->NumberOfOwnDescriptors(), 1);
6916   new_descriptors->Append(descriptor);
6917 
6918   return CopyReplaceDescriptors(
6919       map, new_descriptors, flag, descriptor->GetKey(), SIMPLE_TRANSITION);
6920 }
6921 
6922 
CopyInsertDescriptor(Handle<Map> map,Descriptor * descriptor,TransitionFlag flag)6923 Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
6924                                       Descriptor* descriptor,
6925                                       TransitionFlag flag) {
6926   Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
6927 
6928   // Ensure the key is unique.
6929   descriptor->KeyToUniqueName();
6930 
6931   // We replace the key if it is already present.
6932   int index = old_descriptors->SearchWithCache(*descriptor->GetKey(), *map);
6933   if (index != DescriptorArray::kNotFound) {
6934     return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
6935   }
6936   return CopyAddDescriptor(map, descriptor, flag);
6937 }
6938 
6939 
CopyUpTo(Handle<DescriptorArray> desc,int enumeration_index,int slack)6940 Handle<DescriptorArray> DescriptorArray::CopyUpTo(
6941     Handle<DescriptorArray> desc,
6942     int enumeration_index,
6943     int slack) {
6944   return DescriptorArray::CopyUpToAddAttributes(
6945       desc, enumeration_index, NONE, slack);
6946 }
6947 
6948 
CopyUpToAddAttributes(Handle<DescriptorArray> desc,int enumeration_index,PropertyAttributes attributes,int slack)6949 Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
6950     Handle<DescriptorArray> desc,
6951     int enumeration_index,
6952     PropertyAttributes attributes,
6953     int slack) {
6954   if (enumeration_index + slack == 0) {
6955     return desc->GetIsolate()->factory()->empty_descriptor_array();
6956   }
6957 
6958   int size = enumeration_index;
6959 
6960   Handle<DescriptorArray> descriptors =
6961       DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
6962   DescriptorArray::WhitenessWitness witness(*descriptors);
6963 
6964   if (attributes != NONE) {
6965     for (int i = 0; i < size; ++i) {
6966       Object* value = desc->GetValue(i);
6967       Name* key = desc->GetKey(i);
6968       PropertyDetails details = desc->GetDetails(i);
6969       // Bulk attribute changes never affect private properties.
6970       if (!key->IsSymbol() || !Symbol::cast(key)->is_private()) {
6971         int mask = DONT_DELETE | DONT_ENUM;
6972         // READ_ONLY is an invalid attribute for JS setters/getters.
6973         if (details.type() != CALLBACKS || !value->IsAccessorPair()) {
6974           mask |= READ_ONLY;
6975         }
6976         details = details.CopyAddAttributes(
6977             static_cast<PropertyAttributes>(attributes & mask));
6978       }
6979       Descriptor inner_desc(
6980           handle(key), handle(value, desc->GetIsolate()), details);
6981       descriptors->Set(i, &inner_desc, witness);
6982     }
6983   } else {
6984     for (int i = 0; i < size; ++i) {
6985       descriptors->CopyFrom(i, *desc, witness);
6986     }
6987   }
6988 
6989   if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
6990 
6991   return descriptors;
6992 }
6993 
6994 
CopyReplaceDescriptor(Handle<Map> map,Handle<DescriptorArray> descriptors,Descriptor * descriptor,int insertion_index,TransitionFlag flag)6995 Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
6996                                        Handle<DescriptorArray> descriptors,
6997                                        Descriptor* descriptor,
6998                                        int insertion_index,
6999                                        TransitionFlag flag) {
7000   // Ensure the key is unique.
7001   descriptor->KeyToUniqueName();
7002 
7003   Handle<Name> key = descriptor->GetKey();
7004   DCHECK(*key == descriptors->GetKey(insertion_index));
7005 
7006   Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
7007       descriptors, map->NumberOfOwnDescriptors());
7008 
7009   new_descriptors->Replace(insertion_index, descriptor);
7010 
7011   SimpleTransitionFlag simple_flag =
7012       (insertion_index == descriptors->number_of_descriptors() - 1)
7013       ? SIMPLE_TRANSITION
7014       : FULL_TRANSITION;
7015   return CopyReplaceDescriptors(map, new_descriptors, flag, key, simple_flag);
7016 }
7017 
7018 
UpdateCodeCache(Handle<Map> map,Handle<Name> name,Handle<Code> code)7019 void Map::UpdateCodeCache(Handle<Map> map,
7020                           Handle<Name> name,
7021                           Handle<Code> code) {
7022   Isolate* isolate = map->GetIsolate();
7023   HandleScope scope(isolate);
7024   // Allocate the code cache if not present.
7025   if (map->code_cache()->IsFixedArray()) {
7026     Handle<Object> result = isolate->factory()->NewCodeCache();
7027     map->set_code_cache(*result);
7028   }
7029 
7030   // Update the code cache.
7031   Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
7032   CodeCache::Update(code_cache, name, code);
7033 }
7034 
7035 
FindInCodeCache(Name * name,Code::Flags flags)7036 Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
7037   // Do a lookup if a code cache exists.
7038   if (!code_cache()->IsFixedArray()) {
7039     return CodeCache::cast(code_cache())->Lookup(name, flags);
7040   } else {
7041     return GetHeap()->undefined_value();
7042   }
7043 }
7044 
7045 
IndexInCodeCache(Object * name,Code * code)7046 int Map::IndexInCodeCache(Object* name, Code* code) {
7047   // Get the internal index if a code cache exists.
7048   if (!code_cache()->IsFixedArray()) {
7049     return CodeCache::cast(code_cache())->GetIndex(name, code);
7050   }
7051   return -1;
7052 }
7053 
7054 
RemoveFromCodeCache(Name * name,Code * code,int index)7055 void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
7056   // No GC is supposed to happen between a call to IndexInCodeCache and
7057   // RemoveFromCodeCache so the code cache must be there.
7058   DCHECK(!code_cache()->IsFixedArray());
7059   CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
7060 }
7061 
7062 
7063 // An iterator over all map transitions in an descriptor array, reusing the
7064 // constructor field of the map while it is running. Negative values in
7065 // the constructor field indicate an active map transition iteration. The
7066 // original constructor is restored after iterating over all entries.
7067 class IntrusiveMapTransitionIterator {
7068  public:
IntrusiveMapTransitionIterator(Map * map,TransitionArray * transition_array,Object * constructor)7069   IntrusiveMapTransitionIterator(
7070       Map* map, TransitionArray* transition_array, Object* constructor)
7071       : map_(map),
7072         transition_array_(transition_array),
7073         constructor_(constructor) { }
7074 
StartIfNotStarted()7075   void StartIfNotStarted() {
7076     DCHECK(!(*IteratorField())->IsSmi() || IsIterating());
7077     if (!(*IteratorField())->IsSmi()) {
7078       DCHECK(*IteratorField() == constructor_);
7079       *IteratorField() = Smi::FromInt(-1);
7080     }
7081   }
7082 
IsIterating()7083   bool IsIterating() {
7084     return (*IteratorField())->IsSmi() &&
7085            Smi::cast(*IteratorField())->value() < 0;
7086   }
7087 
Next()7088   Map* Next() {
7089     DCHECK(IsIterating());
7090     int value = Smi::cast(*IteratorField())->value();
7091     int index = -value - 1;
7092     int number_of_transitions = transition_array_->number_of_transitions();
7093     while (index < number_of_transitions) {
7094       *IteratorField() = Smi::FromInt(value - 1);
7095       return transition_array_->GetTarget(index);
7096     }
7097 
7098     *IteratorField() = constructor_;
7099     return NULL;
7100   }
7101 
7102  private:
IteratorField()7103   Object** IteratorField() {
7104     return HeapObject::RawField(map_, Map::kConstructorOffset);
7105   }
7106 
7107   Map* map_;
7108   TransitionArray* transition_array_;
7109   Object* constructor_;
7110 };
7111 
7112 
7113 // An iterator over all prototype transitions, reusing the constructor field
7114 // of the map while it is running.  Positive values in the constructor field
7115 // indicate an active prototype transition iteration. The original constructor
7116 // is restored after iterating over all entries.
7117 class IntrusivePrototypeTransitionIterator {
7118  public:
IntrusivePrototypeTransitionIterator(Map * map,HeapObject * proto_trans,Object * constructor)7119   IntrusivePrototypeTransitionIterator(
7120       Map* map, HeapObject* proto_trans, Object* constructor)
7121       : map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
7122 
StartIfNotStarted()7123   void StartIfNotStarted() {
7124     if (!(*IteratorField())->IsSmi()) {
7125       DCHECK(*IteratorField() == constructor_);
7126       *IteratorField() = Smi::FromInt(0);
7127     }
7128   }
7129 
IsIterating()7130   bool IsIterating() {
7131     return (*IteratorField())->IsSmi() &&
7132            Smi::cast(*IteratorField())->value() >= 0;
7133   }
7134 
Next()7135   Map* Next() {
7136     DCHECK(IsIterating());
7137     int transitionNumber = Smi::cast(*IteratorField())->value();
7138     if (transitionNumber < NumberOfTransitions()) {
7139       *IteratorField() = Smi::FromInt(transitionNumber + 1);
7140       return GetTransition(transitionNumber);
7141     }
7142     *IteratorField() = constructor_;
7143     return NULL;
7144   }
7145 
7146  private:
IteratorField()7147   Object** IteratorField() {
7148     return HeapObject::RawField(map_, Map::kConstructorOffset);
7149   }
7150 
NumberOfTransitions()7151   int NumberOfTransitions() {
7152     FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7153     Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
7154     return Smi::cast(num)->value();
7155   }
7156 
GetTransition(int transitionNumber)7157   Map* GetTransition(int transitionNumber) {
7158     FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7159     return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
7160   }
7161 
IndexFor(int transitionNumber)7162   int IndexFor(int transitionNumber) {
7163     return Map::kProtoTransitionHeaderSize +
7164         Map::kProtoTransitionMapOffset +
7165         transitionNumber * Map::kProtoTransitionElementsPerEntry;
7166   }
7167 
7168   Map* map_;
7169   HeapObject* proto_trans_;
7170   Object* constructor_;
7171 };
7172 
7173 
7174 // To traverse the transition tree iteratively, we have to store two kinds of
7175 // information in a map: The parent map in the traversal and which children of a
7176 // node have already been visited. To do this without additional memory, we
7177 // temporarily reuse two fields with known values:
7178 //
7179 //  (1) The map of the map temporarily holds the parent, and is restored to the
7180 //      meta map afterwards.
7181 //
7182 //  (2) The info which children have already been visited depends on which part
7183 //      of the map we currently iterate. We use the constructor field of the
7184 //      map to store the current index. We can do that because the constructor
7185 //      is the same for all involved maps.
7186 //
7187 //    (a) If we currently follow normal map transitions, we temporarily store
7188 //        the current index in the constructor field, and restore it to the
7189 //        original constructor afterwards. Note that a single descriptor can
7190 //        have 0, 1, or 2 transitions.
7191 //
7192 //    (b) If we currently follow prototype transitions, we temporarily store
7193 //        the current index in the constructor field, and restore it to the
7194 //        original constructor afterwards.
7195 //
7196 // Note that the child iterator is just a concatenation of two iterators: One
7197 // iterating over map transitions and one iterating over prototype transisitons.
7198 class TraversableMap : public Map {
7199  public:
7200   // Record the parent in the traversal within this map. Note that this destroys
7201   // this map's map!
SetParent(TraversableMap * parent)7202   void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7203 
7204   // Reset the current map's map, returning the parent previously stored in it.
GetAndResetParent()7205   TraversableMap* GetAndResetParent() {
7206     TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7207     set_map_no_write_barrier(GetHeap()->meta_map());
7208     return old_parent;
7209   }
7210 
7211   // If we have an unvisited child map, return that one and advance. If we have
7212   // none, return NULL and restore the overwritten constructor field.
ChildIteratorNext(Object * constructor)7213   TraversableMap* ChildIteratorNext(Object* constructor) {
7214     if (!HasTransitionArray()) return NULL;
7215 
7216     TransitionArray* transition_array = transitions();
7217     if (transition_array->HasPrototypeTransitions()) {
7218       HeapObject* proto_transitions =
7219           transition_array->GetPrototypeTransitions();
7220       IntrusivePrototypeTransitionIterator proto_iterator(this,
7221                                                           proto_transitions,
7222                                                           constructor);
7223       proto_iterator.StartIfNotStarted();
7224       if (proto_iterator.IsIterating()) {
7225         Map* next = proto_iterator.Next();
7226         if (next != NULL) return static_cast<TraversableMap*>(next);
7227       }
7228     }
7229 
7230     IntrusiveMapTransitionIterator transition_iterator(this,
7231                                                        transition_array,
7232                                                        constructor);
7233     transition_iterator.StartIfNotStarted();
7234     if (transition_iterator.IsIterating()) {
7235       Map* next = transition_iterator.Next();
7236       if (next != NULL) return static_cast<TraversableMap*>(next);
7237     }
7238 
7239     return NULL;
7240   }
7241 };
7242 
7243 
7244 // Traverse the transition tree in postorder without using the C++ stack by
7245 // doing pointer reversal.
TraverseTransitionTree(TraverseCallback callback,void * data)7246 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
7247   // Make sure that we do not allocate in the callback.
7248   DisallowHeapAllocation no_allocation;
7249 
7250   TraversableMap* current = static_cast<TraversableMap*>(this);
7251   // Get the root constructor here to restore it later when finished iterating
7252   // over maps.
7253   Object* root_constructor = constructor();
7254   while (true) {
7255     TraversableMap* child = current->ChildIteratorNext(root_constructor);
7256     if (child != NULL) {
7257       child->SetParent(current);
7258       current = child;
7259     } else {
7260       TraversableMap* parent = current->GetAndResetParent();
7261       callback(current, data);
7262       if (current == this) break;
7263       current = parent;
7264     }
7265   }
7266 }
7267 
7268 
Update(Handle<CodeCache> code_cache,Handle<Name> name,Handle<Code> code)7269 void CodeCache::Update(
7270     Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
7271   // The number of monomorphic stubs for normal load/store/call IC's can grow to
7272   // a large number and therefore they need to go into a hash table. They are
7273   // used to load global properties from cells.
7274   if (code->type() == Code::NORMAL) {
7275     // Make sure that a hash table is allocated for the normal load code cache.
7276     if (code_cache->normal_type_cache()->IsUndefined()) {
7277       Handle<Object> result =
7278           CodeCacheHashTable::New(code_cache->GetIsolate(),
7279                                   CodeCacheHashTable::kInitialSize);
7280       code_cache->set_normal_type_cache(*result);
7281     }
7282     UpdateNormalTypeCache(code_cache, name, code);
7283   } else {
7284     DCHECK(code_cache->default_cache()->IsFixedArray());
7285     UpdateDefaultCache(code_cache, name, code);
7286   }
7287 }
7288 
7289 
UpdateDefaultCache(Handle<CodeCache> code_cache,Handle<Name> name,Handle<Code> code)7290 void CodeCache::UpdateDefaultCache(
7291     Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
7292   // When updating the default code cache we disregard the type encoded in the
7293   // flags. This allows call constant stubs to overwrite call field
7294   // stubs, etc.
7295   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
7296 
7297   // First check whether we can update existing code cache without
7298   // extending it.
7299   Handle<FixedArray> cache = handle(code_cache->default_cache());
7300   int length = cache->length();
7301   {
7302     DisallowHeapAllocation no_alloc;
7303     int deleted_index = -1;
7304     for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7305       Object* key = cache->get(i);
7306       if (key->IsNull()) {
7307         if (deleted_index < 0) deleted_index = i;
7308         continue;
7309       }
7310       if (key->IsUndefined()) {
7311         if (deleted_index >= 0) i = deleted_index;
7312         cache->set(i + kCodeCacheEntryNameOffset, *name);
7313         cache->set(i + kCodeCacheEntryCodeOffset, *code);
7314         return;
7315       }
7316       if (name->Equals(Name::cast(key))) {
7317         Code::Flags found =
7318             Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
7319         if (Code::RemoveTypeFromFlags(found) == flags) {
7320           cache->set(i + kCodeCacheEntryCodeOffset, *code);
7321           return;
7322         }
7323       }
7324     }
7325 
7326     // Reached the end of the code cache.  If there were deleted
7327     // elements, reuse the space for the first of them.
7328     if (deleted_index >= 0) {
7329       cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
7330       cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
7331       return;
7332     }
7333   }
7334 
7335   // Extend the code cache with some new entries (at least one). Must be a
7336   // multiple of the entry size.
7337   int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
7338   new_length = new_length - new_length % kCodeCacheEntrySize;
7339   DCHECK((new_length % kCodeCacheEntrySize) == 0);
7340   cache = FixedArray::CopySize(cache, new_length);
7341 
7342   // Add the (name, code) pair to the new cache.
7343   cache->set(length + kCodeCacheEntryNameOffset, *name);
7344   cache->set(length + kCodeCacheEntryCodeOffset, *code);
7345   code_cache->set_default_cache(*cache);
7346 }
7347 
7348 
UpdateNormalTypeCache(Handle<CodeCache> code_cache,Handle<Name> name,Handle<Code> code)7349 void CodeCache::UpdateNormalTypeCache(
7350     Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
7351   // Adding a new entry can cause a new cache to be allocated.
7352   Handle<CodeCacheHashTable> cache(
7353       CodeCacheHashTable::cast(code_cache->normal_type_cache()));
7354   Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
7355   code_cache->set_normal_type_cache(*new_cache);
7356 }
7357 
7358 
Lookup(Name * name,Code::Flags flags)7359 Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
7360   Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
7361   if (result->IsCode()) {
7362     if (Code::cast(result)->flags() == flags) return result;
7363     return GetHeap()->undefined_value();
7364   }
7365   return LookupNormalTypeCache(name, flags);
7366 }
7367 
7368 
LookupDefaultCache(Name * name,Code::Flags flags)7369 Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
7370   FixedArray* cache = default_cache();
7371   int length = cache->length();
7372   for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7373     Object* key = cache->get(i + kCodeCacheEntryNameOffset);
7374     // Skip deleted elements.
7375     if (key->IsNull()) continue;
7376     if (key->IsUndefined()) return key;
7377     if (name->Equals(Name::cast(key))) {
7378       Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
7379       if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
7380         return code;
7381       }
7382     }
7383   }
7384   return GetHeap()->undefined_value();
7385 }
7386 
7387 
LookupNormalTypeCache(Name * name,Code::Flags flags)7388 Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
7389   if (!normal_type_cache()->IsUndefined()) {
7390     CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7391     return cache->Lookup(name, flags);
7392   } else {
7393     return GetHeap()->undefined_value();
7394   }
7395 }
7396 
7397 
GetIndex(Object * name,Code * code)7398 int CodeCache::GetIndex(Object* name, Code* code) {
7399   if (code->type() == Code::NORMAL) {
7400     if (normal_type_cache()->IsUndefined()) return -1;
7401     CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7402     return cache->GetIndex(Name::cast(name), code->flags());
7403   }
7404 
7405   FixedArray* array = default_cache();
7406   int len = array->length();
7407   for (int i = 0; i < len; i += kCodeCacheEntrySize) {
7408     if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
7409   }
7410   return -1;
7411 }
7412 
7413 
RemoveByIndex(Object * name,Code * code,int index)7414 void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
7415   if (code->type() == Code::NORMAL) {
7416     DCHECK(!normal_type_cache()->IsUndefined());
7417     CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7418     DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index);
7419     cache->RemoveByIndex(index);
7420   } else {
7421     FixedArray* array = default_cache();
7422     DCHECK(array->length() >= index && array->get(index)->IsCode());
7423     // Use null instead of undefined for deleted elements to distinguish
7424     // deleted elements from unused elements.  This distinction is used
7425     // when looking up in the cache and when updating the cache.
7426     DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
7427     array->set_null(index - 1);  // Name.
7428     array->set_null(index);  // Code.
7429   }
7430 }
7431 
7432 
7433 // The key in the code cache hash table consists of the property name and the
7434 // code object. The actual match is on the name and the code flags. If a key
7435 // is created using the flags and not a code object it can only be used for
7436 // lookup not to create a new entry.
7437 class CodeCacheHashTableKey : public HashTableKey {
7438  public:
CodeCacheHashTableKey(Handle<Name> name,Code::Flags flags)7439   CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
7440       : name_(name), flags_(flags), code_() { }
7441 
CodeCacheHashTableKey(Handle<Name> name,Handle<Code> code)7442   CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
7443       : name_(name), flags_(code->flags()), code_(code) { }
7444 
IsMatch(Object * other)7445   bool IsMatch(Object* other) OVERRIDE {
7446     if (!other->IsFixedArray()) return false;
7447     FixedArray* pair = FixedArray::cast(other);
7448     Name* name = Name::cast(pair->get(0));
7449     Code::Flags flags = Code::cast(pair->get(1))->flags();
7450     if (flags != flags_) {
7451       return false;
7452     }
7453     return name_->Equals(name);
7454   }
7455 
NameFlagsHashHelper(Name * name,Code::Flags flags)7456   static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
7457     return name->Hash() ^ flags;
7458   }
7459 
Hash()7460   uint32_t Hash() OVERRIDE { return NameFlagsHashHelper(*name_, flags_); }
7461 
HashForObject(Object * obj)7462   uint32_t HashForObject(Object* obj) OVERRIDE {
7463     FixedArray* pair = FixedArray::cast(obj);
7464     Name* name = Name::cast(pair->get(0));
7465     Code* code = Code::cast(pair->get(1));
7466     return NameFlagsHashHelper(name, code->flags());
7467   }
7468 
AsHandle(Isolate * isolate)7469   MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
7470     Handle<Code> code = code_.ToHandleChecked();
7471     Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
7472     pair->set(0, *name_);
7473     pair->set(1, *code);
7474     return pair;
7475   }
7476 
7477  private:
7478   Handle<Name> name_;
7479   Code::Flags flags_;
7480   // TODO(jkummerow): We should be able to get by without this.
7481   MaybeHandle<Code> code_;
7482 };
7483 
7484 
Lookup(Name * name,Code::Flags flags)7485 Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
7486   DisallowHeapAllocation no_alloc;
7487   CodeCacheHashTableKey key(handle(name), flags);
7488   int entry = FindEntry(&key);
7489   if (entry == kNotFound) return GetHeap()->undefined_value();
7490   return get(EntryToIndex(entry) + 1);
7491 }
7492 
7493 
Put(Handle<CodeCacheHashTable> cache,Handle<Name> name,Handle<Code> code)7494 Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
7495     Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
7496   CodeCacheHashTableKey key(name, code);
7497 
7498   Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
7499 
7500   int entry = new_cache->FindInsertionEntry(key.Hash());
7501   Handle<Object> k = key.AsHandle(cache->GetIsolate());
7502 
7503   new_cache->set(EntryToIndex(entry), *k);
7504   new_cache->set(EntryToIndex(entry) + 1, *code);
7505   new_cache->ElementAdded();
7506   return new_cache;
7507 }
7508 
7509 
GetIndex(Name * name,Code::Flags flags)7510 int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
7511   DisallowHeapAllocation no_alloc;
7512   CodeCacheHashTableKey key(handle(name), flags);
7513   int entry = FindEntry(&key);
7514   return (entry == kNotFound) ? -1 : entry;
7515 }
7516 
7517 
RemoveByIndex(int index)7518 void CodeCacheHashTable::RemoveByIndex(int index) {
7519   DCHECK(index >= 0);
7520   Heap* heap = GetHeap();
7521   set(EntryToIndex(index), heap->the_hole_value());
7522   set(EntryToIndex(index) + 1, heap->the_hole_value());
7523   ElementRemoved();
7524 }
7525 
7526 
Update(Handle<PolymorphicCodeCache> code_cache,MapHandleList * maps,Code::Flags flags,Handle<Code> code)7527 void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
7528                                   MapHandleList* maps,
7529                                   Code::Flags flags,
7530                                   Handle<Code> code) {
7531   Isolate* isolate = code_cache->GetIsolate();
7532   if (code_cache->cache()->IsUndefined()) {
7533     Handle<PolymorphicCodeCacheHashTable> result =
7534         PolymorphicCodeCacheHashTable::New(
7535             isolate,
7536             PolymorphicCodeCacheHashTable::kInitialSize);
7537     code_cache->set_cache(*result);
7538   } else {
7539     // This entry shouldn't be contained in the cache yet.
7540     DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
7541                ->Lookup(maps, flags)->IsUndefined());
7542   }
7543   Handle<PolymorphicCodeCacheHashTable> hash_table =
7544       handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
7545   Handle<PolymorphicCodeCacheHashTable> new_cache =
7546       PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
7547   code_cache->set_cache(*new_cache);
7548 }
7549 
7550 
Lookup(MapHandleList * maps,Code::Flags flags)7551 Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
7552                                             Code::Flags flags) {
7553   if (!cache()->IsUndefined()) {
7554     PolymorphicCodeCacheHashTable* hash_table =
7555         PolymorphicCodeCacheHashTable::cast(cache());
7556     return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
7557   } else {
7558     return GetIsolate()->factory()->undefined_value();
7559   }
7560 }
7561 
7562 
7563 // Despite their name, object of this class are not stored in the actual
7564 // hash table; instead they're temporarily used for lookups. It is therefore
7565 // safe to have a weak (non-owning) pointer to a MapList as a member field.
7566 class PolymorphicCodeCacheHashTableKey : public HashTableKey {
7567  public:
7568   // Callers must ensure that |maps| outlives the newly constructed object.
PolymorphicCodeCacheHashTableKey(MapHandleList * maps,int code_flags)7569   PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
7570       : maps_(maps),
7571         code_flags_(code_flags) {}
7572 
IsMatch(Object * other)7573   bool IsMatch(Object* other) OVERRIDE {
7574     MapHandleList other_maps(kDefaultListAllocationSize);
7575     int other_flags;
7576     FromObject(other, &other_flags, &other_maps);
7577     if (code_flags_ != other_flags) return false;
7578     if (maps_->length() != other_maps.length()) return false;
7579     // Compare just the hashes first because it's faster.
7580     int this_hash = MapsHashHelper(maps_, code_flags_);
7581     int other_hash = MapsHashHelper(&other_maps, other_flags);
7582     if (this_hash != other_hash) return false;
7583 
7584     // Full comparison: for each map in maps_, look for an equivalent map in
7585     // other_maps. This implementation is slow, but probably good enough for
7586     // now because the lists are short (<= 4 elements currently).
7587     for (int i = 0; i < maps_->length(); ++i) {
7588       bool match_found = false;
7589       for (int j = 0; j < other_maps.length(); ++j) {
7590         if (*(maps_->at(i)) == *(other_maps.at(j))) {
7591           match_found = true;
7592           break;
7593         }
7594       }
7595       if (!match_found) return false;
7596     }
7597     return true;
7598   }
7599 
MapsHashHelper(MapHandleList * maps,int code_flags)7600   static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
7601     uint32_t hash = code_flags;
7602     for (int i = 0; i < maps->length(); ++i) {
7603       hash ^= maps->at(i)->Hash();
7604     }
7605     return hash;
7606   }
7607 
Hash()7608   uint32_t Hash() OVERRIDE {
7609     return MapsHashHelper(maps_, code_flags_);
7610   }
7611 
HashForObject(Object * obj)7612   uint32_t HashForObject(Object* obj) OVERRIDE {
7613     MapHandleList other_maps(kDefaultListAllocationSize);
7614     int other_flags;
7615     FromObject(obj, &other_flags, &other_maps);
7616     return MapsHashHelper(&other_maps, other_flags);
7617   }
7618 
AsHandle(Isolate * isolate)7619   MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
7620     // The maps in |maps_| must be copied to a newly allocated FixedArray,
7621     // both because the referenced MapList is short-lived, and because C++
7622     // objects can't be stored in the heap anyway.
7623     Handle<FixedArray> list =
7624         isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
7625     list->set(0, Smi::FromInt(code_flags_));
7626     for (int i = 0; i < maps_->length(); ++i) {
7627       list->set(i + 1, *maps_->at(i));
7628     }
7629     return list;
7630   }
7631 
7632  private:
FromObject(Object * obj,int * code_flags,MapHandleList * maps)7633   static MapHandleList* FromObject(Object* obj,
7634                                    int* code_flags,
7635                                    MapHandleList* maps) {
7636     FixedArray* list = FixedArray::cast(obj);
7637     maps->Rewind(0);
7638     *code_flags = Smi::cast(list->get(0))->value();
7639     for (int i = 1; i < list->length(); ++i) {
7640       maps->Add(Handle<Map>(Map::cast(list->get(i))));
7641     }
7642     return maps;
7643   }
7644 
7645   MapHandleList* maps_;  // weak.
7646   int code_flags_;
7647   static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
7648 };
7649 
7650 
Lookup(MapHandleList * maps,int code_kind)7651 Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
7652                                               int code_kind) {
7653   DisallowHeapAllocation no_alloc;
7654   PolymorphicCodeCacheHashTableKey key(maps, code_kind);
7655   int entry = FindEntry(&key);
7656   if (entry == kNotFound) return GetHeap()->undefined_value();
7657   return get(EntryToIndex(entry) + 1);
7658 }
7659 
7660 
Put(Handle<PolymorphicCodeCacheHashTable> hash_table,MapHandleList * maps,int code_kind,Handle<Code> code)7661 Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
7662       Handle<PolymorphicCodeCacheHashTable> hash_table,
7663       MapHandleList* maps,
7664       int code_kind,
7665       Handle<Code> code) {
7666   PolymorphicCodeCacheHashTableKey key(maps, code_kind);
7667   Handle<PolymorphicCodeCacheHashTable> cache =
7668       EnsureCapacity(hash_table, 1, &key);
7669   int entry = cache->FindInsertionEntry(key.Hash());
7670 
7671   Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
7672   cache->set(EntryToIndex(entry), *obj);
7673   cache->set(EntryToIndex(entry) + 1, *code);
7674   cache->ElementAdded();
7675   return cache;
7676 }
7677 
7678 
Shrink(int new_length)7679 void FixedArray::Shrink(int new_length) {
7680   DCHECK(0 <= new_length && new_length <= length());
7681   if (new_length < length()) {
7682     GetHeap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(
7683         this, length() - new_length);
7684   }
7685 }
7686 
7687 
AddKeysFromArrayLike(Handle<FixedArray> content,Handle<JSObject> array)7688 MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike(
7689     Handle<FixedArray> content,
7690     Handle<JSObject> array) {
7691   DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements());
7692   ElementsAccessor* accessor = array->GetElementsAccessor();
7693   Handle<FixedArray> result;
7694   ASSIGN_RETURN_ON_EXCEPTION(
7695       array->GetIsolate(), result,
7696       accessor->AddElementsToFixedArray(array, array, content),
7697       FixedArray);
7698 
7699 #ifdef ENABLE_SLOW_DCHECKS
7700   if (FLAG_enable_slow_asserts) {
7701     DisallowHeapAllocation no_allocation;
7702     for (int i = 0; i < result->length(); i++) {
7703       Object* current = result->get(i);
7704       DCHECK(current->IsNumber() || current->IsName());
7705     }
7706   }
7707 #endif
7708   return result;
7709 }
7710 
7711 
UnionOfKeys(Handle<FixedArray> first,Handle<FixedArray> second)7712 MaybeHandle<FixedArray> FixedArray::UnionOfKeys(Handle<FixedArray> first,
7713                                                 Handle<FixedArray> second) {
7714   ElementsAccessor* accessor = ElementsAccessor::ForArray(second);
7715   Handle<FixedArray> result;
7716   ASSIGN_RETURN_ON_EXCEPTION(
7717       first->GetIsolate(), result,
7718       accessor->AddElementsToFixedArray(
7719           Handle<Object>::null(),     // receiver
7720           Handle<JSObject>::null(),   // holder
7721           first,
7722           Handle<FixedArrayBase>::cast(second)),
7723       FixedArray);
7724 
7725 #ifdef ENABLE_SLOW_DCHECKS
7726   if (FLAG_enable_slow_asserts) {
7727     DisallowHeapAllocation no_allocation;
7728     for (int i = 0; i < result->length(); i++) {
7729       Object* current = result->get(i);
7730       DCHECK(current->IsNumber() || current->IsName());
7731     }
7732   }
7733 #endif
7734   return result;
7735 }
7736 
7737 
CopySize(Handle<FixedArray> array,int new_length,PretenureFlag pretenure)7738 Handle<FixedArray> FixedArray::CopySize(
7739     Handle<FixedArray> array, int new_length, PretenureFlag pretenure) {
7740   Isolate* isolate = array->GetIsolate();
7741   if (new_length == 0) return isolate->factory()->empty_fixed_array();
7742   Handle<FixedArray> result =
7743       isolate->factory()->NewFixedArray(new_length, pretenure);
7744   // Copy the content
7745   DisallowHeapAllocation no_gc;
7746   int len = array->length();
7747   if (new_length < len) len = new_length;
7748   // We are taking the map from the old fixed array so the map is sure to
7749   // be an immortal immutable object.
7750   result->set_map_no_write_barrier(array->map());
7751   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
7752   for (int i = 0; i < len; i++) {
7753     result->set(i, array->get(i), mode);
7754   }
7755   return result;
7756 }
7757 
7758 
CopyTo(int pos,FixedArray * dest,int dest_pos,int len)7759 void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
7760   DisallowHeapAllocation no_gc;
7761   WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
7762   for (int index = 0; index < len; index++) {
7763     dest->set(dest_pos+index, get(pos+index), mode);
7764   }
7765 }
7766 
7767 
7768 #ifdef DEBUG
IsEqualTo(FixedArray * other)7769 bool FixedArray::IsEqualTo(FixedArray* other) {
7770   if (length() != other->length()) return false;
7771   for (int i = 0 ; i < length(); ++i) {
7772     if (get(i) != other->get(i)) return false;
7773   }
7774   return true;
7775 }
7776 #endif
7777 
7778 
Allocate(Isolate * isolate,int number_of_descriptors,int slack)7779 Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
7780                                                   int number_of_descriptors,
7781                                                   int slack) {
7782   DCHECK(0 <= number_of_descriptors);
7783   Factory* factory = isolate->factory();
7784   // Do not use DescriptorArray::cast on incomplete object.
7785   int size = number_of_descriptors + slack;
7786   if (size == 0) return factory->empty_descriptor_array();
7787   // Allocate the array of keys.
7788   Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size));
7789 
7790   result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
7791   result->set(kEnumCacheIndex, Smi::FromInt(0));
7792   return Handle<DescriptorArray>::cast(result);
7793 }
7794 
7795 
ClearEnumCache()7796 void DescriptorArray::ClearEnumCache() {
7797   set(kEnumCacheIndex, Smi::FromInt(0));
7798 }
7799 
7800 
Replace(int index,Descriptor * descriptor)7801 void DescriptorArray::Replace(int index, Descriptor* descriptor) {
7802   descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
7803   Set(index, descriptor);
7804 }
7805 
7806 
SetEnumCache(FixedArray * bridge_storage,FixedArray * new_cache,Object * new_index_cache)7807 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
7808                                    FixedArray* new_cache,
7809                                    Object* new_index_cache) {
7810   DCHECK(bridge_storage->length() >= kEnumCacheBridgeLength);
7811   DCHECK(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
7812   DCHECK(!IsEmpty());
7813   DCHECK(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
7814   FixedArray::cast(bridge_storage)->
7815     set(kEnumCacheBridgeCacheIndex, new_cache);
7816   FixedArray::cast(bridge_storage)->
7817     set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
7818   set(kEnumCacheIndex, bridge_storage);
7819 }
7820 
7821 
CopyFrom(int index,DescriptorArray * src,const WhitenessWitness & witness)7822 void DescriptorArray::CopyFrom(int index,
7823                                DescriptorArray* src,
7824                                const WhitenessWitness& witness) {
7825   Object* value = src->GetValue(index);
7826   PropertyDetails details = src->GetDetails(index);
7827   Descriptor desc(handle(src->GetKey(index)),
7828                   handle(value, src->GetIsolate()),
7829                   details);
7830   Set(index, &desc, witness);
7831 }
7832 
7833 
7834 // We need the whiteness witness since sort will reshuffle the entries in the
7835 // descriptor array. If the descriptor array were to be black, the shuffling
7836 // would move a slot that was already recorded as pointing into an evacuation
7837 // candidate. This would result in missing updates upon evacuation.
Sort()7838 void DescriptorArray::Sort() {
7839   // In-place heap sort.
7840   int len = number_of_descriptors();
7841   // Reset sorting since the descriptor array might contain invalid pointers.
7842   for (int i = 0; i < len; ++i) SetSortedKey(i, i);
7843   // Bottom-up max-heap construction.
7844   // Index of the last node with children
7845   const int max_parent_index = (len / 2) - 1;
7846   for (int i = max_parent_index; i >= 0; --i) {
7847     int parent_index = i;
7848     const uint32_t parent_hash = GetSortedKey(i)->Hash();
7849     while (parent_index <= max_parent_index) {
7850       int child_index = 2 * parent_index + 1;
7851       uint32_t child_hash = GetSortedKey(child_index)->Hash();
7852       if (child_index + 1 < len) {
7853         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
7854         if (right_child_hash > child_hash) {
7855           child_index++;
7856           child_hash = right_child_hash;
7857         }
7858       }
7859       if (child_hash <= parent_hash) break;
7860       SwapSortedKeys(parent_index, child_index);
7861       // Now element at child_index could be < its children.
7862       parent_index = child_index;  // parent_hash remains correct.
7863     }
7864   }
7865 
7866   // Extract elements and create sorted array.
7867   for (int i = len - 1; i > 0; --i) {
7868     // Put max element at the back of the array.
7869     SwapSortedKeys(0, i);
7870     // Shift down the new top element.
7871     int parent_index = 0;
7872     const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
7873     const int max_parent_index = (i / 2) - 1;
7874     while (parent_index <= max_parent_index) {
7875       int child_index = parent_index * 2 + 1;
7876       uint32_t child_hash = GetSortedKey(child_index)->Hash();
7877       if (child_index + 1 < i) {
7878         uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
7879         if (right_child_hash > child_hash) {
7880           child_index++;
7881           child_hash = right_child_hash;
7882         }
7883       }
7884       if (child_hash <= parent_hash) break;
7885       SwapSortedKeys(parent_index, child_index);
7886       parent_index = child_index;
7887     }
7888   }
7889   DCHECK(IsSortedNoDuplicates());
7890 }
7891 
7892 
Copy(Handle<AccessorPair> pair)7893 Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
7894   Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
7895   copy->set_getter(pair->getter());
7896   copy->set_setter(pair->setter());
7897   return copy;
7898 }
7899 
7900 
GetComponent(AccessorComponent component)7901 Object* AccessorPair::GetComponent(AccessorComponent component) {
7902   Object* accessor = get(component);
7903   return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
7904 }
7905 
7906 
New(Isolate * isolate,int deopt_entry_count,PretenureFlag pretenure)7907 Handle<DeoptimizationInputData> DeoptimizationInputData::New(
7908     Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
7909   DCHECK(deopt_entry_count > 0);
7910   return Handle<DeoptimizationInputData>::cast(
7911       isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
7912                                         pretenure));
7913 }
7914 
7915 
New(Isolate * isolate,int number_of_deopt_points,PretenureFlag pretenure)7916 Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
7917     Isolate* isolate,
7918     int number_of_deopt_points,
7919     PretenureFlag pretenure) {
7920   Handle<FixedArray> result;
7921   if (number_of_deopt_points == 0) {
7922     result = isolate->factory()->empty_fixed_array();
7923   } else {
7924     result = isolate->factory()->NewFixedArray(
7925         LengthOfFixedArray(number_of_deopt_points), pretenure);
7926   }
7927   return Handle<DeoptimizationOutputData>::cast(result);
7928 }
7929 
7930 
7931 #ifdef DEBUG
IsEqualTo(DescriptorArray * other)7932 bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
7933   if (IsEmpty()) return other->IsEmpty();
7934   if (other->IsEmpty()) return false;
7935   if (length() != other->length()) return false;
7936   for (int i = 0; i < length(); ++i) {
7937     if (get(i) != other->get(i)) return false;
7938   }
7939   return true;
7940 }
7941 #endif
7942 
7943 
LooksValid()7944 bool String::LooksValid() {
7945   if (!GetIsolate()->heap()->Contains(this)) return false;
7946   return true;
7947 }
7948 
7949 
GetFlatContent()7950 String::FlatContent String::GetFlatContent() {
7951   DCHECK(!AllowHeapAllocation::IsAllowed());
7952   int length = this->length();
7953   StringShape shape(this);
7954   String* string = this;
7955   int offset = 0;
7956   if (shape.representation_tag() == kConsStringTag) {
7957     ConsString* cons = ConsString::cast(string);
7958     if (cons->second()->length() != 0) {
7959       return FlatContent();
7960     }
7961     string = cons->first();
7962     shape = StringShape(string);
7963   }
7964   if (shape.representation_tag() == kSlicedStringTag) {
7965     SlicedString* slice = SlicedString::cast(string);
7966     offset = slice->offset();
7967     string = slice->parent();
7968     shape = StringShape(string);
7969     DCHECK(shape.representation_tag() != kConsStringTag &&
7970            shape.representation_tag() != kSlicedStringTag);
7971   }
7972   if (shape.encoding_tag() == kOneByteStringTag) {
7973     const uint8_t* start;
7974     if (shape.representation_tag() == kSeqStringTag) {
7975       start = SeqOneByteString::cast(string)->GetChars();
7976     } else {
7977       start = ExternalOneByteString::cast(string)->GetChars();
7978     }
7979     return FlatContent(start + offset, length);
7980   } else {
7981     DCHECK(shape.encoding_tag() == kTwoByteStringTag);
7982     const uc16* start;
7983     if (shape.representation_tag() == kSeqStringTag) {
7984       start = SeqTwoByteString::cast(string)->GetChars();
7985     } else {
7986       start = ExternalTwoByteString::cast(string)->GetChars();
7987     }
7988     return FlatContent(start + offset, length);
7989   }
7990 }
7991 
7992 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int offset,int length,int * length_return)7993 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
7994                                           RobustnessFlag robust_flag,
7995                                           int offset,
7996                                           int length,
7997                                           int* length_return) {
7998   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
7999     return SmartArrayPointer<char>(NULL);
8000   }
8001   Heap* heap = GetHeap();
8002 
8003   // Negative length means the to the end of the string.
8004   if (length < 0) length = kMaxInt - offset;
8005 
8006   // Compute the size of the UTF-8 string. Start at the specified offset.
8007   Access<ConsStringIteratorOp> op(
8008       heap->isolate()->objects_string_iterator());
8009   StringCharacterStream stream(this, op.value(), offset);
8010   int character_position = offset;
8011   int utf8_bytes = 0;
8012   int last = unibrow::Utf16::kNoPreviousCharacter;
8013   while (stream.HasMore() && character_position++ < offset + length) {
8014     uint16_t character = stream.GetNext();
8015     utf8_bytes += unibrow::Utf8::Length(character, last);
8016     last = character;
8017   }
8018 
8019   if (length_return) {
8020     *length_return = utf8_bytes;
8021   }
8022 
8023   char* result = NewArray<char>(utf8_bytes + 1);
8024 
8025   // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
8026   stream.Reset(this, offset);
8027   character_position = offset;
8028   int utf8_byte_position = 0;
8029   last = unibrow::Utf16::kNoPreviousCharacter;
8030   while (stream.HasMore() && character_position++ < offset + length) {
8031     uint16_t character = stream.GetNext();
8032     if (allow_nulls == DISALLOW_NULLS && character == 0) {
8033       character = ' ';
8034     }
8035     utf8_byte_position +=
8036         unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
8037     last = character;
8038   }
8039   result[utf8_byte_position] = 0;
8040   return SmartArrayPointer<char>(result);
8041 }
8042 
8043 
ToCString(AllowNullsFlag allow_nulls,RobustnessFlag robust_flag,int * length_return)8044 SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8045                                           RobustnessFlag robust_flag,
8046                                           int* length_return) {
8047   return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
8048 }
8049 
8050 
GetTwoByteData(unsigned start)8051 const uc16* String::GetTwoByteData(unsigned start) {
8052   DCHECK(!IsOneByteRepresentationUnderneath());
8053   switch (StringShape(this).representation_tag()) {
8054     case kSeqStringTag:
8055       return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
8056     case kExternalStringTag:
8057       return ExternalTwoByteString::cast(this)->
8058         ExternalTwoByteStringGetData(start);
8059     case kSlicedStringTag: {
8060       SlicedString* slice = SlicedString::cast(this);
8061       return slice->parent()->GetTwoByteData(start + slice->offset());
8062     }
8063     case kConsStringTag:
8064       UNREACHABLE();
8065       return NULL;
8066   }
8067   UNREACHABLE();
8068   return NULL;
8069 }
8070 
8071 
ToWideCString(RobustnessFlag robust_flag)8072 SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
8073   if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
8074     return SmartArrayPointer<uc16>();
8075   }
8076   Heap* heap = GetHeap();
8077 
8078   Access<ConsStringIteratorOp> op(
8079       heap->isolate()->objects_string_iterator());
8080   StringCharacterStream stream(this, op.value());
8081 
8082   uc16* result = NewArray<uc16>(length() + 1);
8083 
8084   int i = 0;
8085   while (stream.HasMore()) {
8086     uint16_t character = stream.GetNext();
8087     result[i++] = character;
8088   }
8089   result[i] = 0;
8090   return SmartArrayPointer<uc16>(result);
8091 }
8092 
8093 
SeqTwoByteStringGetData(unsigned start)8094 const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
8095   return reinterpret_cast<uc16*>(
8096       reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
8097 }
8098 
8099 
PostGarbageCollectionProcessing(Isolate * isolate)8100 void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
8101   Relocatable* current = isolate->relocatable_top();
8102   while (current != NULL) {
8103     current->PostGarbageCollection();
8104     current = current->prev_;
8105   }
8106 }
8107 
8108 
8109 // Reserve space for statics needing saving and restoring.
ArchiveSpacePerThread()8110 int Relocatable::ArchiveSpacePerThread() {
8111   return sizeof(Relocatable*);  // NOLINT
8112 }
8113 
8114 
8115 // Archive statics that are thread-local.
ArchiveState(Isolate * isolate,char * to)8116 char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
8117   *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
8118   isolate->set_relocatable_top(NULL);
8119   return to + ArchiveSpacePerThread();
8120 }
8121 
8122 
8123 // Restore statics that are thread-local.
RestoreState(Isolate * isolate,char * from)8124 char* Relocatable::RestoreState(Isolate* isolate, char* from) {
8125   isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
8126   return from + ArchiveSpacePerThread();
8127 }
8128 
8129 
Iterate(ObjectVisitor * v,char * thread_storage)8130 char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
8131   Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
8132   Iterate(v, top);
8133   return thread_storage + ArchiveSpacePerThread();
8134 }
8135 
8136 
Iterate(Isolate * isolate,ObjectVisitor * v)8137 void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
8138   Iterate(v, isolate->relocatable_top());
8139 }
8140 
8141 
Iterate(ObjectVisitor * v,Relocatable * top)8142 void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
8143   Relocatable* current = top;
8144   while (current != NULL) {
8145     current->IterateInstance(v);
8146     current = current->prev_;
8147   }
8148 }
8149 
8150 
FlatStringReader(Isolate * isolate,Handle<String> str)8151 FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
8152     : Relocatable(isolate),
8153       str_(str.location()),
8154       length_(str->length()) {
8155   PostGarbageCollection();
8156 }
8157 
8158 
FlatStringReader(Isolate * isolate,Vector<const char> input)8159 FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
8160     : Relocatable(isolate),
8161       str_(0),
8162       is_one_byte_(true),
8163       length_(input.length()),
8164       start_(input.start()) {}
8165 
8166 
PostGarbageCollection()8167 void FlatStringReader::PostGarbageCollection() {
8168   if (str_ == NULL) return;
8169   Handle<String> str(str_);
8170   DCHECK(str->IsFlat());
8171   DisallowHeapAllocation no_gc;
8172   // This does not actually prevent the vector from being relocated later.
8173   String::FlatContent content = str->GetFlatContent();
8174   DCHECK(content.IsFlat());
8175   is_one_byte_ = content.IsOneByte();
8176   if (is_one_byte_) {
8177     start_ = content.ToOneByteVector().start();
8178   } else {
8179     start_ = content.ToUC16Vector().start();
8180   }
8181 }
8182 
8183 
Initialize(ConsString * cons_string,int offset)8184 void ConsStringIteratorOp::Initialize(ConsString* cons_string, int offset) {
8185   DCHECK(cons_string != NULL);
8186   root_ = cons_string;
8187   consumed_ = offset;
8188   // Force stack blown condition to trigger restart.
8189   depth_ = 1;
8190   maximum_depth_ = kStackSize + depth_;
8191   DCHECK(StackBlown());
8192 }
8193 
8194 
Continue(int * offset_out)8195 String* ConsStringIteratorOp::Continue(int* offset_out) {
8196   DCHECK(depth_ != 0);
8197   DCHECK_EQ(0, *offset_out);
8198   bool blew_stack = StackBlown();
8199   String* string = NULL;
8200   // Get the next leaf if there is one.
8201   if (!blew_stack) string = NextLeaf(&blew_stack);
8202   // Restart search from root.
8203   if (blew_stack) {
8204     DCHECK(string == NULL);
8205     string = Search(offset_out);
8206   }
8207   // Ensure future calls return null immediately.
8208   if (string == NULL) Reset(NULL);
8209   return string;
8210 }
8211 
8212 
Search(int * offset_out)8213 String* ConsStringIteratorOp::Search(int* offset_out) {
8214   ConsString* cons_string = root_;
8215   // Reset the stack, pushing the root string.
8216   depth_ = 1;
8217   maximum_depth_ = 1;
8218   frames_[0] = cons_string;
8219   const int consumed = consumed_;
8220   int offset = 0;
8221   while (true) {
8222     // Loop until the string is found which contains the target offset.
8223     String* string = cons_string->first();
8224     int length = string->length();
8225     int32_t type;
8226     if (consumed < offset + length) {
8227       // Target offset is in the left branch.
8228       // Keep going if we're still in a ConString.
8229       type = string->map()->instance_type();
8230       if ((type & kStringRepresentationMask) == kConsStringTag) {
8231         cons_string = ConsString::cast(string);
8232         PushLeft(cons_string);
8233         continue;
8234       }
8235       // Tell the stack we're done descending.
8236       AdjustMaximumDepth();
8237     } else {
8238       // Descend right.
8239       // Update progress through the string.
8240       offset += length;
8241       // Keep going if we're still in a ConString.
8242       string = cons_string->second();
8243       type = string->map()->instance_type();
8244       if ((type & kStringRepresentationMask) == kConsStringTag) {
8245         cons_string = ConsString::cast(string);
8246         PushRight(cons_string);
8247         continue;
8248       }
8249       // Need this to be updated for the current string.
8250       length = string->length();
8251       // Account for the possibility of an empty right leaf.
8252       // This happens only if we have asked for an offset outside the string.
8253       if (length == 0) {
8254         // Reset so future operations will return null immediately.
8255         Reset(NULL);
8256         return NULL;
8257       }
8258       // Tell the stack we're done descending.
8259       AdjustMaximumDepth();
8260       // Pop stack so next iteration is in correct place.
8261       Pop();
8262     }
8263     DCHECK(length != 0);
8264     // Adjust return values and exit.
8265     consumed_ = offset + length;
8266     *offset_out = consumed - offset;
8267     return string;
8268   }
8269   UNREACHABLE();
8270   return NULL;
8271 }
8272 
8273 
NextLeaf(bool * blew_stack)8274 String* ConsStringIteratorOp::NextLeaf(bool* blew_stack) {
8275   while (true) {
8276     // Tree traversal complete.
8277     if (depth_ == 0) {
8278       *blew_stack = false;
8279       return NULL;
8280     }
8281     // We've lost track of higher nodes.
8282     if (StackBlown()) {
8283       *blew_stack = true;
8284       return NULL;
8285     }
8286     // Go right.
8287     ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
8288     String* string = cons_string->second();
8289     int32_t type = string->map()->instance_type();
8290     if ((type & kStringRepresentationMask) != kConsStringTag) {
8291       // Pop stack so next iteration is in correct place.
8292       Pop();
8293       int length = string->length();
8294       // Could be a flattened ConsString.
8295       if (length == 0) continue;
8296       consumed_ += length;
8297       return string;
8298     }
8299     cons_string = ConsString::cast(string);
8300     PushRight(cons_string);
8301     // Need to traverse all the way left.
8302     while (true) {
8303       // Continue left.
8304       string = cons_string->first();
8305       type = string->map()->instance_type();
8306       if ((type & kStringRepresentationMask) != kConsStringTag) {
8307         AdjustMaximumDepth();
8308         int length = string->length();
8309         DCHECK(length != 0);
8310         consumed_ += length;
8311         return string;
8312       }
8313       cons_string = ConsString::cast(string);
8314       PushLeft(cons_string);
8315     }
8316   }
8317   UNREACHABLE();
8318   return NULL;
8319 }
8320 
8321 
ConsStringGet(int index)8322 uint16_t ConsString::ConsStringGet(int index) {
8323   DCHECK(index >= 0 && index < this->length());
8324 
8325   // Check for a flattened cons string
8326   if (second()->length() == 0) {
8327     String* left = first();
8328     return left->Get(index);
8329   }
8330 
8331   String* string = String::cast(this);
8332 
8333   while (true) {
8334     if (StringShape(string).IsCons()) {
8335       ConsString* cons_string = ConsString::cast(string);
8336       String* left = cons_string->first();
8337       if (left->length() > index) {
8338         string = left;
8339       } else {
8340         index -= left->length();
8341         string = cons_string->second();
8342       }
8343     } else {
8344       return string->Get(index);
8345     }
8346   }
8347 
8348   UNREACHABLE();
8349   return 0;
8350 }
8351 
8352 
SlicedStringGet(int index)8353 uint16_t SlicedString::SlicedStringGet(int index) {
8354   return parent()->Get(offset() + index);
8355 }
8356 
8357 
8358 template <typename sinkchar>
WriteToFlat(String * src,sinkchar * sink,int f,int t)8359 void String::WriteToFlat(String* src,
8360                          sinkchar* sink,
8361                          int f,
8362                          int t) {
8363   String* source = src;
8364   int from = f;
8365   int to = t;
8366   while (true) {
8367     DCHECK(0 <= from && from <= to && to <= source->length());
8368     switch (StringShape(source).full_representation_tag()) {
8369       case kOneByteStringTag | kExternalStringTag: {
8370         CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
8371                   to - from);
8372         return;
8373       }
8374       case kTwoByteStringTag | kExternalStringTag: {
8375         const uc16* data =
8376             ExternalTwoByteString::cast(source)->GetChars();
8377         CopyChars(sink,
8378                   data + from,
8379                   to - from);
8380         return;
8381       }
8382       case kOneByteStringTag | kSeqStringTag: {
8383         CopyChars(sink,
8384                   SeqOneByteString::cast(source)->GetChars() + from,
8385                   to - from);
8386         return;
8387       }
8388       case kTwoByteStringTag | kSeqStringTag: {
8389         CopyChars(sink,
8390                   SeqTwoByteString::cast(source)->GetChars() + from,
8391                   to - from);
8392         return;
8393       }
8394       case kOneByteStringTag | kConsStringTag:
8395       case kTwoByteStringTag | kConsStringTag: {
8396         ConsString* cons_string = ConsString::cast(source);
8397         String* first = cons_string->first();
8398         int boundary = first->length();
8399         if (to - boundary >= boundary - from) {
8400           // Right hand side is longer.  Recurse over left.
8401           if (from < boundary) {
8402             WriteToFlat(first, sink, from, boundary);
8403             sink += boundary - from;
8404             from = 0;
8405           } else {
8406             from -= boundary;
8407           }
8408           to -= boundary;
8409           source = cons_string->second();
8410         } else {
8411           // Left hand side is longer.  Recurse over right.
8412           if (to > boundary) {
8413             String* second = cons_string->second();
8414             // When repeatedly appending to a string, we get a cons string that
8415             // is unbalanced to the left, a list, essentially.  We inline the
8416             // common case of sequential one-byte right child.
8417             if (to - boundary == 1) {
8418               sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
8419             } else if (second->IsSeqOneByteString()) {
8420               CopyChars(sink + boundary - from,
8421                         SeqOneByteString::cast(second)->GetChars(),
8422                         to - boundary);
8423             } else {
8424               WriteToFlat(second,
8425                           sink + boundary - from,
8426                           0,
8427                           to - boundary);
8428             }
8429             to = boundary;
8430           }
8431           source = first;
8432         }
8433         break;
8434       }
8435       case kOneByteStringTag | kSlicedStringTag:
8436       case kTwoByteStringTag | kSlicedStringTag: {
8437         SlicedString* slice = SlicedString::cast(source);
8438         unsigned offset = slice->offset();
8439         WriteToFlat(slice->parent(), sink, from + offset, to + offset);
8440         return;
8441       }
8442     }
8443   }
8444 }
8445 
8446 
8447 
8448 template <typename SourceChar>
CalculateLineEndsImpl(Isolate * isolate,List<int> * line_ends,Vector<const SourceChar> src,bool include_ending_line)8449 static void CalculateLineEndsImpl(Isolate* isolate,
8450                                   List<int>* line_ends,
8451                                   Vector<const SourceChar> src,
8452                                   bool include_ending_line) {
8453   const int src_len = src.length();
8454   StringSearch<uint8_t, SourceChar> search(isolate, STATIC_CHAR_VECTOR("\n"));
8455 
8456   // Find and record line ends.
8457   int position = 0;
8458   while (position != -1 && position < src_len) {
8459     position = search.Search(src, position);
8460     if (position != -1) {
8461       line_ends->Add(position);
8462       position++;
8463     } else if (include_ending_line) {
8464       // Even if the last line misses a line end, it is counted.
8465       line_ends->Add(src_len);
8466       return;
8467     }
8468   }
8469 }
8470 
8471 
CalculateLineEnds(Handle<String> src,bool include_ending_line)8472 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
8473                                              bool include_ending_line) {
8474   src = Flatten(src);
8475   // Rough estimate of line count based on a roughly estimated average
8476   // length of (unpacked) code.
8477   int line_count_estimate = src->length() >> 4;
8478   List<int> line_ends(line_count_estimate);
8479   Isolate* isolate = src->GetIsolate();
8480   { DisallowHeapAllocation no_allocation;  // ensure vectors stay valid.
8481     // Dispatch on type of strings.
8482     String::FlatContent content = src->GetFlatContent();
8483     DCHECK(content.IsFlat());
8484     if (content.IsOneByte()) {
8485       CalculateLineEndsImpl(isolate,
8486                             &line_ends,
8487                             content.ToOneByteVector(),
8488                             include_ending_line);
8489     } else {
8490       CalculateLineEndsImpl(isolate,
8491                             &line_ends,
8492                             content.ToUC16Vector(),
8493                             include_ending_line);
8494     }
8495   }
8496   int line_count = line_ends.length();
8497   Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
8498   for (int i = 0; i < line_count; i++) {
8499     array->set(i, Smi::FromInt(line_ends[i]));
8500   }
8501   return array;
8502 }
8503 
8504 
8505 // Compares the contents of two strings by reading and comparing
8506 // int-sized blocks of characters.
8507 template <typename Char>
CompareRawStringContents(const Char * const a,const Char * const b,int length)8508 static inline bool CompareRawStringContents(const Char* const a,
8509                                             const Char* const b,
8510                                             int length) {
8511   return CompareChars(a, b, length) == 0;
8512 }
8513 
8514 
8515 template<typename Chars1, typename Chars2>
8516 class RawStringComparator : public AllStatic {
8517  public:
compare(const Chars1 * a,const Chars2 * b,int len)8518   static inline bool compare(const Chars1* a, const Chars2* b, int len) {
8519     DCHECK(sizeof(Chars1) != sizeof(Chars2));
8520     for (int i = 0; i < len; i++) {
8521       if (a[i] != b[i]) {
8522         return false;
8523       }
8524     }
8525     return true;
8526   }
8527 };
8528 
8529 
8530 template<>
8531 class RawStringComparator<uint16_t, uint16_t> {
8532  public:
compare(const uint16_t * a,const uint16_t * b,int len)8533   static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
8534     return CompareRawStringContents(a, b, len);
8535   }
8536 };
8537 
8538 
8539 template<>
8540 class RawStringComparator<uint8_t, uint8_t> {
8541  public:
compare(const uint8_t * a,const uint8_t * b,int len)8542   static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
8543     return CompareRawStringContents(a, b, len);
8544   }
8545 };
8546 
8547 
8548 class StringComparator {
8549   class State {
8550    public:
State(ConsStringIteratorOp * op)8551     explicit inline State(ConsStringIteratorOp* op)
8552       : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
8553 
Init(String * string)8554     inline void Init(String* string) {
8555       ConsString* cons_string = String::VisitFlat(this, string);
8556       op_->Reset(cons_string);
8557       if (cons_string != NULL) {
8558         int offset;
8559         string = op_->Next(&offset);
8560         String::VisitFlat(this, string, offset);
8561       }
8562     }
8563 
VisitOneByteString(const uint8_t * chars,int length)8564     inline void VisitOneByteString(const uint8_t* chars, int length) {
8565       is_one_byte_ = true;
8566       buffer8_ = chars;
8567       length_ = length;
8568     }
8569 
VisitTwoByteString(const uint16_t * chars,int length)8570     inline void VisitTwoByteString(const uint16_t* chars, int length) {
8571       is_one_byte_ = false;
8572       buffer16_ = chars;
8573       length_ = length;
8574     }
8575 
Advance(int consumed)8576     void Advance(int consumed) {
8577       DCHECK(consumed <= length_);
8578       // Still in buffer.
8579       if (length_ != consumed) {
8580         if (is_one_byte_) {
8581           buffer8_ += consumed;
8582         } else {
8583           buffer16_ += consumed;
8584         }
8585         length_ -= consumed;
8586         return;
8587       }
8588       // Advance state.
8589       int offset;
8590       String* next = op_->Next(&offset);
8591       DCHECK_EQ(0, offset);
8592       DCHECK(next != NULL);
8593       String::VisitFlat(this, next);
8594     }
8595 
8596     ConsStringIteratorOp* const op_;
8597     bool is_one_byte_;
8598     int length_;
8599     union {
8600       const uint8_t* buffer8_;
8601       const uint16_t* buffer16_;
8602     };
8603 
8604    private:
8605     DISALLOW_IMPLICIT_CONSTRUCTORS(State);
8606   };
8607 
8608  public:
StringComparator(ConsStringIteratorOp * op_1,ConsStringIteratorOp * op_2)8609   inline StringComparator(ConsStringIteratorOp* op_1,
8610                           ConsStringIteratorOp* op_2)
8611     : state_1_(op_1),
8612       state_2_(op_2) {
8613   }
8614 
8615   template<typename Chars1, typename Chars2>
Equals(State * state_1,State * state_2,int to_check)8616   static inline bool Equals(State* state_1, State* state_2, int to_check) {
8617     const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
8618     const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
8619     return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
8620   }
8621 
Equals(String * string_1,String * string_2)8622   bool Equals(String* string_1, String* string_2) {
8623     int length = string_1->length();
8624     state_1_.Init(string_1);
8625     state_2_.Init(string_2);
8626     while (true) {
8627       int to_check = Min(state_1_.length_, state_2_.length_);
8628       DCHECK(to_check > 0 && to_check <= length);
8629       bool is_equal;
8630       if (state_1_.is_one_byte_) {
8631         if (state_2_.is_one_byte_) {
8632           is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
8633         } else {
8634           is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
8635         }
8636       } else {
8637         if (state_2_.is_one_byte_) {
8638           is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
8639         } else {
8640           is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
8641         }
8642       }
8643       // Looping done.
8644       if (!is_equal) return false;
8645       length -= to_check;
8646       // Exit condition. Strings are equal.
8647       if (length == 0) return true;
8648       state_1_.Advance(to_check);
8649       state_2_.Advance(to_check);
8650     }
8651   }
8652 
8653  private:
8654   State state_1_;
8655   State state_2_;
8656   DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
8657 };
8658 
8659 
SlowEquals(String * other)8660 bool String::SlowEquals(String* other) {
8661   DisallowHeapAllocation no_gc;
8662   // Fast check: negative check with lengths.
8663   int len = length();
8664   if (len != other->length()) return false;
8665   if (len == 0) return true;
8666 
8667   // Fast check: if hash code is computed for both strings
8668   // a fast negative check can be performed.
8669   if (HasHashCode() && other->HasHashCode()) {
8670 #ifdef ENABLE_SLOW_DCHECKS
8671     if (FLAG_enable_slow_asserts) {
8672       if (Hash() != other->Hash()) {
8673         bool found_difference = false;
8674         for (int i = 0; i < len; i++) {
8675           if (Get(i) != other->Get(i)) {
8676             found_difference = true;
8677             break;
8678           }
8679         }
8680         DCHECK(found_difference);
8681       }
8682     }
8683 #endif
8684     if (Hash() != other->Hash()) return false;
8685   }
8686 
8687   // We know the strings are both non-empty. Compare the first chars
8688   // before we try to flatten the strings.
8689   if (this->Get(0) != other->Get(0)) return false;
8690 
8691   if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
8692     const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
8693     const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
8694     return CompareRawStringContents(str1, str2, len);
8695   }
8696 
8697   Isolate* isolate = GetIsolate();
8698   StringComparator comparator(isolate->objects_string_compare_iterator_a(),
8699                               isolate->objects_string_compare_iterator_b());
8700 
8701   return comparator.Equals(this, other);
8702 }
8703 
8704 
SlowEquals(Handle<String> one,Handle<String> two)8705 bool String::SlowEquals(Handle<String> one, Handle<String> two) {
8706   // Fast check: negative check with lengths.
8707   int one_length = one->length();
8708   if (one_length != two->length()) return false;
8709   if (one_length == 0) return true;
8710 
8711   // Fast check: if hash code is computed for both strings
8712   // a fast negative check can be performed.
8713   if (one->HasHashCode() && two->HasHashCode()) {
8714 #ifdef ENABLE_SLOW_DCHECKS
8715     if (FLAG_enable_slow_asserts) {
8716       if (one->Hash() != two->Hash()) {
8717         bool found_difference = false;
8718         for (int i = 0; i < one_length; i++) {
8719           if (one->Get(i) != two->Get(i)) {
8720             found_difference = true;
8721             break;
8722           }
8723         }
8724         DCHECK(found_difference);
8725       }
8726     }
8727 #endif
8728     if (one->Hash() != two->Hash()) return false;
8729   }
8730 
8731   // We know the strings are both non-empty. Compare the first chars
8732   // before we try to flatten the strings.
8733   if (one->Get(0) != two->Get(0)) return false;
8734 
8735   one = String::Flatten(one);
8736   two = String::Flatten(two);
8737 
8738   DisallowHeapAllocation no_gc;
8739   String::FlatContent flat1 = one->GetFlatContent();
8740   String::FlatContent flat2 = two->GetFlatContent();
8741 
8742   if (flat1.IsOneByte() && flat2.IsOneByte()) {
8743       return CompareRawStringContents(flat1.ToOneByteVector().start(),
8744                                       flat2.ToOneByteVector().start(),
8745                                       one_length);
8746   } else {
8747     for (int i = 0; i < one_length; i++) {
8748       if (flat1.Get(i) != flat2.Get(i)) return false;
8749     }
8750     return true;
8751   }
8752 }
8753 
8754 
MarkAsUndetectable()8755 bool String::MarkAsUndetectable() {
8756   if (StringShape(this).IsInternalized()) return false;
8757 
8758   Map* map = this->map();
8759   Heap* heap = GetHeap();
8760   if (map == heap->string_map()) {
8761     this->set_map(heap->undetectable_string_map());
8762     return true;
8763   } else if (map == heap->one_byte_string_map()) {
8764     this->set_map(heap->undetectable_one_byte_string_map());
8765     return true;
8766   }
8767   // Rest cannot be marked as undetectable
8768   return false;
8769 }
8770 
8771 
IsUtf8EqualTo(Vector<const char> str,bool allow_prefix_match)8772 bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
8773   int slen = length();
8774   // Can't check exact length equality, but we can check bounds.
8775   int str_len = str.length();
8776   if (!allow_prefix_match &&
8777       (str_len < slen ||
8778           str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
8779     return false;
8780   }
8781   int i;
8782   unsigned remaining_in_str = static_cast<unsigned>(str_len);
8783   const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
8784   for (i = 0; i < slen && remaining_in_str > 0; i++) {
8785     unsigned cursor = 0;
8786     uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
8787     DCHECK(cursor > 0 && cursor <= remaining_in_str);
8788     if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
8789       if (i > slen - 1) return false;
8790       if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
8791       if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
8792     } else {
8793       if (Get(i) != r) return false;
8794     }
8795     utf8_data += cursor;
8796     remaining_in_str -= cursor;
8797   }
8798   return (allow_prefix_match || i == slen) && remaining_in_str == 0;
8799 }
8800 
8801 
IsOneByteEqualTo(Vector<const uint8_t> str)8802 bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
8803   int slen = length();
8804   if (str.length() != slen) return false;
8805   DisallowHeapAllocation no_gc;
8806   FlatContent content = GetFlatContent();
8807   if (content.IsOneByte()) {
8808     return CompareChars(content.ToOneByteVector().start(),
8809                         str.start(), slen) == 0;
8810   }
8811   for (int i = 0; i < slen; i++) {
8812     if (Get(i) != static_cast<uint16_t>(str[i])) return false;
8813   }
8814   return true;
8815 }
8816 
8817 
IsTwoByteEqualTo(Vector<const uc16> str)8818 bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
8819   int slen = length();
8820   if (str.length() != slen) return false;
8821   DisallowHeapAllocation no_gc;
8822   FlatContent content = GetFlatContent();
8823   if (content.IsTwoByte()) {
8824     return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
8825   }
8826   for (int i = 0; i < slen; i++) {
8827     if (Get(i) != str[i]) return false;
8828   }
8829   return true;
8830 }
8831 
8832 
ComputeAndSetHash()8833 uint32_t String::ComputeAndSetHash() {
8834   // Should only be called if hash code has not yet been computed.
8835   DCHECK(!HasHashCode());
8836 
8837   // Store the hash code in the object.
8838   uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
8839   set_hash_field(field);
8840 
8841   // Check the hash code is there.
8842   DCHECK(HasHashCode());
8843   uint32_t result = field >> kHashShift;
8844   DCHECK(result != 0);  // Ensure that the hash value of 0 is never computed.
8845   return result;
8846 }
8847 
8848 
ComputeArrayIndex(uint32_t * index)8849 bool String::ComputeArrayIndex(uint32_t* index) {
8850   int length = this->length();
8851   if (length == 0 || length > kMaxArrayIndexSize) return false;
8852   ConsStringIteratorOp op;
8853   StringCharacterStream stream(this, &op);
8854   return StringToArrayIndex(&stream, index);
8855 }
8856 
8857 
SlowAsArrayIndex(uint32_t * index)8858 bool String::SlowAsArrayIndex(uint32_t* index) {
8859   if (length() <= kMaxCachedArrayIndexLength) {
8860     Hash();  // force computation of hash code
8861     uint32_t field = hash_field();
8862     if ((field & kIsNotArrayIndexMask) != 0) return false;
8863     // Isolate the array index form the full hash field.
8864     *index = ArrayIndexValueBits::decode(field);
8865     return true;
8866   } else {
8867     return ComputeArrayIndex(index);
8868   }
8869 }
8870 
8871 
Truncate(Handle<SeqString> string,int new_length)8872 Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
8873   int new_size, old_size;
8874   int old_length = string->length();
8875   if (old_length <= new_length) return string;
8876 
8877   if (string->IsSeqOneByteString()) {
8878     old_size = SeqOneByteString::SizeFor(old_length);
8879     new_size = SeqOneByteString::SizeFor(new_length);
8880   } else {
8881     DCHECK(string->IsSeqTwoByteString());
8882     old_size = SeqTwoByteString::SizeFor(old_length);
8883     new_size = SeqTwoByteString::SizeFor(new_length);
8884   }
8885 
8886   int delta = old_size - new_size;
8887 
8888   Address start_of_string = string->address();
8889   DCHECK_OBJECT_ALIGNED(start_of_string);
8890   DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
8891 
8892   Heap* heap = string->GetHeap();
8893   NewSpace* newspace = heap->new_space();
8894   if (newspace->Contains(start_of_string) &&
8895       newspace->top() == start_of_string + old_size) {
8896     // Last allocated object in new space.  Simply lower allocation top.
8897     newspace->set_top(start_of_string + new_size);
8898   } else {
8899     // Sizes are pointer size aligned, so that we can use filler objects
8900     // that are a multiple of pointer size.
8901     heap->CreateFillerObjectAt(start_of_string + new_size, delta);
8902   }
8903   heap->AdjustLiveBytes(start_of_string, -delta, Heap::FROM_MUTATOR);
8904 
8905   // We are storing the new length using release store after creating a filler
8906   // for the left-over space to avoid races with the sweeper thread.
8907   string->synchronized_set_length(new_length);
8908 
8909   if (new_length == 0) return heap->isolate()->factory()->empty_string();
8910   return string;
8911 }
8912 
8913 
MakeArrayIndexHash(uint32_t value,int length)8914 uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
8915   // For array indexes mix the length into the hash as an array index could
8916   // be zero.
8917   DCHECK(length > 0);
8918   DCHECK(length <= String::kMaxArrayIndexSize);
8919   DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
8920          (1 << String::kArrayIndexValueBits));
8921 
8922   value <<= String::ArrayIndexValueBits::kShift;
8923   value |= length << String::ArrayIndexLengthBits::kShift;
8924 
8925   DCHECK((value & String::kIsNotArrayIndexMask) == 0);
8926   DCHECK((length > String::kMaxCachedArrayIndexLength) ||
8927          (value & String::kContainsCachedArrayIndexMask) == 0);
8928   return value;
8929 }
8930 
8931 
GetHashField()8932 uint32_t StringHasher::GetHashField() {
8933   if (length_ <= String::kMaxHashCalcLength) {
8934     if (is_array_index_) {
8935       return MakeArrayIndexHash(array_index_, length_);
8936     }
8937     return (GetHashCore(raw_running_hash_) << String::kHashShift) |
8938            String::kIsNotArrayIndexMask;
8939   } else {
8940     return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
8941   }
8942 }
8943 
8944 
ComputeUtf8Hash(Vector<const char> chars,uint32_t seed,int * utf16_length_out)8945 uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
8946                                        uint32_t seed,
8947                                        int* utf16_length_out) {
8948   int vector_length = chars.length();
8949   // Handle some edge cases
8950   if (vector_length <= 1) {
8951     DCHECK(vector_length == 0 ||
8952            static_cast<uint8_t>(chars.start()[0]) <=
8953                unibrow::Utf8::kMaxOneByteChar);
8954     *utf16_length_out = vector_length;
8955     return HashSequentialString(chars.start(), vector_length, seed);
8956   }
8957   // Start with a fake length which won't affect computation.
8958   // It will be updated later.
8959   StringHasher hasher(String::kMaxArrayIndexSize, seed);
8960   unsigned remaining = static_cast<unsigned>(vector_length);
8961   const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
8962   int utf16_length = 0;
8963   bool is_index = true;
8964   DCHECK(hasher.is_array_index_);
8965   while (remaining > 0) {
8966     unsigned consumed = 0;
8967     uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
8968     DCHECK(consumed > 0 && consumed <= remaining);
8969     stream += consumed;
8970     remaining -= consumed;
8971     bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
8972     utf16_length += is_two_characters ? 2 : 1;
8973     // No need to keep hashing. But we do need to calculate utf16_length.
8974     if (utf16_length > String::kMaxHashCalcLength) continue;
8975     if (is_two_characters) {
8976       uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
8977       uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
8978       hasher.AddCharacter(c1);
8979       hasher.AddCharacter(c2);
8980       if (is_index) is_index = hasher.UpdateIndex(c1);
8981       if (is_index) is_index = hasher.UpdateIndex(c2);
8982     } else {
8983       hasher.AddCharacter(c);
8984       if (is_index) is_index = hasher.UpdateIndex(c);
8985     }
8986   }
8987   *utf16_length_out = static_cast<int>(utf16_length);
8988   // Must set length here so that hash computation is correct.
8989   hasher.length_ = utf16_length;
8990   return hasher.GetHashField();
8991 }
8992 
8993 
PrintOn(FILE * file)8994 void String::PrintOn(FILE* file) {
8995   int length = this->length();
8996   for (int i = 0; i < length; i++) {
8997     PrintF(file, "%c", Get(i));
8998   }
8999 }
9000 
9001 
Hash()9002 int Map::Hash() {
9003   // For performance reasons we only hash the 3 most variable fields of a map:
9004   // constructor, prototype and bit_field2.
9005 
9006   // Shift away the tag.
9007   int hash = (static_cast<uint32_t>(
9008         reinterpret_cast<uintptr_t>(constructor())) >> 2);
9009 
9010   // XOR-ing the prototype and constructor directly yields too many zero bits
9011   // when the two pointers are close (which is fairly common).
9012   // To avoid this we shift the prototype 4 bits relatively to the constructor.
9013   hash ^= (static_cast<uint32_t>(
9014         reinterpret_cast<uintptr_t>(prototype())) << 2);
9015 
9016   return hash ^ (hash >> 16) ^ bit_field2();
9017 }
9018 
9019 
CheckEquivalent(Map * first,Map * second)9020 static bool CheckEquivalent(Map* first, Map* second) {
9021   return
9022     first->constructor() == second->constructor() &&
9023     first->prototype() == second->prototype() &&
9024     first->instance_type() == second->instance_type() &&
9025     first->bit_field() == second->bit_field() &&
9026     first->bit_field2() == second->bit_field2() &&
9027     first->is_frozen() == second->is_frozen() &&
9028     first->has_instance_call_handler() == second->has_instance_call_handler();
9029 }
9030 
9031 
EquivalentToForTransition(Map * other)9032 bool Map::EquivalentToForTransition(Map* other) {
9033   return CheckEquivalent(this, other);
9034 }
9035 
9036 
EquivalentToForNormalization(Map * other,PropertyNormalizationMode mode)9037 bool Map::EquivalentToForNormalization(Map* other,
9038                                        PropertyNormalizationMode mode) {
9039   int properties = mode == CLEAR_INOBJECT_PROPERTIES
9040       ? 0 : other->inobject_properties();
9041   return CheckEquivalent(this, other) && inobject_properties() == properties;
9042 }
9043 
9044 
ConstantPoolIterateBody(ObjectVisitor * v)9045 void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) {
9046   // Unfortunately the serializer relies on pointers within an object being
9047   // visited in-order, so we have to iterate both the code and heap pointers in
9048   // the small section before doing so in the extended section.
9049   for (int s = 0; s <= final_section(); ++s) {
9050     LayoutSection section = static_cast<LayoutSection>(s);
9051     ConstantPoolArray::Iterator code_iter(this, ConstantPoolArray::CODE_PTR,
9052                                           section);
9053     while (!code_iter.is_finished()) {
9054       v->VisitCodeEntry(reinterpret_cast<Address>(
9055           RawFieldOfElementAt(code_iter.next_index())));
9056     }
9057 
9058     ConstantPoolArray::Iterator heap_iter(this, ConstantPoolArray::HEAP_PTR,
9059                                           section);
9060     while (!heap_iter.is_finished()) {
9061       v->VisitPointer(RawFieldOfElementAt(heap_iter.next_index()));
9062     }
9063   }
9064 }
9065 
9066 
ClearPtrEntries(Isolate * isolate)9067 void ConstantPoolArray::ClearPtrEntries(Isolate* isolate) {
9068   Type type[] = { CODE_PTR, HEAP_PTR };
9069   Address default_value[] = {
9070         isolate->builtins()->builtin(Builtins::kIllegal)->entry(),
9071         reinterpret_cast<Address>(isolate->heap()->undefined_value()) };
9072 
9073   for (int i = 0; i < 2; ++i) {
9074     for (int s = 0; s <= final_section(); ++s) {
9075       LayoutSection section = static_cast<LayoutSection>(s);
9076       if (number_of_entries(type[i], section) > 0) {
9077         int offset = OffsetOfElementAt(first_index(type[i], section));
9078         MemsetPointer(
9079           reinterpret_cast<Address*>(HeapObject::RawField(this, offset)),
9080           default_value[i],
9081           number_of_entries(type[i], section));
9082       }
9083     }
9084   }
9085 }
9086 
9087 
JSFunctionIterateBody(int object_size,ObjectVisitor * v)9088 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
9089   // Iterate over all fields in the body but take care in dealing with
9090   // the code entry.
9091   IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
9092   v->VisitCodeEntry(this->address() + kCodeEntryOffset);
9093   IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
9094 }
9095 
9096 
MarkForOptimization()9097 void JSFunction::MarkForOptimization() {
9098   DCHECK(!IsOptimized());
9099   DCHECK(shared()->allows_lazy_compilation() ||
9100          code()->optimizable());
9101   DCHECK(!shared()->is_generator());
9102   set_code_no_write_barrier(
9103       GetIsolate()->builtins()->builtin(Builtins::kCompileOptimized));
9104   // No write barrier required, since the builtin is part of the root set.
9105 }
9106 
9107 
MarkForConcurrentOptimization()9108 void JSFunction::MarkForConcurrentOptimization() {
9109   DCHECK(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
9110   DCHECK(!IsOptimized());
9111   DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
9112   DCHECK(!shared()->is_generator());
9113   DCHECK(GetIsolate()->concurrent_recompilation_enabled());
9114   if (FLAG_trace_concurrent_recompilation) {
9115     PrintF("  ** Marking ");
9116     ShortPrint();
9117     PrintF(" for concurrent recompilation.\n");
9118   }
9119   set_code_no_write_barrier(
9120       GetIsolate()->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
9121   // No write barrier required, since the builtin is part of the root set.
9122 }
9123 
9124 
MarkInOptimizationQueue()9125 void JSFunction::MarkInOptimizationQueue() {
9126   // We can only arrive here via the concurrent-recompilation builtin.  If
9127   // break points were set, the code would point to the lazy-compile builtin.
9128   DCHECK(!GetIsolate()->DebuggerHasBreakPoints());
9129   DCHECK(IsMarkedForConcurrentOptimization() && !IsOptimized());
9130   DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
9131   DCHECK(GetIsolate()->concurrent_recompilation_enabled());
9132   if (FLAG_trace_concurrent_recompilation) {
9133     PrintF("  ** Queueing ");
9134     ShortPrint();
9135     PrintF(" for concurrent recompilation.\n");
9136   }
9137   set_code_no_write_barrier(
9138       GetIsolate()->builtins()->builtin(Builtins::kInOptimizationQueue));
9139   // No write barrier required, since the builtin is part of the root set.
9140 }
9141 
9142 
CloneClosure(Handle<JSFunction> function)9143 Handle<JSFunction> JSFunction::CloneClosure(Handle<JSFunction> function) {
9144   Isolate* isolate = function->GetIsolate();
9145   Handle<Map> map(function->map());
9146   Handle<SharedFunctionInfo> shared(function->shared());
9147   Handle<Context> context(function->context());
9148   Handle<JSFunction> clone =
9149       isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
9150 
9151   if (shared->bound()) {
9152     clone->set_function_bindings(function->function_bindings());
9153   }
9154 
9155   // In typical case, __proto__ of ``function`` is the default Function
9156   // prototype, which means that SetPrototype below is a no-op.
9157   // In rare cases when that is not true, we mutate the clone's __proto__.
9158   Handle<Object> original_prototype(map->prototype(), isolate);
9159   if (*original_prototype != clone->map()->prototype()) {
9160     JSObject::SetPrototype(clone, original_prototype, false).Assert();
9161   }
9162 
9163   return clone;
9164 }
9165 
9166 
AddToOptimizedCodeMap(Handle<SharedFunctionInfo> shared,Handle<Context> native_context,Handle<Code> code,Handle<FixedArray> literals,BailoutId osr_ast_id)9167 void SharedFunctionInfo::AddToOptimizedCodeMap(
9168     Handle<SharedFunctionInfo> shared,
9169     Handle<Context> native_context,
9170     Handle<Code> code,
9171     Handle<FixedArray> literals,
9172     BailoutId osr_ast_id) {
9173   Isolate* isolate = shared->GetIsolate();
9174   DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
9175   DCHECK(native_context->IsNativeContext());
9176   STATIC_ASSERT(kEntryLength == 4);
9177   Handle<FixedArray> new_code_map;
9178   Handle<Object> value(shared->optimized_code_map(), isolate);
9179   int old_length;
9180   if (value->IsSmi()) {
9181     // No optimized code map.
9182     DCHECK_EQ(0, Smi::cast(*value)->value());
9183     // Create 3 entries per context {context, code, literals}.
9184     new_code_map = isolate->factory()->NewFixedArray(kInitialLength);
9185     old_length = kEntriesStart;
9186   } else {
9187     // Copy old map and append one new entry.
9188     Handle<FixedArray> old_code_map = Handle<FixedArray>::cast(value);
9189     DCHECK_EQ(-1, shared->SearchOptimizedCodeMap(*native_context, osr_ast_id));
9190     old_length = old_code_map->length();
9191     new_code_map = FixedArray::CopySize(
9192         old_code_map, old_length + kEntryLength);
9193     // Zap the old map for the sake of the heap verifier.
9194     if (Heap::ShouldZapGarbage()) {
9195       Object** data = old_code_map->data_start();
9196       MemsetPointer(data, isolate->heap()->the_hole_value(), old_length);
9197     }
9198   }
9199   new_code_map->set(old_length + kContextOffset, *native_context);
9200   new_code_map->set(old_length + kCachedCodeOffset, *code);
9201   new_code_map->set(old_length + kLiteralsOffset, *literals);
9202   new_code_map->set(old_length + kOsrAstIdOffset,
9203                     Smi::FromInt(osr_ast_id.ToInt()));
9204 
9205 #ifdef DEBUG
9206   for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
9207     DCHECK(new_code_map->get(i + kContextOffset)->IsNativeContext());
9208     DCHECK(new_code_map->get(i + kCachedCodeOffset)->IsCode());
9209     DCHECK(Code::cast(new_code_map->get(i + kCachedCodeOffset))->kind() ==
9210            Code::OPTIMIZED_FUNCTION);
9211     DCHECK(new_code_map->get(i + kLiteralsOffset)->IsFixedArray());
9212     DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
9213   }
9214 #endif
9215   shared->set_optimized_code_map(*new_code_map);
9216 }
9217 
9218 
GetLiteralsFromOptimizedCodeMap(int index)9219 FixedArray* SharedFunctionInfo::GetLiteralsFromOptimizedCodeMap(int index) {
9220   DCHECK(index > kEntriesStart);
9221   FixedArray* code_map = FixedArray::cast(optimized_code_map());
9222   if (!bound()) {
9223     FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
9224     DCHECK_NE(NULL, cached_literals);
9225     return cached_literals;
9226   }
9227   return NULL;
9228 }
9229 
9230 
GetCodeFromOptimizedCodeMap(int index)9231 Code* SharedFunctionInfo::GetCodeFromOptimizedCodeMap(int index) {
9232   DCHECK(index > kEntriesStart);
9233   FixedArray* code_map = FixedArray::cast(optimized_code_map());
9234   Code* code = Code::cast(code_map->get(index));
9235   DCHECK_NE(NULL, code);
9236   return code;
9237 }
9238 
9239 
ClearOptimizedCodeMap()9240 void SharedFunctionInfo::ClearOptimizedCodeMap() {
9241   FixedArray* code_map = FixedArray::cast(optimized_code_map());
9242 
9243   // If the next map link slot is already used then the function was
9244   // enqueued with code flushing and we remove it now.
9245   if (!code_map->get(kNextMapIndex)->IsUndefined()) {
9246     CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
9247     flusher->EvictOptimizedCodeMap(this);
9248   }
9249 
9250   DCHECK(code_map->get(kNextMapIndex)->IsUndefined());
9251   set_optimized_code_map(Smi::FromInt(0));
9252 }
9253 
9254 
EvictFromOptimizedCodeMap(Code * optimized_code,const char * reason)9255 void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
9256                                                    const char* reason) {
9257   DisallowHeapAllocation no_gc;
9258   if (optimized_code_map()->IsSmi()) return;
9259 
9260   FixedArray* code_map = FixedArray::cast(optimized_code_map());
9261   int dst = kEntriesStart;
9262   int length = code_map->length();
9263   for (int src = kEntriesStart; src < length; src += kEntryLength) {
9264     DCHECK(code_map->get(src)->IsNativeContext());
9265     if (Code::cast(code_map->get(src + kCachedCodeOffset)) == optimized_code) {
9266       // Evict the src entry by not copying it to the dst entry.
9267       if (FLAG_trace_opt) {
9268         PrintF("[evicting entry from optimizing code map (%s) for ", reason);
9269         ShortPrint();
9270         BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
9271         if (osr.IsNone()) {
9272           PrintF("]\n");
9273         } else {
9274           PrintF(" (osr ast id %d)]\n", osr.ToInt());
9275         }
9276       }
9277     } else {
9278       // Keep the src entry by copying it to the dst entry.
9279       if (dst != src) {
9280         code_map->set(dst + kContextOffset,
9281                       code_map->get(src + kContextOffset));
9282         code_map->set(dst + kCachedCodeOffset,
9283                       code_map->get(src + kCachedCodeOffset));
9284         code_map->set(dst + kLiteralsOffset,
9285                       code_map->get(src + kLiteralsOffset));
9286         code_map->set(dst + kOsrAstIdOffset,
9287                       code_map->get(src + kOsrAstIdOffset));
9288       }
9289       dst += kEntryLength;
9290     }
9291   }
9292   if (dst != length) {
9293     // Always trim even when array is cleared because of heap verifier.
9294     GetHeap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(code_map, length - dst);
9295     if (code_map->length() == kEntriesStart) ClearOptimizedCodeMap();
9296   }
9297 }
9298 
9299 
TrimOptimizedCodeMap(int shrink_by)9300 void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
9301   FixedArray* code_map = FixedArray::cast(optimized_code_map());
9302   DCHECK(shrink_by % kEntryLength == 0);
9303   DCHECK(shrink_by <= code_map->length() - kEntriesStart);
9304   // Always trim even when array is cleared because of heap verifier.
9305   GetHeap()->RightTrimFixedArray<Heap::FROM_GC>(code_map, shrink_by);
9306   if (code_map->length() == kEntriesStart) {
9307     ClearOptimizedCodeMap();
9308   }
9309 }
9310 
9311 
OptimizeAsPrototype(Handle<JSObject> object,PrototypeOptimizationMode mode)9312 void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
9313                                    PrototypeOptimizationMode mode) {
9314   if (object->IsGlobalObject()) return;
9315   if (object->IsJSGlobalProxy()) return;
9316   if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) {
9317     // First normalize to ensure all JSFunctions are CONSTANT.
9318     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
9319   }
9320   if (!object->HasFastProperties()) {
9321     JSObject::MigrateSlowToFast(object, 0);
9322   }
9323   if (mode == FAST_PROTOTYPE && object->HasFastProperties() &&
9324       !object->map()->is_prototype_map()) {
9325     Handle<Map> new_map = Map::Copy(handle(object->map()));
9326     JSObject::MigrateToMap(object, new_map);
9327     object->map()->set_is_prototype_map(true);
9328   }
9329 }
9330 
9331 
ReoptimizeIfPrototype(Handle<JSObject> object)9332 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
9333   if (!object->map()->is_prototype_map()) return;
9334   OptimizeAsPrototype(object, FAST_PROTOTYPE);
9335 }
9336 
9337 
CacheInitialJSArrayMaps(Handle<Context> native_context,Handle<Map> initial_map)9338 Handle<Object> CacheInitialJSArrayMaps(
9339     Handle<Context> native_context, Handle<Map> initial_map) {
9340   // Replace all of the cached initial array maps in the native context with
9341   // the appropriate transitioned elements kind maps.
9342   Factory* factory = native_context->GetIsolate()->factory();
9343   Handle<FixedArray> maps = factory->NewFixedArrayWithHoles(
9344       kElementsKindCount, TENURED);
9345 
9346   Handle<Map> current_map = initial_map;
9347   ElementsKind kind = current_map->elements_kind();
9348   DCHECK(kind == GetInitialFastElementsKind());
9349   maps->set(kind, *current_map);
9350   for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
9351        i < kFastElementsKindCount; ++i) {
9352     Handle<Map> new_map;
9353     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
9354     if (current_map->HasElementsTransition()) {
9355       new_map = handle(current_map->elements_transition_map());
9356       DCHECK(new_map->elements_kind() == next_kind);
9357     } else {
9358       new_map = Map::CopyAsElementsKind(
9359           current_map, next_kind, INSERT_TRANSITION);
9360     }
9361     maps->set(next_kind, *new_map);
9362     current_map = new_map;
9363   }
9364   native_context->set_js_array_maps(*maps);
9365   return initial_map;
9366 }
9367 
9368 
SetInstancePrototype(Handle<JSFunction> function,Handle<Object> value)9369 void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
9370                                       Handle<Object> value) {
9371   Isolate* isolate = function->GetIsolate();
9372 
9373   DCHECK(value->IsJSReceiver());
9374 
9375   // Now some logic for the maps of the objects that are created by using this
9376   // function as a constructor.
9377   if (function->has_initial_map()) {
9378     // If the function has allocated the initial map replace it with a
9379     // copy containing the new prototype.  Also complete any in-object
9380     // slack tracking that is in progress at this point because it is
9381     // still tracking the old copy.
9382     if (function->IsInobjectSlackTrackingInProgress()) {
9383       function->CompleteInobjectSlackTracking();
9384     }
9385 
9386     Handle<Map> initial_map(function->initial_map(), isolate);
9387 
9388     if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
9389         initial_map->instance_type() == JS_OBJECT_TYPE) {
9390       // Put the value in the initial map field until an initial map is needed.
9391       // At that point, a new initial map is created and the prototype is put
9392       // into the initial map where it belongs.
9393       function->set_prototype_or_initial_map(*value);
9394     } else {
9395       Handle<Map> new_map = Map::Copy(initial_map);
9396       JSFunction::SetInitialMap(function, new_map, value);
9397 
9398       // If the function is used as the global Array function, cache the
9399       // initial map (and transitioned versions) in the native context.
9400       Context* native_context = function->context()->native_context();
9401       Object* array_function =
9402           native_context->get(Context::ARRAY_FUNCTION_INDEX);
9403       if (array_function->IsJSFunction() &&
9404           *function == JSFunction::cast(array_function)) {
9405         CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
9406       }
9407     }
9408 
9409     // Deoptimize all code that embeds the previous initial map.
9410     initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
9411         isolate, DependentCode::kInitialMapChangedGroup);
9412   } else {
9413     // Put the value in the initial map field until an initial map is
9414     // needed.  At that point, a new initial map is created and the
9415     // prototype is put into the initial map where it belongs.
9416     function->set_prototype_or_initial_map(*value);
9417   }
9418   isolate->heap()->ClearInstanceofCache();
9419 }
9420 
9421 
SetPrototype(Handle<JSFunction> function,Handle<Object> value)9422 void JSFunction::SetPrototype(Handle<JSFunction> function,
9423                               Handle<Object> value) {
9424   DCHECK(function->should_have_prototype());
9425   Handle<Object> construct_prototype = value;
9426 
9427   // If the value is not a JSReceiver, store the value in the map's
9428   // constructor field so it can be accessed.  Also, set the prototype
9429   // used for constructing objects to the original object prototype.
9430   // See ECMA-262 13.2.2.
9431   if (!value->IsJSReceiver()) {
9432     // Copy the map so this does not affect unrelated functions.
9433     // Remove map transitions because they point to maps with a
9434     // different prototype.
9435     Handle<Map> new_map = Map::Copy(handle(function->map()));
9436 
9437     JSObject::MigrateToMap(function, new_map);
9438     new_map->set_constructor(*value);
9439     new_map->set_non_instance_prototype(true);
9440     Isolate* isolate = new_map->GetIsolate();
9441     construct_prototype = handle(
9442         isolate->context()->native_context()->initial_object_prototype(),
9443         isolate);
9444   } else {
9445     function->map()->set_non_instance_prototype(false);
9446   }
9447 
9448   return SetInstancePrototype(function, construct_prototype);
9449 }
9450 
9451 
RemovePrototype()9452 bool JSFunction::RemovePrototype() {
9453   Context* native_context = context()->native_context();
9454   Map* no_prototype_map = shared()->strict_mode() == SLOPPY
9455       ? native_context->sloppy_function_without_prototype_map()
9456       : native_context->strict_function_without_prototype_map();
9457 
9458   if (map() == no_prototype_map) return true;
9459 
9460 #ifdef DEBUG
9461   if (map() != (shared()->strict_mode() == SLOPPY
9462                    ? native_context->sloppy_function_map()
9463                    : native_context->strict_function_map())) {
9464     return false;
9465   }
9466 #endif
9467 
9468   set_map(no_prototype_map);
9469   set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
9470   return true;
9471 }
9472 
9473 
SetInitialMap(Handle<JSFunction> function,Handle<Map> map,Handle<Object> prototype)9474 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
9475                                Handle<Object> prototype) {
9476   if (prototype->IsJSObject()) {
9477     Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype);
9478     JSObject::OptimizeAsPrototype(js_proto, FAST_PROTOTYPE);
9479   }
9480   map->set_prototype(*prototype);
9481   function->set_prototype_or_initial_map(*map);
9482   map->set_constructor(*function);
9483 }
9484 
9485 
EnsureHasInitialMap(Handle<JSFunction> function)9486 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
9487   if (function->has_initial_map()) return;
9488   Isolate* isolate = function->GetIsolate();
9489 
9490   // First create a new map with the size and number of in-object properties
9491   // suggested by the function.
9492   InstanceType instance_type;
9493   int instance_size;
9494   int in_object_properties;
9495   if (function->shared()->is_generator()) {
9496     instance_type = JS_GENERATOR_OBJECT_TYPE;
9497     instance_size = JSGeneratorObject::kSize;
9498     in_object_properties = 0;
9499   } else {
9500     instance_type = JS_OBJECT_TYPE;
9501     instance_size = function->shared()->CalculateInstanceSize();
9502     in_object_properties = function->shared()->CalculateInObjectProperties();
9503   }
9504   Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
9505 
9506   // Fetch or allocate prototype.
9507   Handle<Object> prototype;
9508   if (function->has_instance_prototype()) {
9509     prototype = handle(function->instance_prototype(), isolate);
9510   } else {
9511     prototype = isolate->factory()->NewFunctionPrototype(function);
9512   }
9513   map->set_inobject_properties(in_object_properties);
9514   map->set_unused_property_fields(in_object_properties);
9515   DCHECK(map->has_fast_object_elements());
9516 
9517   // Finally link initial map and constructor function.
9518   JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype));
9519 
9520   if (!function->shared()->is_generator()) {
9521     function->StartInobjectSlackTracking();
9522   }
9523 }
9524 
9525 
SetInstanceClassName(String * name)9526 void JSFunction::SetInstanceClassName(String* name) {
9527   shared()->set_instance_class_name(name);
9528 }
9529 
9530 
PrintName(FILE * out)9531 void JSFunction::PrintName(FILE* out) {
9532   SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
9533   PrintF(out, "%s", name.get());
9534 }
9535 
9536 
NativeContextFromLiterals(FixedArray * literals)9537 Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
9538   return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
9539 }
9540 
9541 
9542 // The filter is a pattern that matches function names in this way:
9543 //   "*"      all; the default
9544 //   "-"      all but the top-level function
9545 //   "-name"  all but the function "name"
9546 //   ""       only the top-level function
9547 //   "name"   only the function "name"
9548 //   "name*"  only functions starting with "name"
9549 //   "~"      none; the tilde is not an identifier
PassesFilter(const char * raw_filter)9550 bool JSFunction::PassesFilter(const char* raw_filter) {
9551   if (*raw_filter == '*') return true;
9552   String* name = shared()->DebugName();
9553   Vector<const char> filter = CStrVector(raw_filter);
9554   if (filter.length() == 0) return name->length() == 0;
9555   if (filter[0] == '-') {
9556     // Negative filter.
9557     if (filter.length() == 1) {
9558       return (name->length() != 0);
9559     } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
9560       return false;
9561     }
9562     if (filter[filter.length() - 1] == '*' &&
9563         name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
9564       return false;
9565     }
9566     return true;
9567 
9568   } else if (name->IsUtf8EqualTo(filter)) {
9569     return true;
9570   }
9571   if (filter[filter.length() - 1] == '*' &&
9572       name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
9573     return true;
9574   }
9575   return false;
9576 }
9577 
9578 
Initialize(Isolate * isolate,Handle<Oddball> oddball,const char * to_string,Handle<Object> to_number,byte kind)9579 void Oddball::Initialize(Isolate* isolate,
9580                          Handle<Oddball> oddball,
9581                          const char* to_string,
9582                          Handle<Object> to_number,
9583                          byte kind) {
9584   Handle<String> internalized_to_string =
9585       isolate->factory()->InternalizeUtf8String(to_string);
9586   oddball->set_to_string(*internalized_to_string);
9587   oddball->set_to_number(*to_number);
9588   oddball->set_kind(kind);
9589 }
9590 
9591 
InitLineEnds(Handle<Script> script)9592 void Script::InitLineEnds(Handle<Script> script) {
9593   if (!script->line_ends()->IsUndefined()) return;
9594 
9595   Isolate* isolate = script->GetIsolate();
9596 
9597   if (!script->source()->IsString()) {
9598     DCHECK(script->source()->IsUndefined());
9599     Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
9600     script->set_line_ends(*empty);
9601     DCHECK(script->line_ends()->IsFixedArray());
9602     return;
9603   }
9604 
9605   Handle<String> src(String::cast(script->source()), isolate);
9606 
9607   Handle<FixedArray> array = String::CalculateLineEnds(src, true);
9608 
9609   if (*array != isolate->heap()->empty_fixed_array()) {
9610     array->set_map(isolate->heap()->fixed_cow_array_map());
9611   }
9612 
9613   script->set_line_ends(*array);
9614   DCHECK(script->line_ends()->IsFixedArray());
9615 }
9616 
9617 
GetColumnNumber(Handle<Script> script,int code_pos)9618 int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
9619   int line_number = GetLineNumber(script, code_pos);
9620   if (line_number == -1) return -1;
9621 
9622   DisallowHeapAllocation no_allocation;
9623   FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
9624   line_number = line_number - script->line_offset()->value();
9625   if (line_number == 0) return code_pos + script->column_offset()->value();
9626   int prev_line_end_pos =
9627       Smi::cast(line_ends_array->get(line_number - 1))->value();
9628   return code_pos - (prev_line_end_pos + 1);
9629 }
9630 
9631 
GetLineNumberWithArray(int code_pos)9632 int Script::GetLineNumberWithArray(int code_pos) {
9633   DisallowHeapAllocation no_allocation;
9634   DCHECK(line_ends()->IsFixedArray());
9635   FixedArray* line_ends_array = FixedArray::cast(line_ends());
9636   int line_ends_len = line_ends_array->length();
9637   if (line_ends_len == 0) return -1;
9638 
9639   if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
9640     return line_offset()->value();
9641   }
9642 
9643   int left = 0;
9644   int right = line_ends_len;
9645   while (int half = (right - left) / 2) {
9646     if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
9647       right -= half;
9648     } else {
9649       left += half;
9650     }
9651   }
9652   return right + line_offset()->value();
9653 }
9654 
9655 
GetLineNumber(Handle<Script> script,int code_pos)9656 int Script::GetLineNumber(Handle<Script> script, int code_pos) {
9657   InitLineEnds(script);
9658   return script->GetLineNumberWithArray(code_pos);
9659 }
9660 
9661 
GetLineNumber(int code_pos)9662 int Script::GetLineNumber(int code_pos) {
9663   DisallowHeapAllocation no_allocation;
9664   if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
9665 
9666   // Slow mode: we do not have line_ends. We have to iterate through source.
9667   if (!source()->IsString()) return -1;
9668 
9669   String* source_string = String::cast(source());
9670   int line = 0;
9671   int len = source_string->length();
9672   for (int pos = 0; pos < len; pos++) {
9673     if (pos == code_pos) break;
9674     if (source_string->Get(pos) == '\n') line++;
9675   }
9676   return line;
9677 }
9678 
9679 
GetNameOrSourceURL(Handle<Script> script)9680 Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
9681   Isolate* isolate = script->GetIsolate();
9682   Handle<String> name_or_source_url_key =
9683       isolate->factory()->InternalizeOneByteString(
9684           STATIC_CHAR_VECTOR("nameOrSourceURL"));
9685   Handle<JSObject> script_wrapper = Script::GetWrapper(script);
9686   Handle<Object> property = Object::GetProperty(
9687       script_wrapper, name_or_source_url_key).ToHandleChecked();
9688   DCHECK(property->IsJSFunction());
9689   Handle<JSFunction> method = Handle<JSFunction>::cast(property);
9690   Handle<Object> result;
9691   // Do not check against pending exception, since this function may be called
9692   // when an exception has already been pending.
9693   if (!Execution::TryCall(method, script_wrapper, 0, NULL).ToHandle(&result)) {
9694     return isolate->factory()->undefined_value();
9695   }
9696   return result;
9697 }
9698 
9699 
9700 // Wrappers for scripts are kept alive and cached in weak global
9701 // handles referred from foreign objects held by the scripts as long as
9702 // they are used. When they are not used anymore, the garbage
9703 // collector will call the weak callback on the global handle
9704 // associated with the wrapper and get rid of both the wrapper and the
9705 // handle.
ClearWrapperCacheWeakCallback(const v8::WeakCallbackData<v8::Value,void> & data)9706 static void ClearWrapperCacheWeakCallback(
9707     const v8::WeakCallbackData<v8::Value, void>& data) {
9708   Object** location = reinterpret_cast<Object**>(data.GetParameter());
9709   JSValue* wrapper = JSValue::cast(*location);
9710   Script::cast(wrapper->value())->ClearWrapperCache();
9711 }
9712 
9713 
ClearWrapperCache()9714 void Script::ClearWrapperCache() {
9715   Foreign* foreign = wrapper();
9716   Object** location = reinterpret_cast<Object**>(foreign->foreign_address());
9717   DCHECK_EQ(foreign->foreign_address(), reinterpret_cast<Address>(location));
9718   foreign->set_foreign_address(0);
9719   GlobalHandles::Destroy(location);
9720   GetIsolate()->counters()->script_wrappers()->Decrement();
9721 }
9722 
9723 
GetWrapper(Handle<Script> script)9724 Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
9725   if (script->wrapper()->foreign_address() != NULL) {
9726     // Return a handle for the existing script wrapper from the cache.
9727     return Handle<JSValue>(
9728         *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
9729   }
9730   Isolate* isolate = script->GetIsolate();
9731   // Construct a new script wrapper.
9732   isolate->counters()->script_wrappers()->Increment();
9733   Handle<JSFunction> constructor = isolate->script_function();
9734   Handle<JSValue> result =
9735       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
9736 
9737   result->set_value(*script);
9738 
9739   // Create a new weak global handle and use it to cache the wrapper
9740   // for future use. The cache will automatically be cleared by the
9741   // garbage collector when it is not used anymore.
9742   Handle<Object> handle = isolate->global_handles()->Create(*result);
9743   GlobalHandles::MakeWeak(handle.location(),
9744                           reinterpret_cast<void*>(handle.location()),
9745                           &ClearWrapperCacheWeakCallback);
9746   script->wrapper()->set_foreign_address(
9747       reinterpret_cast<Address>(handle.location()));
9748   return result;
9749 }
9750 
9751 
DebugName()9752 String* SharedFunctionInfo::DebugName() {
9753   Object* n = name();
9754   if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
9755   return String::cast(n);
9756 }
9757 
9758 
HasSourceCode() const9759 bool SharedFunctionInfo::HasSourceCode() const {
9760   return !script()->IsUndefined() &&
9761          !reinterpret_cast<Script*>(script())->source()->IsUndefined();
9762 }
9763 
9764 
GetSourceCode()9765 Handle<Object> SharedFunctionInfo::GetSourceCode() {
9766   if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
9767   Handle<String> source(String::cast(Script::cast(script())->source()));
9768   return GetIsolate()->factory()->NewSubString(
9769       source, start_position(), end_position());
9770 }
9771 
9772 
IsInlineable()9773 bool SharedFunctionInfo::IsInlineable() {
9774   // Check that the function has a script associated with it.
9775   if (!script()->IsScript()) return false;
9776   if (optimization_disabled()) return false;
9777   // If we never ran this (unlikely) then lets try to optimize it.
9778   if (code()->kind() != Code::FUNCTION) return true;
9779   return code()->optimizable();
9780 }
9781 
9782 
SourceSize()9783 int SharedFunctionInfo::SourceSize() {
9784   return end_position() - start_position();
9785 }
9786 
9787 
CalculateInstanceSize()9788 int SharedFunctionInfo::CalculateInstanceSize() {
9789   int instance_size =
9790       JSObject::kHeaderSize +
9791       expected_nof_properties() * kPointerSize;
9792   if (instance_size > JSObject::kMaxInstanceSize) {
9793     instance_size = JSObject::kMaxInstanceSize;
9794   }
9795   return instance_size;
9796 }
9797 
9798 
CalculateInObjectProperties()9799 int SharedFunctionInfo::CalculateInObjectProperties() {
9800   return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
9801 }
9802 
9803 
9804 // Output the source code without any allocation in the heap.
operator <<(OStream & os,const SourceCodeOf & v)9805 OStream& operator<<(OStream& os, const SourceCodeOf& v) {
9806   const SharedFunctionInfo* s = v.value;
9807   // For some native functions there is no source.
9808   if (!s->HasSourceCode()) return os << "<No Source>";
9809 
9810   // Get the source for the script which this function came from.
9811   // Don't use String::cast because we don't want more assertion errors while
9812   // we are already creating a stack dump.
9813   String* script_source =
9814       reinterpret_cast<String*>(Script::cast(s->script())->source());
9815 
9816   if (!script_source->LooksValid()) return os << "<Invalid Source>";
9817 
9818   if (!s->is_toplevel()) {
9819     os << "function ";
9820     Object* name = s->name();
9821     if (name->IsString() && String::cast(name)->length() > 0) {
9822       String::cast(name)->PrintUC16(os);
9823     }
9824   }
9825 
9826   int len = s->end_position() - s->start_position();
9827   if (len <= v.max_length || v.max_length < 0) {
9828     script_source->PrintUC16(os, s->start_position(), s->end_position());
9829     return os;
9830   } else {
9831     script_source->PrintUC16(os, s->start_position(),
9832                              s->start_position() + v.max_length);
9833     return os << "...\n";
9834   }
9835 }
9836 
9837 
IsCodeEquivalent(Code * code,Code * recompiled)9838 static bool IsCodeEquivalent(Code* code, Code* recompiled) {
9839   if (code->instruction_size() != recompiled->instruction_size()) return false;
9840   ByteArray* code_relocation = code->relocation_info();
9841   ByteArray* recompiled_relocation = recompiled->relocation_info();
9842   int length = code_relocation->length();
9843   if (length != recompiled_relocation->length()) return false;
9844   int compare = memcmp(code_relocation->GetDataStartAddress(),
9845                        recompiled_relocation->GetDataStartAddress(),
9846                        length);
9847   return compare == 0;
9848 }
9849 
9850 
EnableDeoptimizationSupport(Code * recompiled)9851 void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
9852   DCHECK(!has_deoptimization_support());
9853   DisallowHeapAllocation no_allocation;
9854   Code* code = this->code();
9855   if (IsCodeEquivalent(code, recompiled)) {
9856     // Copy the deoptimization data from the recompiled code.
9857     code->set_deoptimization_data(recompiled->deoptimization_data());
9858     code->set_has_deoptimization_support(true);
9859   } else {
9860     // TODO(3025757): In case the recompiled isn't equivalent to the
9861     // old code, we have to replace it. We should try to avoid this
9862     // altogether because it flushes valuable type feedback by
9863     // effectively resetting all IC state.
9864     ReplaceCode(recompiled);
9865   }
9866   DCHECK(has_deoptimization_support());
9867 }
9868 
9869 
DisableOptimization(BailoutReason reason)9870 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
9871   // Disable optimization for the shared function info and mark the
9872   // code as non-optimizable. The marker on the shared function info
9873   // is there because we flush non-optimized code thereby loosing the
9874   // non-optimizable information for the code. When the code is
9875   // regenerated and set on the shared function info it is marked as
9876   // non-optimizable if optimization is disabled for the shared
9877   // function info.
9878   set_optimization_disabled(true);
9879   set_bailout_reason(reason);
9880   // Code should be the lazy compilation stub or else unoptimized.  If the
9881   // latter, disable optimization for the code too.
9882   DCHECK(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
9883   if (code()->kind() == Code::FUNCTION) {
9884     code()->set_optimizable(false);
9885   }
9886   PROFILE(GetIsolate(), CodeDisableOptEvent(code(), this));
9887   if (FLAG_trace_opt) {
9888     PrintF("[disabled optimization for ");
9889     ShortPrint();
9890     PrintF(", reason: %s]\n", GetBailoutReason(reason));
9891   }
9892 }
9893 
9894 
VerifyBailoutId(BailoutId id)9895 bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
9896   DCHECK(!id.IsNone());
9897   Code* unoptimized = code();
9898   DeoptimizationOutputData* data =
9899       DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
9900   unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
9901   USE(ignore);
9902   return true;  // Return true if there was no DCHECK.
9903 }
9904 
9905 
StartInobjectSlackTracking()9906 void JSFunction::StartInobjectSlackTracking() {
9907   DCHECK(has_initial_map() && !IsInobjectSlackTrackingInProgress());
9908 
9909   if (!FLAG_clever_optimizations) return;
9910   Map* map = initial_map();
9911 
9912   // Only initiate the tracking the first time.
9913   if (map->done_inobject_slack_tracking()) return;
9914   map->set_done_inobject_slack_tracking(true);
9915 
9916   // No tracking during the snapshot construction phase.
9917   Isolate* isolate = GetIsolate();
9918   if (isolate->serializer_enabled()) return;
9919 
9920   if (map->unused_property_fields() == 0) return;
9921 
9922   map->set_construction_count(kGenerousAllocationCount);
9923 }
9924 
9925 
ResetForNewContext(int new_ic_age)9926 void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
9927   code()->ClearInlineCaches();
9928   // If we clear ICs, we need to clear the type feedback vector too, since
9929   // CallICs are synced with a feedback vector slot.
9930   ClearTypeFeedbackInfo();
9931   set_ic_age(new_ic_age);
9932   if (code()->kind() == Code::FUNCTION) {
9933     code()->set_profiler_ticks(0);
9934     if (optimization_disabled() &&
9935         opt_count() >= FLAG_max_opt_count) {
9936       // Re-enable optimizations if they were disabled due to opt_count limit.
9937       set_optimization_disabled(false);
9938       code()->set_optimizable(true);
9939     }
9940     set_opt_count(0);
9941     set_deopt_count(0);
9942   }
9943 }
9944 
9945 
GetMinInobjectSlack(Map * map,void * data)9946 static void GetMinInobjectSlack(Map* map, void* data) {
9947   int slack = map->unused_property_fields();
9948   if (*reinterpret_cast<int*>(data) > slack) {
9949     *reinterpret_cast<int*>(data) = slack;
9950   }
9951 }
9952 
9953 
ShrinkInstanceSize(Map * map,void * data)9954 static void ShrinkInstanceSize(Map* map, void* data) {
9955   int slack = *reinterpret_cast<int*>(data);
9956   map->set_inobject_properties(map->inobject_properties() - slack);
9957   map->set_unused_property_fields(map->unused_property_fields() - slack);
9958   map->set_instance_size(map->instance_size() - slack * kPointerSize);
9959 
9960   // Visitor id might depend on the instance size, recalculate it.
9961   map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
9962 }
9963 
9964 
CompleteInobjectSlackTracking()9965 void JSFunction::CompleteInobjectSlackTracking() {
9966   DCHECK(has_initial_map());
9967   Map* map = initial_map();
9968 
9969   DCHECK(map->done_inobject_slack_tracking());
9970   map->set_construction_count(kNoSlackTracking);
9971 
9972   int slack = map->unused_property_fields();
9973   map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
9974   if (slack != 0) {
9975     // Resize the initial map and all maps in its transition tree.
9976     map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
9977   }
9978 }
9979 
9980 
SearchOptimizedCodeMap(Context * native_context,BailoutId osr_ast_id)9981 int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
9982                                                BailoutId osr_ast_id) {
9983   DisallowHeapAllocation no_gc;
9984   DCHECK(native_context->IsNativeContext());
9985   if (!FLAG_cache_optimized_code) return -1;
9986   Object* value = optimized_code_map();
9987   if (!value->IsSmi()) {
9988     FixedArray* optimized_code_map = FixedArray::cast(value);
9989     int length = optimized_code_map->length();
9990     Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
9991     for (int i = kEntriesStart; i < length; i += kEntryLength) {
9992       if (optimized_code_map->get(i + kContextOffset) == native_context &&
9993           optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
9994         return i + kCachedCodeOffset;
9995       }
9996     }
9997     if (FLAG_trace_opt) {
9998       PrintF("[didn't find optimized code in optimized code map for ");
9999       ShortPrint();
10000       PrintF("]\n");
10001     }
10002   }
10003   return -1;
10004 }
10005 
10006 
10007 #define DECLARE_TAG(ignore1, name, ignore2) name,
10008 const char* const VisitorSynchronization::kTags[
10009     VisitorSynchronization::kNumberOfSyncTags] = {
10010   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10011 };
10012 #undef DECLARE_TAG
10013 
10014 
10015 #define DECLARE_TAG(ignore1, ignore2, name) name,
10016 const char* const VisitorSynchronization::kTagNames[
10017     VisitorSynchronization::kNumberOfSyncTags] = {
10018   VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10019 };
10020 #undef DECLARE_TAG
10021 
10022 
VisitCodeTarget(RelocInfo * rinfo)10023 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
10024   DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
10025   Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
10026   Object* old_target = target;
10027   VisitPointer(&target);
10028   CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
10029 }
10030 
10031 
VisitCodeAgeSequence(RelocInfo * rinfo)10032 void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
10033   DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
10034   Object* stub = rinfo->code_age_stub();
10035   if (stub) {
10036     VisitPointer(&stub);
10037   }
10038 }
10039 
10040 
VisitCodeEntry(Address entry_address)10041 void ObjectVisitor::VisitCodeEntry(Address entry_address) {
10042   Object* code = Code::GetObjectFromEntryAddress(entry_address);
10043   Object* old_code = code;
10044   VisitPointer(&code);
10045   if (code != old_code) {
10046     Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
10047   }
10048 }
10049 
10050 
VisitCell(RelocInfo * rinfo)10051 void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
10052   DCHECK(rinfo->rmode() == RelocInfo::CELL);
10053   Object* cell = rinfo->target_cell();
10054   Object* old_cell = cell;
10055   VisitPointer(&cell);
10056   if (cell != old_cell) {
10057     rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
10058   }
10059 }
10060 
10061 
VisitDebugTarget(RelocInfo * rinfo)10062 void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
10063   DCHECK((RelocInfo::IsJSReturn(rinfo->rmode()) &&
10064           rinfo->IsPatchedReturnSequence()) ||
10065          (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
10066           rinfo->IsPatchedDebugBreakSlotSequence()));
10067   Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
10068   Object* old_target = target;
10069   VisitPointer(&target);
10070   CHECK_EQ(target, old_target);  // VisitPointer doesn't change Code* *target.
10071 }
10072 
10073 
VisitEmbeddedPointer(RelocInfo * rinfo)10074 void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
10075   DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
10076   Object* p = rinfo->target_object();
10077   VisitPointer(&p);
10078 }
10079 
10080 
VisitExternalReference(RelocInfo * rinfo)10081 void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
10082   Address p = rinfo->target_reference();
10083   VisitExternalReference(&p);
10084 }
10085 
10086 
InvalidateRelocation()10087 void Code::InvalidateRelocation() {
10088   InvalidateEmbeddedObjects();
10089   set_relocation_info(GetHeap()->empty_byte_array());
10090 }
10091 
10092 
InvalidateEmbeddedObjects()10093 void Code::InvalidateEmbeddedObjects() {
10094   Object* undefined = GetHeap()->undefined_value();
10095   Cell* undefined_cell = GetHeap()->undefined_cell();
10096   int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
10097                   RelocInfo::ModeMask(RelocInfo::CELL);
10098   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10099     RelocInfo::Mode mode = it.rinfo()->rmode();
10100     if (mode == RelocInfo::EMBEDDED_OBJECT) {
10101       it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
10102     } else if (mode == RelocInfo::CELL) {
10103       it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
10104     }
10105   }
10106 }
10107 
10108 
Relocate(intptr_t delta)10109 void Code::Relocate(intptr_t delta) {
10110   for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
10111     it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
10112   }
10113   CpuFeatures::FlushICache(instruction_start(), instruction_size());
10114 }
10115 
10116 
CopyFrom(const CodeDesc & desc)10117 void Code::CopyFrom(const CodeDesc& desc) {
10118   DCHECK(Marking::Color(this) == Marking::WHITE_OBJECT);
10119 
10120   // copy code
10121   CopyBytes(instruction_start(), desc.buffer,
10122             static_cast<size_t>(desc.instr_size));
10123 
10124   // copy reloc info
10125   CopyBytes(relocation_start(),
10126             desc.buffer + desc.buffer_size - desc.reloc_size,
10127             static_cast<size_t>(desc.reloc_size));
10128 
10129   // unbox handles and relocate
10130   intptr_t delta = instruction_start() - desc.buffer;
10131   int mode_mask = RelocInfo::kCodeTargetMask |
10132                   RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
10133                   RelocInfo::ModeMask(RelocInfo::CELL) |
10134                   RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
10135                   RelocInfo::kApplyMask;
10136   // Needed to find target_object and runtime_entry on X64
10137   Assembler* origin = desc.origin;
10138   AllowDeferredHandleDereference embedding_raw_address;
10139   for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10140     RelocInfo::Mode mode = it.rinfo()->rmode();
10141     if (mode == RelocInfo::EMBEDDED_OBJECT) {
10142       Handle<Object> p = it.rinfo()->target_object_handle(origin);
10143       it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
10144     } else if (mode == RelocInfo::CELL) {
10145       Handle<Cell> cell  = it.rinfo()->target_cell_handle();
10146       it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
10147     } else if (RelocInfo::IsCodeTarget(mode)) {
10148       // rewrite code handles in inline cache targets to direct
10149       // pointers to the first instruction in the code object
10150       Handle<Object> p = it.rinfo()->target_object_handle(origin);
10151       Code* code = Code::cast(*p);
10152       it.rinfo()->set_target_address(code->instruction_start(),
10153                                      SKIP_WRITE_BARRIER,
10154                                      SKIP_ICACHE_FLUSH);
10155     } else if (RelocInfo::IsRuntimeEntry(mode)) {
10156       Address p = it.rinfo()->target_runtime_entry(origin);
10157       it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER,
10158                                            SKIP_ICACHE_FLUSH);
10159     } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
10160       Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
10161       Code* code = Code::cast(*p);
10162       it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
10163     } else {
10164       it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
10165     }
10166   }
10167   CpuFeatures::FlushICache(instruction_start(), instruction_size());
10168 }
10169 
10170 
10171 // Locate the source position which is closest to the address in the code. This
10172 // is using the source position information embedded in the relocation info.
10173 // The position returned is relative to the beginning of the script where the
10174 // source for this function is found.
SourcePosition(Address pc)10175 int Code::SourcePosition(Address pc) {
10176   int distance = kMaxInt;
10177   int position = RelocInfo::kNoPosition;  // Initially no position found.
10178   // Run through all the relocation info to find the best matching source
10179   // position. All the code needs to be considered as the sequence of the
10180   // instructions in the code does not necessarily follow the same order as the
10181   // source.
10182   RelocIterator it(this, RelocInfo::kPositionMask);
10183   while (!it.done()) {
10184     // Only look at positions after the current pc.
10185     if (it.rinfo()->pc() < pc) {
10186       // Get position and distance.
10187 
10188       int dist = static_cast<int>(pc - it.rinfo()->pc());
10189       int pos = static_cast<int>(it.rinfo()->data());
10190       // If this position is closer than the current candidate or if it has the
10191       // same distance as the current candidate and the position is higher then
10192       // this position is the new candidate.
10193       if ((dist < distance) ||
10194           (dist == distance && pos > position)) {
10195         position = pos;
10196         distance = dist;
10197       }
10198     }
10199     it.next();
10200   }
10201   return position;
10202 }
10203 
10204 
10205 // Same as Code::SourcePosition above except it only looks for statement
10206 // positions.
SourceStatementPosition(Address pc)10207 int Code::SourceStatementPosition(Address pc) {
10208   // First find the position as close as possible using all position
10209   // information.
10210   int position = SourcePosition(pc);
10211   // Now find the closest statement position before the position.
10212   int statement_position = 0;
10213   RelocIterator it(this, RelocInfo::kPositionMask);
10214   while (!it.done()) {
10215     if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
10216       int p = static_cast<int>(it.rinfo()->data());
10217       if (statement_position < p && p <= position) {
10218         statement_position = p;
10219       }
10220     }
10221     it.next();
10222   }
10223   return statement_position;
10224 }
10225 
10226 
GetSafepointEntry(Address pc)10227 SafepointEntry Code::GetSafepointEntry(Address pc) {
10228   SafepointTable table(this);
10229   return table.FindEntry(pc);
10230 }
10231 
10232 
FindNthObject(int n,Map * match_map)10233 Object* Code::FindNthObject(int n, Map* match_map) {
10234   DCHECK(is_inline_cache_stub());
10235   DisallowHeapAllocation no_allocation;
10236   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10237   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10238     RelocInfo* info = it.rinfo();
10239     Object* object = info->target_object();
10240     if (object->IsHeapObject()) {
10241       if (HeapObject::cast(object)->map() == match_map) {
10242         if (--n == 0) return object;
10243       }
10244     }
10245   }
10246   return NULL;
10247 }
10248 
10249 
FindFirstAllocationSite()10250 AllocationSite* Code::FindFirstAllocationSite() {
10251   Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
10252   return (result != NULL) ? AllocationSite::cast(result) : NULL;
10253 }
10254 
10255 
FindFirstMap()10256 Map* Code::FindFirstMap() {
10257   Object* result = FindNthObject(1, GetHeap()->meta_map());
10258   return (result != NULL) ? Map::cast(result) : NULL;
10259 }
10260 
10261 
FindAndReplace(const FindAndReplacePattern & pattern)10262 void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
10263   DCHECK(is_inline_cache_stub() || is_handler());
10264   DisallowHeapAllocation no_allocation;
10265   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10266   STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
10267   int current_pattern = 0;
10268   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10269     RelocInfo* info = it.rinfo();
10270     Object* object = info->target_object();
10271     if (object->IsHeapObject()) {
10272       Map* map = HeapObject::cast(object)->map();
10273       if (map == *pattern.find_[current_pattern]) {
10274         info->set_target_object(*pattern.replace_[current_pattern]);
10275         if (++current_pattern == pattern.count_) return;
10276       }
10277     }
10278   }
10279   UNREACHABLE();
10280 }
10281 
10282 
FindAllMaps(MapHandleList * maps)10283 void Code::FindAllMaps(MapHandleList* maps) {
10284   DCHECK(is_inline_cache_stub());
10285   DisallowHeapAllocation no_allocation;
10286   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10287   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10288     RelocInfo* info = it.rinfo();
10289     Object* object = info->target_object();
10290     if (object->IsMap()) maps->Add(handle(Map::cast(object)));
10291   }
10292 }
10293 
10294 
FindFirstHandler()10295 Code* Code::FindFirstHandler() {
10296   DCHECK(is_inline_cache_stub());
10297   DisallowHeapAllocation no_allocation;
10298   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10299   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10300     RelocInfo* info = it.rinfo();
10301     Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10302     if (code->kind() == Code::HANDLER) return code;
10303   }
10304   return NULL;
10305 }
10306 
10307 
FindHandlers(CodeHandleList * code_list,int length)10308 bool Code::FindHandlers(CodeHandleList* code_list, int length) {
10309   DCHECK(is_inline_cache_stub());
10310   DisallowHeapAllocation no_allocation;
10311   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10312   int i = 0;
10313   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10314     if (i == length) return true;
10315     RelocInfo* info = it.rinfo();
10316     Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10317     // IC stubs with handlers never contain non-handler code objects before
10318     // handler targets.
10319     if (code->kind() != Code::HANDLER) break;
10320     code_list->Add(Handle<Code>(code));
10321     i++;
10322   }
10323   return i == length;
10324 }
10325 
10326 
FindHandlerForMap(Map * map)10327 MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
10328   DCHECK(is_inline_cache_stub());
10329   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10330              RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10331   bool return_next = false;
10332   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10333     RelocInfo* info = it.rinfo();
10334     if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
10335       Object* object = info->target_object();
10336       if (object == map) return_next = true;
10337     } else if (return_next) {
10338       Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10339       DCHECK(code->kind() == Code::HANDLER);
10340       return handle(code);
10341     }
10342   }
10343   return MaybeHandle<Code>();
10344 }
10345 
10346 
FindFirstName()10347 Name* Code::FindFirstName() {
10348   DCHECK(is_inline_cache_stub());
10349   DisallowHeapAllocation no_allocation;
10350   int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10351   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10352     RelocInfo* info = it.rinfo();
10353     Object* object = info->target_object();
10354     if (object->IsName()) return Name::cast(object);
10355   }
10356   return NULL;
10357 }
10358 
10359 
ClearInlineCaches()10360 void Code::ClearInlineCaches() {
10361   ClearInlineCaches(NULL);
10362 }
10363 
10364 
ClearInlineCaches(Code::Kind kind)10365 void Code::ClearInlineCaches(Code::Kind kind) {
10366   ClearInlineCaches(&kind);
10367 }
10368 
10369 
ClearInlineCaches(Code::Kind * kind)10370 void Code::ClearInlineCaches(Code::Kind* kind) {
10371   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10372              RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
10373              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
10374   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10375     RelocInfo* info = it.rinfo();
10376     Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
10377     if (target->is_inline_cache_stub()) {
10378       if (kind == NULL || *kind == target->kind()) {
10379         IC::Clear(this->GetIsolate(), info->pc(),
10380                   info->host()->constant_pool());
10381       }
10382     }
10383   }
10384 }
10385 
10386 
ClearTypeFeedbackInfo()10387 void SharedFunctionInfo::ClearTypeFeedbackInfo() {
10388   TypeFeedbackVector* vector = feedback_vector();
10389   Heap* heap = GetHeap();
10390   int length = vector->length();
10391 
10392   for (int i = 0; i < length; i++) {
10393     Object* obj = vector->get(i);
10394     if (obj->IsHeapObject()) {
10395       InstanceType instance_type =
10396           HeapObject::cast(obj)->map()->instance_type();
10397       switch (instance_type) {
10398         case ALLOCATION_SITE_TYPE:
10399           // AllocationSites are not cleared because they do not store
10400           // information that leaks.
10401           break;
10402           // Fall through...
10403         default:
10404           vector->set(i, TypeFeedbackVector::RawUninitializedSentinel(heap),
10405                       SKIP_WRITE_BARRIER);
10406       }
10407     }
10408   }
10409 }
10410 
10411 
TranslatePcOffsetToAstId(uint32_t pc_offset)10412 BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
10413   DisallowHeapAllocation no_gc;
10414   DCHECK(kind() == FUNCTION);
10415   BackEdgeTable back_edges(this, &no_gc);
10416   for (uint32_t i = 0; i < back_edges.length(); i++) {
10417     if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
10418   }
10419   return BailoutId::None();
10420 }
10421 
10422 
TranslateAstIdToPcOffset(BailoutId ast_id)10423 uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
10424   DisallowHeapAllocation no_gc;
10425   DCHECK(kind() == FUNCTION);
10426   BackEdgeTable back_edges(this, &no_gc);
10427   for (uint32_t i = 0; i < back_edges.length(); i++) {
10428     if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
10429   }
10430   UNREACHABLE();  // We expect to find the back edge.
10431   return 0;
10432 }
10433 
10434 
MakeCodeAgeSequenceYoung(byte * sequence,Isolate * isolate)10435 void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
10436   PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
10437 }
10438 
10439 
MarkCodeAsExecuted(byte * sequence,Isolate * isolate)10440 void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
10441   PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
10442       NO_MARKING_PARITY);
10443 }
10444 
10445 
EffectiveAge(Code::Age age)10446 static Code::Age EffectiveAge(Code::Age age) {
10447   if (age == Code::kNotExecutedCodeAge) {
10448     // Treat that's never been executed as old immediately.
10449     age = Code::kIsOldCodeAge;
10450   } else if (age == Code::kExecutedOnceCodeAge) {
10451     // Pre-age code that has only been executed once.
10452     age = Code::kPreAgedCodeAge;
10453   }
10454   return age;
10455 }
10456 
10457 
MakeOlder(MarkingParity current_parity)10458 void Code::MakeOlder(MarkingParity current_parity) {
10459   byte* sequence = FindCodeAgeSequence();
10460   if (sequence != NULL) {
10461     Age age;
10462     MarkingParity code_parity;
10463     Isolate* isolate = GetIsolate();
10464     GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
10465     age = EffectiveAge(age);
10466     if (age != kLastCodeAge && code_parity != current_parity) {
10467       PatchPlatformCodeAge(isolate,
10468                            sequence,
10469                            static_cast<Age>(age + 1),
10470                            current_parity);
10471     }
10472   }
10473 }
10474 
10475 
IsOld()10476 bool Code::IsOld() {
10477   return GetAge() >= kIsOldCodeAge;
10478 }
10479 
10480 
FindCodeAgeSequence()10481 byte* Code::FindCodeAgeSequence() {
10482   return FLAG_age_code &&
10483       prologue_offset() != Code::kPrologueOffsetNotSet &&
10484       (kind() == OPTIMIZED_FUNCTION ||
10485        (kind() == FUNCTION && !has_debug_break_slots()))
10486       ? instruction_start() + prologue_offset()
10487       : NULL;
10488 }
10489 
10490 
GetAge()10491 Code::Age Code::GetAge() {
10492   return EffectiveAge(GetRawAge());
10493 }
10494 
10495 
GetRawAge()10496 Code::Age Code::GetRawAge() {
10497   byte* sequence = FindCodeAgeSequence();
10498   if (sequence == NULL) {
10499     return kNoAgeCodeAge;
10500   }
10501   Age age;
10502   MarkingParity parity;
10503   GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
10504   return age;
10505 }
10506 
10507 
GetCodeAgeAndParity(Code * code,Age * age,MarkingParity * parity)10508 void Code::GetCodeAgeAndParity(Code* code, Age* age,
10509                                MarkingParity* parity) {
10510   Isolate* isolate = code->GetIsolate();
10511   Builtins* builtins = isolate->builtins();
10512   Code* stub = NULL;
10513 #define HANDLE_CODE_AGE(AGE)                                            \
10514   stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking();             \
10515   if (code == stub) {                                                   \
10516     *age = k##AGE##CodeAge;                                             \
10517     *parity = EVEN_MARKING_PARITY;                                      \
10518     return;                                                             \
10519   }                                                                     \
10520   stub = *builtins->Make##AGE##CodeYoungAgainOddMarking();              \
10521   if (code == stub) {                                                   \
10522     *age = k##AGE##CodeAge;                                             \
10523     *parity = ODD_MARKING_PARITY;                                       \
10524     return;                                                             \
10525   }
10526   CODE_AGE_LIST(HANDLE_CODE_AGE)
10527 #undef HANDLE_CODE_AGE
10528   stub = *builtins->MarkCodeAsExecutedOnce();
10529   if (code == stub) {
10530     *age = kNotExecutedCodeAge;
10531     *parity = NO_MARKING_PARITY;
10532     return;
10533   }
10534   stub = *builtins->MarkCodeAsExecutedTwice();
10535   if (code == stub) {
10536     *age = kExecutedOnceCodeAge;
10537     *parity = NO_MARKING_PARITY;
10538     return;
10539   }
10540   UNREACHABLE();
10541 }
10542 
10543 
GetCodeAgeStub(Isolate * isolate,Age age,MarkingParity parity)10544 Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
10545   Builtins* builtins = isolate->builtins();
10546   switch (age) {
10547 #define HANDLE_CODE_AGE(AGE)                                            \
10548     case k##AGE##CodeAge: {                                             \
10549       Code* stub = parity == EVEN_MARKING_PARITY                        \
10550           ? *builtins->Make##AGE##CodeYoungAgainEvenMarking()           \
10551           : *builtins->Make##AGE##CodeYoungAgainOddMarking();           \
10552       return stub;                                                      \
10553     }
10554     CODE_AGE_LIST(HANDLE_CODE_AGE)
10555 #undef HANDLE_CODE_AGE
10556     case kNotExecutedCodeAge: {
10557       DCHECK(parity == NO_MARKING_PARITY);
10558       return *builtins->MarkCodeAsExecutedOnce();
10559     }
10560     case kExecutedOnceCodeAge: {
10561       DCHECK(parity == NO_MARKING_PARITY);
10562       return *builtins->MarkCodeAsExecutedTwice();
10563     }
10564     default:
10565       UNREACHABLE();
10566       break;
10567   }
10568   return NULL;
10569 }
10570 
10571 
PrintDeoptLocation(FILE * out,int bailout_id)10572 void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
10573   const char* last_comment = NULL;
10574   int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
10575       | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
10576   for (RelocIterator it(this, mask); !it.done(); it.next()) {
10577     RelocInfo* info = it.rinfo();
10578     if (info->rmode() == RelocInfo::COMMENT) {
10579       last_comment = reinterpret_cast<const char*>(info->data());
10580     } else if (last_comment != NULL) {
10581       if ((bailout_id == Deoptimizer::GetDeoptimizationId(
10582               GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
10583           (bailout_id == Deoptimizer::GetDeoptimizationId(
10584               GetIsolate(), info->target_address(), Deoptimizer::SOFT)) ||
10585           (bailout_id == Deoptimizer::GetDeoptimizationId(
10586               GetIsolate(), info->target_address(), Deoptimizer::LAZY))) {
10587         CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
10588         PrintF(out, "            %s\n", last_comment);
10589         return;
10590       }
10591     }
10592   }
10593 }
10594 
10595 
CanDeoptAt(Address pc)10596 bool Code::CanDeoptAt(Address pc) {
10597   DeoptimizationInputData* deopt_data =
10598       DeoptimizationInputData::cast(deoptimization_data());
10599   Address code_start_address = instruction_start();
10600   for (int i = 0; i < deopt_data->DeoptCount(); i++) {
10601     if (deopt_data->Pc(i)->value() == -1) continue;
10602     Address address = code_start_address + deopt_data->Pc(i)->value();
10603     if (address == pc) return true;
10604   }
10605   return false;
10606 }
10607 
10608 
10609 // Identify kind of code.
Kind2String(Kind kind)10610 const char* Code::Kind2String(Kind kind) {
10611   switch (kind) {
10612 #define CASE(name) case name: return #name;
10613     CODE_KIND_LIST(CASE)
10614 #undef CASE
10615     case NUMBER_OF_KINDS: break;
10616   }
10617   UNREACHABLE();
10618   return NULL;
10619 }
10620 
10621 
10622 #ifdef ENABLE_DISASSEMBLER
10623 
DeoptimizationInputDataPrint(OStream & os)10624 void DeoptimizationInputData::DeoptimizationInputDataPrint(
10625     OStream& os) {  // NOLINT
10626   disasm::NameConverter converter;
10627   int deopt_count = DeoptCount();
10628   os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
10629   if (0 != deopt_count) {
10630     os << " index  ast id    argc     pc";
10631     if (FLAG_print_code_verbose) os << "  commands";
10632     os << "\n";
10633   }
10634   for (int i = 0; i < deopt_count; i++) {
10635     // TODO(svenpanne) Add some basic formatting to our streams.
10636     Vector<char> buf1 = Vector<char>::New(128);
10637     SNPrintF(buf1, "%6d  %6d  %6d %6d", i, AstId(i).ToInt(),
10638              ArgumentsStackHeight(i)->value(), Pc(i)->value());
10639     os << buf1.start();
10640 
10641     if (!FLAG_print_code_verbose) {
10642       os << "\n";
10643       continue;
10644     }
10645     // Print details of the frame translation.
10646     int translation_index = TranslationIndex(i)->value();
10647     TranslationIterator iterator(TranslationByteArray(), translation_index);
10648     Translation::Opcode opcode =
10649         static_cast<Translation::Opcode>(iterator.Next());
10650     DCHECK(Translation::BEGIN == opcode);
10651     int frame_count = iterator.Next();
10652     int jsframe_count = iterator.Next();
10653     os << "  " << Translation::StringFor(opcode)
10654        << " {frame count=" << frame_count
10655        << ", js frame count=" << jsframe_count << "}\n";
10656 
10657     while (iterator.HasNext() &&
10658            Translation::BEGIN !=
10659            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
10660       Vector<char> buf2 = Vector<char>::New(128);
10661       SNPrintF(buf2, "%27s    %s ", "", Translation::StringFor(opcode));
10662       os << buf2.start();
10663 
10664       switch (opcode) {
10665         case Translation::BEGIN:
10666           UNREACHABLE();
10667           break;
10668 
10669         case Translation::JS_FRAME: {
10670           int ast_id = iterator.Next();
10671           int function_id = iterator.Next();
10672           unsigned height = iterator.Next();
10673           os << "{ast_id=" << ast_id << ", function=";
10674           if (function_id != Translation::kSelfLiteralId) {
10675             Object* function = LiteralArray()->get(function_id);
10676             os << Brief(JSFunction::cast(function)->shared()->DebugName());
10677           } else {
10678             os << "<self>";
10679           }
10680           os << ", height=" << height << "}";
10681           break;
10682         }
10683 
10684         case Translation::COMPILED_STUB_FRAME: {
10685           Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
10686           os << "{kind=" << stub_kind << "}";
10687           break;
10688         }
10689 
10690         case Translation::ARGUMENTS_ADAPTOR_FRAME:
10691         case Translation::CONSTRUCT_STUB_FRAME: {
10692           int function_id = iterator.Next();
10693           JSFunction* function =
10694               JSFunction::cast(LiteralArray()->get(function_id));
10695           unsigned height = iterator.Next();
10696           os << "{function=" << Brief(function->shared()->DebugName())
10697              << ", height=" << height << "}";
10698           break;
10699         }
10700 
10701         case Translation::GETTER_STUB_FRAME:
10702         case Translation::SETTER_STUB_FRAME: {
10703           int function_id = iterator.Next();
10704           JSFunction* function =
10705               JSFunction::cast(LiteralArray()->get(function_id));
10706           os << "{function=" << Brief(function->shared()->DebugName()) << "}";
10707           break;
10708         }
10709 
10710         case Translation::REGISTER: {
10711           int reg_code = iterator.Next();
10712           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
10713           break;
10714         }
10715 
10716         case Translation::INT32_REGISTER: {
10717           int reg_code = iterator.Next();
10718           os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
10719           break;
10720         }
10721 
10722         case Translation::UINT32_REGISTER: {
10723           int reg_code = iterator.Next();
10724           os << "{input=" << converter.NameOfCPURegister(reg_code)
10725              << " (unsigned)}";
10726           break;
10727         }
10728 
10729         case Translation::DOUBLE_REGISTER: {
10730           int reg_code = iterator.Next();
10731           os << "{input=" << DoubleRegister::AllocationIndexToString(reg_code)
10732              << "}";
10733           break;
10734         }
10735 
10736         case Translation::STACK_SLOT: {
10737           int input_slot_index = iterator.Next();
10738           os << "{input=" << input_slot_index << "}";
10739           break;
10740         }
10741 
10742         case Translation::INT32_STACK_SLOT: {
10743           int input_slot_index = iterator.Next();
10744           os << "{input=" << input_slot_index << "}";
10745           break;
10746         }
10747 
10748         case Translation::UINT32_STACK_SLOT: {
10749           int input_slot_index = iterator.Next();
10750           os << "{input=" << input_slot_index << " (unsigned)}";
10751           break;
10752         }
10753 
10754         case Translation::DOUBLE_STACK_SLOT: {
10755           int input_slot_index = iterator.Next();
10756           os << "{input=" << input_slot_index << "}";
10757           break;
10758         }
10759 
10760         case Translation::LITERAL: {
10761           unsigned literal_index = iterator.Next();
10762           os << "{literal_id=" << literal_index << "}";
10763           break;
10764         }
10765 
10766         case Translation::DUPLICATED_OBJECT: {
10767           int object_index = iterator.Next();
10768           os << "{object_index=" << object_index << "}";
10769           break;
10770         }
10771 
10772         case Translation::ARGUMENTS_OBJECT:
10773         case Translation::CAPTURED_OBJECT: {
10774           int args_length = iterator.Next();
10775           os << "{length=" << args_length << "}";
10776           break;
10777         }
10778       }
10779       os << "\n";
10780     }
10781   }
10782 }
10783 
10784 
DeoptimizationOutputDataPrint(OStream & os)10785 void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
10786     OStream& os) {  // NOLINT
10787   os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
10788      << ")\n";
10789   if (this->DeoptPoints() == 0) return;
10790 
10791   os << "ast id        pc  state\n";
10792   for (int i = 0; i < this->DeoptPoints(); i++) {
10793     int pc_and_state = this->PcAndState(i)->value();
10794     // TODO(svenpanne) Add some basic formatting to our streams.
10795     Vector<char> buf = Vector<char>::New(100);
10796     SNPrintF(buf, "%6d  %8d  %s\n", this->AstId(i).ToInt(),
10797              FullCodeGenerator::PcField::decode(pc_and_state),
10798              FullCodeGenerator::State2String(
10799                  FullCodeGenerator::StateField::decode(pc_and_state)));
10800     os << buf.start();
10801   }
10802 }
10803 
10804 
ICState2String(InlineCacheState state)10805 const char* Code::ICState2String(InlineCacheState state) {
10806   switch (state) {
10807     case UNINITIALIZED: return "UNINITIALIZED";
10808     case PREMONOMORPHIC: return "PREMONOMORPHIC";
10809     case MONOMORPHIC: return "MONOMORPHIC";
10810     case PROTOTYPE_FAILURE:
10811       return "PROTOTYPE_FAILURE";
10812     case POLYMORPHIC: return "POLYMORPHIC";
10813     case MEGAMORPHIC: return "MEGAMORPHIC";
10814     case GENERIC: return "GENERIC";
10815     case DEBUG_STUB: return "DEBUG_STUB";
10816     case DEFAULT:
10817       return "DEFAULT";
10818   }
10819   UNREACHABLE();
10820   return NULL;
10821 }
10822 
10823 
StubType2String(StubType type)10824 const char* Code::StubType2String(StubType type) {
10825   switch (type) {
10826     case NORMAL: return "NORMAL";
10827     case FAST: return "FAST";
10828   }
10829   UNREACHABLE();  // keep the compiler happy
10830   return NULL;
10831 }
10832 
10833 
PrintExtraICState(OStream & os,Kind kind,ExtraICState extra)10834 void Code::PrintExtraICState(OStream& os,  // NOLINT
10835                              Kind kind, ExtraICState extra) {
10836   os << "extra_ic_state = ";
10837   if ((kind == STORE_IC || kind == KEYED_STORE_IC) && (extra == STRICT)) {
10838     os << "STRICT\n";
10839   } else {
10840     os << extra << "\n";
10841   }
10842 }
10843 
10844 
Disassemble(const char * name,OStream & os)10845 void Code::Disassemble(const char* name, OStream& os) {  // NOLINT
10846   os << "kind = " << Kind2String(kind()) << "\n";
10847   if (IsCodeStubOrIC()) {
10848     const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this), true);
10849     os << "major_key = " << (n == NULL ? "null" : n) << "\n";
10850   }
10851   if (is_inline_cache_stub()) {
10852     os << "ic_state = " << ICState2String(ic_state()) << "\n";
10853     PrintExtraICState(os, kind(), extra_ic_state());
10854     if (ic_state() == MONOMORPHIC) {
10855       os << "type = " << StubType2String(type()) << "\n";
10856     }
10857     if (is_compare_ic_stub()) {
10858       DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
10859       CompareICStub stub(stub_key(), GetIsolate());
10860       os << "compare_state = " << CompareICState::GetStateName(stub.left())
10861          << "*" << CompareICState::GetStateName(stub.right()) << " -> "
10862          << CompareICState::GetStateName(stub.state()) << "\n";
10863       os << "compare_operation = " << Token::Name(stub.op()) << "\n";
10864     }
10865   }
10866   if ((name != NULL) && (name[0] != '\0')) {
10867     os << "name = " << name << "\n";
10868   }
10869   if (kind() == OPTIMIZED_FUNCTION) {
10870     os << "stack_slots = " << stack_slots() << "\n";
10871   }
10872 
10873   os << "Instructions (size = " << instruction_size() << ")\n";
10874   // TODO(svenpanne) The Disassembler should use streams, too!
10875   {
10876     CodeTracer::Scope trace_scope(GetIsolate()->GetCodeTracer());
10877     Disassembler::Decode(trace_scope.file(), this);
10878   }
10879   os << "\n";
10880 
10881   if (kind() == FUNCTION) {
10882     DeoptimizationOutputData* data =
10883         DeoptimizationOutputData::cast(this->deoptimization_data());
10884     data->DeoptimizationOutputDataPrint(os);
10885   } else if (kind() == OPTIMIZED_FUNCTION) {
10886     DeoptimizationInputData* data =
10887         DeoptimizationInputData::cast(this->deoptimization_data());
10888     data->DeoptimizationInputDataPrint(os);
10889   }
10890   os << "\n";
10891 
10892   if (is_crankshafted()) {
10893     SafepointTable table(this);
10894     os << "Safepoints (size = " << table.size() << ")\n";
10895     for (unsigned i = 0; i < table.length(); i++) {
10896       unsigned pc_offset = table.GetPcOffset(i);
10897       os << (instruction_start() + pc_offset) << "  ";
10898       // TODO(svenpanne) Add some basic formatting to our streams.
10899       Vector<char> buf1 = Vector<char>::New(30);
10900       SNPrintF(buf1, "%4d", pc_offset);
10901       os << buf1.start() << "  ";
10902       table.PrintEntry(i, os);
10903       os << " (sp -> fp)  ";
10904       SafepointEntry entry = table.GetEntry(i);
10905       if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
10906         Vector<char> buf2 = Vector<char>::New(30);
10907         SNPrintF(buf2, "%6d", entry.deoptimization_index());
10908         os << buf2.start();
10909       } else {
10910         os << "<none>";
10911       }
10912       if (entry.argument_count() > 0) {
10913         os << " argc: " << entry.argument_count();
10914       }
10915       os << "\n";
10916     }
10917     os << "\n";
10918   } else if (kind() == FUNCTION) {
10919     unsigned offset = back_edge_table_offset();
10920     // If there is no back edge table, the "table start" will be at or after
10921     // (due to alignment) the end of the instruction stream.
10922     if (static_cast<int>(offset) < instruction_size()) {
10923       DisallowHeapAllocation no_gc;
10924       BackEdgeTable back_edges(this, &no_gc);
10925 
10926       os << "Back edges (size = " << back_edges.length() << ")\n";
10927       os << "ast_id  pc_offset  loop_depth\n";
10928 
10929       for (uint32_t i = 0; i < back_edges.length(); i++) {
10930         Vector<char> buf = Vector<char>::New(100);
10931         SNPrintF(buf, "%6d  %9u  %10u\n", back_edges.ast_id(i).ToInt(),
10932                  back_edges.pc_offset(i), back_edges.loop_depth(i));
10933         os << buf.start();
10934       }
10935 
10936       os << "\n";
10937     }
10938 #ifdef OBJECT_PRINT
10939     if (!type_feedback_info()->IsUndefined()) {
10940       OFStream os(stdout);
10941       TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
10942       os << "\n";
10943     }
10944 #endif
10945   }
10946 
10947   os << "RelocInfo (size = " << relocation_size() << ")\n";
10948   for (RelocIterator it(this); !it.done(); it.next()) {
10949     it.rinfo()->Print(GetIsolate(), os);
10950   }
10951   os << "\n";
10952 }
10953 #endif  // ENABLE_DISASSEMBLER
10954 
10955 
SetFastElementsCapacityAndLength(Handle<JSObject> object,int capacity,int length,SetFastElementsCapacitySmiMode smi_mode)10956 Handle<FixedArray> JSObject::SetFastElementsCapacityAndLength(
10957     Handle<JSObject> object,
10958     int capacity,
10959     int length,
10960     SetFastElementsCapacitySmiMode smi_mode) {
10961   // We should never end in here with a pixel or external array.
10962   DCHECK(!object->HasExternalArrayElements());
10963 
10964   // Allocate a new fast elements backing store.
10965   Handle<FixedArray> new_elements =
10966       object->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
10967 
10968   ElementsKind elements_kind = object->GetElementsKind();
10969   ElementsKind new_elements_kind;
10970   // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
10971   // or if it's allowed and the old elements array contained only SMIs.
10972   bool has_fast_smi_elements =
10973       (smi_mode == kForceSmiElements) ||
10974       ((smi_mode == kAllowSmiElements) && object->HasFastSmiElements());
10975   if (has_fast_smi_elements) {
10976     if (IsHoleyElementsKind(elements_kind)) {
10977       new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
10978     } else {
10979       new_elements_kind = FAST_SMI_ELEMENTS;
10980     }
10981   } else {
10982     if (IsHoleyElementsKind(elements_kind)) {
10983       new_elements_kind = FAST_HOLEY_ELEMENTS;
10984     } else {
10985       new_elements_kind = FAST_ELEMENTS;
10986     }
10987   }
10988   Handle<FixedArrayBase> old_elements(object->elements());
10989   ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
10990   accessor->CopyElements(object, new_elements, elements_kind);
10991 
10992   if (elements_kind != SLOPPY_ARGUMENTS_ELEMENTS) {
10993     Handle<Map> new_map = (new_elements_kind != elements_kind)
10994         ? GetElementsTransitionMap(object, new_elements_kind)
10995         : handle(object->map());
10996     JSObject::ValidateElements(object);
10997     JSObject::SetMapAndElements(object, new_map, new_elements);
10998 
10999     // Transition through the allocation site as well if present.
11000     JSObject::UpdateAllocationSite(object, new_elements_kind);
11001   } else {
11002     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements);
11003     parameter_map->set(1, *new_elements);
11004   }
11005 
11006   if (FLAG_trace_elements_transitions) {
11007     PrintElementsTransition(stdout, object, elements_kind, old_elements,
11008                             object->GetElementsKind(), new_elements);
11009   }
11010 
11011   if (object->IsJSArray()) {
11012     Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
11013   }
11014   return new_elements;
11015 }
11016 
11017 
SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object,int capacity,int length)11018 void JSObject::SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object,
11019                                                       int capacity,
11020                                                       int length) {
11021   // We should never end in here with a pixel or external array.
11022   DCHECK(!object->HasExternalArrayElements());
11023 
11024   Handle<FixedArrayBase> elems =
11025       object->GetIsolate()->factory()->NewFixedDoubleArray(capacity);
11026 
11027   ElementsKind elements_kind = object->GetElementsKind();
11028   CHECK(elements_kind != SLOPPY_ARGUMENTS_ELEMENTS);
11029   ElementsKind new_elements_kind = elements_kind;
11030   if (IsHoleyElementsKind(elements_kind)) {
11031     new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
11032   } else {
11033     new_elements_kind = FAST_DOUBLE_ELEMENTS;
11034   }
11035 
11036   Handle<Map> new_map = GetElementsTransitionMap(object, new_elements_kind);
11037 
11038   Handle<FixedArrayBase> old_elements(object->elements());
11039   ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS);
11040   accessor->CopyElements(object, elems, elements_kind);
11041 
11042   JSObject::ValidateElements(object);
11043   JSObject::SetMapAndElements(object, new_map, elems);
11044 
11045   if (FLAG_trace_elements_transitions) {
11046     PrintElementsTransition(stdout, object, elements_kind, old_elements,
11047                             object->GetElementsKind(), elems);
11048   }
11049 
11050   if (object->IsJSArray()) {
11051     Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
11052   }
11053 }
11054 
11055 
11056 // static
Initialize(Handle<JSArray> array,int capacity,int length)11057 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
11058   DCHECK(capacity >= 0);
11059   array->GetIsolate()->factory()->NewJSArrayStorage(
11060       array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
11061 }
11062 
11063 
Expand(Handle<JSArray> array,int required_size)11064 void JSArray::Expand(Handle<JSArray> array, int required_size) {
11065   ElementsAccessor* accessor = array->GetElementsAccessor();
11066   accessor->SetCapacityAndLength(array, required_size, required_size);
11067 }
11068 
11069 
11070 // Returns false if the passed-in index is marked non-configurable,
11071 // which will cause the ES5 truncation operation to halt, and thus
11072 // no further old values need be collected.
GetOldValue(Isolate * isolate,Handle<JSObject> object,uint32_t index,List<Handle<Object>> * old_values,List<uint32_t> * indices)11073 static bool GetOldValue(Isolate* isolate,
11074                         Handle<JSObject> object,
11075                         uint32_t index,
11076                         List<Handle<Object> >* old_values,
11077                         List<uint32_t>* indices) {
11078   Maybe<PropertyAttributes> maybe =
11079       JSReceiver::GetOwnElementAttribute(object, index);
11080   DCHECK(maybe.has_value);
11081   DCHECK(maybe.value != ABSENT);
11082   if (maybe.value == DONT_DELETE) return false;
11083   Handle<Object> value;
11084   if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) {
11085     value = Handle<Object>::cast(isolate->factory()->the_hole_value());
11086   } else {
11087     value = Object::GetElement(isolate, object, index).ToHandleChecked();
11088   }
11089   old_values->Add(value);
11090   indices->Add(index);
11091   return true;
11092 }
11093 
EnqueueSpliceRecord(Handle<JSArray> object,uint32_t index,Handle<JSArray> deleted,uint32_t add_count)11094 static void EnqueueSpliceRecord(Handle<JSArray> object,
11095                                 uint32_t index,
11096                                 Handle<JSArray> deleted,
11097                                 uint32_t add_count) {
11098   Isolate* isolate = object->GetIsolate();
11099   HandleScope scope(isolate);
11100   Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
11101   Handle<Object> add_count_object =
11102       isolate->factory()->NewNumberFromUint(add_count);
11103 
11104   Handle<Object> args[] =
11105       { object, index_object, deleted, add_count_object };
11106 
11107   Execution::Call(isolate,
11108                   Handle<JSFunction>(isolate->observers_enqueue_splice()),
11109                   isolate->factory()->undefined_value(),
11110                   arraysize(args),
11111                   args).Assert();
11112 }
11113 
11114 
BeginPerformSplice(Handle<JSArray> object)11115 static void BeginPerformSplice(Handle<JSArray> object) {
11116   Isolate* isolate = object->GetIsolate();
11117   HandleScope scope(isolate);
11118   Handle<Object> args[] = { object };
11119 
11120   Execution::Call(isolate,
11121                   Handle<JSFunction>(isolate->observers_begin_perform_splice()),
11122                   isolate->factory()->undefined_value(),
11123                   arraysize(args),
11124                   args).Assert();
11125 }
11126 
11127 
EndPerformSplice(Handle<JSArray> object)11128 static void EndPerformSplice(Handle<JSArray> object) {
11129   Isolate* isolate = object->GetIsolate();
11130   HandleScope scope(isolate);
11131   Handle<Object> args[] = { object };
11132 
11133   Execution::Call(isolate,
11134                   Handle<JSFunction>(isolate->observers_end_perform_splice()),
11135                   isolate->factory()->undefined_value(),
11136                   arraysize(args),
11137                   args).Assert();
11138 }
11139 
11140 
SetElementsLength(Handle<JSArray> array,Handle<Object> new_length_handle)11141 MaybeHandle<Object> JSArray::SetElementsLength(
11142     Handle<JSArray> array,
11143     Handle<Object> new_length_handle) {
11144   if (array->HasFastElements()) {
11145     // If the new array won't fit in a some non-trivial fraction of the max old
11146     // space size, then force it to go dictionary mode.
11147     int max_fast_array_size = static_cast<int>(
11148         (array->GetHeap()->MaxOldGenerationSize() / kDoubleSize) / 4);
11149     if (new_length_handle->IsNumber() &&
11150         NumberToInt32(*new_length_handle) >= max_fast_array_size) {
11151       NormalizeElements(array);
11152     }
11153   }
11154 
11155   // We should never end in here with a pixel or external array.
11156   DCHECK(array->AllowsSetElementsLength());
11157   if (!array->map()->is_observed()) {
11158     return array->GetElementsAccessor()->SetLength(array, new_length_handle);
11159   }
11160 
11161   Isolate* isolate = array->GetIsolate();
11162   List<uint32_t> indices;
11163   List<Handle<Object> > old_values;
11164   Handle<Object> old_length_handle(array->length(), isolate);
11165   uint32_t old_length = 0;
11166   CHECK(old_length_handle->ToArrayIndex(&old_length));
11167   uint32_t new_length = 0;
11168   CHECK(new_length_handle->ToArrayIndex(&new_length));
11169 
11170   static const PropertyAttributes kNoAttrFilter = NONE;
11171   int num_elements = array->NumberOfOwnElements(kNoAttrFilter);
11172   if (num_elements > 0) {
11173     if (old_length == static_cast<uint32_t>(num_elements)) {
11174       // Simple case for arrays without holes.
11175       for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
11176         if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
11177       }
11178     } else {
11179       // For sparse arrays, only iterate over existing elements.
11180       // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
11181       // the to-be-removed indices twice.
11182       Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
11183       array->GetOwnElementKeys(*keys, kNoAttrFilter);
11184       while (num_elements-- > 0) {
11185         uint32_t index = NumberToUint32(keys->get(num_elements));
11186         if (index < new_length) break;
11187         if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
11188       }
11189     }
11190   }
11191 
11192   Handle<Object> hresult;
11193   ASSIGN_RETURN_ON_EXCEPTION(
11194       isolate, hresult,
11195       array->GetElementsAccessor()->SetLength(array, new_length_handle),
11196       Object);
11197 
11198   CHECK(array->length()->ToArrayIndex(&new_length));
11199   if (old_length == new_length) return hresult;
11200 
11201   BeginPerformSplice(array);
11202 
11203   for (int i = 0; i < indices.length(); ++i) {
11204     // For deletions where the property was an accessor, old_values[i]
11205     // will be the hole, which instructs EnqueueChangeRecord to elide
11206     // the "oldValue" property.
11207     JSObject::EnqueueChangeRecord(
11208         array, "delete", isolate->factory()->Uint32ToString(indices[i]),
11209         old_values[i]);
11210   }
11211   JSObject::EnqueueChangeRecord(
11212       array, "update", isolate->factory()->length_string(),
11213       old_length_handle);
11214 
11215   EndPerformSplice(array);
11216 
11217   uint32_t index = Min(old_length, new_length);
11218   uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
11219   uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
11220   Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
11221   if (delete_count > 0) {
11222     for (int i = indices.length() - 1; i >= 0; i--) {
11223       // Skip deletions where the property was an accessor, leaving holes
11224       // in the array of old values.
11225       if (old_values[i]->IsTheHole()) continue;
11226       JSObject::SetElement(
11227           deleted, indices[i] - index, old_values[i], NONE, SLOPPY).Assert();
11228     }
11229 
11230     SetProperty(deleted, isolate->factory()->length_string(),
11231                 isolate->factory()->NewNumberFromUint(delete_count),
11232                 STRICT).Assert();
11233   }
11234 
11235   EnqueueSpliceRecord(array, index, deleted, add_count);
11236 
11237   return hresult;
11238 }
11239 
11240 
GetPrototypeTransition(Handle<Map> map,Handle<Object> prototype)11241 Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
11242                                         Handle<Object> prototype) {
11243   FixedArray* cache = map->GetPrototypeTransitions();
11244   int number_of_transitions = map->NumberOfProtoTransitions();
11245   const int proto_offset =
11246       kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
11247   const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
11248   const int step = kProtoTransitionElementsPerEntry;
11249   for (int i = 0; i < number_of_transitions; i++) {
11250     if (cache->get(proto_offset + i * step) == *prototype) {
11251       Object* result = cache->get(map_offset + i * step);
11252       return Handle<Map>(Map::cast(result));
11253     }
11254   }
11255   return Handle<Map>();
11256 }
11257 
11258 
PutPrototypeTransition(Handle<Map> map,Handle<Object> prototype,Handle<Map> target_map)11259 Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
11260                                         Handle<Object> prototype,
11261                                         Handle<Map> target_map) {
11262   DCHECK(target_map->IsMap());
11263   DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
11264   // Don't cache prototype transition if this map is either shared, or a map of
11265   // a prototype.
11266   if (map->is_prototype_map()) return map;
11267   if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
11268 
11269   const int step = kProtoTransitionElementsPerEntry;
11270   const int header = kProtoTransitionHeaderSize;
11271 
11272   Handle<FixedArray> cache(map->GetPrototypeTransitions());
11273   int capacity = (cache->length() - header) / step;
11274   int transitions = map->NumberOfProtoTransitions() + 1;
11275 
11276   if (transitions > capacity) {
11277     if (capacity > kMaxCachedPrototypeTransitions) return map;
11278 
11279     // Grow array by factor 2 over and above what we need.
11280     cache = FixedArray::CopySize(cache, transitions * 2 * step + header);
11281 
11282     SetPrototypeTransitions(map, cache);
11283   }
11284 
11285   // Reload number of transitions as GC might shrink them.
11286   int last = map->NumberOfProtoTransitions();
11287   int entry = header + last * step;
11288 
11289   cache->set(entry + kProtoTransitionPrototypeOffset, *prototype);
11290   cache->set(entry + kProtoTransitionMapOffset, *target_map);
11291   map->SetNumberOfProtoTransitions(last + 1);
11292 
11293   return map;
11294 }
11295 
11296 
ZapTransitions()11297 void Map::ZapTransitions() {
11298   TransitionArray* transition_array = transitions();
11299   // TODO(mstarzinger): Temporarily use a slower version instead of the faster
11300   // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
11301   Object** data = transition_array->data_start();
11302   Object* the_hole = GetHeap()->the_hole_value();
11303   int length = transition_array->length();
11304   for (int i = 0; i < length; i++) {
11305     data[i] = the_hole;
11306   }
11307 }
11308 
11309 
ZapPrototypeTransitions()11310 void Map::ZapPrototypeTransitions() {
11311   FixedArray* proto_transitions = GetPrototypeTransitions();
11312   MemsetPointer(proto_transitions->data_start(),
11313                 GetHeap()->the_hole_value(),
11314                 proto_transitions->length());
11315 }
11316 
11317 
11318 // static
AddDependentCompilationInfo(Handle<Map> map,DependentCode::DependencyGroup group,CompilationInfo * info)11319 void Map::AddDependentCompilationInfo(Handle<Map> map,
11320                                       DependentCode::DependencyGroup group,
11321                                       CompilationInfo* info) {
11322   Handle<DependentCode> codes =
11323       DependentCode::Insert(handle(map->dependent_code(), info->isolate()),
11324                             group, info->object_wrapper());
11325   if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
11326   info->dependencies(group)->Add(map, info->zone());
11327 }
11328 
11329 
11330 // static
AddDependentCode(Handle<Map> map,DependentCode::DependencyGroup group,Handle<Code> code)11331 void Map::AddDependentCode(Handle<Map> map,
11332                            DependentCode::DependencyGroup group,
11333                            Handle<Code> code) {
11334   Handle<DependentCode> codes = DependentCode::Insert(
11335       Handle<DependentCode>(map->dependent_code()), group, code);
11336   if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
11337 }
11338 
11339 
11340 // static
AddDependentIC(Handle<Map> map,Handle<Code> stub)11341 void Map::AddDependentIC(Handle<Map> map,
11342                          Handle<Code> stub) {
11343   DCHECK(stub->next_code_link()->IsUndefined());
11344   int n = map->dependent_code()->number_of_entries(DependentCode::kWeakICGroup);
11345   if (n == 0) {
11346     // Slow path: insert the head of the list with possible heap allocation.
11347     Map::AddDependentCode(map, DependentCode::kWeakICGroup, stub);
11348   } else {
11349     // Fast path: link the stub to the existing head of the list without any
11350     // heap allocation.
11351     DCHECK(n == 1);
11352     map->dependent_code()->AddToDependentICList(stub);
11353   }
11354 }
11355 
11356 
GroupStartIndexes(DependentCode * entries)11357 DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
11358   Recompute(entries);
11359 }
11360 
11361 
Recompute(DependentCode * entries)11362 void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
11363   start_indexes_[0] = 0;
11364   for (int g = 1; g <= kGroupCount; g++) {
11365     int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
11366     start_indexes_[g] = start_indexes_[g - 1] + count;
11367   }
11368 }
11369 
11370 
ForObject(Handle<HeapObject> object,DependencyGroup group)11371 DependentCode* DependentCode::ForObject(Handle<HeapObject> object,
11372                                         DependencyGroup group) {
11373   AllowDeferredHandleDereference dependencies_are_safe;
11374   if (group == DependentCode::kPropertyCellChangedGroup) {
11375     return Handle<PropertyCell>::cast(object)->dependent_code();
11376   } else if (group == DependentCode::kAllocationSiteTenuringChangedGroup ||
11377       group == DependentCode::kAllocationSiteTransitionChangedGroup) {
11378     return Handle<AllocationSite>::cast(object)->dependent_code();
11379   }
11380   return Handle<Map>::cast(object)->dependent_code();
11381 }
11382 
11383 
Insert(Handle<DependentCode> entries,DependencyGroup group,Handle<Object> object)11384 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
11385                                             DependencyGroup group,
11386                                             Handle<Object> object) {
11387   GroupStartIndexes starts(*entries);
11388   int start = starts.at(group);
11389   int end = starts.at(group + 1);
11390   int number_of_entries = starts.number_of_entries();
11391   // Check for existing entry to avoid duplicates.
11392   for (int i = start; i < end; i++) {
11393     if (entries->object_at(i) == *object) return entries;
11394   }
11395   if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
11396     int capacity = kCodesStartIndex + number_of_entries + 1;
11397     if (capacity > 5) capacity = capacity * 5 / 4;
11398     Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
11399         FixedArray::CopySize(entries, capacity, TENURED));
11400     // The number of codes can change after GC.
11401     starts.Recompute(*entries);
11402     start = starts.at(group);
11403     end = starts.at(group + 1);
11404     number_of_entries = starts.number_of_entries();
11405     for (int i = 0; i < number_of_entries; i++) {
11406       entries->clear_at(i);
11407     }
11408     // If the old fixed array was empty, we need to reset counters of the
11409     // new array.
11410     if (number_of_entries == 0) {
11411       for (int g = 0; g < kGroupCount; g++) {
11412         new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
11413       }
11414     }
11415     entries = new_entries;
11416   }
11417   entries->ExtendGroup(group);
11418   entries->set_object_at(end, *object);
11419   entries->set_number_of_entries(group, end + 1 - start);
11420   return entries;
11421 }
11422 
11423 
UpdateToFinishedCode(DependencyGroup group,CompilationInfo * info,Code * code)11424 void DependentCode::UpdateToFinishedCode(DependencyGroup group,
11425                                          CompilationInfo* info,
11426                                          Code* code) {
11427   DisallowHeapAllocation no_gc;
11428   AllowDeferredHandleDereference get_object_wrapper;
11429   Foreign* info_wrapper = *info->object_wrapper();
11430   GroupStartIndexes starts(this);
11431   int start = starts.at(group);
11432   int end = starts.at(group + 1);
11433   for (int i = start; i < end; i++) {
11434     if (object_at(i) == info_wrapper) {
11435       set_object_at(i, code);
11436       break;
11437     }
11438   }
11439 
11440 #ifdef DEBUG
11441   for (int i = start; i < end; i++) {
11442     DCHECK(is_code_at(i) || compilation_info_at(i) != info);
11443   }
11444 #endif
11445 }
11446 
11447 
RemoveCompilationInfo(DependentCode::DependencyGroup group,CompilationInfo * info)11448 void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
11449                                           CompilationInfo* info) {
11450   DisallowHeapAllocation no_allocation;
11451   AllowDeferredHandleDereference get_object_wrapper;
11452   Foreign* info_wrapper = *info->object_wrapper();
11453   GroupStartIndexes starts(this);
11454   int start = starts.at(group);
11455   int end = starts.at(group + 1);
11456   // Find compilation info wrapper.
11457   int info_pos = -1;
11458   for (int i = start; i < end; i++) {
11459     if (object_at(i) == info_wrapper) {
11460       info_pos = i;
11461       break;
11462     }
11463   }
11464   if (info_pos == -1) return;  // Not found.
11465   int gap = info_pos;
11466   // Use the last of each group to fill the gap in the previous group.
11467   for (int i = group; i < kGroupCount; i++) {
11468     int last_of_group = starts.at(i + 1) - 1;
11469     DCHECK(last_of_group >= gap);
11470     if (last_of_group == gap) continue;
11471     copy(last_of_group, gap);
11472     gap = last_of_group;
11473   }
11474   DCHECK(gap == starts.number_of_entries() - 1);
11475   clear_at(gap);  // Clear last gap.
11476   set_number_of_entries(group, end - start - 1);
11477 
11478 #ifdef DEBUG
11479   for (int i = start; i < end - 1; i++) {
11480     DCHECK(is_code_at(i) || compilation_info_at(i) != info);
11481   }
11482 #endif
11483 }
11484 
11485 
CodeListContains(Object * head,Code * code)11486 static bool CodeListContains(Object* head, Code* code) {
11487   while (!head->IsUndefined()) {
11488     if (head == code) return true;
11489     head = Code::cast(head)->next_code_link();
11490   }
11491   return false;
11492 }
11493 
11494 
Contains(DependencyGroup group,Code * code)11495 bool DependentCode::Contains(DependencyGroup group, Code* code) {
11496   GroupStartIndexes starts(this);
11497   int start = starts.at(group);
11498   int end = starts.at(group + 1);
11499   if (group == kWeakICGroup) {
11500     return CodeListContains(object_at(start), code);
11501   }
11502   for (int i = start; i < end; i++) {
11503     if (object_at(i) == code) return true;
11504   }
11505   return false;
11506 }
11507 
11508 
MarkCodeForDeoptimization(Isolate * isolate,DependentCode::DependencyGroup group)11509 bool DependentCode::MarkCodeForDeoptimization(
11510     Isolate* isolate,
11511     DependentCode::DependencyGroup group) {
11512   DisallowHeapAllocation no_allocation_scope;
11513   DependentCode::GroupStartIndexes starts(this);
11514   int start = starts.at(group);
11515   int end = starts.at(group + 1);
11516   int code_entries = starts.number_of_entries();
11517   if (start == end) return false;
11518 
11519   // Mark all the code that needs to be deoptimized.
11520   bool marked = false;
11521   for (int i = start; i < end; i++) {
11522     if (is_code_at(i)) {
11523       Code* code = code_at(i);
11524       if (!code->marked_for_deoptimization()) {
11525         SetMarkedForDeoptimization(code, group);
11526         marked = true;
11527       }
11528     } else {
11529       CompilationInfo* info = compilation_info_at(i);
11530       info->AbortDueToDependencyChange();
11531     }
11532   }
11533   // Compact the array by moving all subsequent groups to fill in the new holes.
11534   for (int src = end, dst = start; src < code_entries; src++, dst++) {
11535     copy(src, dst);
11536   }
11537   // Now the holes are at the end of the array, zap them for heap-verifier.
11538   int removed = end - start;
11539   for (int i = code_entries - removed; i < code_entries; i++) {
11540     clear_at(i);
11541   }
11542   set_number_of_entries(group, 0);
11543   return marked;
11544 }
11545 
11546 
DeoptimizeDependentCodeGroup(Isolate * isolate,DependentCode::DependencyGroup group)11547 void DependentCode::DeoptimizeDependentCodeGroup(
11548     Isolate* isolate,
11549     DependentCode::DependencyGroup group) {
11550   DCHECK(AllowCodeDependencyChange::IsAllowed());
11551   DisallowHeapAllocation no_allocation_scope;
11552   bool marked = MarkCodeForDeoptimization(isolate, group);
11553 
11554   if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
11555 }
11556 
11557 
AddToDependentICList(Handle<Code> stub)11558 void DependentCode::AddToDependentICList(Handle<Code> stub) {
11559   DisallowHeapAllocation no_heap_allocation;
11560   GroupStartIndexes starts(this);
11561   int i = starts.at(kWeakICGroup);
11562   Object* head = object_at(i);
11563   // Try to insert the stub after the head of the list to minimize number of
11564   // writes to the DependentCode array, since a write to the array can make it
11565   // strong if it was alread marked by incremental marker.
11566   if (head->IsCode()) {
11567     stub->set_next_code_link(Code::cast(head)->next_code_link());
11568     Code::cast(head)->set_next_code_link(*stub);
11569   } else {
11570     stub->set_next_code_link(head);
11571     set_object_at(i, *stub);
11572   }
11573 }
11574 
11575 
SetMarkedForDeoptimization(Code * code,DependencyGroup group)11576 void DependentCode::SetMarkedForDeoptimization(Code* code,
11577                                                DependencyGroup group) {
11578   code->set_marked_for_deoptimization(true);
11579   if (FLAG_trace_deopt &&
11580       (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
11581     DeoptimizationInputData* deopt_data =
11582         DeoptimizationInputData::cast(code->deoptimization_data());
11583     CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
11584     PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
11585                          " (opt #%d) for deoptimization, reason: %s]\n",
11586            reinterpret_cast<intptr_t>(code),
11587            deopt_data->OptimizationId()->value(), DependencyGroupName(group));
11588   }
11589 }
11590 
11591 
DependencyGroupName(DependencyGroup group)11592 const char* DependentCode::DependencyGroupName(DependencyGroup group) {
11593   switch (group) {
11594     case kWeakICGroup:
11595       return "weak-ic";
11596     case kWeakCodeGroup:
11597       return "weak-code";
11598     case kTransitionGroup:
11599       return "transition";
11600     case kPrototypeCheckGroup:
11601       return "prototype-check";
11602     case kElementsCantBeAddedGroup:
11603       return "elements-cant-be-added";
11604     case kPropertyCellChangedGroup:
11605       return "property-cell-changed";
11606     case kFieldTypeGroup:
11607       return "field-type";
11608     case kInitialMapChangedGroup:
11609       return "initial-map-changed";
11610     case kAllocationSiteTenuringChangedGroup:
11611       return "allocation-site-tenuring-changed";
11612     case kAllocationSiteTransitionChangedGroup:
11613       return "allocation-site-transition-changed";
11614   }
11615   UNREACHABLE();
11616   return "?";
11617 }
11618 
11619 
TransitionToPrototype(Handle<Map> map,Handle<Object> prototype)11620 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
11621                                        Handle<Object> prototype) {
11622   Handle<Map> new_map = GetPrototypeTransition(map, prototype);
11623   if (new_map.is_null()) {
11624     new_map = Copy(map);
11625     PutPrototypeTransition(map, prototype, new_map);
11626     new_map->set_prototype(*prototype);
11627   }
11628   return new_map;
11629 }
11630 
11631 
SetPrototype(Handle<JSObject> object,Handle<Object> value,bool from_javascript)11632 MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
11633                                            Handle<Object> value,
11634                                            bool from_javascript) {
11635 #ifdef DEBUG
11636   int size = object->Size();
11637 #endif
11638 
11639   Isolate* isolate = object->GetIsolate();
11640   Heap* heap = isolate->heap();
11641   // Silently ignore the change if value is not a JSObject or null.
11642   // SpiderMonkey behaves this way.
11643   if (!value->IsJSReceiver() && !value->IsNull()) return value;
11644 
11645   // From 8.6.2 Object Internal Methods
11646   // ...
11647   // In addition, if [[Extensible]] is false the value of the [[Class]] and
11648   // [[Prototype]] internal properties of the object may not be modified.
11649   // ...
11650   // Implementation specific extensions that modify [[Class]], [[Prototype]]
11651   // or [[Extensible]] must not violate the invariants defined in the preceding
11652   // paragraph.
11653   if (!object->map()->is_extensible()) {
11654     Handle<Object> args[] = { object };
11655     THROW_NEW_ERROR(isolate, NewTypeError("non_extensible_proto",
11656                                           HandleVector(args, arraysize(args))),
11657                     Object);
11658   }
11659 
11660   // Before we can set the prototype we need to be sure
11661   // prototype cycles are prevented.
11662   // It is sufficient to validate that the receiver is not in the new prototype
11663   // chain.
11664   for (PrototypeIterator iter(isolate, *value,
11665                               PrototypeIterator::START_AT_RECEIVER);
11666        !iter.IsAtEnd(); iter.Advance()) {
11667     if (JSReceiver::cast(iter.GetCurrent()) == *object) {
11668       // Cycle detected.
11669       THROW_NEW_ERROR(isolate,
11670                       NewError("cyclic_proto", HandleVector<Object>(NULL, 0)),
11671                       Object);
11672     }
11673   }
11674 
11675   bool dictionary_elements_in_chain =
11676       object->map()->DictionaryElementsInPrototypeChainOnly();
11677   Handle<JSObject> real_receiver = object;
11678 
11679   if (from_javascript) {
11680     // Find the first object in the chain whose prototype object is not
11681     // hidden and set the new prototype on that object.
11682     PrototypeIterator iter(isolate, real_receiver);
11683     while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
11684       real_receiver =
11685           Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
11686       iter.Advance();
11687     }
11688   }
11689 
11690   // Set the new prototype of the object.
11691   Handle<Map> map(real_receiver->map());
11692 
11693   // Nothing to do if prototype is already set.
11694   if (map->prototype() == *value) return value;
11695 
11696   if (value->IsJSObject()) {
11697     PrototypeOptimizationMode mode =
11698         from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
11699     JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), mode);
11700   }
11701 
11702   Handle<Map> new_map = Map::TransitionToPrototype(map, value);
11703   DCHECK(new_map->prototype() == *value);
11704   JSObject::MigrateToMap(real_receiver, new_map);
11705 
11706   if (!dictionary_elements_in_chain &&
11707       new_map->DictionaryElementsInPrototypeChainOnly()) {
11708     // If the prototype chain didn't previously have element callbacks, then
11709     // KeyedStoreICs need to be cleared to ensure any that involve this
11710     // map go generic.
11711     object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
11712   }
11713 
11714   heap->ClearInstanceofCache();
11715   DCHECK(size == object->Size());
11716   return value;
11717 }
11718 
11719 
EnsureCanContainElements(Handle<JSObject> object,Arguments * args,uint32_t first_arg,uint32_t arg_count,EnsureElementsMode mode)11720 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
11721                                         Arguments* args,
11722                                         uint32_t first_arg,
11723                                         uint32_t arg_count,
11724                                         EnsureElementsMode mode) {
11725   // Elements in |Arguments| are ordered backwards (because they're on the
11726   // stack), but the method that's called here iterates over them in forward
11727   // direction.
11728   return EnsureCanContainElements(
11729       object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
11730 }
11731 
11732 
GetOwnElementAccessorPair(Handle<JSObject> object,uint32_t index)11733 MaybeHandle<AccessorPair> JSObject::GetOwnElementAccessorPair(
11734     Handle<JSObject> object,
11735     uint32_t index) {
11736   if (object->IsJSGlobalProxy()) {
11737     PrototypeIterator iter(object->GetIsolate(), object);
11738     if (iter.IsAtEnd()) return MaybeHandle<AccessorPair>();
11739     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
11740     return GetOwnElementAccessorPair(
11741         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
11742   }
11743 
11744   // Check for lookup interceptor.
11745   if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>();
11746 
11747   return object->GetElementsAccessor()->GetAccessorPair(object, object, index);
11748 }
11749 
11750 
SetElementWithInterceptor(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,StrictMode strict_mode,bool check_prototype,SetPropertyMode set_mode)11751 MaybeHandle<Object> JSObject::SetElementWithInterceptor(
11752     Handle<JSObject> object,
11753     uint32_t index,
11754     Handle<Object> value,
11755     PropertyAttributes attributes,
11756     StrictMode strict_mode,
11757     bool check_prototype,
11758     SetPropertyMode set_mode) {
11759   Isolate* isolate = object->GetIsolate();
11760 
11761   // Make sure that the top context does not change when doing
11762   // callbacks or interceptor calls.
11763   AssertNoContextChange ncc(isolate);
11764 
11765   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
11766   if (!interceptor->setter()->IsUndefined()) {
11767     v8::IndexedPropertySetterCallback setter =
11768         v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
11769     LOG(isolate,
11770         ApiIndexedPropertyAccess("interceptor-indexed-set", *object, index));
11771     PropertyCallbackArguments args(isolate, interceptor->data(), *object,
11772                                    *object);
11773     v8::Handle<v8::Value> result =
11774         args.Call(setter, index, v8::Utils::ToLocal(value));
11775     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
11776     if (!result.IsEmpty()) return value;
11777   }
11778 
11779   return SetElementWithoutInterceptor(object, index, value, attributes,
11780                                       strict_mode,
11781                                       check_prototype,
11782                                       set_mode);
11783 }
11784 
11785 
GetElementWithCallback(Handle<JSObject> object,Handle<Object> receiver,Handle<Object> structure,uint32_t index,Handle<Object> holder)11786 MaybeHandle<Object> JSObject::GetElementWithCallback(
11787     Handle<JSObject> object,
11788     Handle<Object> receiver,
11789     Handle<Object> structure,
11790     uint32_t index,
11791     Handle<Object> holder) {
11792   Isolate* isolate = object->GetIsolate();
11793   DCHECK(!structure->IsForeign());
11794   // api style callbacks.
11795   if (structure->IsExecutableAccessorInfo()) {
11796     Handle<ExecutableAccessorInfo> data =
11797         Handle<ExecutableAccessorInfo>::cast(structure);
11798     Object* fun_obj = data->getter();
11799     v8::AccessorNameGetterCallback call_fun =
11800         v8::ToCData<v8::AccessorNameGetterCallback>(fun_obj);
11801     if (call_fun == NULL) return isolate->factory()->undefined_value();
11802     Handle<JSObject> holder_handle = Handle<JSObject>::cast(holder);
11803     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
11804     Handle<String> key = isolate->factory()->NumberToString(number);
11805     LOG(isolate, ApiNamedPropertyAccess("load", *holder_handle, *key));
11806     PropertyCallbackArguments
11807         args(isolate, data->data(), *receiver, *holder_handle);
11808     v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key));
11809     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
11810     if (result.IsEmpty()) return isolate->factory()->undefined_value();
11811     Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
11812     result_internal->VerifyApiCallResultType();
11813     // Rebox handle before return.
11814     return handle(*result_internal, isolate);
11815   }
11816 
11817   // __defineGetter__ callback
11818   if (structure->IsAccessorPair()) {
11819     Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
11820                           isolate);
11821     if (getter->IsSpecFunction()) {
11822       // TODO(rossberg): nicer would be to cast to some JSCallable here...
11823       return GetPropertyWithDefinedGetter(
11824           receiver, Handle<JSReceiver>::cast(getter));
11825     }
11826     // Getter is not a function.
11827     return isolate->factory()->undefined_value();
11828   }
11829 
11830   if (structure->IsDeclaredAccessorInfo()) {
11831     return GetDeclaredAccessorProperty(
11832         receiver, Handle<DeclaredAccessorInfo>::cast(structure), isolate);
11833   }
11834 
11835   UNREACHABLE();
11836   return MaybeHandle<Object>();
11837 }
11838 
11839 
SetElementWithCallback(Handle<JSObject> object,Handle<Object> structure,uint32_t index,Handle<Object> value,Handle<JSObject> holder,StrictMode strict_mode)11840 MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object,
11841                                                      Handle<Object> structure,
11842                                                      uint32_t index,
11843                                                      Handle<Object> value,
11844                                                      Handle<JSObject> holder,
11845                                                      StrictMode strict_mode) {
11846   Isolate* isolate = object->GetIsolate();
11847 
11848   // We should never get here to initialize a const with the hole
11849   // value since a const declaration would conflict with the setter.
11850   DCHECK(!value->IsTheHole());
11851   DCHECK(!structure->IsForeign());
11852   if (structure->IsExecutableAccessorInfo()) {
11853     // api style callbacks
11854     Handle<ExecutableAccessorInfo> data =
11855         Handle<ExecutableAccessorInfo>::cast(structure);
11856     Object* call_obj = data->setter();
11857     v8::AccessorNameSetterCallback call_fun =
11858         v8::ToCData<v8::AccessorNameSetterCallback>(call_obj);
11859     if (call_fun == NULL) return value;
11860     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
11861     Handle<String> key(isolate->factory()->NumberToString(number));
11862     LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
11863     PropertyCallbackArguments
11864         args(isolate, data->data(), *object, *holder);
11865     args.Call(call_fun,
11866               v8::Utils::ToLocal(key),
11867               v8::Utils::ToLocal(value));
11868     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
11869     return value;
11870   }
11871 
11872   if (structure->IsAccessorPair()) {
11873     Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
11874     if (setter->IsSpecFunction()) {
11875       // TODO(rossberg): nicer would be to cast to some JSCallable here...
11876       return SetPropertyWithDefinedSetter(
11877           object, Handle<JSReceiver>::cast(setter), value);
11878     } else {
11879       if (strict_mode == SLOPPY) return value;
11880       Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
11881       Handle<Object> args[2] = { key, holder };
11882       THROW_NEW_ERROR(
11883           isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
11884           Object);
11885     }
11886   }
11887 
11888   // TODO(dcarney): Handle correctly.
11889   if (structure->IsDeclaredAccessorInfo()) return value;
11890 
11891   UNREACHABLE();
11892   return MaybeHandle<Object>();
11893 }
11894 
11895 
HasFastArgumentsElements()11896 bool JSObject::HasFastArgumentsElements() {
11897   Heap* heap = GetHeap();
11898   if (!elements()->IsFixedArray()) return false;
11899   FixedArray* elements = FixedArray::cast(this->elements());
11900   if (elements->map() != heap->sloppy_arguments_elements_map()) {
11901     return false;
11902   }
11903   FixedArray* arguments = FixedArray::cast(elements->get(1));
11904   return !arguments->IsDictionary();
11905 }
11906 
11907 
HasDictionaryArgumentsElements()11908 bool JSObject::HasDictionaryArgumentsElements() {
11909   Heap* heap = GetHeap();
11910   if (!elements()->IsFixedArray()) return false;
11911   FixedArray* elements = FixedArray::cast(this->elements());
11912   if (elements->map() != heap->sloppy_arguments_elements_map()) {
11913     return false;
11914   }
11915   FixedArray* arguments = FixedArray::cast(elements->get(1));
11916   return arguments->IsDictionary();
11917 }
11918 
11919 
11920 // Adding n elements in fast case is O(n*n).
11921 // Note: revisit design to have dual undefined values to capture absent
11922 // elements.
SetFastElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,StrictMode strict_mode,bool check_prototype)11923 MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
11924                                              uint32_t index,
11925                                              Handle<Object> value,
11926                                              StrictMode strict_mode,
11927                                              bool check_prototype) {
11928   DCHECK(object->HasFastSmiOrObjectElements() ||
11929          object->HasFastArgumentsElements());
11930 
11931   Isolate* isolate = object->GetIsolate();
11932 
11933   // Array optimizations rely on the prototype lookups of Array objects always
11934   // returning undefined. If there is a store to the initial prototype object,
11935   // make sure all of these optimizations are invalidated.
11936   if (isolate->is_initial_object_prototype(*object) ||
11937       isolate->is_initial_array_prototype(*object)) {
11938     object->map()->dependent_code()->DeoptimizeDependentCodeGroup(isolate,
11939         DependentCode::kElementsCantBeAddedGroup);
11940   }
11941 
11942   Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
11943   if (backing_store->map() ==
11944       isolate->heap()->sloppy_arguments_elements_map()) {
11945     backing_store = handle(FixedArray::cast(backing_store->get(1)));
11946   } else {
11947     backing_store = EnsureWritableFastElements(object);
11948   }
11949   uint32_t capacity = static_cast<uint32_t>(backing_store->length());
11950 
11951   if (check_prototype &&
11952       (index >= capacity || backing_store->get(index)->IsTheHole())) {
11953     bool found;
11954     MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
11955         object, index, value, &found, strict_mode);
11956     if (found) return result;
11957   }
11958 
11959   uint32_t new_capacity = capacity;
11960   // Check if the length property of this object needs to be updated.
11961   uint32_t array_length = 0;
11962   bool must_update_array_length = false;
11963   bool introduces_holes = true;
11964   if (object->IsJSArray()) {
11965     CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
11966     introduces_holes = index > array_length;
11967     if (index >= array_length) {
11968       must_update_array_length = true;
11969       array_length = index + 1;
11970     }
11971   } else {
11972     introduces_holes = index >= capacity;
11973   }
11974 
11975   // If the array is growing, and it's not growth by a single element at the
11976   // end, make sure that the ElementsKind is HOLEY.
11977   ElementsKind elements_kind = object->GetElementsKind();
11978   if (introduces_holes &&
11979       IsFastElementsKind(elements_kind) &&
11980       !IsFastHoleyElementsKind(elements_kind)) {
11981     ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
11982     TransitionElementsKind(object, transitioned_kind);
11983   }
11984 
11985   // Check if the capacity of the backing store needs to be increased, or if
11986   // a transition to slow elements is necessary.
11987   if (index >= capacity) {
11988     bool convert_to_slow = true;
11989     if ((index - capacity) < kMaxGap) {
11990       new_capacity = NewElementsCapacity(index + 1);
11991       DCHECK(new_capacity > index);
11992       if (!object->ShouldConvertToSlowElements(new_capacity)) {
11993         convert_to_slow = false;
11994       }
11995     }
11996     if (convert_to_slow) {
11997       NormalizeElements(object);
11998       return SetDictionaryElement(object, index, value, NONE, strict_mode,
11999                                   check_prototype);
12000     }
12001   }
12002   // Convert to fast double elements if appropriate.
12003   if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
12004     // Consider fixing the boilerplate as well if we have one.
12005     ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
12006         ? FAST_HOLEY_DOUBLE_ELEMENTS
12007         : FAST_DOUBLE_ELEMENTS;
12008 
12009     UpdateAllocationSite(object, to_kind);
12010 
12011     SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length);
12012     FixedDoubleArray::cast(object->elements())->set(index, value->Number());
12013     JSObject::ValidateElements(object);
12014     return value;
12015   }
12016   // Change elements kind from Smi-only to generic FAST if necessary.
12017   if (object->HasFastSmiElements() && !value->IsSmi()) {
12018     ElementsKind kind = object->HasFastHoleyElements()
12019         ? FAST_HOLEY_ELEMENTS
12020         : FAST_ELEMENTS;
12021 
12022     UpdateAllocationSite(object, kind);
12023     Handle<Map> new_map = GetElementsTransitionMap(object, kind);
12024     JSObject::MigrateToMap(object, new_map);
12025     DCHECK(IsFastObjectElementsKind(object->GetElementsKind()));
12026   }
12027   // Increase backing store capacity if that's been decided previously.
12028   if (new_capacity != capacity) {
12029     SetFastElementsCapacitySmiMode smi_mode =
12030         value->IsSmi() && object->HasFastSmiElements()
12031             ? kAllowSmiElements
12032             : kDontAllowSmiElements;
12033     Handle<FixedArray> new_elements =
12034         SetFastElementsCapacityAndLength(object, new_capacity, array_length,
12035                                          smi_mode);
12036     new_elements->set(index, *value);
12037     JSObject::ValidateElements(object);
12038     return value;
12039   }
12040 
12041   // Finally, set the new element and length.
12042   DCHECK(object->elements()->IsFixedArray());
12043   backing_store->set(index, *value);
12044   if (must_update_array_length) {
12045     Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
12046   }
12047   return value;
12048 }
12049 
12050 
SetDictionaryElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,StrictMode strict_mode,bool check_prototype,SetPropertyMode set_mode)12051 MaybeHandle<Object> JSObject::SetDictionaryElement(
12052     Handle<JSObject> object,
12053     uint32_t index,
12054     Handle<Object> value,
12055     PropertyAttributes attributes,
12056     StrictMode strict_mode,
12057     bool check_prototype,
12058     SetPropertyMode set_mode) {
12059   DCHECK(object->HasDictionaryElements() ||
12060          object->HasDictionaryArgumentsElements());
12061   Isolate* isolate = object->GetIsolate();
12062 
12063   // Insert element in the dictionary.
12064   Handle<FixedArray> elements(FixedArray::cast(object->elements()));
12065   bool is_arguments =
12066       (elements->map() == isolate->heap()->sloppy_arguments_elements_map());
12067   Handle<SeededNumberDictionary> dictionary(is_arguments
12068     ? SeededNumberDictionary::cast(elements->get(1))
12069     : SeededNumberDictionary::cast(*elements));
12070 
12071   int entry = dictionary->FindEntry(index);
12072   if (entry != SeededNumberDictionary::kNotFound) {
12073     Handle<Object> element(dictionary->ValueAt(entry), isolate);
12074     PropertyDetails details = dictionary->DetailsAt(entry);
12075     if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
12076       return SetElementWithCallback(object, element, index, value, object,
12077                                     strict_mode);
12078     } else {
12079       dictionary->UpdateMaxNumberKey(index);
12080       // If a value has not been initialized we allow writing to it even if it
12081       // is read-only (a declared const that has not been initialized).  If a
12082       // value is being defined we skip attribute checks completely.
12083       if (set_mode == DEFINE_PROPERTY) {
12084         details = PropertyDetails(
12085             attributes, NORMAL, details.dictionary_index());
12086         dictionary->DetailsAtPut(entry, details);
12087       } else if (details.IsReadOnly() && !element->IsTheHole()) {
12088         if (strict_mode == SLOPPY) {
12089           return isolate->factory()->undefined_value();
12090         } else {
12091           Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12092           Handle<Object> args[2] = { number, object };
12093           THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
12094                                                 HandleVector(args, 2)),
12095                           Object);
12096         }
12097       }
12098       // Elements of the arguments object in slow mode might be slow aliases.
12099       if (is_arguments && element->IsAliasedArgumentsEntry()) {
12100         Handle<AliasedArgumentsEntry> entry =
12101             Handle<AliasedArgumentsEntry>::cast(element);
12102         Handle<Context> context(Context::cast(elements->get(0)));
12103         int context_index = entry->aliased_context_slot();
12104         DCHECK(!context->get(context_index)->IsTheHole());
12105         context->set(context_index, *value);
12106         // For elements that are still writable we keep slow aliasing.
12107         if (!details.IsReadOnly()) value = element;
12108       }
12109       dictionary->ValueAtPut(entry, *value);
12110     }
12111   } else {
12112     // Index not already used. Look for an accessor in the prototype chain.
12113     // Can cause GC!
12114     if (check_prototype) {
12115       bool found;
12116       MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12117           object, index, value, &found, strict_mode);
12118       if (found) return result;
12119     }
12120 
12121     // When we set the is_extensible flag to false we always force the
12122     // element into dictionary mode (and force them to stay there).
12123     if (!object->map()->is_extensible()) {
12124       if (strict_mode == SLOPPY) {
12125         return isolate->factory()->undefined_value();
12126       } else {
12127         Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12128         Handle<String> name = isolate->factory()->NumberToString(number);
12129         Handle<Object> args[1] = { name };
12130         THROW_NEW_ERROR(isolate, NewTypeError("object_not_extensible",
12131                                               HandleVector(args, 1)),
12132                         Object);
12133       }
12134     }
12135 
12136     PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
12137     Handle<SeededNumberDictionary> new_dictionary =
12138         SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
12139                                                details);
12140     if (*dictionary != *new_dictionary) {
12141       if (is_arguments) {
12142         elements->set(1, *new_dictionary);
12143       } else {
12144         object->set_elements(*new_dictionary);
12145       }
12146       dictionary = new_dictionary;
12147     }
12148   }
12149 
12150   // Update the array length if this JSObject is an array.
12151   if (object->IsJSArray()) {
12152     JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index,
12153                                           value);
12154   }
12155 
12156   // Attempt to put this object back in fast case.
12157   if (object->ShouldConvertToFastElements()) {
12158     uint32_t new_length = 0;
12159     if (object->IsJSArray()) {
12160       CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&new_length));
12161     } else {
12162       new_length = dictionary->max_number_key() + 1;
12163     }
12164     bool has_smi_only_elements = false;
12165     bool should_convert_to_fast_double_elements =
12166         object->ShouldConvertToFastDoubleElements(&has_smi_only_elements);
12167     SetFastElementsCapacitySmiMode smi_mode =
12168         has_smi_only_elements ? kForceSmiElements : kAllowSmiElements;
12169 
12170     if (should_convert_to_fast_double_elements) {
12171       SetFastDoubleElementsCapacityAndLength(object, new_length, new_length);
12172     } else {
12173       SetFastElementsCapacityAndLength(object, new_length, new_length,
12174                                        smi_mode);
12175     }
12176     JSObject::ValidateElements(object);
12177 #ifdef DEBUG
12178     if (FLAG_trace_normalization) {
12179       OFStream os(stdout);
12180       os << "Object elements are fast case again:\n";
12181       object->Print(os);
12182     }
12183 #endif
12184   }
12185   return value;
12186 }
12187 
SetFastDoubleElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,StrictMode strict_mode,bool check_prototype)12188 MaybeHandle<Object> JSObject::SetFastDoubleElement(
12189     Handle<JSObject> object,
12190     uint32_t index,
12191     Handle<Object> value,
12192     StrictMode strict_mode,
12193     bool check_prototype) {
12194   DCHECK(object->HasFastDoubleElements());
12195 
12196   Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
12197   uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
12198 
12199   // If storing to an element that isn't in the array, pass the store request
12200   // up the prototype chain before storing in the receiver's elements.
12201   if (check_prototype &&
12202       (index >= elms_length ||
12203        Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) {
12204     bool found;
12205     MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12206         object, index, value, &found, strict_mode);
12207     if (found) return result;
12208   }
12209 
12210   // If the value object is not a heap number, switch to fast elements and try
12211   // again.
12212   bool value_is_smi = value->IsSmi();
12213   bool introduces_holes = true;
12214   uint32_t length = elms_length;
12215   if (object->IsJSArray()) {
12216     CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&length));
12217     introduces_holes = index > length;
12218   } else {
12219     introduces_holes = index >= elms_length;
12220   }
12221 
12222   if (!value->IsNumber()) {
12223     SetFastElementsCapacityAndLength(object, elms_length, length,
12224                                      kDontAllowSmiElements);
12225     Handle<Object> result;
12226     ASSIGN_RETURN_ON_EXCEPTION(
12227         object->GetIsolate(), result,
12228         SetFastElement(object, index, value, strict_mode, check_prototype),
12229         Object);
12230     JSObject::ValidateElements(object);
12231     return result;
12232   }
12233 
12234   double double_value = value_is_smi
12235       ? static_cast<double>(Handle<Smi>::cast(value)->value())
12236       : Handle<HeapNumber>::cast(value)->value();
12237 
12238   // If the array is growing, and it's not growth by a single element at the
12239   // end, make sure that the ElementsKind is HOLEY.
12240   ElementsKind elements_kind = object->GetElementsKind();
12241   if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
12242     ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12243     TransitionElementsKind(object, transitioned_kind);
12244   }
12245 
12246   // Check whether there is extra space in the fixed array.
12247   if (index < elms_length) {
12248     Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements()));
12249     elms->set(index, double_value);
12250     if (object->IsJSArray()) {
12251       // Update the length of the array if needed.
12252       uint32_t array_length = 0;
12253       CHECK(
12254           Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
12255       if (index >= array_length) {
12256         Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1));
12257       }
12258     }
12259     return value;
12260   }
12261 
12262   // Allow gap in fast case.
12263   if ((index - elms_length) < kMaxGap) {
12264     // Try allocating extra space.
12265     int new_capacity = NewElementsCapacity(index+1);
12266     if (!object->ShouldConvertToSlowElements(new_capacity)) {
12267       DCHECK(static_cast<uint32_t>(new_capacity) > index);
12268       SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1);
12269       FixedDoubleArray::cast(object->elements())->set(index, double_value);
12270       JSObject::ValidateElements(object);
12271       return value;
12272     }
12273   }
12274 
12275   // Otherwise default to slow case.
12276   DCHECK(object->HasFastDoubleElements());
12277   DCHECK(object->map()->has_fast_double_elements());
12278   DCHECK(object->elements()->IsFixedDoubleArray() ||
12279          object->elements()->length() == 0);
12280 
12281   NormalizeElements(object);
12282   DCHECK(object->HasDictionaryElements());
12283   return SetElement(object, index, value, NONE, strict_mode, check_prototype);
12284 }
12285 
12286 
SetElement(Handle<JSReceiver> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,StrictMode strict_mode)12287 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
12288                                            uint32_t index,
12289                                            Handle<Object> value,
12290                                            PropertyAttributes attributes,
12291                                            StrictMode strict_mode) {
12292   if (object->IsJSProxy()) {
12293     return JSProxy::SetElementWithHandler(
12294         Handle<JSProxy>::cast(object), object, index, value, strict_mode);
12295   }
12296   return JSObject::SetElement(
12297       Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
12298 }
12299 
12300 
SetOwnElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,StrictMode strict_mode)12301 MaybeHandle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
12302                                             uint32_t index,
12303                                             Handle<Object> value,
12304                                             StrictMode strict_mode) {
12305   DCHECK(!object->HasExternalArrayElements());
12306   return JSObject::SetElement(object, index, value, NONE, strict_mode, false);
12307 }
12308 
12309 
SetElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,StrictMode strict_mode,bool check_prototype,SetPropertyMode set_mode)12310 MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
12311                                          uint32_t index,
12312                                          Handle<Object> value,
12313                                          PropertyAttributes attributes,
12314                                          StrictMode strict_mode,
12315                                          bool check_prototype,
12316                                          SetPropertyMode set_mode) {
12317   Isolate* isolate = object->GetIsolate();
12318 
12319   if (object->HasExternalArrayElements() ||
12320       object->HasFixedTypedArrayElements()) {
12321     if (!value->IsNumber() && !value->IsUndefined()) {
12322       ASSIGN_RETURN_ON_EXCEPTION(
12323           isolate, value,
12324           Execution::ToNumber(isolate, value), Object);
12325     }
12326   }
12327 
12328   // Check access rights if needed.
12329   if (object->IsAccessCheckNeeded()) {
12330     if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_SET)) {
12331       isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
12332       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12333       return value;
12334     }
12335   }
12336 
12337   if (object->IsJSGlobalProxy()) {
12338     PrototypeIterator iter(isolate, object);
12339     if (iter.IsAtEnd()) return value;
12340     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
12341     return SetElement(
12342         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
12343         value, attributes, strict_mode, check_prototype, set_mode);
12344   }
12345 
12346   // Don't allow element properties to be redefined for external arrays.
12347   if ((object->HasExternalArrayElements() ||
12348           object->HasFixedTypedArrayElements()) &&
12349       set_mode == DEFINE_PROPERTY) {
12350     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12351     Handle<Object> args[] = { object, number };
12352     THROW_NEW_ERROR(isolate, NewTypeError("redef_external_array_element",
12353                                           HandleVector(args, arraysize(args))),
12354                     Object);
12355   }
12356 
12357   // Normalize the elements to enable attributes on the property.
12358   if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
12359     Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
12360     // Make sure that we never go back to fast case.
12361     dictionary->set_requires_slow_elements();
12362   }
12363 
12364   if (!object->map()->is_observed()) {
12365     return object->HasIndexedInterceptor()
12366       ? SetElementWithInterceptor(object, index, value, attributes,
12367                                   strict_mode, check_prototype, set_mode)
12368       : SetElementWithoutInterceptor(object, index, value, attributes,
12369                                      strict_mode, check_prototype, set_mode);
12370   }
12371 
12372   Maybe<PropertyAttributes> maybe =
12373       JSReceiver::GetOwnElementAttribute(object, index);
12374   if (!maybe.has_value) return MaybeHandle<Object>();
12375   PropertyAttributes old_attributes = maybe.value;
12376 
12377   Handle<Object> old_value = isolate->factory()->the_hole_value();
12378   Handle<Object> old_length_handle;
12379   Handle<Object> new_length_handle;
12380 
12381   if (old_attributes != ABSENT) {
12382     if (GetOwnElementAccessorPair(object, index).is_null()) {
12383       old_value = Object::GetElement(isolate, object, index).ToHandleChecked();
12384     }
12385   } else if (object->IsJSArray()) {
12386     // Store old array length in case adding an element grows the array.
12387     old_length_handle = handle(Handle<JSArray>::cast(object)->length(),
12388                                isolate);
12389   }
12390 
12391   // Check for lookup interceptor
12392   Handle<Object> result;
12393   ASSIGN_RETURN_ON_EXCEPTION(
12394       isolate, result,
12395       object->HasIndexedInterceptor()
12396           ? SetElementWithInterceptor(
12397               object, index, value, attributes,
12398               strict_mode, check_prototype, set_mode)
12399           : SetElementWithoutInterceptor(
12400               object, index, value, attributes,
12401               strict_mode, check_prototype, set_mode),
12402       Object);
12403 
12404   Handle<String> name = isolate->factory()->Uint32ToString(index);
12405   maybe = GetOwnElementAttribute(object, index);
12406   if (!maybe.has_value) return MaybeHandle<Object>();
12407   PropertyAttributes new_attributes = maybe.value;
12408 
12409   if (old_attributes == ABSENT) {
12410     if (object->IsJSArray() &&
12411         !old_length_handle->SameValue(
12412             Handle<JSArray>::cast(object)->length())) {
12413       new_length_handle = handle(Handle<JSArray>::cast(object)->length(),
12414                                  isolate);
12415       uint32_t old_length = 0;
12416       uint32_t new_length = 0;
12417       CHECK(old_length_handle->ToArrayIndex(&old_length));
12418       CHECK(new_length_handle->ToArrayIndex(&new_length));
12419 
12420       BeginPerformSplice(Handle<JSArray>::cast(object));
12421       EnqueueChangeRecord(object, "add", name, old_value);
12422       EnqueueChangeRecord(object, "update", isolate->factory()->length_string(),
12423                           old_length_handle);
12424       EndPerformSplice(Handle<JSArray>::cast(object));
12425       Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
12426       EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, deleted,
12427                           new_length - old_length);
12428     } else {
12429       EnqueueChangeRecord(object, "add", name, old_value);
12430     }
12431   } else if (old_value->IsTheHole()) {
12432     EnqueueChangeRecord(object, "reconfigure", name, old_value);
12433   } else {
12434     Handle<Object> new_value =
12435         Object::GetElement(isolate, object, index).ToHandleChecked();
12436     bool value_changed = !old_value->SameValue(*new_value);
12437     if (old_attributes != new_attributes) {
12438       if (!value_changed) old_value = isolate->factory()->the_hole_value();
12439       EnqueueChangeRecord(object, "reconfigure", name, old_value);
12440     } else if (value_changed) {
12441       EnqueueChangeRecord(object, "update", name, old_value);
12442     }
12443   }
12444 
12445   return result;
12446 }
12447 
12448 
SetElementWithoutInterceptor(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,StrictMode strict_mode,bool check_prototype,SetPropertyMode set_mode)12449 MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
12450     Handle<JSObject> object,
12451     uint32_t index,
12452     Handle<Object> value,
12453     PropertyAttributes attributes,
12454     StrictMode strict_mode,
12455     bool check_prototype,
12456     SetPropertyMode set_mode) {
12457   DCHECK(object->HasDictionaryElements() ||
12458          object->HasDictionaryArgumentsElements() ||
12459          (attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
12460   Isolate* isolate = object->GetIsolate();
12461   if (FLAG_trace_external_array_abuse &&
12462       IsExternalArrayElementsKind(object->GetElementsKind())) {
12463     CheckArrayAbuse(object, "external elements write", index);
12464   }
12465   if (FLAG_trace_js_array_abuse &&
12466       !IsExternalArrayElementsKind(object->GetElementsKind())) {
12467     if (object->IsJSArray()) {
12468       CheckArrayAbuse(object, "elements write", index, true);
12469     }
12470   }
12471   if (object->IsJSArray() && JSArray::WouldChangeReadOnlyLength(
12472       Handle<JSArray>::cast(object), index)) {
12473     if (strict_mode == SLOPPY) {
12474       return value;
12475     } else {
12476       return JSArray::ReadOnlyLengthError(Handle<JSArray>::cast(object));
12477     }
12478   }
12479   switch (object->GetElementsKind()) {
12480     case FAST_SMI_ELEMENTS:
12481     case FAST_ELEMENTS:
12482     case FAST_HOLEY_SMI_ELEMENTS:
12483     case FAST_HOLEY_ELEMENTS:
12484       return SetFastElement(object, index, value, strict_mode, check_prototype);
12485     case FAST_DOUBLE_ELEMENTS:
12486     case FAST_HOLEY_DOUBLE_ELEMENTS:
12487       return SetFastDoubleElement(object, index, value, strict_mode,
12488                                   check_prototype);
12489 
12490 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
12491     case EXTERNAL_##TYPE##_ELEMENTS: {                                        \
12492       Handle<External##Type##Array> array(                                    \
12493           External##Type##Array::cast(object->elements()));                   \
12494       return External##Type##Array::SetValue(array, index, value);            \
12495     }                                                                         \
12496     case TYPE##_ELEMENTS: {                                                   \
12497       Handle<Fixed##Type##Array> array(                                       \
12498           Fixed##Type##Array::cast(object->elements()));                      \
12499       return Fixed##Type##Array::SetValue(array, index, value);               \
12500     }
12501 
12502     TYPED_ARRAYS(TYPED_ARRAY_CASE)
12503 
12504 #undef TYPED_ARRAY_CASE
12505 
12506     case DICTIONARY_ELEMENTS:
12507       return SetDictionaryElement(object, index, value, attributes, strict_mode,
12508                                   check_prototype,
12509                                   set_mode);
12510     case SLOPPY_ARGUMENTS_ELEMENTS: {
12511       Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
12512       uint32_t length = parameter_map->length();
12513       Handle<Object> probe = index < length - 2 ?
12514           Handle<Object>(parameter_map->get(index + 2), isolate) :
12515           Handle<Object>();
12516       if (!probe.is_null() && !probe->IsTheHole()) {
12517         Handle<Context> context(Context::cast(parameter_map->get(0)));
12518         int context_index = Handle<Smi>::cast(probe)->value();
12519         DCHECK(!context->get(context_index)->IsTheHole());
12520         context->set(context_index, *value);
12521         // Redefining attributes of an aliased element destroys fast aliasing.
12522         if (set_mode == SET_PROPERTY || attributes == NONE) return value;
12523         parameter_map->set_the_hole(index + 2);
12524         // For elements that are still writable we re-establish slow aliasing.
12525         if ((attributes & READ_ONLY) == 0) {
12526           value = Handle<Object>::cast(
12527               isolate->factory()->NewAliasedArgumentsEntry(context_index));
12528         }
12529       }
12530       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
12531       if (arguments->IsDictionary()) {
12532         return SetDictionaryElement(object, index, value, attributes,
12533                                     strict_mode,
12534                                     check_prototype,
12535                                     set_mode);
12536       } else {
12537         return SetFastElement(object, index, value, strict_mode,
12538                               check_prototype);
12539       }
12540     }
12541   }
12542   // All possible cases have been handled above. Add a return to avoid the
12543   // complaints from the compiler.
12544   UNREACHABLE();
12545   return isolate->factory()->null_value();
12546 }
12547 
12548 
12549 const double AllocationSite::kPretenureRatio = 0.85;
12550 
12551 
ResetPretenureDecision()12552 void AllocationSite::ResetPretenureDecision() {
12553   set_pretenure_decision(kUndecided);
12554   set_memento_found_count(0);
12555   set_memento_create_count(0);
12556 }
12557 
12558 
GetPretenureMode()12559 PretenureFlag AllocationSite::GetPretenureMode() {
12560   PretenureDecision mode = pretenure_decision();
12561   // Zombie objects "decide" to be untenured.
12562   return mode == kTenure ? TENURED : NOT_TENURED;
12563 }
12564 
12565 
IsNestedSite()12566 bool AllocationSite::IsNestedSite() {
12567   DCHECK(FLAG_trace_track_allocation_sites);
12568   Object* current = GetHeap()->allocation_sites_list();
12569   while (current->IsAllocationSite()) {
12570     AllocationSite* current_site = AllocationSite::cast(current);
12571     if (current_site->nested_site() == this) {
12572       return true;
12573     }
12574     current = current_site->weak_next();
12575   }
12576   return false;
12577 }
12578 
12579 
DigestTransitionFeedback(Handle<AllocationSite> site,ElementsKind to_kind)12580 void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
12581                                               ElementsKind to_kind) {
12582   Isolate* isolate = site->GetIsolate();
12583 
12584   if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
12585     Handle<JSArray> transition_info =
12586         handle(JSArray::cast(site->transition_info()));
12587     ElementsKind kind = transition_info->GetElementsKind();
12588     // if kind is holey ensure that to_kind is as well.
12589     if (IsHoleyElementsKind(kind)) {
12590       to_kind = GetHoleyElementsKind(to_kind);
12591     }
12592     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
12593       // If the array is huge, it's not likely to be defined in a local
12594       // function, so we shouldn't make new instances of it very often.
12595       uint32_t length = 0;
12596       CHECK(transition_info->length()->ToArrayIndex(&length));
12597       if (length <= kMaximumArrayBytesToPretransition) {
12598         if (FLAG_trace_track_allocation_sites) {
12599           bool is_nested = site->IsNestedSite();
12600           PrintF(
12601               "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
12602               reinterpret_cast<void*>(*site),
12603               is_nested ? "(nested)" : "",
12604               ElementsKindToString(kind),
12605               ElementsKindToString(to_kind));
12606         }
12607         JSObject::TransitionElementsKind(transition_info, to_kind);
12608         site->dependent_code()->DeoptimizeDependentCodeGroup(
12609             isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
12610       }
12611     }
12612   } else {
12613     ElementsKind kind = site->GetElementsKind();
12614     // if kind is holey ensure that to_kind is as well.
12615     if (IsHoleyElementsKind(kind)) {
12616       to_kind = GetHoleyElementsKind(to_kind);
12617     }
12618     if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
12619       if (FLAG_trace_track_allocation_sites) {
12620         PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
12621                reinterpret_cast<void*>(*site),
12622                ElementsKindToString(kind),
12623                ElementsKindToString(to_kind));
12624       }
12625       site->SetElementsKind(to_kind);
12626       site->dependent_code()->DeoptimizeDependentCodeGroup(
12627           isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
12628     }
12629   }
12630 }
12631 
12632 
12633 // static
AddDependentCompilationInfo(Handle<AllocationSite> site,Reason reason,CompilationInfo * info)12634 void AllocationSite::AddDependentCompilationInfo(Handle<AllocationSite> site,
12635                                                  Reason reason,
12636                                                  CompilationInfo* info) {
12637   DependentCode::DependencyGroup group = site->ToDependencyGroup(reason);
12638   Handle<DependentCode> dep(site->dependent_code());
12639   Handle<DependentCode> codes =
12640       DependentCode::Insert(dep, group, info->object_wrapper());
12641   if (*codes != site->dependent_code()) site->set_dependent_code(*codes);
12642   info->dependencies(group)->Add(Handle<HeapObject>(*site), info->zone());
12643 }
12644 
12645 
PretenureDecisionName(PretenureDecision decision)12646 const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
12647   switch (decision) {
12648     case kUndecided: return "undecided";
12649     case kDontTenure: return "don't tenure";
12650     case kMaybeTenure: return "maybe tenure";
12651     case kTenure: return "tenure";
12652     case kZombie: return "zombie";
12653     default: UNREACHABLE();
12654   }
12655   return NULL;
12656 }
12657 
12658 
UpdateAllocationSite(Handle<JSObject> object,ElementsKind to_kind)12659 void JSObject::UpdateAllocationSite(Handle<JSObject> object,
12660                                     ElementsKind to_kind) {
12661   if (!object->IsJSArray()) return;
12662 
12663   Heap* heap = object->GetHeap();
12664   if (!heap->InNewSpace(*object)) return;
12665 
12666   Handle<AllocationSite> site;
12667   {
12668     DisallowHeapAllocation no_allocation;
12669 
12670     AllocationMemento* memento = heap->FindAllocationMemento(*object);
12671     if (memento == NULL) return;
12672 
12673     // Walk through to the Allocation Site
12674     site = handle(memento->GetAllocationSite());
12675   }
12676   AllocationSite::DigestTransitionFeedback(site, to_kind);
12677 }
12678 
12679 
TransitionElementsKind(Handle<JSObject> object,ElementsKind to_kind)12680 void JSObject::TransitionElementsKind(Handle<JSObject> object,
12681                                       ElementsKind to_kind) {
12682   ElementsKind from_kind = object->map()->elements_kind();
12683 
12684   if (IsFastHoleyElementsKind(from_kind)) {
12685     to_kind = GetHoleyElementsKind(to_kind);
12686   }
12687 
12688   if (from_kind == to_kind) return;
12689   // Don't update the site if to_kind isn't fast
12690   if (IsFastElementsKind(to_kind)) {
12691     UpdateAllocationSite(object, to_kind);
12692   }
12693 
12694   Isolate* isolate = object->GetIsolate();
12695   if (object->elements() == isolate->heap()->empty_fixed_array() ||
12696       (IsFastSmiOrObjectElementsKind(from_kind) &&
12697        IsFastSmiOrObjectElementsKind(to_kind)) ||
12698       (from_kind == FAST_DOUBLE_ELEMENTS &&
12699        to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
12700     DCHECK(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
12701     // No change is needed to the elements() buffer, the transition
12702     // only requires a map change.
12703     Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
12704     MigrateToMap(object, new_map);
12705     if (FLAG_trace_elements_transitions) {
12706       Handle<FixedArrayBase> elms(object->elements());
12707       PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
12708     }
12709     return;
12710   }
12711 
12712   Handle<FixedArrayBase> elms(object->elements());
12713   uint32_t capacity = static_cast<uint32_t>(elms->length());
12714   uint32_t length = capacity;
12715 
12716   if (object->IsJSArray()) {
12717     Object* raw_length = Handle<JSArray>::cast(object)->length();
12718     if (raw_length->IsUndefined()) {
12719       // If length is undefined, then JSArray is being initialized and has no
12720       // elements, assume a length of zero.
12721       length = 0;
12722     } else {
12723       CHECK(raw_length->ToArrayIndex(&length));
12724     }
12725   }
12726 
12727   if (IsFastSmiElementsKind(from_kind) &&
12728       IsFastDoubleElementsKind(to_kind)) {
12729     SetFastDoubleElementsCapacityAndLength(object, capacity, length);
12730     JSObject::ValidateElements(object);
12731     return;
12732   }
12733 
12734   if (IsFastDoubleElementsKind(from_kind) &&
12735       IsFastObjectElementsKind(to_kind)) {
12736     SetFastElementsCapacityAndLength(object, capacity, length,
12737                                      kDontAllowSmiElements);
12738     JSObject::ValidateElements(object);
12739     return;
12740   }
12741 
12742   // This method should never be called for any other case than the ones
12743   // handled above.
12744   UNREACHABLE();
12745 }
12746 
12747 
12748 // static
IsValidElementsTransition(ElementsKind from_kind,ElementsKind to_kind)12749 bool Map::IsValidElementsTransition(ElementsKind from_kind,
12750                                     ElementsKind to_kind) {
12751   // Transitions can't go backwards.
12752   if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
12753     return false;
12754   }
12755 
12756   // Transitions from HOLEY -> PACKED are not allowed.
12757   return !IsFastHoleyElementsKind(from_kind) ||
12758       IsFastHoleyElementsKind(to_kind);
12759 }
12760 
12761 
JSArrayUpdateLengthFromIndex(Handle<JSArray> array,uint32_t index,Handle<Object> value)12762 void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
12763                                            uint32_t index,
12764                                            Handle<Object> value) {
12765   uint32_t old_len = 0;
12766   CHECK(array->length()->ToArrayIndex(&old_len));
12767   // Check to see if we need to update the length. For now, we make
12768   // sure that the length stays within 32-bits (unsigned).
12769   if (index >= old_len && index != 0xffffffff) {
12770     Handle<Object> len = array->GetIsolate()->factory()->NewNumber(
12771         static_cast<double>(index) + 1);
12772     array->set_length(*len);
12773   }
12774 }
12775 
12776 
IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map)12777 bool JSArray::IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
12778   Isolate* isolate = jsarray_map->GetIsolate();
12779   DCHECK(!jsarray_map->is_dictionary_map());
12780   LookupResult lookup(isolate);
12781   Handle<Name> length_string = isolate->factory()->length_string();
12782   jsarray_map->LookupDescriptor(NULL, *length_string, &lookup);
12783   return lookup.IsReadOnly();
12784 }
12785 
12786 
WouldChangeReadOnlyLength(Handle<JSArray> array,uint32_t index)12787 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
12788                                         uint32_t index) {
12789   uint32_t length = 0;
12790   CHECK(array->length()->ToArrayIndex(&length));
12791   if (length <= index) {
12792     LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
12793                       LookupIterator::OWN_SKIP_INTERCEPTOR);
12794     CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
12795     CHECK(it.IsFound());
12796     CHECK_EQ(LookupIterator::ACCESSOR, it.state());
12797     return it.IsReadOnly();
12798   }
12799   return false;
12800 }
12801 
12802 
ReadOnlyLengthError(Handle<JSArray> array)12803 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) {
12804   Isolate* isolate = array->GetIsolate();
12805   Handle<Name> length = isolate->factory()->length_string();
12806   Handle<Object> args[2] = { length, array };
12807   THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
12808                                         HandleVector(args, arraysize(args))),
12809                   Object);
12810 }
12811 
12812 
GetElementWithInterceptor(Handle<JSObject> object,Handle<Object> receiver,uint32_t index)12813 MaybeHandle<Object> JSObject::GetElementWithInterceptor(
12814     Handle<JSObject> object,
12815     Handle<Object> receiver,
12816     uint32_t index) {
12817   Isolate* isolate = object->GetIsolate();
12818 
12819   // Make sure that the top context does not change when doing
12820   // callbacks or interceptor calls.
12821   AssertNoContextChange ncc(isolate);
12822 
12823   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate);
12824   if (!interceptor->getter()->IsUndefined()) {
12825     v8::IndexedPropertyGetterCallback getter =
12826         v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
12827     LOG(isolate,
12828         ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index));
12829     PropertyCallbackArguments
12830         args(isolate, interceptor->data(), *receiver, *object);
12831     v8::Handle<v8::Value> result = args.Call(getter, index);
12832     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12833     if (!result.IsEmpty()) {
12834       Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
12835       result_internal->VerifyApiCallResultType();
12836       // Rebox handle before return.
12837       return handle(*result_internal, isolate);
12838     }
12839   }
12840 
12841   ElementsAccessor* handler = object->GetElementsAccessor();
12842   Handle<Object> result;
12843   ASSIGN_RETURN_ON_EXCEPTION(
12844       isolate, result, handler->Get(receiver,  object, index),
12845       Object);
12846   if (!result->IsTheHole()) return result;
12847 
12848   PrototypeIterator iter(isolate, object);
12849   if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
12850   return Object::GetElementWithReceiver(
12851       isolate, PrototypeIterator::GetCurrent(iter), receiver, index);
12852 }
12853 
12854 
HasDenseElements()12855 bool JSObject::HasDenseElements() {
12856   int capacity = 0;
12857   int used = 0;
12858   GetElementsCapacityAndUsage(&capacity, &used);
12859   return (capacity == 0) || (used > (capacity / 2));
12860 }
12861 
12862 
GetElementsCapacityAndUsage(int * capacity,int * used)12863 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
12864   *capacity = 0;
12865   *used = 0;
12866 
12867   FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
12868   FixedArray* backing_store = NULL;
12869   switch (GetElementsKind()) {
12870     case SLOPPY_ARGUMENTS_ELEMENTS:
12871       backing_store_base =
12872           FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
12873       backing_store = FixedArray::cast(backing_store_base);
12874       if (backing_store->IsDictionary()) {
12875         SeededNumberDictionary* dictionary =
12876             SeededNumberDictionary::cast(backing_store);
12877         *capacity = dictionary->Capacity();
12878         *used = dictionary->NumberOfElements();
12879         break;
12880       }
12881       // Fall through.
12882     case FAST_SMI_ELEMENTS:
12883     case FAST_ELEMENTS:
12884       if (IsJSArray()) {
12885         *capacity = backing_store_base->length();
12886         *used = Smi::cast(JSArray::cast(this)->length())->value();
12887         break;
12888       }
12889       // Fall through if packing is not guaranteed.
12890     case FAST_HOLEY_SMI_ELEMENTS:
12891     case FAST_HOLEY_ELEMENTS:
12892       backing_store = FixedArray::cast(backing_store_base);
12893       *capacity = backing_store->length();
12894       for (int i = 0; i < *capacity; ++i) {
12895         if (!backing_store->get(i)->IsTheHole()) ++(*used);
12896       }
12897       break;
12898     case DICTIONARY_ELEMENTS: {
12899       SeededNumberDictionary* dictionary = element_dictionary();
12900       *capacity = dictionary->Capacity();
12901       *used = dictionary->NumberOfElements();
12902       break;
12903     }
12904     case FAST_DOUBLE_ELEMENTS:
12905       if (IsJSArray()) {
12906         *capacity = backing_store_base->length();
12907         *used = Smi::cast(JSArray::cast(this)->length())->value();
12908         break;
12909       }
12910       // Fall through if packing is not guaranteed.
12911     case FAST_HOLEY_DOUBLE_ELEMENTS: {
12912       *capacity = elements()->length();
12913       if (*capacity == 0) break;
12914       FixedDoubleArray * elms = FixedDoubleArray::cast(elements());
12915       for (int i = 0; i < *capacity; i++) {
12916         if (!elms->is_the_hole(i)) ++(*used);
12917       }
12918       break;
12919     }
12920 
12921 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
12922     case EXTERNAL_##TYPE##_ELEMENTS:                                         \
12923     case TYPE##_ELEMENTS:                                                    \
12924 
12925     TYPED_ARRAYS(TYPED_ARRAY_CASE)
12926 #undef TYPED_ARRAY_CASE
12927     {
12928       // External arrays are considered 100% used.
12929       FixedArrayBase* external_array = FixedArrayBase::cast(elements());
12930       *capacity = external_array->length();
12931       *used = external_array->length();
12932       break;
12933     }
12934   }
12935 }
12936 
12937 
WouldConvertToSlowElements(Handle<Object> key)12938 bool JSObject::WouldConvertToSlowElements(Handle<Object> key) {
12939   uint32_t index;
12940   if (HasFastElements() && key->ToArrayIndex(&index)) {
12941     Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
12942     uint32_t capacity = static_cast<uint32_t>(backing_store->length());
12943     if (index >= capacity) {
12944       if ((index - capacity) >= kMaxGap) return true;
12945       uint32_t new_capacity = NewElementsCapacity(index + 1);
12946       return ShouldConvertToSlowElements(new_capacity);
12947     }
12948   }
12949   return false;
12950 }
12951 
12952 
ShouldConvertToSlowElements(int new_capacity)12953 bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
12954   STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
12955                 kMaxUncheckedFastElementsLength);
12956   if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
12957       (new_capacity <= kMaxUncheckedFastElementsLength &&
12958        GetHeap()->InNewSpace(this))) {
12959     return false;
12960   }
12961   // If the fast-case backing storage takes up roughly three times as
12962   // much space (in machine words) as a dictionary backing storage
12963   // would, the object should have slow elements.
12964   int old_capacity = 0;
12965   int used_elements = 0;
12966   GetElementsCapacityAndUsage(&old_capacity, &used_elements);
12967   int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
12968       SeededNumberDictionary::kEntrySize;
12969   return 3 * dictionary_size <= new_capacity;
12970 }
12971 
12972 
ShouldConvertToFastElements()12973 bool JSObject::ShouldConvertToFastElements() {
12974   DCHECK(HasDictionaryElements() || HasDictionaryArgumentsElements());
12975   // If the elements are sparse, we should not go back to fast case.
12976   if (!HasDenseElements()) return false;
12977   // An object requiring access checks is never allowed to have fast
12978   // elements.  If it had fast elements we would skip security checks.
12979   if (IsAccessCheckNeeded()) return false;
12980   // Observed objects may not go to fast mode because they rely on map checks,
12981   // and for fast element accesses we sometimes check element kinds only.
12982   if (map()->is_observed()) return false;
12983 
12984   FixedArray* elements = FixedArray::cast(this->elements());
12985   SeededNumberDictionary* dictionary = NULL;
12986   if (elements->map() == GetHeap()->sloppy_arguments_elements_map()) {
12987     dictionary = SeededNumberDictionary::cast(elements->get(1));
12988   } else {
12989     dictionary = SeededNumberDictionary::cast(elements);
12990   }
12991   // If an element has been added at a very high index in the elements
12992   // dictionary, we cannot go back to fast case.
12993   if (dictionary->requires_slow_elements()) return false;
12994   // If the dictionary backing storage takes up roughly half as much
12995   // space (in machine words) as a fast-case backing storage would,
12996   // the object should have fast elements.
12997   uint32_t array_size = 0;
12998   if (IsJSArray()) {
12999     CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
13000   } else {
13001     array_size = dictionary->max_number_key();
13002   }
13003   uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
13004       SeededNumberDictionary::kEntrySize;
13005   return 2 * dictionary_size >= array_size;
13006 }
13007 
13008 
ShouldConvertToFastDoubleElements(bool * has_smi_only_elements)13009 bool JSObject::ShouldConvertToFastDoubleElements(
13010     bool* has_smi_only_elements) {
13011   *has_smi_only_elements = false;
13012   if (HasSloppyArgumentsElements()) return false;
13013   if (FLAG_unbox_double_arrays) {
13014     DCHECK(HasDictionaryElements());
13015     SeededNumberDictionary* dictionary = element_dictionary();
13016     bool found_double = false;
13017     for (int i = 0; i < dictionary->Capacity(); i++) {
13018       Object* key = dictionary->KeyAt(i);
13019       if (key->IsNumber()) {
13020         Object* value = dictionary->ValueAt(i);
13021         if (!value->IsNumber()) return false;
13022         if (!value->IsSmi()) {
13023           found_double = true;
13024         }
13025       }
13026     }
13027     *has_smi_only_elements = !found_double;
13028     return found_double;
13029   } else {
13030     return false;
13031   }
13032 }
13033 
13034 
13035 // Certain compilers request function template instantiation when they
13036 // see the definition of the other template functions in the
13037 // class. This requires us to have the template functions put
13038 // together, so even though this function belongs in objects-debug.cc,
13039 // we keep it here instead to satisfy certain compilers.
13040 #ifdef OBJECT_PRINT
13041 template <typename Derived, typename Shape, typename Key>
Print(OStream & os)13042 void Dictionary<Derived, Shape, Key>::Print(OStream& os) {  // NOLINT
13043   int capacity = DerivedHashTable::Capacity();
13044   for (int i = 0; i < capacity; i++) {
13045     Object* k = DerivedHashTable::KeyAt(i);
13046     if (DerivedHashTable::IsKey(k)) {
13047       os << " ";
13048       if (k->IsString()) {
13049         String::cast(k)->StringPrint(os);
13050       } else {
13051         os << Brief(k);
13052       }
13053       os << ": " << Brief(ValueAt(i)) << "\n";
13054     }
13055   }
13056 }
13057 #endif
13058 
13059 
13060 template<typename Derived, typename Shape, typename Key>
CopyValuesTo(FixedArray * elements)13061 void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
13062   int pos = 0;
13063   int capacity = DerivedHashTable::Capacity();
13064   DisallowHeapAllocation no_gc;
13065   WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
13066   for (int i = 0; i < capacity; i++) {
13067     Object* k =  Dictionary::KeyAt(i);
13068     if (Dictionary::IsKey(k)) {
13069       elements->set(pos++, ValueAt(i), mode);
13070     }
13071   }
13072   DCHECK(pos == elements->length());
13073 }
13074 
13075 
GetNamedInterceptor()13076 InterceptorInfo* JSObject::GetNamedInterceptor() {
13077   DCHECK(map()->has_named_interceptor());
13078   JSFunction* constructor = JSFunction::cast(map()->constructor());
13079   DCHECK(constructor->shared()->IsApiFunction());
13080   Object* result =
13081       constructor->shared()->get_api_func_data()->named_property_handler();
13082   return InterceptorInfo::cast(result);
13083 }
13084 
13085 
GetIndexedInterceptor()13086 InterceptorInfo* JSObject::GetIndexedInterceptor() {
13087   DCHECK(map()->has_indexed_interceptor());
13088   JSFunction* constructor = JSFunction::cast(map()->constructor());
13089   DCHECK(constructor->shared()->IsApiFunction());
13090   Object* result =
13091       constructor->shared()->get_api_func_data()->indexed_property_handler();
13092   return InterceptorInfo::cast(result);
13093 }
13094 
13095 
GetPropertyWithInterceptor(Handle<JSObject> holder,Handle<Object> receiver,Handle<Name> name)13096 MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(
13097     Handle<JSObject> holder,
13098     Handle<Object> receiver,
13099     Handle<Name> name) {
13100   Isolate* isolate = holder->GetIsolate();
13101 
13102   // TODO(rossberg): Support symbols in the API.
13103   if (name->IsSymbol()) return isolate->factory()->undefined_value();
13104 
13105   Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
13106   Handle<String> name_string = Handle<String>::cast(name);
13107 
13108   if (interceptor->getter()->IsUndefined()) return MaybeHandle<Object>();
13109 
13110   v8::NamedPropertyGetterCallback getter =
13111       v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
13112   LOG(isolate,
13113       ApiNamedPropertyAccess("interceptor-named-get", *holder, *name));
13114   PropertyCallbackArguments
13115       args(isolate, interceptor->data(), *receiver, *holder);
13116   v8::Handle<v8::Value> result =
13117       args.Call(getter, v8::Utils::ToLocal(name_string));
13118   RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
13119   if (result.IsEmpty()) return MaybeHandle<Object>();
13120 
13121   Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13122   result_internal->VerifyApiCallResultType();
13123   // Rebox handle before return
13124   return handle(*result_internal, isolate);
13125 }
13126 
13127 
13128 // Compute the property keys from the interceptor.
13129 // TODO(rossberg): support symbols in API, and filter here if needed.
GetKeysForNamedInterceptor(Handle<JSObject> object,Handle<JSReceiver> receiver)13130 MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor(
13131     Handle<JSObject> object, Handle<JSReceiver> receiver) {
13132   Isolate* isolate = receiver->GetIsolate();
13133   Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
13134   PropertyCallbackArguments
13135       args(isolate, interceptor->data(), *receiver, *object);
13136   v8::Handle<v8::Object> result;
13137   if (!interceptor->enumerator()->IsUndefined()) {
13138     v8::NamedPropertyEnumeratorCallback enum_fun =
13139         v8::ToCData<v8::NamedPropertyEnumeratorCallback>(
13140             interceptor->enumerator());
13141     LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
13142     result = args.Call(enum_fun);
13143   }
13144   if (result.IsEmpty()) return MaybeHandle<JSObject>();
13145 #if ENABLE_EXTRA_CHECKS
13146   CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13147         v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13148 #endif
13149   // Rebox before returning.
13150   return handle(*v8::Utils::OpenHandle(*result), isolate);
13151 }
13152 
13153 
13154 // Compute the element keys from the interceptor.
GetKeysForIndexedInterceptor(Handle<JSObject> object,Handle<JSReceiver> receiver)13155 MaybeHandle<JSObject> JSObject::GetKeysForIndexedInterceptor(
13156     Handle<JSObject> object, Handle<JSReceiver> receiver) {
13157   Isolate* isolate = receiver->GetIsolate();
13158   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
13159   PropertyCallbackArguments
13160       args(isolate, interceptor->data(), *receiver, *object);
13161   v8::Handle<v8::Object> result;
13162   if (!interceptor->enumerator()->IsUndefined()) {
13163     v8::IndexedPropertyEnumeratorCallback enum_fun =
13164         v8::ToCData<v8::IndexedPropertyEnumeratorCallback>(
13165             interceptor->enumerator());
13166     LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
13167     result = args.Call(enum_fun);
13168   }
13169   if (result.IsEmpty()) return MaybeHandle<JSObject>();
13170 #if ENABLE_EXTRA_CHECKS
13171   CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13172         v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13173 #endif
13174   // Rebox before returning.
13175   return handle(*v8::Utils::OpenHandle(*result), isolate);
13176 }
13177 
13178 
HasRealNamedProperty(Handle<JSObject> object,Handle<Name> key)13179 Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
13180                                            Handle<Name> key) {
13181   LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
13182   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
13183   if (!maybe_result.has_value) return Maybe<bool>();
13184   return maybe(it.IsFound());
13185 }
13186 
13187 
HasRealElementProperty(Handle<JSObject> object,uint32_t index)13188 Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
13189                                              uint32_t index) {
13190   Isolate* isolate = object->GetIsolate();
13191   HandleScope scope(isolate);
13192   // Check access rights if needed.
13193   if (object->IsAccessCheckNeeded()) {
13194     if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
13195       isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
13196       RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<bool>());
13197       return maybe(false);
13198     }
13199   }
13200 
13201   if (object->IsJSGlobalProxy()) {
13202     HandleScope scope(isolate);
13203     PrototypeIterator iter(isolate, object);
13204     if (iter.IsAtEnd()) return maybe(false);
13205     DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
13206     return HasRealElementProperty(
13207         Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
13208   }
13209 
13210   Maybe<PropertyAttributes> result =
13211       GetElementAttributeWithoutInterceptor(object, object, index, false);
13212   if (!result.has_value) return Maybe<bool>();
13213   return maybe(result.value != ABSENT);
13214 }
13215 
13216 
HasRealNamedCallbackProperty(Handle<JSObject> object,Handle<Name> key)13217 Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
13218                                                    Handle<Name> key) {
13219   LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
13220   Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
13221   if (!maybe_result.has_value) return Maybe<bool>();
13222   return maybe(it.state() == LookupIterator::ACCESSOR);
13223 }
13224 
13225 
NumberOfOwnProperties(PropertyAttributes filter)13226 int JSObject::NumberOfOwnProperties(PropertyAttributes filter) {
13227   if (HasFastProperties()) {
13228     Map* map = this->map();
13229     if (filter == NONE) return map->NumberOfOwnDescriptors();
13230     if (filter & DONT_ENUM) {
13231       int result = map->EnumLength();
13232       if (result != kInvalidEnumCacheSentinel) return result;
13233     }
13234     return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
13235   }
13236   return property_dictionary()->NumberOfElementsFilterAttributes(filter);
13237 }
13238 
13239 
SwapPairs(FixedArray * numbers,int i,int j)13240 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
13241   Object* temp = get(i);
13242   set(i, get(j));
13243   set(j, temp);
13244   if (this != numbers) {
13245     temp = numbers->get(i);
13246     numbers->set(i, Smi::cast(numbers->get(j)));
13247     numbers->set(j, Smi::cast(temp));
13248   }
13249 }
13250 
13251 
InsertionSortPairs(FixedArray * content,FixedArray * numbers,int len)13252 static void InsertionSortPairs(FixedArray* content,
13253                                FixedArray* numbers,
13254                                int len) {
13255   for (int i = 1; i < len; i++) {
13256     int j = i;
13257     while (j > 0 &&
13258            (NumberToUint32(numbers->get(j - 1)) >
13259             NumberToUint32(numbers->get(j)))) {
13260       content->SwapPairs(numbers, j - 1, j);
13261       j--;
13262     }
13263   }
13264 }
13265 
13266 
HeapSortPairs(FixedArray * content,FixedArray * numbers,int len)13267 void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
13268   // In-place heap sort.
13269   DCHECK(content->length() == numbers->length());
13270 
13271   // Bottom-up max-heap construction.
13272   for (int i = 1; i < len; ++i) {
13273     int child_index = i;
13274     while (child_index > 0) {
13275       int parent_index = ((child_index + 1) >> 1) - 1;
13276       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13277       uint32_t child_value = NumberToUint32(numbers->get(child_index));
13278       if (parent_value < child_value) {
13279         content->SwapPairs(numbers, parent_index, child_index);
13280       } else {
13281         break;
13282       }
13283       child_index = parent_index;
13284     }
13285   }
13286 
13287   // Extract elements and create sorted array.
13288   for (int i = len - 1; i > 0; --i) {
13289     // Put max element at the back of the array.
13290     content->SwapPairs(numbers, 0, i);
13291     // Sift down the new top element.
13292     int parent_index = 0;
13293     while (true) {
13294       int child_index = ((parent_index + 1) << 1) - 1;
13295       if (child_index >= i) break;
13296       uint32_t child1_value = NumberToUint32(numbers->get(child_index));
13297       uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
13298       uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13299       if (child_index + 1 >= i || child1_value > child2_value) {
13300         if (parent_value > child1_value) break;
13301         content->SwapPairs(numbers, parent_index, child_index);
13302         parent_index = child_index;
13303       } else {
13304         if (parent_value > child2_value) break;
13305         content->SwapPairs(numbers, parent_index, child_index + 1);
13306         parent_index = child_index + 1;
13307       }
13308     }
13309   }
13310 }
13311 
13312 
13313 // Sort this array and the numbers as pairs wrt. the (distinct) numbers.
SortPairs(FixedArray * numbers,uint32_t len)13314 void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
13315   DCHECK(this->length() == numbers->length());
13316   // For small arrays, simply use insertion sort.
13317   if (len <= 10) {
13318     InsertionSortPairs(this, numbers, len);
13319     return;
13320   }
13321   // Check the range of indices.
13322   uint32_t min_index = NumberToUint32(numbers->get(0));
13323   uint32_t max_index = min_index;
13324   uint32_t i;
13325   for (i = 1; i < len; i++) {
13326     if (NumberToUint32(numbers->get(i)) < min_index) {
13327       min_index = NumberToUint32(numbers->get(i));
13328     } else if (NumberToUint32(numbers->get(i)) > max_index) {
13329       max_index = NumberToUint32(numbers->get(i));
13330     }
13331   }
13332   if (max_index - min_index + 1 == len) {
13333     // Indices form a contiguous range, unless there are duplicates.
13334     // Do an in-place linear time sort assuming distinct numbers, but
13335     // avoid hanging in case they are not.
13336     for (i = 0; i < len; i++) {
13337       uint32_t p;
13338       uint32_t j = 0;
13339       // While the current element at i is not at its correct position p,
13340       // swap the elements at these two positions.
13341       while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
13342              j++ < len) {
13343         SwapPairs(numbers, i, p);
13344       }
13345     }
13346   } else {
13347     HeapSortPairs(this, numbers, len);
13348     return;
13349   }
13350 }
13351 
13352 
13353 // Fill in the names of own properties into the supplied storage. The main
13354 // purpose of this function is to provide reflection information for the object
13355 // mirrors.
GetOwnPropertyNames(FixedArray * storage,int index,PropertyAttributes filter)13356 void JSObject::GetOwnPropertyNames(
13357     FixedArray* storage, int index, PropertyAttributes filter) {
13358   DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index));
13359   if (HasFastProperties()) {
13360     int real_size = map()->NumberOfOwnDescriptors();
13361     DescriptorArray* descs = map()->instance_descriptors();
13362     for (int i = 0; i < real_size; i++) {
13363       if ((descs->GetDetails(i).attributes() & filter) == 0 &&
13364           !FilterKey(descs->GetKey(i), filter)) {
13365         storage->set(index++, descs->GetKey(i));
13366       }
13367     }
13368   } else {
13369     property_dictionary()->CopyKeysTo(storage,
13370                                       index,
13371                                       filter,
13372                                       NameDictionary::UNSORTED);
13373   }
13374 }
13375 
13376 
NumberOfOwnElements(PropertyAttributes filter)13377 int JSObject::NumberOfOwnElements(PropertyAttributes filter) {
13378   return GetOwnElementKeys(NULL, filter);
13379 }
13380 
13381 
NumberOfEnumElements()13382 int JSObject::NumberOfEnumElements() {
13383   // Fast case for objects with no elements.
13384   if (!IsJSValue() && HasFastObjectElements()) {
13385     uint32_t length = IsJSArray() ?
13386         static_cast<uint32_t>(
13387             Smi::cast(JSArray::cast(this)->length())->value()) :
13388         static_cast<uint32_t>(FixedArray::cast(elements())->length());
13389     if (length == 0) return 0;
13390   }
13391   // Compute the number of enumerable elements.
13392   return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM));
13393 }
13394 
13395 
GetOwnElementKeys(FixedArray * storage,PropertyAttributes filter)13396 int JSObject::GetOwnElementKeys(FixedArray* storage,
13397                                 PropertyAttributes filter) {
13398   int counter = 0;
13399   switch (GetElementsKind()) {
13400     case FAST_SMI_ELEMENTS:
13401     case FAST_ELEMENTS:
13402     case FAST_HOLEY_SMI_ELEMENTS:
13403     case FAST_HOLEY_ELEMENTS: {
13404       int length = IsJSArray() ?
13405           Smi::cast(JSArray::cast(this)->length())->value() :
13406           FixedArray::cast(elements())->length();
13407       for (int i = 0; i < length; i++) {
13408         if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
13409           if (storage != NULL) {
13410             storage->set(counter, Smi::FromInt(i));
13411           }
13412           counter++;
13413         }
13414       }
13415       DCHECK(!storage || storage->length() >= counter);
13416       break;
13417     }
13418     case FAST_DOUBLE_ELEMENTS:
13419     case FAST_HOLEY_DOUBLE_ELEMENTS: {
13420       int length = IsJSArray() ?
13421           Smi::cast(JSArray::cast(this)->length())->value() :
13422           FixedArrayBase::cast(elements())->length();
13423       for (int i = 0; i < length; i++) {
13424         if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
13425           if (storage != NULL) {
13426             storage->set(counter, Smi::FromInt(i));
13427           }
13428           counter++;
13429         }
13430       }
13431       DCHECK(!storage || storage->length() >= counter);
13432       break;
13433     }
13434 
13435 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                      \
13436     case EXTERNAL_##TYPE##_ELEMENTS:                                         \
13437     case TYPE##_ELEMENTS:                                                    \
13438 
13439     TYPED_ARRAYS(TYPED_ARRAY_CASE)
13440 #undef TYPED_ARRAY_CASE
13441     {
13442       int length = FixedArrayBase::cast(elements())->length();
13443       while (counter < length) {
13444         if (storage != NULL) {
13445           storage->set(counter, Smi::FromInt(counter));
13446         }
13447         counter++;
13448       }
13449       DCHECK(!storage || storage->length() >= counter);
13450       break;
13451     }
13452 
13453     case DICTIONARY_ELEMENTS: {
13454       if (storage != NULL) {
13455         element_dictionary()->CopyKeysTo(storage,
13456                                          filter,
13457                                          SeededNumberDictionary::SORTED);
13458       }
13459       counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
13460       break;
13461     }
13462     case SLOPPY_ARGUMENTS_ELEMENTS: {
13463       FixedArray* parameter_map = FixedArray::cast(elements());
13464       int mapped_length = parameter_map->length() - 2;
13465       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
13466       if (arguments->IsDictionary()) {
13467         // Copy the keys from arguments first, because Dictionary::CopyKeysTo
13468         // will insert in storage starting at index 0.
13469         SeededNumberDictionary* dictionary =
13470             SeededNumberDictionary::cast(arguments);
13471         if (storage != NULL) {
13472           dictionary->CopyKeysTo(
13473               storage, filter, SeededNumberDictionary::UNSORTED);
13474         }
13475         counter += dictionary->NumberOfElementsFilterAttributes(filter);
13476         for (int i = 0; i < mapped_length; ++i) {
13477           if (!parameter_map->get(i + 2)->IsTheHole()) {
13478             if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13479             ++counter;
13480           }
13481         }
13482         if (storage != NULL) storage->SortPairs(storage, counter);
13483 
13484       } else {
13485         int backing_length = arguments->length();
13486         int i = 0;
13487         for (; i < mapped_length; ++i) {
13488           if (!parameter_map->get(i + 2)->IsTheHole()) {
13489             if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13490             ++counter;
13491           } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
13492             if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13493             ++counter;
13494           }
13495         }
13496         for (; i < backing_length; ++i) {
13497           if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13498           ++counter;
13499         }
13500       }
13501       break;
13502     }
13503   }
13504 
13505   if (this->IsJSValue()) {
13506     Object* val = JSValue::cast(this)->value();
13507     if (val->IsString()) {
13508       String* str = String::cast(val);
13509       if (storage) {
13510         for (int i = 0; i < str->length(); i++) {
13511           storage->set(counter + i, Smi::FromInt(i));
13512         }
13513       }
13514       counter += str->length();
13515     }
13516   }
13517   DCHECK(!storage || storage->length() == counter);
13518   return counter;
13519 }
13520 
13521 
GetEnumElementKeys(FixedArray * storage)13522 int JSObject::GetEnumElementKeys(FixedArray* storage) {
13523   return GetOwnElementKeys(storage, static_cast<PropertyAttributes>(DONT_ENUM));
13524 }
13525 
13526 
13527 // StringSharedKeys are used as keys in the eval cache.
13528 class StringSharedKey : public HashTableKey {
13529  public:
StringSharedKey(Handle<String> source,Handle<SharedFunctionInfo> shared,StrictMode strict_mode,int scope_position)13530   StringSharedKey(Handle<String> source,
13531                   Handle<SharedFunctionInfo> shared,
13532                   StrictMode strict_mode,
13533                   int scope_position)
13534       : source_(source),
13535         shared_(shared),
13536         strict_mode_(strict_mode),
13537         scope_position_(scope_position) { }
13538 
IsMatch(Object * other)13539   bool IsMatch(Object* other) OVERRIDE {
13540     DisallowHeapAllocation no_allocation;
13541     if (!other->IsFixedArray()) return false;
13542     FixedArray* other_array = FixedArray::cast(other);
13543     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
13544     if (shared != *shared_) return false;
13545     int strict_unchecked = Smi::cast(other_array->get(2))->value();
13546     DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
13547     StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
13548     if (strict_mode != strict_mode_) return false;
13549     int scope_position = Smi::cast(other_array->get(3))->value();
13550     if (scope_position != scope_position_) return false;
13551     String* source = String::cast(other_array->get(1));
13552     return source->Equals(*source_);
13553   }
13554 
StringSharedHashHelper(String * source,SharedFunctionInfo * shared,StrictMode strict_mode,int scope_position)13555   static uint32_t StringSharedHashHelper(String* source,
13556                                          SharedFunctionInfo* shared,
13557                                          StrictMode strict_mode,
13558                                          int scope_position) {
13559     uint32_t hash = source->Hash();
13560     if (shared->HasSourceCode()) {
13561       // Instead of using the SharedFunctionInfo pointer in the hash
13562       // code computation, we use a combination of the hash of the
13563       // script source code and the start position of the calling scope.
13564       // We do this to ensure that the cache entries can survive garbage
13565       // collection.
13566       Script* script(Script::cast(shared->script()));
13567       hash ^= String::cast(script->source())->Hash();
13568       if (strict_mode == STRICT) hash ^= 0x8000;
13569       hash += scope_position;
13570     }
13571     return hash;
13572   }
13573 
Hash()13574   uint32_t Hash() OVERRIDE {
13575     return StringSharedHashHelper(*source_, *shared_, strict_mode_,
13576                                   scope_position_);
13577   }
13578 
HashForObject(Object * obj)13579   uint32_t HashForObject(Object* obj) OVERRIDE {
13580     DisallowHeapAllocation no_allocation;
13581     FixedArray* other_array = FixedArray::cast(obj);
13582     SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
13583     String* source = String::cast(other_array->get(1));
13584     int strict_unchecked = Smi::cast(other_array->get(2))->value();
13585     DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
13586     StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
13587     int scope_position = Smi::cast(other_array->get(3))->value();
13588     return StringSharedHashHelper(
13589         source, shared, strict_mode, scope_position);
13590   }
13591 
13592 
AsHandle(Isolate * isolate)13593   Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
13594     Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
13595     array->set(0, *shared_);
13596     array->set(1, *source_);
13597     array->set(2, Smi::FromInt(strict_mode_));
13598     array->set(3, Smi::FromInt(scope_position_));
13599     return array;
13600   }
13601 
13602  private:
13603   Handle<String> source_;
13604   Handle<SharedFunctionInfo> shared_;
13605   StrictMode strict_mode_;
13606   int scope_position_;
13607 };
13608 
13609 
13610 // RegExpKey carries the source and flags of a regular expression as key.
13611 class RegExpKey : public HashTableKey {
13612  public:
RegExpKey(Handle<String> string,JSRegExp::Flags flags)13613   RegExpKey(Handle<String> string, JSRegExp::Flags flags)
13614       : string_(string),
13615         flags_(Smi::FromInt(flags.value())) { }
13616 
13617   // Rather than storing the key in the hash table, a pointer to the
13618   // stored value is stored where the key should be.  IsMatch then
13619   // compares the search key to the found object, rather than comparing
13620   // a key to a key.
IsMatch(Object * obj)13621   bool IsMatch(Object* obj) OVERRIDE {
13622     FixedArray* val = FixedArray::cast(obj);
13623     return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
13624         && (flags_ == val->get(JSRegExp::kFlagsIndex));
13625   }
13626 
Hash()13627   uint32_t Hash() OVERRIDE { return RegExpHash(*string_, flags_); }
13628 
AsHandle(Isolate * isolate)13629   Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
13630     // Plain hash maps, which is where regexp keys are used, don't
13631     // use this function.
13632     UNREACHABLE();
13633     return MaybeHandle<Object>().ToHandleChecked();
13634   }
13635 
HashForObject(Object * obj)13636   uint32_t HashForObject(Object* obj) OVERRIDE {
13637     FixedArray* val = FixedArray::cast(obj);
13638     return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
13639                       Smi::cast(val->get(JSRegExp::kFlagsIndex)));
13640   }
13641 
RegExpHash(String * string,Smi * flags)13642   static uint32_t RegExpHash(String* string, Smi* flags) {
13643     return string->Hash() + flags->value();
13644   }
13645 
13646   Handle<String> string_;
13647   Smi* flags_;
13648 };
13649 
13650 
AsHandle(Isolate * isolate)13651 Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
13652   if (hash_field_ == 0) Hash();
13653   return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
13654 }
13655 
13656 
AsHandle(Isolate * isolate)13657 Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
13658   if (hash_field_ == 0) Hash();
13659   return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
13660 }
13661 
13662 
AsHandle(Isolate * isolate)13663 Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
13664   if (hash_field_ == 0) Hash();
13665   return isolate->factory()->NewOneByteInternalizedSubString(
13666       string_, from_, length_, hash_field_);
13667 }
13668 
13669 
IsMatch(Object * string)13670 bool SeqOneByteSubStringKey::IsMatch(Object* string) {
13671   Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
13672   return String::cast(string)->IsOneByteEqualTo(chars);
13673 }
13674 
13675 
13676 // InternalizedStringKey carries a string/internalized-string object as key.
13677 class InternalizedStringKey : public HashTableKey {
13678  public:
InternalizedStringKey(Handle<String> string)13679   explicit InternalizedStringKey(Handle<String> string)
13680       : string_(string) { }
13681 
IsMatch(Object * string)13682   virtual bool IsMatch(Object* string) OVERRIDE {
13683     return String::cast(string)->Equals(*string_);
13684   }
13685 
Hash()13686   virtual uint32_t Hash() OVERRIDE { return string_->Hash(); }
13687 
HashForObject(Object * other)13688   virtual uint32_t HashForObject(Object* other) OVERRIDE {
13689     return String::cast(other)->Hash();
13690   }
13691 
AsHandle(Isolate * isolate)13692   virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
13693     // Internalize the string if possible.
13694     MaybeHandle<Map> maybe_map =
13695         isolate->factory()->InternalizedStringMapForString(string_);
13696     Handle<Map> map;
13697     if (maybe_map.ToHandle(&map)) {
13698       string_->set_map_no_write_barrier(*map);
13699       DCHECK(string_->IsInternalizedString());
13700       return string_;
13701     }
13702     // Otherwise allocate a new internalized string.
13703     return isolate->factory()->NewInternalizedStringImpl(
13704         string_, string_->length(), string_->hash_field());
13705   }
13706 
StringHash(Object * obj)13707   static uint32_t StringHash(Object* obj) {
13708     return String::cast(obj)->Hash();
13709   }
13710 
13711   Handle<String> string_;
13712 };
13713 
13714 
13715 template<typename Derived, typename Shape, typename Key>
IteratePrefix(ObjectVisitor * v)13716 void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
13717   IteratePointers(v, 0, kElementsStartOffset);
13718 }
13719 
13720 
13721 template<typename Derived, typename Shape, typename Key>
IterateElements(ObjectVisitor * v)13722 void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
13723   IteratePointers(v,
13724                   kElementsStartOffset,
13725                   kHeaderSize + length() * kPointerSize);
13726 }
13727 
13728 
13729 template<typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,MinimumCapacity capacity_option,PretenureFlag pretenure)13730 Handle<Derived> HashTable<Derived, Shape, Key>::New(
13731     Isolate* isolate,
13732     int at_least_space_for,
13733     MinimumCapacity capacity_option,
13734     PretenureFlag pretenure) {
13735   DCHECK(0 <= at_least_space_for);
13736   DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
13737   int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
13738                      ? at_least_space_for
13739                      : ComputeCapacity(at_least_space_for);
13740   if (capacity > HashTable::kMaxCapacity) {
13741     v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
13742   }
13743 
13744   Factory* factory = isolate->factory();
13745   int length = EntryToIndex(capacity);
13746   Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
13747   array->set_map_no_write_barrier(*factory->hash_table_map());
13748   Handle<Derived> table = Handle<Derived>::cast(array);
13749 
13750   table->SetNumberOfElements(0);
13751   table->SetNumberOfDeletedElements(0);
13752   table->SetCapacity(capacity);
13753   return table;
13754 }
13755 
13756 
13757 // Find entry for key otherwise return kNotFound.
FindEntry(Handle<Name> key)13758 int NameDictionary::FindEntry(Handle<Name> key) {
13759   if (!key->IsUniqueName()) {
13760     return DerivedHashTable::FindEntry(key);
13761   }
13762 
13763   // Optimized for unique names. Knowledge of the key type allows:
13764   // 1. Move the check if the key is unique out of the loop.
13765   // 2. Avoid comparing hash codes in unique-to-unique comparison.
13766   // 3. Detect a case when a dictionary key is not unique but the key is.
13767   //    In case of positive result the dictionary key may be replaced by the
13768   //    internalized string with minimal performance penalty. It gives a chance
13769   //    to perform further lookups in code stubs (and significant performance
13770   //    boost a certain style of code).
13771 
13772   // EnsureCapacity will guarantee the hash table is never full.
13773   uint32_t capacity = Capacity();
13774   uint32_t entry = FirstProbe(key->Hash(), capacity);
13775   uint32_t count = 1;
13776 
13777   while (true) {
13778     int index = EntryToIndex(entry);
13779     Object* element = get(index);
13780     if (element->IsUndefined()) break;  // Empty entry.
13781     if (*key == element) return entry;
13782     if (!element->IsUniqueName() &&
13783         !element->IsTheHole() &&
13784         Name::cast(element)->Equals(*key)) {
13785       // Replace a key that is a non-internalized string by the equivalent
13786       // internalized string for faster further lookups.
13787       set(index, *key);
13788       return entry;
13789     }
13790     DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key));
13791     entry = NextProbe(entry, count++, capacity);
13792   }
13793   return kNotFound;
13794 }
13795 
13796 
13797 template<typename Derived, typename Shape, typename Key>
Rehash(Handle<Derived> new_table,Key key)13798 void HashTable<Derived, Shape, Key>::Rehash(
13799     Handle<Derived> new_table,
13800     Key key) {
13801   DCHECK(NumberOfElements() < new_table->Capacity());
13802 
13803   DisallowHeapAllocation no_gc;
13804   WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
13805 
13806   // Copy prefix to new array.
13807   for (int i = kPrefixStartIndex;
13808        i < kPrefixStartIndex + Shape::kPrefixSize;
13809        i++) {
13810     new_table->set(i, get(i), mode);
13811   }
13812 
13813   // Rehash the elements.
13814   int capacity = Capacity();
13815   for (int i = 0; i < capacity; i++) {
13816     uint32_t from_index = EntryToIndex(i);
13817     Object* k = get(from_index);
13818     if (IsKey(k)) {
13819       uint32_t hash = HashTable::HashForObject(key, k);
13820       uint32_t insertion_index =
13821           EntryToIndex(new_table->FindInsertionEntry(hash));
13822       for (int j = 0; j < Shape::kEntrySize; j++) {
13823         new_table->set(insertion_index + j, get(from_index + j), mode);
13824       }
13825     }
13826   }
13827   new_table->SetNumberOfElements(NumberOfElements());
13828   new_table->SetNumberOfDeletedElements(0);
13829 }
13830 
13831 
13832 template<typename Derived, typename Shape, typename Key>
EntryForProbe(Key key,Object * k,int probe,uint32_t expected)13833 uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
13834     Key key,
13835     Object* k,
13836     int probe,
13837     uint32_t expected) {
13838   uint32_t hash = HashTable::HashForObject(key, k);
13839   uint32_t capacity = Capacity();
13840   uint32_t entry = FirstProbe(hash, capacity);
13841   for (int i = 1; i < probe; i++) {
13842     if (entry == expected) return expected;
13843     entry = NextProbe(entry, i, capacity);
13844   }
13845   return entry;
13846 }
13847 
13848 
13849 template<typename Derived, typename Shape, typename Key>
Swap(uint32_t entry1,uint32_t entry2,WriteBarrierMode mode)13850 void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
13851                                           uint32_t entry2,
13852                                           WriteBarrierMode mode) {
13853   int index1 = EntryToIndex(entry1);
13854   int index2 = EntryToIndex(entry2);
13855   Object* temp[Shape::kEntrySize];
13856   for (int j = 0; j < Shape::kEntrySize; j++) {
13857     temp[j] = get(index1 + j);
13858   }
13859   for (int j = 0; j < Shape::kEntrySize; j++) {
13860     set(index1 + j, get(index2 + j), mode);
13861   }
13862   for (int j = 0; j < Shape::kEntrySize; j++) {
13863     set(index2 + j, temp[j], mode);
13864   }
13865 }
13866 
13867 
13868 template<typename Derived, typename Shape, typename Key>
Rehash(Key key)13869 void HashTable<Derived, Shape, Key>::Rehash(Key key) {
13870   DisallowHeapAllocation no_gc;
13871   WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
13872   uint32_t capacity = Capacity();
13873   bool done = false;
13874   for (int probe = 1; !done; probe++) {
13875     // All elements at entries given by one of the first _probe_ probes
13876     // are placed correctly. Other elements might need to be moved.
13877     done = true;
13878     for (uint32_t current = 0; current < capacity; current++) {
13879       Object* current_key = get(EntryToIndex(current));
13880       if (IsKey(current_key)) {
13881         uint32_t target = EntryForProbe(key, current_key, probe, current);
13882         if (current == target) continue;
13883         Object* target_key = get(EntryToIndex(target));
13884         if (!IsKey(target_key) ||
13885             EntryForProbe(key, target_key, probe, target) != target) {
13886           // Put the current element into the correct position.
13887           Swap(current, target, mode);
13888           // The other element will be processed on the next iteration.
13889           current--;
13890         } else {
13891           // The place for the current element is occupied. Leave the element
13892           // for the next probe.
13893           done = false;
13894         }
13895       }
13896     }
13897   }
13898 }
13899 
13900 
13901 template<typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> table,int n,Key key,PretenureFlag pretenure)13902 Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
13903     Handle<Derived> table,
13904     int n,
13905     Key key,
13906     PretenureFlag pretenure) {
13907   Isolate* isolate = table->GetIsolate();
13908   int capacity = table->Capacity();
13909   int nof = table->NumberOfElements() + n;
13910   int nod = table->NumberOfDeletedElements();
13911   // Return if:
13912   //   50% is still free after adding n elements and
13913   //   at most 50% of the free elements are deleted elements.
13914   if (nod <= (capacity - nof) >> 1) {
13915     int needed_free = nof >> 1;
13916     if (nof + needed_free <= capacity) return table;
13917   }
13918 
13919   const int kMinCapacityForPretenure = 256;
13920   bool should_pretenure = pretenure == TENURED ||
13921       ((capacity > kMinCapacityForPretenure) &&
13922           !isolate->heap()->InNewSpace(*table));
13923   Handle<Derived> new_table = HashTable::New(
13924       isolate,
13925       nof * 2,
13926       USE_DEFAULT_MINIMUM_CAPACITY,
13927       should_pretenure ? TENURED : NOT_TENURED);
13928 
13929   table->Rehash(new_table, key);
13930   return new_table;
13931 }
13932 
13933 
13934 template<typename Derived, typename Shape, typename Key>
Shrink(Handle<Derived> table,Key key)13935 Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
13936                                                        Key key) {
13937   int capacity = table->Capacity();
13938   int nof = table->NumberOfElements();
13939 
13940   // Shrink to fit the number of elements if only a quarter of the
13941   // capacity is filled with elements.
13942   if (nof > (capacity >> 2)) return table;
13943   // Allocate a new dictionary with room for at least the current
13944   // number of elements. The allocation method will make sure that
13945   // there is extra room in the dictionary for additions. Don't go
13946   // lower than room for 16 elements.
13947   int at_least_room_for = nof;
13948   if (at_least_room_for < 16) return table;
13949 
13950   Isolate* isolate = table->GetIsolate();
13951   const int kMinCapacityForPretenure = 256;
13952   bool pretenure =
13953       (at_least_room_for > kMinCapacityForPretenure) &&
13954       !isolate->heap()->InNewSpace(*table);
13955   Handle<Derived> new_table = HashTable::New(
13956       isolate,
13957       at_least_room_for,
13958       USE_DEFAULT_MINIMUM_CAPACITY,
13959       pretenure ? TENURED : NOT_TENURED);
13960 
13961   table->Rehash(new_table, key);
13962   return new_table;
13963 }
13964 
13965 
13966 template<typename Derived, typename Shape, typename Key>
FindInsertionEntry(uint32_t hash)13967 uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
13968   uint32_t capacity = Capacity();
13969   uint32_t entry = FirstProbe(hash, capacity);
13970   uint32_t count = 1;
13971   // EnsureCapacity will guarantee the hash table is never full.
13972   while (true) {
13973     Object* element = KeyAt(entry);
13974     if (element->IsUndefined() || element->IsTheHole()) break;
13975     entry = NextProbe(entry, count++, capacity);
13976   }
13977   return entry;
13978 }
13979 
13980 
13981 // Force instantiation of template instances class.
13982 // Please note this list is compiler dependent.
13983 
13984 template class HashTable<StringTable, StringTableShape, HashTableKey*>;
13985 
13986 template class HashTable<CompilationCacheTable,
13987                          CompilationCacheShape,
13988                          HashTableKey*>;
13989 
13990 template class HashTable<MapCache, MapCacheShape, HashTableKey*>;
13991 
13992 template class HashTable<ObjectHashTable,
13993                          ObjectHashTableShape,
13994                          Handle<Object> >;
13995 
13996 template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
13997 
13998 template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
13999 
14000 template class Dictionary<SeededNumberDictionary,
14001                           SeededNumberDictionaryShape,
14002                           uint32_t>;
14003 
14004 template class Dictionary<UnseededNumberDictionary,
14005                           UnseededNumberDictionaryShape,
14006                           uint32_t>;
14007 
14008 template Handle<SeededNumberDictionary>
14009 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14010     New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
14011 
14012 template Handle<UnseededNumberDictionary>
14013 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14014     New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
14015 
14016 template Handle<NameDictionary>
14017 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14018     New(Isolate*, int n, PretenureFlag pretenure);
14019 
14020 template Handle<SeededNumberDictionary>
14021 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14022     AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
14023 
14024 template Handle<UnseededNumberDictionary>
14025 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14026     AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
14027 
14028 template Object*
14029 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14030     SlowReverseLookup(Object* value);
14031 
14032 template Object*
14033 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14034     SlowReverseLookup(Object* value);
14035 
14036 template void
14037 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14038     CopyKeysTo(
14039         FixedArray*,
14040         PropertyAttributes,
14041         Dictionary<SeededNumberDictionary,
14042                    SeededNumberDictionaryShape,
14043                    uint32_t>::SortMode);
14044 
14045 template Handle<Object>
14046 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
14047     Handle<NameDictionary>, int, JSObject::DeleteMode);
14048 
14049 template Handle<Object>
14050 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14051     DeleteProperty(Handle<SeededNumberDictionary>, int, JSObject::DeleteMode);
14052 
14053 template Handle<NameDictionary>
14054 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14055     New(Isolate*, int, MinimumCapacity, PretenureFlag);
14056 
14057 template Handle<NameDictionary>
14058 HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14059     Shrink(Handle<NameDictionary>, Handle<Name>);
14060 
14061 template Handle<SeededNumberDictionary>
14062 HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14063     Shrink(Handle<SeededNumberDictionary>, uint32_t);
14064 
14065 template void Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14066     CopyKeysTo(
14067         FixedArray*,
14068         int,
14069         PropertyAttributes,
14070         Dictionary<
14071             NameDictionary, NameDictionaryShape, Handle<Name> >::SortMode);
14072 
14073 template int
14074 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14075     NumberOfElementsFilterAttributes(PropertyAttributes);
14076 
14077 template Handle<NameDictionary>
14078 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
14079     Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
14080 
14081 template void
14082 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14083     GenerateNewEnumerationIndices(Handle<NameDictionary>);
14084 
14085 template int
14086 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14087     NumberOfElementsFilterAttributes(PropertyAttributes);
14088 
14089 template Handle<SeededNumberDictionary>
14090 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14091     Add(Handle<SeededNumberDictionary>,
14092         uint32_t,
14093         Handle<Object>,
14094         PropertyDetails);
14095 
14096 template Handle<UnseededNumberDictionary>
14097 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14098     Add(Handle<UnseededNumberDictionary>,
14099         uint32_t,
14100         Handle<Object>,
14101         PropertyDetails);
14102 
14103 template Handle<SeededNumberDictionary>
14104 Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14105     EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
14106 
14107 template Handle<UnseededNumberDictionary>
14108 Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14109     EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
14110 
14111 template Handle<NameDictionary>
14112 Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14113     EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
14114 
14115 template
14116 int Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14117     NumberOfEnumElements();
14118 
14119 template
14120 int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14121     NumberOfEnumElements();
14122 
14123 template
14124 int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14125     FindEntry(uint32_t);
14126 
14127 
PrepareSlowElementsForSort(Handle<JSObject> object,uint32_t limit)14128 Handle<Object> JSObject::PrepareSlowElementsForSort(
14129     Handle<JSObject> object, uint32_t limit) {
14130   DCHECK(object->HasDictionaryElements());
14131   Isolate* isolate = object->GetIsolate();
14132   // Must stay in dictionary mode, either because of requires_slow_elements,
14133   // or because we are not going to sort (and therefore compact) all of the
14134   // elements.
14135   Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
14136   Handle<SeededNumberDictionary> new_dict =
14137       SeededNumberDictionary::New(isolate, dict->NumberOfElements());
14138 
14139   uint32_t pos = 0;
14140   uint32_t undefs = 0;
14141   int capacity = dict->Capacity();
14142   Handle<Smi> bailout(Smi::FromInt(-1), isolate);
14143   // Entry to the new dictionary does not cause it to grow, as we have
14144   // allocated one that is large enough for all entries.
14145   DisallowHeapAllocation no_gc;
14146   for (int i = 0; i < capacity; i++) {
14147     Object* k = dict->KeyAt(i);
14148     if (!dict->IsKey(k)) continue;
14149 
14150     DCHECK(k->IsNumber());
14151     DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
14152     DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
14153     DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
14154 
14155     HandleScope scope(isolate);
14156     Handle<Object> value(dict->ValueAt(i), isolate);
14157     PropertyDetails details = dict->DetailsAt(i);
14158     if (details.type() == CALLBACKS || details.IsReadOnly()) {
14159       // Bail out and do the sorting of undefineds and array holes in JS.
14160       // Also bail out if the element is not supposed to be moved.
14161       return bailout;
14162     }
14163 
14164     uint32_t key = NumberToUint32(k);
14165     if (key < limit) {
14166       if (value->IsUndefined()) {
14167         undefs++;
14168       } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14169         // Adding an entry with the key beyond smi-range requires
14170         // allocation. Bailout.
14171         return bailout;
14172       } else {
14173         Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14174             new_dict, pos, value, details);
14175         DCHECK(result.is_identical_to(new_dict));
14176         USE(result);
14177         pos++;
14178       }
14179     } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
14180       // Adding an entry with the key beyond smi-range requires
14181       // allocation. Bailout.
14182       return bailout;
14183     } else {
14184       Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14185           new_dict, key, value, details);
14186       DCHECK(result.is_identical_to(new_dict));
14187       USE(result);
14188     }
14189   }
14190 
14191   uint32_t result = pos;
14192   PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
14193   while (undefs > 0) {
14194     if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14195       // Adding an entry with the key beyond smi-range requires
14196       // allocation. Bailout.
14197       return bailout;
14198     }
14199     HandleScope scope(isolate);
14200     Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14201         new_dict, pos, isolate->factory()->undefined_value(), no_details);
14202     DCHECK(result.is_identical_to(new_dict));
14203     USE(result);
14204     pos++;
14205     undefs--;
14206   }
14207 
14208   object->set_elements(*new_dict);
14209 
14210   AllowHeapAllocation allocate_return_value;
14211   return isolate->factory()->NewNumberFromUint(result);
14212 }
14213 
14214 
14215 // Collects all defined (non-hole) and non-undefined (array) elements at
14216 // the start of the elements array.
14217 // If the object is in dictionary mode, it is converted to fast elements
14218 // mode.
PrepareElementsForSort(Handle<JSObject> object,uint32_t limit)14219 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
14220                                                 uint32_t limit) {
14221   Isolate* isolate = object->GetIsolate();
14222   if (object->HasSloppyArgumentsElements() ||
14223       object->map()->is_observed()) {
14224     return handle(Smi::FromInt(-1), isolate);
14225   }
14226 
14227   if (object->HasDictionaryElements()) {
14228     // Convert to fast elements containing only the existing properties.
14229     // Ordering is irrelevant, since we are going to sort anyway.
14230     Handle<SeededNumberDictionary> dict(object->element_dictionary());
14231     if (object->IsJSArray() || dict->requires_slow_elements() ||
14232         dict->max_number_key() >= limit) {
14233       return JSObject::PrepareSlowElementsForSort(object, limit);
14234     }
14235     // Convert to fast elements.
14236 
14237     Handle<Map> new_map =
14238         JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
14239 
14240     PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
14241         NOT_TENURED: TENURED;
14242     Handle<FixedArray> fast_elements =
14243         isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
14244     dict->CopyValuesTo(*fast_elements);
14245     JSObject::ValidateElements(object);
14246 
14247     JSObject::SetMapAndElements(object, new_map, fast_elements);
14248   } else if (object->HasExternalArrayElements() ||
14249              object->HasFixedTypedArrayElements()) {
14250     // Typed arrays cannot have holes or undefined elements.
14251     return handle(Smi::FromInt(
14252         FixedArrayBase::cast(object->elements())->length()), isolate);
14253   } else if (!object->HasFastDoubleElements()) {
14254     EnsureWritableFastElements(object);
14255   }
14256   DCHECK(object->HasFastSmiOrObjectElements() ||
14257          object->HasFastDoubleElements());
14258 
14259   // Collect holes at the end, undefined before that and the rest at the
14260   // start, and return the number of non-hole, non-undefined values.
14261 
14262   Handle<FixedArrayBase> elements_base(object->elements());
14263   uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
14264   if (limit > elements_length) {
14265     limit = elements_length ;
14266   }
14267   if (limit == 0) {
14268     return handle(Smi::FromInt(0), isolate);
14269   }
14270 
14271   uint32_t result = 0;
14272   if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
14273     FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
14274     // Split elements into defined and the_hole, in that order.
14275     unsigned int holes = limit;
14276     // Assume most arrays contain no holes and undefined values, so minimize the
14277     // number of stores of non-undefined, non-the-hole values.
14278     for (unsigned int i = 0; i < holes; i++) {
14279       if (elements->is_the_hole(i)) {
14280         holes--;
14281       } else {
14282         continue;
14283       }
14284       // Position i needs to be filled.
14285       while (holes > i) {
14286         if (elements->is_the_hole(holes)) {
14287           holes--;
14288         } else {
14289           elements->set(i, elements->get_scalar(holes));
14290           break;
14291         }
14292       }
14293     }
14294     result = holes;
14295     while (holes < limit) {
14296       elements->set_the_hole(holes);
14297       holes++;
14298     }
14299   } else {
14300     FixedArray* elements = FixedArray::cast(*elements_base);
14301     DisallowHeapAllocation no_gc;
14302 
14303     // Split elements into defined, undefined and the_hole, in that order.  Only
14304     // count locations for undefined and the hole, and fill them afterwards.
14305     WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
14306     unsigned int undefs = limit;
14307     unsigned int holes = limit;
14308     // Assume most arrays contain no holes and undefined values, so minimize the
14309     // number of stores of non-undefined, non-the-hole values.
14310     for (unsigned int i = 0; i < undefs; i++) {
14311       Object* current = elements->get(i);
14312       if (current->IsTheHole()) {
14313         holes--;
14314         undefs--;
14315       } else if (current->IsUndefined()) {
14316         undefs--;
14317       } else {
14318         continue;
14319       }
14320       // Position i needs to be filled.
14321       while (undefs > i) {
14322         current = elements->get(undefs);
14323         if (current->IsTheHole()) {
14324           holes--;
14325           undefs--;
14326         } else if (current->IsUndefined()) {
14327           undefs--;
14328         } else {
14329           elements->set(i, current, write_barrier);
14330           break;
14331         }
14332       }
14333     }
14334     result = undefs;
14335     while (undefs < holes) {
14336       elements->set_undefined(undefs);
14337       undefs++;
14338     }
14339     while (holes < limit) {
14340       elements->set_the_hole(holes);
14341       holes++;
14342     }
14343   }
14344 
14345   return isolate->factory()->NewNumberFromUint(result);
14346 }
14347 
14348 
type()14349 ExternalArrayType JSTypedArray::type() {
14350   switch (elements()->map()->instance_type()) {
14351 #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size)            \
14352     case EXTERNAL_##TYPE##_ARRAY_TYPE:                                        \
14353     case FIXED_##TYPE##_ARRAY_TYPE:                                           \
14354       return kExternal##Type##Array;
14355 
14356     TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
14357 #undef INSTANCE_TYPE_TO_ARRAY_TYPE
14358 
14359     default:
14360       UNREACHABLE();
14361       return static_cast<ExternalArrayType>(-1);
14362   }
14363 }
14364 
14365 
element_size()14366 size_t JSTypedArray::element_size() {
14367   switch (elements()->map()->instance_type()) {
14368 #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size)          \
14369     case EXTERNAL_##TYPE##_ARRAY_TYPE:                                        \
14370       return size;
14371 
14372     TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
14373 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
14374 
14375     default:
14376       UNREACHABLE();
14377       return 0;
14378   }
14379 }
14380 
14381 
SetValue(Handle<ExternalUint8ClampedArray> array,uint32_t index,Handle<Object> value)14382 Handle<Object> ExternalUint8ClampedArray::SetValue(
14383     Handle<ExternalUint8ClampedArray> array,
14384     uint32_t index,
14385     Handle<Object> value) {
14386   uint8_t clamped_value = 0;
14387   if (index < static_cast<uint32_t>(array->length())) {
14388     if (value->IsSmi()) {
14389       int int_value = Handle<Smi>::cast(value)->value();
14390       if (int_value < 0) {
14391         clamped_value = 0;
14392       } else if (int_value > 255) {
14393         clamped_value = 255;
14394       } else {
14395         clamped_value = static_cast<uint8_t>(int_value);
14396       }
14397     } else if (value->IsHeapNumber()) {
14398       double double_value = Handle<HeapNumber>::cast(value)->value();
14399       if (!(double_value > 0)) {
14400         // NaN and less than zero clamp to zero.
14401         clamped_value = 0;
14402       } else if (double_value > 255) {
14403         // Greater than 255 clamp to 255.
14404         clamped_value = 255;
14405       } else {
14406         // Other doubles are rounded to the nearest integer.
14407         clamped_value = static_cast<uint8_t>(lrint(double_value));
14408       }
14409     } else {
14410       // Clamp undefined to zero (default). All other types have been
14411       // converted to a number type further up in the call chain.
14412       DCHECK(value->IsUndefined());
14413     }
14414     array->set(index, clamped_value);
14415   }
14416   return handle(Smi::FromInt(clamped_value), array->GetIsolate());
14417 }
14418 
14419 
14420 template<typename ExternalArrayClass, typename ValueType>
ExternalArrayIntSetter(Isolate * isolate,Handle<ExternalArrayClass> receiver,uint32_t index,Handle<Object> value)14421 static Handle<Object> ExternalArrayIntSetter(
14422     Isolate* isolate,
14423     Handle<ExternalArrayClass> receiver,
14424     uint32_t index,
14425     Handle<Object> value) {
14426   ValueType cast_value = 0;
14427   if (index < static_cast<uint32_t>(receiver->length())) {
14428     if (value->IsSmi()) {
14429       int int_value = Handle<Smi>::cast(value)->value();
14430       cast_value = static_cast<ValueType>(int_value);
14431     } else if (value->IsHeapNumber()) {
14432       double double_value = Handle<HeapNumber>::cast(value)->value();
14433       cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
14434     } else {
14435       // Clamp undefined to zero (default). All other types have been
14436       // converted to a number type further up in the call chain.
14437       DCHECK(value->IsUndefined());
14438     }
14439     receiver->set(index, cast_value);
14440   }
14441   return isolate->factory()->NewNumberFromInt(cast_value);
14442 }
14443 
14444 
SetValue(Handle<ExternalInt8Array> array,uint32_t index,Handle<Object> value)14445 Handle<Object> ExternalInt8Array::SetValue(Handle<ExternalInt8Array> array,
14446                                            uint32_t index,
14447                                            Handle<Object> value) {
14448   return ExternalArrayIntSetter<ExternalInt8Array, int8_t>(
14449       array->GetIsolate(), array, index, value);
14450 }
14451 
14452 
SetValue(Handle<ExternalUint8Array> array,uint32_t index,Handle<Object> value)14453 Handle<Object> ExternalUint8Array::SetValue(Handle<ExternalUint8Array> array,
14454                                             uint32_t index,
14455                                             Handle<Object> value) {
14456   return ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(
14457       array->GetIsolate(), array, index, value);
14458 }
14459 
14460 
SetValue(Handle<ExternalInt16Array> array,uint32_t index,Handle<Object> value)14461 Handle<Object> ExternalInt16Array::SetValue(Handle<ExternalInt16Array> array,
14462                                             uint32_t index,
14463                                             Handle<Object> value) {
14464   return ExternalArrayIntSetter<ExternalInt16Array, int16_t>(
14465       array->GetIsolate(), array, index, value);
14466 }
14467 
14468 
SetValue(Handle<ExternalUint16Array> array,uint32_t index,Handle<Object> value)14469 Handle<Object> ExternalUint16Array::SetValue(Handle<ExternalUint16Array> array,
14470                                              uint32_t index,
14471                                              Handle<Object> value) {
14472   return ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(
14473       array->GetIsolate(), array, index, value);
14474 }
14475 
14476 
SetValue(Handle<ExternalInt32Array> array,uint32_t index,Handle<Object> value)14477 Handle<Object> ExternalInt32Array::SetValue(Handle<ExternalInt32Array> array,
14478                                             uint32_t index,
14479                                             Handle<Object> value) {
14480   return ExternalArrayIntSetter<ExternalInt32Array, int32_t>(
14481       array->GetIsolate(), array, index, value);
14482 }
14483 
14484 
SetValue(Handle<ExternalUint32Array> array,uint32_t index,Handle<Object> value)14485 Handle<Object> ExternalUint32Array::SetValue(
14486     Handle<ExternalUint32Array> array,
14487     uint32_t index,
14488     Handle<Object> value) {
14489   uint32_t cast_value = 0;
14490   if (index < static_cast<uint32_t>(array->length())) {
14491     if (value->IsSmi()) {
14492       int int_value = Handle<Smi>::cast(value)->value();
14493       cast_value = static_cast<uint32_t>(int_value);
14494     } else if (value->IsHeapNumber()) {
14495       double double_value = Handle<HeapNumber>::cast(value)->value();
14496       cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
14497     } else {
14498       // Clamp undefined to zero (default). All other types have been
14499       // converted to a number type further up in the call chain.
14500       DCHECK(value->IsUndefined());
14501     }
14502     array->set(index, cast_value);
14503   }
14504   return array->GetIsolate()->factory()->NewNumberFromUint(cast_value);
14505 }
14506 
14507 
SetValue(Handle<ExternalFloat32Array> array,uint32_t index,Handle<Object> value)14508 Handle<Object> ExternalFloat32Array::SetValue(
14509     Handle<ExternalFloat32Array> array,
14510     uint32_t index,
14511     Handle<Object> value) {
14512   float cast_value = static_cast<float>(base::OS::nan_value());
14513   if (index < static_cast<uint32_t>(array->length())) {
14514     if (value->IsSmi()) {
14515       int int_value = Handle<Smi>::cast(value)->value();
14516       cast_value = static_cast<float>(int_value);
14517     } else if (value->IsHeapNumber()) {
14518       double double_value = Handle<HeapNumber>::cast(value)->value();
14519       cast_value = static_cast<float>(double_value);
14520     } else {
14521       // Clamp undefined to NaN (default). All other types have been
14522       // converted to a number type further up in the call chain.
14523       DCHECK(value->IsUndefined());
14524     }
14525     array->set(index, cast_value);
14526   }
14527   return array->GetIsolate()->factory()->NewNumber(cast_value);
14528 }
14529 
14530 
SetValue(Handle<ExternalFloat64Array> array,uint32_t index,Handle<Object> value)14531 Handle<Object> ExternalFloat64Array::SetValue(
14532     Handle<ExternalFloat64Array> array,
14533     uint32_t index,
14534     Handle<Object> value) {
14535   double double_value = base::OS::nan_value();
14536   if (index < static_cast<uint32_t>(array->length())) {
14537     if (value->IsNumber()) {
14538       double_value = value->Number();
14539     } else {
14540       // Clamp undefined to NaN (default). All other types have been
14541       // converted to a number type further up in the call chain.
14542       DCHECK(value->IsUndefined());
14543     }
14544     array->set(index, double_value);
14545   }
14546   return array->GetIsolate()->factory()->NewNumber(double_value);
14547 }
14548 
14549 
EnsurePropertyCell(Handle<JSGlobalObject> global,Handle<Name> name)14550 Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
14551     Handle<JSGlobalObject> global,
14552     Handle<Name> name) {
14553   DCHECK(!global->HasFastProperties());
14554   int entry = global->property_dictionary()->FindEntry(name);
14555   if (entry == NameDictionary::kNotFound) {
14556     Isolate* isolate = global->GetIsolate();
14557     Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
14558         isolate->factory()->the_hole_value());
14559     PropertyDetails details(NONE, NORMAL, 0);
14560     details = details.AsDeleted();
14561     Handle<NameDictionary> dictionary = NameDictionary::Add(
14562         handle(global->property_dictionary()), name, cell, details);
14563     global->set_properties(*dictionary);
14564     return cell;
14565   } else {
14566     Object* value = global->property_dictionary()->ValueAt(entry);
14567     DCHECK(value->IsPropertyCell());
14568     return handle(PropertyCell::cast(value));
14569   }
14570 }
14571 
14572 
14573 // This class is used for looking up two character strings in the string table.
14574 // If we don't have a hit we don't want to waste much time so we unroll the
14575 // string hash calculation loop here for speed.  Doesn't work if the two
14576 // characters form a decimal integer, since such strings have a different hash
14577 // algorithm.
14578 class TwoCharHashTableKey : public HashTableKey {
14579  public:
TwoCharHashTableKey(uint16_t c1,uint16_t c2,uint32_t seed)14580   TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
14581     : c1_(c1), c2_(c2) {
14582     // Char 1.
14583     uint32_t hash = seed;
14584     hash += c1;
14585     hash += hash << 10;
14586     hash ^= hash >> 6;
14587     // Char 2.
14588     hash += c2;
14589     hash += hash << 10;
14590     hash ^= hash >> 6;
14591     // GetHash.
14592     hash += hash << 3;
14593     hash ^= hash >> 11;
14594     hash += hash << 15;
14595     if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
14596     hash_ = hash;
14597 #ifdef DEBUG
14598     // If this assert fails then we failed to reproduce the two-character
14599     // version of the string hashing algorithm above.  One reason could be
14600     // that we were passed two digits as characters, since the hash
14601     // algorithm is different in that case.
14602     uint16_t chars[2] = {c1, c2};
14603     uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
14604     hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
14605     DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
14606 #endif
14607   }
14608 
IsMatch(Object * o)14609   bool IsMatch(Object* o) OVERRIDE {
14610     if (!o->IsString()) return false;
14611     String* other = String::cast(o);
14612     if (other->length() != 2) return false;
14613     if (other->Get(0) != c1_) return false;
14614     return other->Get(1) == c2_;
14615   }
14616 
Hash()14617   uint32_t Hash() OVERRIDE { return hash_; }
HashForObject(Object * key)14618   uint32_t HashForObject(Object* key) OVERRIDE {
14619     if (!key->IsString()) return 0;
14620     return String::cast(key)->Hash();
14621   }
14622 
AsHandle(Isolate * isolate)14623   Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
14624     // The TwoCharHashTableKey is only used for looking in the string
14625     // table, not for adding to it.
14626     UNREACHABLE();
14627     return MaybeHandle<Object>().ToHandleChecked();
14628   }
14629 
14630  private:
14631   uint16_t c1_;
14632   uint16_t c2_;
14633   uint32_t hash_;
14634 };
14635 
14636 
InternalizeStringIfExists(Isolate * isolate,Handle<String> string)14637 MaybeHandle<String> StringTable::InternalizeStringIfExists(
14638     Isolate* isolate,
14639     Handle<String> string) {
14640   if (string->IsInternalizedString()) {
14641     return string;
14642   }
14643   return LookupStringIfExists(isolate, string);
14644 }
14645 
14646 
LookupStringIfExists(Isolate * isolate,Handle<String> string)14647 MaybeHandle<String> StringTable::LookupStringIfExists(
14648     Isolate* isolate,
14649     Handle<String> string) {
14650   Handle<StringTable> string_table = isolate->factory()->string_table();
14651   InternalizedStringKey key(string);
14652   int entry = string_table->FindEntry(&key);
14653   if (entry == kNotFound) {
14654     return MaybeHandle<String>();
14655   } else {
14656     Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
14657     DCHECK(StringShape(*result).IsInternalized());
14658     return result;
14659   }
14660 }
14661 
14662 
LookupTwoCharsStringIfExists(Isolate * isolate,uint16_t c1,uint16_t c2)14663 MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
14664     Isolate* isolate,
14665     uint16_t c1,
14666     uint16_t c2) {
14667   Handle<StringTable> string_table = isolate->factory()->string_table();
14668   TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
14669   int entry = string_table->FindEntry(&key);
14670   if (entry == kNotFound) {
14671     return MaybeHandle<String>();
14672   } else {
14673     Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
14674     DCHECK(StringShape(*result).IsInternalized());
14675     return result;
14676   }
14677 }
14678 
14679 
LookupString(Isolate * isolate,Handle<String> string)14680 Handle<String> StringTable::LookupString(Isolate* isolate,
14681                                          Handle<String> string) {
14682   InternalizedStringKey key(string);
14683   return LookupKey(isolate, &key);
14684 }
14685 
14686 
LookupKey(Isolate * isolate,HashTableKey * key)14687 Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
14688   Handle<StringTable> table = isolate->factory()->string_table();
14689   int entry = table->FindEntry(key);
14690 
14691   // String already in table.
14692   if (entry != kNotFound) {
14693     return handle(String::cast(table->KeyAt(entry)), isolate);
14694   }
14695 
14696   // Adding new string. Grow table if needed.
14697   table = StringTable::EnsureCapacity(table, 1, key);
14698 
14699   // Create string object.
14700   Handle<Object> string = key->AsHandle(isolate);
14701   // There must be no attempts to internalize strings that could throw
14702   // InvalidStringLength error.
14703   CHECK(!string.is_null());
14704 
14705   // Add the new string and return it along with the string table.
14706   entry = table->FindInsertionEntry(key->Hash());
14707   table->set(EntryToIndex(entry), *string);
14708   table->ElementAdded();
14709 
14710   isolate->factory()->set_string_table(table);
14711   return Handle<String>::cast(string);
14712 }
14713 
14714 
Lookup(Handle<String> src,Handle<Context> context)14715 Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
14716                                              Handle<Context> context) {
14717   Isolate* isolate = GetIsolate();
14718   Handle<SharedFunctionInfo> shared(context->closure()->shared());
14719   StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
14720                       RelocInfo::kNoPosition);
14721   int entry = FindEntry(&key);
14722   if (entry == kNotFound) return isolate->factory()->undefined_value();
14723   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
14724 }
14725 
14726 
LookupEval(Handle<String> src,Handle<SharedFunctionInfo> outer_info,StrictMode strict_mode,int scope_position)14727 Handle<Object> CompilationCacheTable::LookupEval(
14728     Handle<String> src, Handle<SharedFunctionInfo> outer_info,
14729     StrictMode strict_mode, int scope_position) {
14730   Isolate* isolate = GetIsolate();
14731   // Cache key is the tuple (source, outer shared function info, scope position)
14732   // to unambiguously identify the context chain the cached eval code assumes.
14733   StringSharedKey key(src, outer_info, strict_mode, scope_position);
14734   int entry = FindEntry(&key);
14735   if (entry == kNotFound) return isolate->factory()->undefined_value();
14736   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
14737 }
14738 
14739 
LookupRegExp(Handle<String> src,JSRegExp::Flags flags)14740 Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
14741                                                    JSRegExp::Flags flags) {
14742   Isolate* isolate = GetIsolate();
14743   DisallowHeapAllocation no_allocation;
14744   RegExpKey key(src, flags);
14745   int entry = FindEntry(&key);
14746   if (entry == kNotFound) return isolate->factory()->undefined_value();
14747   return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
14748 }
14749 
14750 
Put(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<Context> context,Handle<Object> value)14751 Handle<CompilationCacheTable> CompilationCacheTable::Put(
14752     Handle<CompilationCacheTable> cache, Handle<String> src,
14753     Handle<Context> context, Handle<Object> value) {
14754   Isolate* isolate = cache->GetIsolate();
14755   Handle<SharedFunctionInfo> shared(context->closure()->shared());
14756   StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
14757                       RelocInfo::kNoPosition);
14758   cache = EnsureCapacity(cache, 1, &key);
14759   Handle<Object> k = key.AsHandle(isolate);
14760   int entry = cache->FindInsertionEntry(key.Hash());
14761   cache->set(EntryToIndex(entry), *k);
14762   cache->set(EntryToIndex(entry) + 1, *value);
14763   cache->ElementAdded();
14764   return cache;
14765 }
14766 
14767 
PutEval(Handle<CompilationCacheTable> cache,Handle<String> src,Handle<SharedFunctionInfo> outer_info,Handle<SharedFunctionInfo> value,int scope_position)14768 Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
14769     Handle<CompilationCacheTable> cache, Handle<String> src,
14770     Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
14771     int scope_position) {
14772   Isolate* isolate = cache->GetIsolate();
14773   StringSharedKey key(src, outer_info, value->strict_mode(), scope_position);
14774   cache = EnsureCapacity(cache, 1, &key);
14775   Handle<Object> k = key.AsHandle(isolate);
14776   int entry = cache->FindInsertionEntry(key.Hash());
14777   cache->set(EntryToIndex(entry), *k);
14778   cache->set(EntryToIndex(entry) + 1, *value);
14779   cache->ElementAdded();
14780   return cache;
14781 }
14782 
14783 
PutRegExp(Handle<CompilationCacheTable> cache,Handle<String> src,JSRegExp::Flags flags,Handle<FixedArray> value)14784 Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
14785       Handle<CompilationCacheTable> cache, Handle<String> src,
14786       JSRegExp::Flags flags, Handle<FixedArray> value) {
14787   RegExpKey key(src, flags);
14788   cache = EnsureCapacity(cache, 1, &key);
14789   int entry = cache->FindInsertionEntry(key.Hash());
14790   // We store the value in the key slot, and compare the search key
14791   // to the stored value with a custon IsMatch function during lookups.
14792   cache->set(EntryToIndex(entry), *value);
14793   cache->set(EntryToIndex(entry) + 1, *value);
14794   cache->ElementAdded();
14795   return cache;
14796 }
14797 
14798 
Remove(Object * value)14799 void CompilationCacheTable::Remove(Object* value) {
14800   DisallowHeapAllocation no_allocation;
14801   Object* the_hole_value = GetHeap()->the_hole_value();
14802   for (int entry = 0, size = Capacity(); entry < size; entry++) {
14803     int entry_index = EntryToIndex(entry);
14804     int value_index = entry_index + 1;
14805     if (get(value_index) == value) {
14806       NoWriteBarrierSet(this, entry_index, the_hole_value);
14807       NoWriteBarrierSet(this, value_index, the_hole_value);
14808       ElementRemoved();
14809     }
14810   }
14811   return;
14812 }
14813 
14814 
14815 // StringsKey used for HashTable where key is array of internalized strings.
14816 class StringsKey : public HashTableKey {
14817  public:
StringsKey(Handle<FixedArray> strings)14818   explicit StringsKey(Handle<FixedArray> strings) : strings_(strings) { }
14819 
IsMatch(Object * strings)14820   bool IsMatch(Object* strings) OVERRIDE {
14821     FixedArray* o = FixedArray::cast(strings);
14822     int len = strings_->length();
14823     if (o->length() != len) return false;
14824     for (int i = 0; i < len; i++) {
14825       if (o->get(i) != strings_->get(i)) return false;
14826     }
14827     return true;
14828   }
14829 
Hash()14830   uint32_t Hash() OVERRIDE { return HashForObject(*strings_); }
14831 
HashForObject(Object * obj)14832   uint32_t HashForObject(Object* obj) OVERRIDE {
14833     FixedArray* strings = FixedArray::cast(obj);
14834     int len = strings->length();
14835     uint32_t hash = 0;
14836     for (int i = 0; i < len; i++) {
14837       hash ^= String::cast(strings->get(i))->Hash();
14838     }
14839     return hash;
14840   }
14841 
AsHandle(Isolate * isolate)14842   Handle<Object> AsHandle(Isolate* isolate) OVERRIDE { return strings_; }
14843 
14844  private:
14845   Handle<FixedArray> strings_;
14846 };
14847 
14848 
Lookup(FixedArray * array)14849 Object* MapCache::Lookup(FixedArray* array) {
14850   DisallowHeapAllocation no_alloc;
14851   StringsKey key(handle(array));
14852   int entry = FindEntry(&key);
14853   if (entry == kNotFound) return GetHeap()->undefined_value();
14854   return get(EntryToIndex(entry) + 1);
14855 }
14856 
14857 
Put(Handle<MapCache> map_cache,Handle<FixedArray> array,Handle<Map> value)14858 Handle<MapCache> MapCache::Put(
14859     Handle<MapCache> map_cache, Handle<FixedArray> array, Handle<Map> value) {
14860   StringsKey key(array);
14861 
14862   Handle<MapCache> new_cache = EnsureCapacity(map_cache, 1, &key);
14863   int entry = new_cache->FindInsertionEntry(key.Hash());
14864   new_cache->set(EntryToIndex(entry), *array);
14865   new_cache->set(EntryToIndex(entry) + 1, *value);
14866   new_cache->ElementAdded();
14867   return new_cache;
14868 }
14869 
14870 
14871 template<typename Derived, typename Shape, typename Key>
New(Isolate * isolate,int at_least_space_for,PretenureFlag pretenure)14872 Handle<Derived> Dictionary<Derived, Shape, Key>::New(
14873     Isolate* isolate,
14874     int at_least_space_for,
14875     PretenureFlag pretenure) {
14876   DCHECK(0 <= at_least_space_for);
14877   Handle<Derived> dict = DerivedHashTable::New(isolate,
14878                                                at_least_space_for,
14879                                                USE_DEFAULT_MINIMUM_CAPACITY,
14880                                                pretenure);
14881 
14882   // Initialize the next enumeration index.
14883   dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
14884   return dict;
14885 }
14886 
14887 
14888 template<typename Derived, typename Shape, typename Key>
GenerateNewEnumerationIndices(Handle<Derived> dictionary)14889 void Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
14890     Handle<Derived> dictionary) {
14891   Factory* factory = dictionary->GetIsolate()->factory();
14892   int length = dictionary->NumberOfElements();
14893 
14894   // Allocate and initialize iteration order array.
14895   Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
14896   for (int i = 0; i < length; i++) {
14897     iteration_order->set(i, Smi::FromInt(i));
14898   }
14899 
14900   // Allocate array with enumeration order.
14901   Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
14902 
14903   // Fill the enumeration order array with property details.
14904   int capacity = dictionary->Capacity();
14905   int pos = 0;
14906   for (int i = 0; i < capacity; i++) {
14907     if (dictionary->IsKey(dictionary->KeyAt(i))) {
14908       int index = dictionary->DetailsAt(i).dictionary_index();
14909       enumeration_order->set(pos++, Smi::FromInt(index));
14910     }
14911   }
14912 
14913   // Sort the arrays wrt. enumeration order.
14914   iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
14915 
14916   // Overwrite the enumeration_order with the enumeration indices.
14917   for (int i = 0; i < length; i++) {
14918     int index = Smi::cast(iteration_order->get(i))->value();
14919     int enum_index = PropertyDetails::kInitialIndex + i;
14920     enumeration_order->set(index, Smi::FromInt(enum_index));
14921   }
14922 
14923   // Update the dictionary with new indices.
14924   capacity = dictionary->Capacity();
14925   pos = 0;
14926   for (int i = 0; i < capacity; i++) {
14927     if (dictionary->IsKey(dictionary->KeyAt(i))) {
14928       int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
14929       PropertyDetails details = dictionary->DetailsAt(i);
14930       PropertyDetails new_details = PropertyDetails(
14931           details.attributes(), details.type(), enum_index);
14932       dictionary->DetailsAtPut(i, new_details);
14933     }
14934   }
14935 
14936   // Set the next enumeration index.
14937   dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
14938 }
14939 
14940 
14941 template<typename Derived, typename Shape, typename Key>
EnsureCapacity(Handle<Derived> dictionary,int n,Key key)14942 Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
14943     Handle<Derived> dictionary, int n, Key key) {
14944   // Check whether there are enough enumeration indices to add n elements.
14945   if (Shape::kIsEnumerable &&
14946       !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
14947     // If not, we generate new indices for the properties.
14948     GenerateNewEnumerationIndices(dictionary);
14949   }
14950   return DerivedHashTable::EnsureCapacity(dictionary, n, key);
14951 }
14952 
14953 
14954 template<typename Derived, typename Shape, typename Key>
DeleteProperty(Handle<Derived> dictionary,int entry,JSObject::DeleteMode mode)14955 Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
14956     Handle<Derived> dictionary,
14957     int entry,
14958     JSObject::DeleteMode mode) {
14959   Factory* factory = dictionary->GetIsolate()->factory();
14960   PropertyDetails details = dictionary->DetailsAt(entry);
14961   // Ignore attributes if forcing a deletion.
14962   if (!details.IsConfigurable() && mode != JSReceiver::FORCE_DELETION) {
14963     return factory->false_value();
14964   }
14965 
14966   dictionary->SetEntry(
14967       entry, factory->the_hole_value(), factory->the_hole_value());
14968   dictionary->ElementRemoved();
14969   return factory->true_value();
14970 }
14971 
14972 
14973 template<typename Derived, typename Shape, typename Key>
AtPut(Handle<Derived> dictionary,Key key,Handle<Object> value)14974 Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
14975     Handle<Derived> dictionary, Key key, Handle<Object> value) {
14976   int entry = dictionary->FindEntry(key);
14977 
14978   // If the entry is present set the value;
14979   if (entry != Dictionary::kNotFound) {
14980     dictionary->ValueAtPut(entry, *value);
14981     return dictionary;
14982   }
14983 
14984   // Check whether the dictionary should be extended.
14985   dictionary = EnsureCapacity(dictionary, 1, key);
14986 #ifdef DEBUG
14987   USE(Shape::AsHandle(dictionary->GetIsolate(), key));
14988 #endif
14989   PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
14990 
14991   AddEntry(dictionary, key, value, details, dictionary->Hash(key));
14992   return dictionary;
14993 }
14994 
14995 
14996 template<typename Derived, typename Shape, typename Key>
Add(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details)14997 Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
14998     Handle<Derived> dictionary,
14999     Key key,
15000     Handle<Object> value,
15001     PropertyDetails details) {
15002   // Valdate key is absent.
15003   SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
15004   // Check whether the dictionary should be extended.
15005   dictionary = EnsureCapacity(dictionary, 1, key);
15006 
15007   AddEntry(dictionary, key, value, details, dictionary->Hash(key));
15008   return dictionary;
15009 }
15010 
15011 
15012 // Add a key, value pair to the dictionary.
15013 template<typename Derived, typename Shape, typename Key>
AddEntry(Handle<Derived> dictionary,Key key,Handle<Object> value,PropertyDetails details,uint32_t hash)15014 void Dictionary<Derived, Shape, Key>::AddEntry(
15015     Handle<Derived> dictionary,
15016     Key key,
15017     Handle<Object> value,
15018     PropertyDetails details,
15019     uint32_t hash) {
15020   // Compute the key object.
15021   Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
15022 
15023   uint32_t entry = dictionary->FindInsertionEntry(hash);
15024   // Insert element at empty or deleted entry
15025   if (!details.IsDeleted() &&
15026       details.dictionary_index() == 0 &&
15027       Shape::kIsEnumerable) {
15028     // Assign an enumeration index to the property and update
15029     // SetNextEnumerationIndex.
15030     int index = dictionary->NextEnumerationIndex();
15031     details = PropertyDetails(details.attributes(), details.type(), index);
15032     dictionary->SetNextEnumerationIndex(index + 1);
15033   }
15034   dictionary->SetEntry(entry, k, value, details);
15035   DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
15036           dictionary->KeyAt(entry)->IsName()));
15037   dictionary->ElementAdded();
15038 }
15039 
15040 
UpdateMaxNumberKey(uint32_t key)15041 void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
15042   DisallowHeapAllocation no_allocation;
15043   // If the dictionary requires slow elements an element has already
15044   // been added at a high index.
15045   if (requires_slow_elements()) return;
15046   // Check if this index is high enough that we should require slow
15047   // elements.
15048   if (key > kRequiresSlowElementsLimit) {
15049     set_requires_slow_elements();
15050     return;
15051   }
15052   // Update max key value.
15053   Object* max_index_object = get(kMaxNumberKeyIndex);
15054   if (!max_index_object->IsSmi() || max_number_key() < key) {
15055     FixedArray::set(kMaxNumberKeyIndex,
15056                     Smi::FromInt(key << kRequiresSlowElementsTagSize));
15057   }
15058 }
15059 
15060 
AddNumberEntry(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details)15061 Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
15062     Handle<SeededNumberDictionary> dictionary,
15063     uint32_t key,
15064     Handle<Object> value,
15065     PropertyDetails details) {
15066   dictionary->UpdateMaxNumberKey(key);
15067   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
15068   return Add(dictionary, key, value, details);
15069 }
15070 
15071 
AddNumberEntry(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)15072 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
15073     Handle<UnseededNumberDictionary> dictionary,
15074     uint32_t key,
15075     Handle<Object> value) {
15076   SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
15077   return Add(dictionary, key, value, PropertyDetails(NONE, NORMAL, 0));
15078 }
15079 
15080 
AtNumberPut(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)15081 Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
15082     Handle<SeededNumberDictionary> dictionary,
15083     uint32_t key,
15084     Handle<Object> value) {
15085   dictionary->UpdateMaxNumberKey(key);
15086   return AtPut(dictionary, key, value);
15087 }
15088 
15089 
AtNumberPut(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)15090 Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
15091     Handle<UnseededNumberDictionary> dictionary,
15092     uint32_t key,
15093     Handle<Object> value) {
15094   return AtPut(dictionary, key, value);
15095 }
15096 
15097 
Set(Handle<SeededNumberDictionary> dictionary,uint32_t key,Handle<Object> value,PropertyDetails details)15098 Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
15099     Handle<SeededNumberDictionary> dictionary,
15100     uint32_t key,
15101     Handle<Object> value,
15102     PropertyDetails details) {
15103   int entry = dictionary->FindEntry(key);
15104   if (entry == kNotFound) {
15105     return AddNumberEntry(dictionary, key, value, details);
15106   }
15107   // Preserve enumeration index.
15108   details = PropertyDetails(details.attributes(),
15109                             details.type(),
15110                             dictionary->DetailsAt(entry).dictionary_index());
15111   Handle<Object> object_key =
15112       SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15113   dictionary->SetEntry(entry, object_key, value, details);
15114   return dictionary;
15115 }
15116 
15117 
Set(Handle<UnseededNumberDictionary> dictionary,uint32_t key,Handle<Object> value)15118 Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
15119     Handle<UnseededNumberDictionary> dictionary,
15120     uint32_t key,
15121     Handle<Object> value) {
15122   int entry = dictionary->FindEntry(key);
15123   if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
15124   Handle<Object> object_key =
15125       UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15126   dictionary->SetEntry(entry, object_key, value);
15127   return dictionary;
15128 }
15129 
15130 
15131 
15132 template<typename Derived, typename Shape, typename Key>
NumberOfElementsFilterAttributes(PropertyAttributes filter)15133 int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
15134     PropertyAttributes filter) {
15135   int capacity = DerivedHashTable::Capacity();
15136   int result = 0;
15137   for (int i = 0; i < capacity; i++) {
15138     Object* k = DerivedHashTable::KeyAt(i);
15139     if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
15140       PropertyDetails details = DetailsAt(i);
15141       if (details.IsDeleted()) continue;
15142       PropertyAttributes attr = details.attributes();
15143       if ((attr & filter) == 0) result++;
15144     }
15145   }
15146   return result;
15147 }
15148 
15149 
15150 template<typename Derived, typename Shape, typename Key>
NumberOfEnumElements()15151 int Dictionary<Derived, Shape, Key>::NumberOfEnumElements() {
15152   return NumberOfElementsFilterAttributes(
15153       static_cast<PropertyAttributes>(DONT_ENUM | SYMBOLIC));
15154 }
15155 
15156 
15157 template<typename Derived, typename Shape, typename Key>
CopyKeysTo(FixedArray * storage,PropertyAttributes filter,typename Dictionary<Derived,Shape,Key>::SortMode sort_mode)15158 void Dictionary<Derived, Shape, Key>::CopyKeysTo(
15159     FixedArray* storage,
15160     PropertyAttributes filter,
15161     typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15162   DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
15163   int capacity = DerivedHashTable::Capacity();
15164   int index = 0;
15165   for (int i = 0; i < capacity; i++) {
15166      Object* k = DerivedHashTable::KeyAt(i);
15167      if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
15168        PropertyDetails details = DetailsAt(i);
15169        if (details.IsDeleted()) continue;
15170        PropertyAttributes attr = details.attributes();
15171        if ((attr & filter) == 0) storage->set(index++, k);
15172      }
15173   }
15174   if (sort_mode == Dictionary::SORTED) {
15175     storage->SortPairs(storage, index);
15176   }
15177   DCHECK(storage->length() >= index);
15178 }
15179 
15180 
15181 struct EnumIndexComparator {
EnumIndexComparatorv8::internal::EnumIndexComparator15182   explicit EnumIndexComparator(NameDictionary* dict) : dict(dict) { }
operator ()v8::internal::EnumIndexComparator15183   bool operator() (Smi* a, Smi* b) {
15184     PropertyDetails da(dict->DetailsAt(a->value()));
15185     PropertyDetails db(dict->DetailsAt(b->value()));
15186     return da.dictionary_index() < db.dictionary_index();
15187   }
15188   NameDictionary* dict;
15189 };
15190 
15191 
CopyEnumKeysTo(FixedArray * storage)15192 void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
15193   int length = storage->length();
15194   int capacity = Capacity();
15195   int properties = 0;
15196   for (int i = 0; i < capacity; i++) {
15197      Object* k = KeyAt(i);
15198      if (IsKey(k) && !k->IsSymbol()) {
15199        PropertyDetails details = DetailsAt(i);
15200        if (details.IsDeleted() || details.IsDontEnum()) continue;
15201        storage->set(properties, Smi::FromInt(i));
15202        properties++;
15203        if (properties == length) break;
15204      }
15205   }
15206   CHECK_EQ(length, properties);
15207   EnumIndexComparator cmp(this);
15208   Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
15209   std::sort(start, start + length, cmp);
15210   for (int i = 0; i < length; i++) {
15211     int index = Smi::cast(storage->get(i))->value();
15212     storage->set(i, KeyAt(index));
15213   }
15214 }
15215 
15216 
15217 template<typename Derived, typename Shape, typename Key>
CopyKeysTo(FixedArray * storage,int index,PropertyAttributes filter,typename Dictionary<Derived,Shape,Key>::SortMode sort_mode)15218 void Dictionary<Derived, Shape, Key>::CopyKeysTo(
15219     FixedArray* storage,
15220     int index,
15221     PropertyAttributes filter,
15222     typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15223   DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
15224   int capacity = DerivedHashTable::Capacity();
15225   for (int i = 0; i < capacity; i++) {
15226     Object* k = DerivedHashTable::KeyAt(i);
15227     if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
15228       PropertyDetails details = DetailsAt(i);
15229       if (details.IsDeleted()) continue;
15230       PropertyAttributes attr = details.attributes();
15231       if ((attr & filter) == 0) storage->set(index++, k);
15232     }
15233   }
15234   if (sort_mode == Dictionary::SORTED) {
15235     storage->SortPairs(storage, index);
15236   }
15237   DCHECK(storage->length() >= index);
15238 }
15239 
15240 
15241 // Backwards lookup (slow).
15242 template<typename Derived, typename Shape, typename Key>
SlowReverseLookup(Object * value)15243 Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
15244   int capacity = DerivedHashTable::Capacity();
15245   for (int i = 0; i < capacity; i++) {
15246     Object* k =  DerivedHashTable::KeyAt(i);
15247     if (Dictionary::IsKey(k)) {
15248       Object* e = ValueAt(i);
15249       if (e->IsPropertyCell()) {
15250         e = PropertyCell::cast(e)->value();
15251       }
15252       if (e == value) return k;
15253     }
15254   }
15255   Heap* heap = Dictionary::GetHeap();
15256   return heap->undefined_value();
15257 }
15258 
15259 
Lookup(Handle<Object> key)15260 Object* ObjectHashTable::Lookup(Handle<Object> key) {
15261   DisallowHeapAllocation no_gc;
15262   DCHECK(IsKey(*key));
15263 
15264   // If the object does not have an identity hash, it was never used as a key.
15265   Object* hash = key->GetHash();
15266   if (hash->IsUndefined()) {
15267     return GetHeap()->the_hole_value();
15268   }
15269   int entry = FindEntry(key);
15270   if (entry == kNotFound) return GetHeap()->the_hole_value();
15271   return get(EntryToIndex(entry) + 1);
15272 }
15273 
15274 
Put(Handle<ObjectHashTable> table,Handle<Object> key,Handle<Object> value)15275 Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
15276                                              Handle<Object> key,
15277                                              Handle<Object> value) {
15278   DCHECK(table->IsKey(*key));
15279   DCHECK(!value->IsTheHole());
15280 
15281   Isolate* isolate = table->GetIsolate();
15282 
15283   // Make sure the key object has an identity hash code.
15284   Handle<Smi> hash = Object::GetOrCreateHash(isolate, key);
15285 
15286   int entry = table->FindEntry(key);
15287 
15288   // Key is already in table, just overwrite value.
15289   if (entry != kNotFound) {
15290     table->set(EntryToIndex(entry) + 1, *value);
15291     return table;
15292   }
15293 
15294   // Check whether the hash table should be extended.
15295   table = EnsureCapacity(table, 1, key);
15296   table->AddEntry(table->FindInsertionEntry(hash->value()),
15297                   *key,
15298                   *value);
15299   return table;
15300 }
15301 
15302 
Remove(Handle<ObjectHashTable> table,Handle<Object> key,bool * was_present)15303 Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
15304                                                 Handle<Object> key,
15305                                                 bool* was_present) {
15306   DCHECK(table->IsKey(*key));
15307 
15308   Object* hash = key->GetHash();
15309   if (hash->IsUndefined()) {
15310     *was_present = false;
15311     return table;
15312   }
15313 
15314   int entry = table->FindEntry(key);
15315   if (entry == kNotFound) {
15316     *was_present = false;
15317     return table;
15318   }
15319 
15320   *was_present = true;
15321   table->RemoveEntry(entry);
15322   return Shrink(table, key);
15323 }
15324 
15325 
AddEntry(int entry,Object * key,Object * value)15326 void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
15327   set(EntryToIndex(entry), key);
15328   set(EntryToIndex(entry) + 1, value);
15329   ElementAdded();
15330 }
15331 
15332 
RemoveEntry(int entry)15333 void ObjectHashTable::RemoveEntry(int entry) {
15334   set_the_hole(EntryToIndex(entry));
15335   set_the_hole(EntryToIndex(entry) + 1);
15336   ElementRemoved();
15337 }
15338 
15339 
Lookup(Handle<Object> key)15340 Object* WeakHashTable::Lookup(Handle<Object> key) {
15341   DisallowHeapAllocation no_gc;
15342   DCHECK(IsKey(*key));
15343   int entry = FindEntry(key);
15344   if (entry == kNotFound) return GetHeap()->the_hole_value();
15345   return get(EntryToValueIndex(entry));
15346 }
15347 
15348 
Put(Handle<WeakHashTable> table,Handle<Object> key,Handle<Object> value)15349 Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
15350                                          Handle<Object> key,
15351                                          Handle<Object> value) {
15352   DCHECK(table->IsKey(*key));
15353   int entry = table->FindEntry(key);
15354   // Key is already in table, just overwrite value.
15355   if (entry != kNotFound) {
15356     // TODO(ulan): Skipping write barrier is a temporary solution to avoid
15357     // memory leaks. Remove this once we have special visitor for weak fixed
15358     // arrays.
15359     table->set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
15360     return table;
15361   }
15362 
15363   // Check whether the hash table should be extended.
15364   table = EnsureCapacity(table, 1, key, TENURED);
15365 
15366   table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key, value);
15367   return table;
15368 }
15369 
15370 
AddEntry(int entry,Handle<Object> key,Handle<Object> value)15371 void WeakHashTable::AddEntry(int entry,
15372                              Handle<Object> key,
15373                              Handle<Object> value) {
15374   DisallowHeapAllocation no_allocation;
15375   // TODO(ulan): Skipping write barrier is a temporary solution to avoid
15376   // memory leaks. Remove this once we have special visitor for weak fixed
15377   // arrays.
15378   set(EntryToIndex(entry), *key, SKIP_WRITE_BARRIER);
15379   set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
15380   ElementAdded();
15381 }
15382 
15383 
15384 template<class Derived, class Iterator, int entrysize>
Allocate(Isolate * isolate,int capacity,PretenureFlag pretenure)15385 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
15386     Isolate* isolate, int capacity, PretenureFlag pretenure) {
15387   // Capacity must be a power of two, since we depend on being able
15388   // to divide and multiple by 2 (kLoadFactor) to derive capacity
15389   // from number of buckets. If we decide to change kLoadFactor
15390   // to something other than 2, capacity should be stored as another
15391   // field of this object.
15392   capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
15393   if (capacity > kMaxCapacity) {
15394     v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
15395   }
15396   int num_buckets = capacity / kLoadFactor;
15397   Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
15398       kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
15399   backing_store->set_map_no_write_barrier(
15400       isolate->heap()->ordered_hash_table_map());
15401   Handle<Derived> table = Handle<Derived>::cast(backing_store);
15402   for (int i = 0; i < num_buckets; ++i) {
15403     table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
15404   }
15405   table->SetNumberOfBuckets(num_buckets);
15406   table->SetNumberOfElements(0);
15407   table->SetNumberOfDeletedElements(0);
15408   return table;
15409 }
15410 
15411 
15412 template<class Derived, class Iterator, int entrysize>
EnsureGrowable(Handle<Derived> table)15413 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
15414     Handle<Derived> table) {
15415   DCHECK(!table->IsObsolete());
15416 
15417   int nof = table->NumberOfElements();
15418   int nod = table->NumberOfDeletedElements();
15419   int capacity = table->Capacity();
15420   if ((nof + nod) < capacity) return table;
15421   // Don't need to grow if we can simply clear out deleted entries instead.
15422   // Note that we can't compact in place, though, so we always allocate
15423   // a new table.
15424   return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
15425 }
15426 
15427 
15428 template<class Derived, class Iterator, int entrysize>
Shrink(Handle<Derived> table)15429 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
15430     Handle<Derived> table) {
15431   DCHECK(!table->IsObsolete());
15432 
15433   int nof = table->NumberOfElements();
15434   int capacity = table->Capacity();
15435   if (nof >= (capacity >> 2)) return table;
15436   return Rehash(table, capacity / 2);
15437 }
15438 
15439 
15440 template<class Derived, class Iterator, int entrysize>
Clear(Handle<Derived> table)15441 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
15442     Handle<Derived> table) {
15443   DCHECK(!table->IsObsolete());
15444 
15445   Handle<Derived> new_table =
15446       Allocate(table->GetIsolate(),
15447                kMinCapacity,
15448                table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
15449 
15450   table->SetNextTable(*new_table);
15451   table->SetNumberOfDeletedElements(-1);
15452 
15453   return new_table;
15454 }
15455 
15456 
15457 template<class Derived, class Iterator, int entrysize>
Remove(Handle<Derived> table,Handle<Object> key,bool * was_present)15458 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Remove(
15459     Handle<Derived> table, Handle<Object> key, bool* was_present) {
15460   int entry = table->FindEntry(key);
15461   if (entry == kNotFound) {
15462     *was_present = false;
15463     return table;
15464   }
15465   *was_present = true;
15466   table->RemoveEntry(entry);
15467   return Shrink(table);
15468 }
15469 
15470 
15471 template<class Derived, class Iterator, int entrysize>
Rehash(Handle<Derived> table,int new_capacity)15472 Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
15473     Handle<Derived> table, int new_capacity) {
15474   DCHECK(!table->IsObsolete());
15475 
15476   Handle<Derived> new_table =
15477       Allocate(table->GetIsolate(),
15478                new_capacity,
15479                table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
15480   int nof = table->NumberOfElements();
15481   int nod = table->NumberOfDeletedElements();
15482   int new_buckets = new_table->NumberOfBuckets();
15483   int new_entry = 0;
15484   int removed_holes_index = 0;
15485 
15486   for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
15487     Object* key = table->KeyAt(old_entry);
15488     if (key->IsTheHole()) {
15489       table->SetRemovedIndexAt(removed_holes_index++, old_entry);
15490       continue;
15491     }
15492 
15493     Object* hash = key->GetHash();
15494     int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
15495     Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
15496     new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
15497     int new_index = new_table->EntryToIndex(new_entry);
15498     int old_index = table->EntryToIndex(old_entry);
15499     for (int i = 0; i < entrysize; ++i) {
15500       Object* value = table->get(old_index + i);
15501       new_table->set(new_index + i, value);
15502     }
15503     new_table->set(new_index + kChainOffset, chain_entry);
15504     ++new_entry;
15505   }
15506 
15507   DCHECK_EQ(nod, removed_holes_index);
15508 
15509   new_table->SetNumberOfElements(nof);
15510   table->SetNextTable(*new_table);
15511 
15512   return new_table;
15513 }
15514 
15515 
15516 template <class Derived, class Iterator, int entrysize>
FindEntry(Handle<Object> key,int hash)15517 int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
15518     Handle<Object> key, int hash) {
15519   DCHECK(!IsObsolete());
15520 
15521   DisallowHeapAllocation no_gc;
15522   DCHECK(!key->IsTheHole());
15523   for (int entry = HashToEntry(hash); entry != kNotFound;
15524        entry = ChainAt(entry)) {
15525     Object* candidate = KeyAt(entry);
15526     if (candidate->SameValueZero(*key))
15527       return entry;
15528   }
15529   return kNotFound;
15530 }
15531 
15532 
15533 template <class Derived, class Iterator, int entrysize>
FindEntry(Handle<Object> key)15534 int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
15535     Handle<Object> key) {
15536   DisallowHeapAllocation no_gc;
15537   Object* hash = key->GetHash();
15538   if (!hash->IsSmi()) return kNotFound;
15539   return FindEntry(key, Smi::cast(hash)->value());
15540 }
15541 
15542 
15543 template <class Derived, class Iterator, int entrysize>
AddEntry(int hash)15544 int OrderedHashTable<Derived, Iterator, entrysize>::AddEntry(int hash) {
15545   DCHECK(!IsObsolete());
15546 
15547   int entry = UsedCapacity();
15548   int bucket = HashToBucket(hash);
15549   int index = EntryToIndex(entry);
15550   Object* chain_entry = get(kHashTableStartIndex + bucket);
15551   set(kHashTableStartIndex + bucket, Smi::FromInt(entry));
15552   set(index + kChainOffset, chain_entry);
15553   SetNumberOfElements(NumberOfElements() + 1);
15554   return index;
15555 }
15556 
15557 
15558 template<class Derived, class Iterator, int entrysize>
RemoveEntry(int entry)15559 void OrderedHashTable<Derived, Iterator, entrysize>::RemoveEntry(int entry) {
15560   DCHECK(!IsObsolete());
15561 
15562   int index = EntryToIndex(entry);
15563   for (int i = 0; i < entrysize; ++i) {
15564     set_the_hole(index + i);
15565   }
15566   SetNumberOfElements(NumberOfElements() - 1);
15567   SetNumberOfDeletedElements(NumberOfDeletedElements() + 1);
15568 }
15569 
15570 
15571 template Handle<OrderedHashSet>
15572 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
15573     Isolate* isolate, int capacity, PretenureFlag pretenure);
15574 
15575 template Handle<OrderedHashSet>
15576 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
15577     Handle<OrderedHashSet> table);
15578 
15579 template Handle<OrderedHashSet>
15580 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
15581     Handle<OrderedHashSet> table);
15582 
15583 template Handle<OrderedHashSet>
15584 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
15585     Handle<OrderedHashSet> table);
15586 
15587 template Handle<OrderedHashSet>
15588 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Remove(
15589     Handle<OrderedHashSet> table, Handle<Object> key, bool* was_present);
15590 
15591 template int OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::FindEntry(
15592     Handle<Object> key, int hash);
15593 template int OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::FindEntry(
15594     Handle<Object> key);
15595 
15596 template int
15597 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::AddEntry(int hash);
15598 
15599 template void
15600 OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::RemoveEntry(int entry);
15601 
15602 
15603 template Handle<OrderedHashMap>
15604 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
15605     Isolate* isolate, int capacity, PretenureFlag pretenure);
15606 
15607 template Handle<OrderedHashMap>
15608 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
15609     Handle<OrderedHashMap> table);
15610 
15611 template Handle<OrderedHashMap>
15612 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
15613     Handle<OrderedHashMap> table);
15614 
15615 template Handle<OrderedHashMap>
15616 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
15617     Handle<OrderedHashMap> table);
15618 
15619 template Handle<OrderedHashMap>
15620 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Remove(
15621     Handle<OrderedHashMap> table, Handle<Object> key, bool* was_present);
15622 
15623 template int OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::FindEntry(
15624     Handle<Object> key, int hash);
15625 template int OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::FindEntry(
15626     Handle<Object> key);
15627 
15628 template int
15629 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::AddEntry(int hash);
15630 
15631 template void
15632 OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::RemoveEntry(int entry);
15633 
15634 
Contains(Handle<Object> key)15635 bool OrderedHashSet::Contains(Handle<Object> key) {
15636   return FindEntry(key) != kNotFound;
15637 }
15638 
15639 
Add(Handle<OrderedHashSet> table,Handle<Object> key)15640 Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
15641                                            Handle<Object> key) {
15642   int hash = GetOrCreateHash(table->GetIsolate(), key)->value();
15643   if (table->FindEntry(key, hash) != kNotFound) return table;
15644 
15645   table = EnsureGrowable(table);
15646 
15647   int index = table->AddEntry(hash);
15648   table->set(index, *key);
15649   return table;
15650 }
15651 
15652 
Lookup(Handle<Object> key)15653 Object* OrderedHashMap::Lookup(Handle<Object> key) {
15654   DisallowHeapAllocation no_gc;
15655   int entry = FindEntry(key);
15656   if (entry == kNotFound) return GetHeap()->the_hole_value();
15657   return ValueAt(entry);
15658 }
15659 
15660 
Put(Handle<OrderedHashMap> table,Handle<Object> key,Handle<Object> value)15661 Handle<OrderedHashMap> OrderedHashMap::Put(Handle<OrderedHashMap> table,
15662                                            Handle<Object> key,
15663                                            Handle<Object> value) {
15664   DCHECK(!key->IsTheHole());
15665 
15666   int hash = GetOrCreateHash(table->GetIsolate(), key)->value();
15667   int entry = table->FindEntry(key, hash);
15668 
15669   if (entry != kNotFound) {
15670     table->set(table->EntryToIndex(entry) + kValueOffset, *value);
15671     return table;
15672   }
15673 
15674   table = EnsureGrowable(table);
15675 
15676   int index = table->AddEntry(hash);
15677   table->set(index, *key);
15678   table->set(index + kValueOffset, *value);
15679   return table;
15680 }
15681 
15682 
15683 template<class Derived, class TableType>
Transition()15684 void OrderedHashTableIterator<Derived, TableType>::Transition() {
15685   DisallowHeapAllocation no_allocation;
15686   TableType* table = TableType::cast(this->table());
15687   if (!table->IsObsolete()) return;
15688 
15689   int index = Smi::cast(this->index())->value();
15690   while (table->IsObsolete()) {
15691     TableType* next_table = table->NextTable();
15692 
15693     if (index > 0) {
15694       int nod = table->NumberOfDeletedElements();
15695 
15696       // When we clear the table we set the number of deleted elements to -1.
15697       if (nod == -1) {
15698         index = 0;
15699       } else {
15700         int old_index = index;
15701         for (int i = 0; i < nod; ++i) {
15702           int removed_index = table->RemovedIndexAt(i);
15703           if (removed_index >= old_index) break;
15704           --index;
15705         }
15706       }
15707     }
15708 
15709     table = next_table;
15710   }
15711 
15712   set_table(table);
15713   set_index(Smi::FromInt(index));
15714 }
15715 
15716 
15717 template<class Derived, class TableType>
HasMore()15718 bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
15719   DisallowHeapAllocation no_allocation;
15720   if (this->table()->IsUndefined()) return false;
15721 
15722   Transition();
15723 
15724   TableType* table = TableType::cast(this->table());
15725   int index = Smi::cast(this->index())->value();
15726   int used_capacity = table->UsedCapacity();
15727 
15728   while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
15729     index++;
15730   }
15731 
15732   set_index(Smi::FromInt(index));
15733 
15734   if (index < used_capacity) return true;
15735 
15736   set_table(GetHeap()->undefined_value());
15737   return false;
15738 }
15739 
15740 
15741 template<class Derived, class TableType>
Next(JSArray * value_array)15742 Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
15743   DisallowHeapAllocation no_allocation;
15744   if (HasMore()) {
15745     FixedArray* array = FixedArray::cast(value_array->elements());
15746     static_cast<Derived*>(this)->PopulateValueArray(array);
15747     MoveNext();
15748     return Smi::cast(kind());
15749   }
15750   return Smi::FromInt(0);
15751 }
15752 
15753 
15754 template Smi*
15755 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
15756     JSArray* value_array);
15757 
15758 template bool
15759 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
15760 
15761 template void
15762 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
15763 
15764 template Object*
15765 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
15766 
15767 template void
15768 OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
15769 
15770 
15771 template Smi*
15772 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
15773     JSArray* value_array);
15774 
15775 template bool
15776 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
15777 
15778 template void
15779 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
15780 
15781 template Object*
15782 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
15783 
15784 template void
15785 OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
15786 
15787 
DeclaredAccessorDescriptorIterator(DeclaredAccessorDescriptor * descriptor)15788 DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
15789     DeclaredAccessorDescriptor* descriptor)
15790     : array_(descriptor->serialized_data()->GetDataStartAddress()),
15791       length_(descriptor->serialized_data()->length()),
15792       offset_(0) {
15793 }
15794 
15795 
15796 const DeclaredAccessorDescriptorData*
Next()15797   DeclaredAccessorDescriptorIterator::Next() {
15798   DCHECK(offset_ < length_);
15799   uint8_t* ptr = &array_[offset_];
15800   DCHECK(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
15801   const DeclaredAccessorDescriptorData* data =
15802       reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
15803   offset_ += sizeof(*data);
15804   DCHECK(offset_ <= length_);
15805   return data;
15806 }
15807 
15808 
Create(Isolate * isolate,const DeclaredAccessorDescriptorData & descriptor,Handle<DeclaredAccessorDescriptor> previous)15809 Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
15810     Isolate* isolate,
15811     const DeclaredAccessorDescriptorData& descriptor,
15812     Handle<DeclaredAccessorDescriptor> previous) {
15813   int previous_length =
15814       previous.is_null() ? 0 : previous->serialized_data()->length();
15815   int length = sizeof(descriptor) + previous_length;
15816   Handle<ByteArray> serialized_descriptor =
15817       isolate->factory()->NewByteArray(length);
15818   Handle<DeclaredAccessorDescriptor> value =
15819       isolate->factory()->NewDeclaredAccessorDescriptor();
15820   value->set_serialized_data(*serialized_descriptor);
15821   // Copy in the data.
15822   {
15823     DisallowHeapAllocation no_allocation;
15824     uint8_t* array = serialized_descriptor->GetDataStartAddress();
15825     if (previous_length != 0) {
15826       uint8_t* previous_array =
15827           previous->serialized_data()->GetDataStartAddress();
15828       MemCopy(array, previous_array, previous_length);
15829       array += previous_length;
15830     }
15831     DCHECK(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
15832     DeclaredAccessorDescriptorData* data =
15833         reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
15834     *data = descriptor;
15835   }
15836   return value;
15837 }
15838 
15839 
15840 // Check if there is a break point at this code position.
HasBreakPoint(int code_position)15841 bool DebugInfo::HasBreakPoint(int code_position) {
15842   // Get the break point info object for this code position.
15843   Object* break_point_info = GetBreakPointInfo(code_position);
15844 
15845   // If there is no break point info object or no break points in the break
15846   // point info object there is no break point at this code position.
15847   if (break_point_info->IsUndefined()) return false;
15848   return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
15849 }
15850 
15851 
15852 // Get the break point info object for this code position.
GetBreakPointInfo(int code_position)15853 Object* DebugInfo::GetBreakPointInfo(int code_position) {
15854   // Find the index of the break point info object for this code position.
15855   int index = GetBreakPointInfoIndex(code_position);
15856 
15857   // Return the break point info object if any.
15858   if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
15859   return BreakPointInfo::cast(break_points()->get(index));
15860 }
15861 
15862 
15863 // Clear a break point at the specified code position.
ClearBreakPoint(Handle<DebugInfo> debug_info,int code_position,Handle<Object> break_point_object)15864 void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
15865                                 int code_position,
15866                                 Handle<Object> break_point_object) {
15867   Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
15868                                   debug_info->GetIsolate());
15869   if (break_point_info->IsUndefined()) return;
15870   BreakPointInfo::ClearBreakPoint(
15871       Handle<BreakPointInfo>::cast(break_point_info),
15872       break_point_object);
15873 }
15874 
15875 
SetBreakPoint(Handle<DebugInfo> debug_info,int code_position,int source_position,int statement_position,Handle<Object> break_point_object)15876 void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
15877                               int code_position,
15878                               int source_position,
15879                               int statement_position,
15880                               Handle<Object> break_point_object) {
15881   Isolate* isolate = debug_info->GetIsolate();
15882   Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
15883                                   isolate);
15884   if (!break_point_info->IsUndefined()) {
15885     BreakPointInfo::SetBreakPoint(
15886         Handle<BreakPointInfo>::cast(break_point_info),
15887         break_point_object);
15888     return;
15889   }
15890 
15891   // Adding a new break point for a code position which did not have any
15892   // break points before. Try to find a free slot.
15893   int index = kNoBreakPointInfo;
15894   for (int i = 0; i < debug_info->break_points()->length(); i++) {
15895     if (debug_info->break_points()->get(i)->IsUndefined()) {
15896       index = i;
15897       break;
15898     }
15899   }
15900   if (index == kNoBreakPointInfo) {
15901     // No free slot - extend break point info array.
15902     Handle<FixedArray> old_break_points =
15903         Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
15904     Handle<FixedArray> new_break_points =
15905         isolate->factory()->NewFixedArray(
15906             old_break_points->length() +
15907             DebugInfo::kEstimatedNofBreakPointsInFunction);
15908 
15909     debug_info->set_break_points(*new_break_points);
15910     for (int i = 0; i < old_break_points->length(); i++) {
15911       new_break_points->set(i, old_break_points->get(i));
15912     }
15913     index = old_break_points->length();
15914   }
15915   DCHECK(index != kNoBreakPointInfo);
15916 
15917   // Allocate new BreakPointInfo object and set the break point.
15918   Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
15919       isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
15920   new_break_point_info->set_code_position(Smi::FromInt(code_position));
15921   new_break_point_info->set_source_position(Smi::FromInt(source_position));
15922   new_break_point_info->
15923       set_statement_position(Smi::FromInt(statement_position));
15924   new_break_point_info->set_break_point_objects(
15925       isolate->heap()->undefined_value());
15926   BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
15927   debug_info->break_points()->set(index, *new_break_point_info);
15928 }
15929 
15930 
15931 // Get the break point objects for a code position.
GetBreakPointObjects(int code_position)15932 Object* DebugInfo::GetBreakPointObjects(int code_position) {
15933   Object* break_point_info = GetBreakPointInfo(code_position);
15934   if (break_point_info->IsUndefined()) {
15935     return GetHeap()->undefined_value();
15936   }
15937   return BreakPointInfo::cast(break_point_info)->break_point_objects();
15938 }
15939 
15940 
15941 // Get the total number of break points.
GetBreakPointCount()15942 int DebugInfo::GetBreakPointCount() {
15943   if (break_points()->IsUndefined()) return 0;
15944   int count = 0;
15945   for (int i = 0; i < break_points()->length(); i++) {
15946     if (!break_points()->get(i)->IsUndefined()) {
15947       BreakPointInfo* break_point_info =
15948           BreakPointInfo::cast(break_points()->get(i));
15949       count += break_point_info->GetBreakPointCount();
15950     }
15951   }
15952   return count;
15953 }
15954 
15955 
FindBreakPointInfo(Handle<DebugInfo> debug_info,Handle<Object> break_point_object)15956 Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
15957                                       Handle<Object> break_point_object) {
15958   Heap* heap = debug_info->GetHeap();
15959   if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
15960   for (int i = 0; i < debug_info->break_points()->length(); i++) {
15961     if (!debug_info->break_points()->get(i)->IsUndefined()) {
15962       Handle<BreakPointInfo> break_point_info =
15963           Handle<BreakPointInfo>(BreakPointInfo::cast(
15964               debug_info->break_points()->get(i)));
15965       if (BreakPointInfo::HasBreakPointObject(break_point_info,
15966                                               break_point_object)) {
15967         return *break_point_info;
15968       }
15969     }
15970   }
15971   return heap->undefined_value();
15972 }
15973 
15974 
15975 // Find the index of the break point info object for the specified code
15976 // position.
GetBreakPointInfoIndex(int code_position)15977 int DebugInfo::GetBreakPointInfoIndex(int code_position) {
15978   if (break_points()->IsUndefined()) return kNoBreakPointInfo;
15979   for (int i = 0; i < break_points()->length(); i++) {
15980     if (!break_points()->get(i)->IsUndefined()) {
15981       BreakPointInfo* break_point_info =
15982           BreakPointInfo::cast(break_points()->get(i));
15983       if (break_point_info->code_position()->value() == code_position) {
15984         return i;
15985       }
15986     }
15987   }
15988   return kNoBreakPointInfo;
15989 }
15990 
15991 
15992 // Remove the specified break point object.
ClearBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)15993 void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
15994                                      Handle<Object> break_point_object) {
15995   Isolate* isolate = break_point_info->GetIsolate();
15996   // If there are no break points just ignore.
15997   if (break_point_info->break_point_objects()->IsUndefined()) return;
15998   // If there is a single break point clear it if it is the same.
15999   if (!break_point_info->break_point_objects()->IsFixedArray()) {
16000     if (break_point_info->break_point_objects() == *break_point_object) {
16001       break_point_info->set_break_point_objects(
16002           isolate->heap()->undefined_value());
16003     }
16004     return;
16005   }
16006   // If there are multiple break points shrink the array
16007   DCHECK(break_point_info->break_point_objects()->IsFixedArray());
16008   Handle<FixedArray> old_array =
16009       Handle<FixedArray>(
16010           FixedArray::cast(break_point_info->break_point_objects()));
16011   Handle<FixedArray> new_array =
16012       isolate->factory()->NewFixedArray(old_array->length() - 1);
16013   int found_count = 0;
16014   for (int i = 0; i < old_array->length(); i++) {
16015     if (old_array->get(i) == *break_point_object) {
16016       DCHECK(found_count == 0);
16017       found_count++;
16018     } else {
16019       new_array->set(i - found_count, old_array->get(i));
16020     }
16021   }
16022   // If the break point was found in the list change it.
16023   if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
16024 }
16025 
16026 
16027 // Add the specified break point object.
SetBreakPoint(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)16028 void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
16029                                    Handle<Object> break_point_object) {
16030   Isolate* isolate = break_point_info->GetIsolate();
16031 
16032   // If there was no break point objects before just set it.
16033   if (break_point_info->break_point_objects()->IsUndefined()) {
16034     break_point_info->set_break_point_objects(*break_point_object);
16035     return;
16036   }
16037   // If the break point object is the same as before just ignore.
16038   if (break_point_info->break_point_objects() == *break_point_object) return;
16039   // If there was one break point object before replace with array.
16040   if (!break_point_info->break_point_objects()->IsFixedArray()) {
16041     Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
16042     array->set(0, break_point_info->break_point_objects());
16043     array->set(1, *break_point_object);
16044     break_point_info->set_break_point_objects(*array);
16045     return;
16046   }
16047   // If there was more than one break point before extend array.
16048   Handle<FixedArray> old_array =
16049       Handle<FixedArray>(
16050           FixedArray::cast(break_point_info->break_point_objects()));
16051   Handle<FixedArray> new_array =
16052       isolate->factory()->NewFixedArray(old_array->length() + 1);
16053   for (int i = 0; i < old_array->length(); i++) {
16054     // If the break point was there before just ignore.
16055     if (old_array->get(i) == *break_point_object) return;
16056     new_array->set(i, old_array->get(i));
16057   }
16058   // Add the new break point.
16059   new_array->set(old_array->length(), *break_point_object);
16060   break_point_info->set_break_point_objects(*new_array);
16061 }
16062 
16063 
HasBreakPointObject(Handle<BreakPointInfo> break_point_info,Handle<Object> break_point_object)16064 bool BreakPointInfo::HasBreakPointObject(
16065     Handle<BreakPointInfo> break_point_info,
16066     Handle<Object> break_point_object) {
16067   // No break point.
16068   if (break_point_info->break_point_objects()->IsUndefined()) return false;
16069   // Single break point.
16070   if (!break_point_info->break_point_objects()->IsFixedArray()) {
16071     return break_point_info->break_point_objects() == *break_point_object;
16072   }
16073   // Multiple break points.
16074   FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
16075   for (int i = 0; i < array->length(); i++) {
16076     if (array->get(i) == *break_point_object) {
16077       return true;
16078     }
16079   }
16080   return false;
16081 }
16082 
16083 
16084 // Get the number of break points.
GetBreakPointCount()16085 int BreakPointInfo::GetBreakPointCount() {
16086   // No break point.
16087   if (break_point_objects()->IsUndefined()) return 0;
16088   // Single break point.
16089   if (!break_point_objects()->IsFixedArray()) return 1;
16090   // Multiple break points.
16091   return FixedArray::cast(break_point_objects())->length();
16092 }
16093 
16094 
GetField(Object * object,Smi * index)16095 Object* JSDate::GetField(Object* object, Smi* index) {
16096   return JSDate::cast(object)->DoGetField(
16097       static_cast<FieldIndex>(index->value()));
16098 }
16099 
16100 
DoGetField(FieldIndex index)16101 Object* JSDate::DoGetField(FieldIndex index) {
16102   DCHECK(index != kDateValue);
16103 
16104   DateCache* date_cache = GetIsolate()->date_cache();
16105 
16106   if (index < kFirstUncachedField) {
16107     Object* stamp = cache_stamp();
16108     if (stamp != date_cache->stamp() && stamp->IsSmi()) {
16109       // Since the stamp is not NaN, the value is also not NaN.
16110       int64_t local_time_ms =
16111           date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
16112       SetCachedFields(local_time_ms, date_cache);
16113     }
16114     switch (index) {
16115       case kYear: return year();
16116       case kMonth: return month();
16117       case kDay: return day();
16118       case kWeekday: return weekday();
16119       case kHour: return hour();
16120       case kMinute: return min();
16121       case kSecond: return sec();
16122       default: UNREACHABLE();
16123     }
16124   }
16125 
16126   if (index >= kFirstUTCField) {
16127     return GetUTCField(index, value()->Number(), date_cache);
16128   }
16129 
16130   double time = value()->Number();
16131   if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
16132 
16133   int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
16134   int days = DateCache::DaysFromTime(local_time_ms);
16135 
16136   if (index == kDays) return Smi::FromInt(days);
16137 
16138   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16139   if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
16140   DCHECK(index == kTimeInDay);
16141   return Smi::FromInt(time_in_day_ms);
16142 }
16143 
16144 
GetUTCField(FieldIndex index,double value,DateCache * date_cache)16145 Object* JSDate::GetUTCField(FieldIndex index,
16146                             double value,
16147                             DateCache* date_cache) {
16148   DCHECK(index >= kFirstUTCField);
16149 
16150   if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
16151 
16152   int64_t time_ms = static_cast<int64_t>(value);
16153 
16154   if (index == kTimezoneOffset) {
16155     return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
16156   }
16157 
16158   int days = DateCache::DaysFromTime(time_ms);
16159 
16160   if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
16161 
16162   if (index <= kDayUTC) {
16163     int year, month, day;
16164     date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16165     if (index == kYearUTC) return Smi::FromInt(year);
16166     if (index == kMonthUTC) return Smi::FromInt(month);
16167     DCHECK(index == kDayUTC);
16168     return Smi::FromInt(day);
16169   }
16170 
16171   int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
16172   switch (index) {
16173     case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
16174     case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
16175     case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
16176     case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
16177     case kDaysUTC: return Smi::FromInt(days);
16178     case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
16179     default: UNREACHABLE();
16180   }
16181 
16182   UNREACHABLE();
16183   return NULL;
16184 }
16185 
16186 
SetValue(Object * value,bool is_value_nan)16187 void JSDate::SetValue(Object* value, bool is_value_nan) {
16188   set_value(value);
16189   if (is_value_nan) {
16190     HeapNumber* nan = GetIsolate()->heap()->nan_value();
16191     set_cache_stamp(nan, SKIP_WRITE_BARRIER);
16192     set_year(nan, SKIP_WRITE_BARRIER);
16193     set_month(nan, SKIP_WRITE_BARRIER);
16194     set_day(nan, SKIP_WRITE_BARRIER);
16195     set_hour(nan, SKIP_WRITE_BARRIER);
16196     set_min(nan, SKIP_WRITE_BARRIER);
16197     set_sec(nan, SKIP_WRITE_BARRIER);
16198     set_weekday(nan, SKIP_WRITE_BARRIER);
16199   } else {
16200     set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
16201   }
16202 }
16203 
16204 
SetCachedFields(int64_t local_time_ms,DateCache * date_cache)16205 void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
16206   int days = DateCache::DaysFromTime(local_time_ms);
16207   int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16208   int year, month, day;
16209   date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16210   int weekday = date_cache->Weekday(days);
16211   int hour = time_in_day_ms / (60 * 60 * 1000);
16212   int min = (time_in_day_ms / (60 * 1000)) % 60;
16213   int sec = (time_in_day_ms / 1000) % 60;
16214   set_cache_stamp(date_cache->stamp());
16215   set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
16216   set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
16217   set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
16218   set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
16219   set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
16220   set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
16221   set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
16222 }
16223 
16224 
Neuter()16225 void JSArrayBuffer::Neuter() {
16226   DCHECK(is_external());
16227   set_backing_store(NULL);
16228   set_byte_length(Smi::FromInt(0));
16229 }
16230 
16231 
NeuterView()16232 void JSArrayBufferView::NeuterView() {
16233   set_byte_offset(Smi::FromInt(0));
16234   set_byte_length(Smi::FromInt(0));
16235 }
16236 
16237 
Neuter()16238 void JSDataView::Neuter() {
16239   NeuterView();
16240 }
16241 
16242 
Neuter()16243 void JSTypedArray::Neuter() {
16244   NeuterView();
16245   set_length(Smi::FromInt(0));
16246   set_elements(GetHeap()->EmptyExternalArrayForMap(map()));
16247 }
16248 
16249 
FixedToExternalElementsKind(ElementsKind elements_kind)16250 static ElementsKind FixedToExternalElementsKind(ElementsKind elements_kind) {
16251   switch (elements_kind) {
16252 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
16253     case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS;
16254 
16255     TYPED_ARRAYS(TYPED_ARRAY_CASE)
16256 #undef TYPED_ARRAY_CASE
16257 
16258     default:
16259       UNREACHABLE();
16260       return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
16261   }
16262 }
16263 
16264 
MaterializeArrayBuffer(Handle<JSTypedArray> typed_array)16265 Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
16266     Handle<JSTypedArray> typed_array) {
16267 
16268   Handle<Map> map(typed_array->map());
16269   Isolate* isolate = typed_array->GetIsolate();
16270 
16271   DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
16272 
16273   Handle<Map> new_map = Map::TransitionElementsTo(
16274           map,
16275           FixedToExternalElementsKind(map->elements_kind()));
16276 
16277   Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
16278   Handle<FixedTypedArrayBase> fixed_typed_array(
16279       FixedTypedArrayBase::cast(typed_array->elements()));
16280   Runtime::SetupArrayBufferAllocatingData(isolate, buffer,
16281       fixed_typed_array->DataSize(), false);
16282   memcpy(buffer->backing_store(),
16283          fixed_typed_array->DataPtr(),
16284          fixed_typed_array->DataSize());
16285   Handle<ExternalArray> new_elements =
16286       isolate->factory()->NewExternalArray(
16287           fixed_typed_array->length(), typed_array->type(),
16288           static_cast<uint8_t*>(buffer->backing_store()));
16289 
16290   buffer->set_weak_first_view(*typed_array);
16291   DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value());
16292   typed_array->set_buffer(*buffer);
16293   JSObject::SetMapAndElements(typed_array, new_map, new_elements);
16294 
16295   return buffer;
16296 }
16297 
16298 
GetBuffer()16299 Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
16300   Handle<Object> result(buffer(), GetIsolate());
16301   if (*result != Smi::FromInt(0)) {
16302     DCHECK(IsExternalArrayElementsKind(map()->elements_kind()));
16303     return Handle<JSArrayBuffer>::cast(result);
16304   }
16305   Handle<JSTypedArray> self(this);
16306   return MaterializeArrayBuffer(self);
16307 }
16308 
16309 
type()16310 HeapType* PropertyCell::type() {
16311   return static_cast<HeapType*>(type_raw());
16312 }
16313 
16314 
set_type(HeapType * type,WriteBarrierMode ignored)16315 void PropertyCell::set_type(HeapType* type, WriteBarrierMode ignored) {
16316   DCHECK(IsPropertyCell());
16317   set_type_raw(type, ignored);
16318 }
16319 
16320 
UpdatedType(Handle<PropertyCell> cell,Handle<Object> value)16321 Handle<HeapType> PropertyCell::UpdatedType(Handle<PropertyCell> cell,
16322                                            Handle<Object> value) {
16323   Isolate* isolate = cell->GetIsolate();
16324   Handle<HeapType> old_type(cell->type(), isolate);
16325   Handle<HeapType> new_type = HeapType::Constant(value, isolate);
16326 
16327   if (new_type->Is(old_type)) return old_type;
16328 
16329   cell->dependent_code()->DeoptimizeDependentCodeGroup(
16330       isolate, DependentCode::kPropertyCellChangedGroup);
16331 
16332   if (old_type->Is(HeapType::None()) || old_type->Is(HeapType::Undefined())) {
16333     return new_type;
16334   }
16335 
16336   return HeapType::Any(isolate);
16337 }
16338 
16339 
SetValueInferType(Handle<PropertyCell> cell,Handle<Object> value)16340 void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
16341                                      Handle<Object> value) {
16342   cell->set_value(*value);
16343   if (!HeapType::Any()->Is(cell->type())) {
16344     Handle<HeapType> new_type = UpdatedType(cell, value);
16345     cell->set_type(*new_type);
16346   }
16347 }
16348 
16349 
16350 // static
AddDependentCompilationInfo(Handle<PropertyCell> cell,CompilationInfo * info)16351 void PropertyCell::AddDependentCompilationInfo(Handle<PropertyCell> cell,
16352                                                CompilationInfo* info) {
16353   Handle<DependentCode> codes =
16354       DependentCode::Insert(handle(cell->dependent_code(), info->isolate()),
16355                             DependentCode::kPropertyCellChangedGroup,
16356                             info->object_wrapper());
16357   if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes);
16358   info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add(
16359       cell, info->zone());
16360 }
16361 
16362 } }  // namespace v8::internal
16363